/**
 * Admin BI Dashboard - Business Intelligence Executive View
 * Admin-only: comprehensive KPIs, revenue analysis, client intelligence, operational metrics
 */
const { buildHeader, buildFooter, buildHead, getChartJsScript } = require('./ui-template');

function buildAdminBIHTML(user) {
  const role = user.role || 'admin';
  const pageScripts = getChartJsScript();

  const now = new Date();
  const firstDayOfMonth = new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10);
  const today = now.toISOString().slice(0, 10);
  const thirtyDaysAgo = new Date(now.getTime() - 30 * 86400000).toISOString().slice(0, 10);

  const pageCSS = `
  /* Smooth scroll for anchor navigation */
  html { scroll-behavior: smooth; scroll-padding-top: 20px; }

  /* === TRADING CONSOLE: Light Mode (professional clean) === */
  body.trading-console {
    --tc-accent: #1E8E3E;
    --tc-accent-bg: rgba(30,142,62,0.08);
    --tc-accent-border: rgba(30,142,62,0.15);
    --tc-glass: rgba(255,255,255,0.85);
    --tc-grid: rgba(0,0,0,0.06);
    background: var(--bg);
    color: var(--text);
  }

  /* === TRADING CONSOLE: Dark Mode (Bloomberg terminal) === */
  [data-theme="dark"] body.trading-console {
    --bg: #0D1117;
    --card: #131A24;
    --text: #E2E8F0;
    --text-secondary: #94A3B8;
    --text-muted: #64748B;
    --border: rgba(0,255,136,0.1);
    --green: #00FF88;
    --green-bg: rgba(0,255,136,0.08);
    --blue: #58A6FF;
    --blue-bg: rgba(88,166,255,0.08);
    --orange: #F0883E;
    --orange-bg: rgba(240,136,62,0.08);
    --red: #FF4444;
    --red-bg: rgba(255,68,68,0.08);
    --purple: #BC8CFF;
    --purple-bg: rgba(188,140,255,0.08);
    --admin-accent: #00FF88;
    --admin-bg: rgba(0,255,136,0.05);
    --tc-accent: #00FF88;
    --tc-accent-bg: rgba(0,255,136,0.08);
    --tc-accent-border: rgba(0,255,136,0.15);
    --tc-glass: rgba(15,25,35,0.92);
    --tc-grid: rgba(0,255,136,0.06);
    background: #0A0F18 !important;
    color: var(--text);
    color-scheme: dark;
  }

  /* Console Cards - Light */
  body.trading-console .hero-card,
  body.trading-console .chart-card,
  body.trading-console .metric-card,
  body.trading-console .filter-bar {
    background: var(--card);
    border: 1px solid var(--border);
    box-shadow: 0 2px 8px rgba(0,0,0,0.06);
  }
  /* Console Cards - Dark */
  [data-theme="dark"] body.trading-console .hero-card,
  [data-theme="dark"] body.trading-console .chart-card,
  [data-theme="dark"] body.trading-console .metric-card,
  [data-theme="dark"] body.trading-console .filter-bar {
    background: rgba(255,255,255,0.03);
    border: 1px solid rgba(0,255,136,0.1);
    box-shadow: 0 2px 12px rgba(0,0,0,0.3), inset 0 1px 0 rgba(0,255,136,0.05);
  }

  /* Console Values - Light: clean professional */
  body.trading-console .hero-value {
    font-variant-numeric: tabular-nums;
  }
  /* Console Values - Dark: monospace terminal */
  [data-theme="dark"] body.trading-console .hero-value {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
    text-shadow: 0 0 8px rgba(226,232,240,0.15);
  }

  /* Console Section Titles - Light */
  body.trading-console .section-title {
    color: var(--text-secondary);
    letter-spacing: 1px;
  }
  body.trading-console .section-title .icon {
    background: var(--tc-accent-bg) !important;
    color: var(--tc-accent) !important;
  }
  /* Console Section Titles - Dark */
  [data-theme="dark"] body.trading-console .section-title {
    color: rgba(0,255,136,0.7);
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
    letter-spacing: 2px;
  }
  [data-theme="dark"] body.trading-console .section-title .icon {
    background: rgba(0,255,136,0.08) !important;
    color: #00FF88 !important;
  }

  /* Console Tables - Light */
  body.trading-console .data-table th {
    background: var(--bg);
    color: var(--text-muted);
  }
  /* Console Tables - Dark */
  [data-theme="dark"] body.trading-console .data-table th {
    background: rgba(0,255,136,0.03);
    color: rgba(0,255,136,0.6);
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
  }
  [data-theme="dark"] body.trading-console .data-table td {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
    font-size: 12px;
    border-bottom-color: rgba(0,255,136,0.06);
  }
  [data-theme="dark"] body.trading-console .data-table tr:hover td {
    background: rgba(0,255,136,0.05);
  }

  /* Console Buttons - Dark only overrides */
  [data-theme="dark"] body.trading-console .preset-btn {
    background: rgba(255,255,255,0.03);
    color: var(--text-secondary);
    border-color: rgba(0,255,136,0.1);
  }
  [data-theme="dark"] body.trading-console .preset-btn:hover {
    border-color: #00FF88; color: #00FF88;
  }
  [data-theme="dark"] body.trading-console .preset-btn.active {
    background: rgba(0,255,136,0.15);
    color: #00FF88; border-color: rgba(0,255,136,0.3);
  }
  [data-theme="dark"] body.trading-console .gran-btn {
    background: rgba(255,255,255,0.03);
    color: var(--text-secondary);
    border-color: rgba(0,255,136,0.1);
  }
  [data-theme="dark"] body.trading-console .gran-btn:hover {
    border-color: #F9A825; color: #F9A825;
  }
  [data-theme="dark"] body.trading-console .gran-btn.active {
    background: rgba(249,168,37,0.15);
    color: #F9A825; border-color: rgba(249,168,37,0.3);
  }
  [data-theme="dark"] body.trading-console .date-inputs input[type="date"] {
    background: rgba(255,255,255,0.03);
    color: var(--text); border-color: rgba(0,255,136,0.1);
  }

  /* Console Ranks - Dark */
  [data-theme="dark"] body.trading-console .rank-1 { background: rgba(249,168,37,0.15); color: #F9A825; }
  [data-theme="dark"] body.trading-console .rank-2 { background: rgba(255,255,255,0.08); color: #9AA0A6; }
  [data-theme="dark"] body.trading-console .rank-3 { background: rgba(216,67,21,0.15); color: #FF7043; }
  [data-theme="dark"] body.trading-console .rank-default { background: rgba(255,255,255,0.05); }

  /* Console Loading - Dark */
  [data-theme="dark"] body.trading-console .loading-overlay { background: rgba(10,15,24,0.85); }

  /* Console Footer - Dark */
  [data-theme="dark"] body.trading-console .app-footer {
    background: #0A0F18; border-top-color: rgba(0,255,136,0.1); color: var(--text-muted);
  }

  /* Console Scrollbars - Dark */
  [data-theme="dark"] body.trading-console ::-webkit-scrollbar { width: 6px; height: 6px; }
  [data-theme="dark"] body.trading-console ::-webkit-scrollbar-track { background: rgba(0,0,0,0.2); }
  [data-theme="dark"] body.trading-console ::-webkit-scrollbar-thumb { background: rgba(0,255,136,0.2); border-radius: 3px; }
  [data-theme="dark"] body.trading-console ::-webkit-scrollbar-thumb:hover { background: rgba(0,255,136,0.35); }

  /* === Folder-Tab Navigation (right edge) === */
  .console-nav {
    position: fixed; right: 0; top: 50%; transform: translateY(-50%);
    z-index: 1000; display: flex; flex-direction: column; gap: 0;
    padding: 0;
    background: none;
  }
  .console-nav-btn {
    display: flex; flex-direction: column; align-items: center; justify-content: center;
    gap: 6px;
    width: 38px;
    padding: 14px 0;
    background: var(--card);
    border: 1px solid var(--border);
    border-right: none;
    border-radius: 8px 0 0 8px;
    margin-bottom: -1px;
    color: var(--text-muted);
    font-size: 11px; font-weight: 600;
    cursor: pointer; transition: all 0.2s ease;
    text-decoration: none; position: relative;
    box-shadow: -2px 0 6px rgba(0,0,0,0.04);
  }
  .console-nav-btn:hover {
    color: var(--text);
    background: var(--bg);
    width: 42px;
  }
  .console-nav-btn.active {
    color: var(--tc-accent);
    background: var(--bg);
    width: 44px;
    border-color: var(--tc-accent);
    border-right: 1px solid var(--bg);
    z-index: 2;
    box-shadow: -3px 0 10px rgba(0,0,0,0.08);
  }
  /* Dark theme tabs */
  [data-theme="dark"] .console-nav-btn {
    background: #161B22;
    border-color: rgba(0,255,136,0.1);
    color: rgba(255,255,255,0.35);
    box-shadow: -2px 0 8px rgba(0,0,0,0.3);
  }
  [data-theme="dark"] .console-nav-btn:hover {
    background: #1A2332;
    color: rgba(255,255,255,0.7);
  }
  [data-theme="dark"] .console-nav-btn.active {
    background: #0D1117;
    color: #00FF88;
    border-color: rgba(0,255,136,0.3);
    border-right-color: #0D1117;
    box-shadow: -3px 0 12px rgba(0,0,0,0.4);
    text-shadow: 0 0 8px rgba(0,255,136,0.4);
  }

  .console-nav-btn .nav-icon {
    font-size: 15px; line-height: 1; flex-shrink: 0;
  }
  .console-nav-btn .nav-label {
    writing-mode: vertical-rl;
    text-orientation: mixed;
    font-size: 9px; letter-spacing: 1px; text-transform: uppercase;
    font-weight: 700;
    white-space: nowrap;
  }
  [data-theme="dark"] .console-nav-btn .nav-label {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
  }

  @media (min-width: 769px) {
    body.trading-console .app-container { padding-right: 50px; }
  }
  /* Tablet: icon + short label */
  @media (max-width: 900px) {
    .console-nav-btn { width: 34px; padding: 10px 0; }
    .console-nav-btn .nav-label { font-size: 8px; }
    .console-nav-btn:hover { width: 38px; }
    .console-nav-btn.active { width: 40px; }
  }
  /* Mobile: icon only */
  @media (max-width: 768px) {
    .console-nav-btn .nav-label { display: none; }
    .console-nav-btn { width: 36px; padding: 12px 0; }
    .console-nav-btn .nav-icon { font-size: 16px; }
    .console-nav-btn:hover { width: 40px; }
    .console-nav-btn.active { width: 42px; }
  }
  @media (max-width: 480px) {
    .console-nav-btn { width: 30px; padding: 10px 0; }
    .console-nav-btn .nav-icon { font-size: 13px; }
    .console-nav-btn:hover { width: 34px; }
    .console-nav-btn.active { width: 36px; }
  }

  /* Trading Terminal - Live Rates: Light */
  .trading-terminal {
    background: linear-gradient(135deg, #F8F9FB 0%, #EEF1F5 50%, #F0F2F5 100%);
    border-top: 1px solid var(--border);
    border-bottom: 1px solid var(--border);
    padding: 16px 40px;
    position: relative; overflow: hidden;
  }
  .trading-terminal::before {
    content: ''; position: absolute; top: 0; left: 0; right: 0; height: 1px;
    background: linear-gradient(90deg, transparent, rgba(30,142,62,0.2), transparent);
  }
  .trading-terminal::after {
    content: ''; position: absolute; bottom: 0; left: 0; right: 0; height: 1px;
    background: linear-gradient(90deg, transparent, rgba(30,142,62,0.2), transparent);
  }
  /* Trading Terminal - Dark */
  [data-theme="dark"] .trading-terminal {
    background: linear-gradient(135deg, #0F1923 0%, #1A2332 50%, #0D1B2A 100%);
    border-top: 1px solid rgba(0,255,136,0.15);
    border-bottom: 1px solid rgba(0,255,136,0.15);
  }
  [data-theme="dark"] .trading-terminal::before {
    background: linear-gradient(90deg, transparent, rgba(0,255,136,0.3), transparent);
  }
  [data-theme="dark"] .trading-terminal::after {
    background: linear-gradient(90deg, transparent, rgba(0,255,136,0.3), transparent);
  }
  .live-rate-bar {
    display: flex; align-items: center; justify-content: center; gap: 20px;
    max-width: 1600px; margin: 0 auto;
  }
  .terminal-title {
    font-size: 10px; font-weight: 700; color: var(--tc-accent);
    text-transform: uppercase; letter-spacing: 2px; margin-right: 8px;
    opacity: 0.7;
  }
  [data-theme="dark"] .terminal-title {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
  }
  .live-rate-dot {
    width: 7px; height: 7px; border-radius: 50%; background: var(--tc-accent);
    display: inline-block; animation: blink 1.5s infinite;
    box-shadow: 0 0 6px var(--tc-accent-bg);
  }
  @keyframes blink { 0%, 100% { opacity: 1; } 50% { opacity: 0.2; } }
  .rate-pair-group {
    display: flex; align-items: center; gap: 8px;
    background: var(--card);
    border: 1px solid var(--border);
    border-radius: 8px; padding: 8px 14px;
  }
  [data-theme="dark"] .rate-pair-group {
    background: rgba(255,255,255,0.03);
    border-color: rgba(255,255,255,0.06);
  }
  .rate-pair-label {
    font-size: 11px; font-weight: 800; color: var(--text-muted);
    text-transform: uppercase; letter-spacing: 1px; writing-mode: vertical-rl;
    text-orientation: mixed;
  }
  [data-theme="dark"] .rate-pair-label {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
    color: rgba(255,255,255,0.35);
  }
  .live-rate-btn {
    display: flex; flex-direction: column; align-items: center; gap: 1px;
    padding: 8px 18px; border-radius: 6px; border: 1px solid transparent;
    font-family: inherit; font-size: 14px; font-weight: 700; cursor: default;
    transition: all 0.25s; min-width: 150px; justify-content: center; position: relative;
  }
  .rate-flags { font-size: 9px; opacity: 0.5; letter-spacing: 1px; line-height: 1; }
  .live-rate-btn.compra { background: var(--green-bg); color: var(--green); border-color: rgba(30,142,62,0.2); }
  .live-rate-btn.compra:hover { background: rgba(30,142,62,0.12); }
  .live-rate-btn.venda { background: var(--red-bg); color: var(--red); border-color: rgba(217,48,37,0.2); }
  .live-rate-btn.venda:hover { background: rgba(217,48,37,0.12); }
  [data-theme="dark"] .live-rate-btn.compra { background: rgba(0,255,136,0.08); color: #00FF88; border-color: rgba(0,255,136,0.2); }
  [data-theme="dark"] .live-rate-btn.compra:hover { background: rgba(0,255,136,0.14); }
  [data-theme="dark"] .live-rate-btn.venda { background: rgba(255,68,68,0.08); color: #FF4444; border-color: rgba(255,68,68,0.2); }
  [data-theme="dark"] .live-rate-btn.venda:hover { background: rgba(255,68,68,0.14); }
  .live-rate-btn .rate-value {
    font-size: 22px; font-weight: 800; letter-spacing: -0.5px;
    font-variant-numeric: tabular-nums;
  }
  [data-theme="dark"] .live-rate-btn .rate-value {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
    text-shadow: 0 0 12px currentColor;
  }
  .live-rate-btn .rate-type {
    font-size: 9px; text-transform: uppercase; letter-spacing: 1.5px;
    opacity: 0.5;
  }
  [data-theme="dark"] .live-rate-btn .rate-type {
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
  }
  .live-rate-btn.pulse .rate-value { animation: ratePulse 0.4s ease; }
  @keyframes ratePulse {
    0% { transform: scale(1); text-shadow: 0 0 12px currentColor; }
    50% { transform: scale(1.06); text-shadow: 0 0 24px currentColor, 0 0 48px currentColor; }
    100% { transform: scale(1); text-shadow: 0 0 12px currentColor; }
  }
  .live-rate-time {
    font-size: 10px; color: var(--text-muted); letter-spacing: 0.5px;
  }
  [data-theme="dark"] .live-rate-time {
    color: rgba(255,255,255,0.25);
    font-family: 'SF Mono', 'Fira Code', 'Consolas', monospace;
  }

  /* Filter Bar */
  .filter-bar {
    background: var(--card); border-radius: 16px; padding: 20px 24px;
    border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,0.04);
    margin-bottom: 24px; display: flex; align-items: center; gap: 16px; flex-wrap: wrap;
  }
  .filter-bar-label { font-size: 13px; font-weight: 600; color: var(--text-secondary); }
  .filter-presets { display: flex; gap: 8px; }
  .preset-btn {
    padding: 8px 16px; border: 1px solid var(--border); border-radius: 8px;
    background: var(--bg); font-size: 13px; font-weight: 600; cursor: pointer;
    color: var(--text-secondary); transition: all 0.15s; font-family: inherit;
  }
  .preset-btn:hover { border-color: var(--admin-accent); color: var(--admin-accent); }
  .preset-btn.active {
    background: var(--admin-accent); color: white; border-color: var(--admin-accent);
  }
  .filter-divider { width: 1px; height: 32px; background: var(--border); }
  .date-inputs { display: flex; align-items: center; gap: 8px; }
  .date-inputs label { font-size: 12px; font-weight: 600; color: var(--text-muted); }
  .date-inputs input[type="date"] {
    padding: 8px 12px; border: 1px solid var(--border); border-radius: 8px;
    font-size: 13px; font-family: inherit; background: var(--bg); color: var(--text);
  }
  .period-info {
    margin-left: auto; font-size: 12px; color: var(--text-muted);
    font-weight: 500; background: var(--bg); padding: 6px 12px; border-radius: 6px;
  }
  .export-btn {
    background: var(--green); color: white; border: none; padding: 8px 16px;
    border-radius: 6px; font-size: 12px; font-weight: 600; cursor: pointer;
    white-space: nowrap; transition: all 0.15s;
  }
  .export-btn:hover { opacity: 0.85; transform: translateY(-1px); }
  [data-theme="dark"] .export-btn { background: rgba(0,255,136,0.15); color: #00FF88; border: 1px solid rgba(0,255,136,0.3); }

  /* Hero KPI Cards */
  .hero-grid {
    display: grid; grid-template-columns: repeat(5, 1fr); gap: 16px; margin-bottom: 28px;
  }
  .hero-card {
    background: var(--card); border-radius: 16px; padding: 20px 18px;
    border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,0.04);
    position: relative; overflow: hidden;
    min-width: 0;
  }
  .hero-card::before {
    content: ''; position: absolute; top: 0; left: 0; right: 0; height: 3px;
  }
  .hero-card.spread::before { background: linear-gradient(90deg, var(--green), #4CAF50); }
  .hero-card.volume::before { background: linear-gradient(90deg, var(--blue), #42A5F5); }
  .hero-card.transactions::before { background: linear-gradient(90deg, var(--purple), #AB47BC); }
  .hero-card.clients::before { background: linear-gradient(90deg, var(--orange), #FFA726); }
  .hero-card.ticket::before { background: linear-gradient(90deg, #00897B, #26A69A); }
  .hero-label {
    font-size: 11px; font-weight: 700; color: var(--text-muted);
    text-transform: uppercase; letter-spacing: 0.5px; margin-bottom: 8px;
  }
  .hero-value {
    font-size: clamp(14px, 1.6vw, 26px); font-weight: 800; color: var(--text); margin-bottom: 4px;
    font-variant-numeric: tabular-nums;
    word-break: break-word; overflow-wrap: break-word;
    min-width: 0; line-height: 1.2;
  }
  .hero-badge {
    display: inline-block; font-size: 11px; font-weight: 700; padding: 3px 10px;
    border-radius: 12px;
  }
  .hero-badge.up { background: var(--green-bg); color: var(--green); }
  .hero-badge.down { background: var(--red-bg); color: var(--red); }
  .hero-badge.neutral { background: var(--blue-bg); color: var(--blue); }
  .hero-sub { font-size: 12px; color: var(--text-muted); margin-top: 6px; }

  /* Section Headers */
  .section-title {
    font-size: 14px; font-weight: 700; color: var(--text-secondary);
    text-transform: uppercase; letter-spacing: 1px; margin-bottom: 16px;
    display: flex; align-items: center; gap: 8px;
  }
  .section-title .icon {
    width: 28px; height: 28px; border-radius: 8px; display: flex;
    align-items: center; justify-content: center; font-size: 14px;
  }

  /* Charts Grid */
  .charts-row {
    display: grid; grid-template-columns: 1fr 2fr; gap: 20px; margin-bottom: 28px;
  }
  .charts-row.equal { grid-template-columns: 1fr 1fr; }
  .charts-row.triple { grid-template-columns: 1fr 1fr 1fr; }
  .chart-card {
    background: var(--card); border-radius: 16px; padding: 24px;
    border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,0.04);
  }
  .chart-card h3 {
    font-size: 14px; font-weight: 700; color: var(--text); margin-bottom: 16px;
    display: flex; align-items: center; gap: 8px;
  }
  .chart-card h3 .badge {
    font-size: 10px; padding: 3px 8px; border-radius: 10px;
    font-weight: 700; background: var(--bg); color: var(--text-muted);
  }
  .chart-wrap { position: relative; height: 280px; }
  .chart-wrap.short { height: 220px; }

  /* Data Tables */
  .data-table {
    width: 100%; border-collapse: collapse; font-size: 13px;
  }
  .data-table th {
    text-align: left; padding: 10px 12px; font-weight: 700; font-size: 11px;
    text-transform: uppercase; letter-spacing: 0.5px; color: var(--text-muted);
    border-bottom: 2px solid var(--border);
  }
  .data-table td {
    padding: 10px 12px; border-bottom: 1px solid var(--border);
    color: var(--text); font-variant-numeric: tabular-nums;
  }
  .data-table tr:last-child td { border-bottom: none; }
  .data-table tr:hover td { background: var(--bg); }
  .data-table .rank {
    width: 32px; height: 32px; border-radius: 50%; display: inline-flex;
    align-items: center; justify-content: center; font-weight: 800; font-size: 12px;
  }
  .rank-1 { background: rgba(249,168,37,0.12); color: #F9A825; }
  .rank-2 { background: rgba(0,0,0,0.04); color: #757575; }
  .rank-3 { background: rgba(216,67,21,0.1); color: #D84315; }
  .rank-default { background: var(--bg); color: var(--text-muted); }

  /* Gauge / Metric Cards */
  .metric-card {
    background: var(--card); border-radius: 16px; padding: 24px;
    border: 1px solid var(--border); box-shadow: 0 2px 8px rgba(0,0,0,0.04);
    text-align: center;
  }
  .metric-card h3 {
    font-size: 14px; font-weight: 700; color: var(--text); margin-bottom: 16px;
  }
  .gauge-value {
    font-size: 48px; font-weight: 800; margin: 12px 0;
    font-variant-numeric: tabular-nums;
  }
  .gauge-value.green { color: var(--green); }
  .gauge-value.red { color: var(--red); }
  .gauge-value.blue { color: var(--blue); }
  .gauge-bar {
    height: 8px; border-radius: 4px; background: var(--bg); overflow: hidden; margin: 12px 0;
  }
  .gauge-bar-fill {
    height: 100%; border-radius: 4px; transition: width 0.6s ease;
  }
  .gauge-bar-fill.green { background: linear-gradient(90deg, var(--green), #4CAF50); }
  .gauge-bar-fill.red { background: linear-gradient(90deg, var(--red), #EF5350); }
  .gauge-bar-fill.blue { background: linear-gradient(90deg, var(--blue), #42A5F5); }
  .gauge-label { font-size: 12px; color: var(--text-muted); }

  /* Netting Gran Buttons */
  .netting-gran-btn {
    width: 32px; height: 32px; border-radius: 50%;
    border: 1px solid var(--border); background: var(--bg);
    font-size: 12px; font-weight: 700; cursor: pointer;
    color: var(--text-secondary); transition: all 0.15s; font-family: inherit;
    display: inline-flex; align-items: center; justify-content: center;
  }
  .netting-gran-btn:hover { border-color: var(--tc-accent); color: var(--tc-accent); }
  .netting-gran-btn.active { background: var(--tc-accent); color: white; border-color: var(--tc-accent); }
  [data-theme="dark"] .netting-gran-btn { background: rgba(255,255,255,0.03); color: var(--text-secondary); border-color: rgba(0,255,136,0.1); }
  [data-theme="dark"] .netting-gran-btn:hover { border-color: #00FF88; color: #00FF88; }
  [data-theme="dark"] .netting-gran-btn.active { background: rgba(0,255,136,0.15); color: #00FF88; border-color: rgba(0,255,136,0.3); }

  /* Netting Card */
  .netting-row {
    display: flex; justify-content: space-between; align-items: center;
    padding: 10px 0; border-bottom: 1px solid var(--border);
  }
  .netting-row:last-child { border-bottom: none; }
  .netting-label { font-size: 13px; color: var(--text-secondary); font-weight: 600; }
  .netting-value { font-size: 15px; font-weight: 700; font-variant-numeric: tabular-nums; }
  .netting-value.green { color: var(--green); }
  .netting-value.red { color: var(--red); }

  /* Revenue Controls */
  .revenue-controls {
    display: flex; align-items: center; justify-content: space-between;
    margin-bottom: 16px; flex-wrap: wrap; gap: 12px;
  }
  .gran-selector { display: flex; align-items: center; gap: 8px; }
  .gran-label {
    font-size: 13px; font-weight: 600; color: var(--text-secondary);
  }
  .gran-btn {
    padding: 8px 18px; border: 1px solid var(--border); border-radius: 8px;
    background: var(--bg); font-size: 13px; font-weight: 600; cursor: pointer;
    color: var(--text-secondary); transition: all 0.15s; font-family: inherit;
  }
  .gran-btn:hover { border-color: #F9A825; color: #F9A825; }
  .gran-btn.active { background: #F9A825; color: white; border-color: #F9A825; }
  .revenue-status {
    font-size: 12px; color: var(--text-muted); font-weight: 500;
    background: var(--bg); padding: 6px 12px; border-radius: 6px;
  }
  .hero-grid-4 { grid-template-columns: repeat(4, 1fr); }
  .hero-card[style*="--top-color"]::before { background: var(--top-color); }

  /* Cohort Heatmap */
  .cohort-table { width: 100%; border-collapse: collapse; font-size: 11px; overflow-x: auto; display: block; }
  .cohort-table th, .cohort-table td { padding: 6px 8px; text-align: center; white-space: nowrap; border: 1px solid var(--border); min-width: 48px; }
  .cohort-table th { font-weight: 700; font-size: 10px; text-transform: uppercase; color: var(--text-muted); background: var(--bg); position: sticky; top: 0; }
  .cohort-table th:first-child, .cohort-table td:first-child { text-align: left; position: sticky; left: 0; z-index: 1; background: var(--card); min-width: 90px; }
  .cohort-table td:nth-child(2) { font-weight: 700; color: var(--text); }
  .cohort-cell { font-weight: 600; font-variant-numeric: tabular-nums; border-radius: 2px; }
  [data-theme="dark"] .cohort-table th:first-child, [data-theme="dark"] .cohort-table td:first-child { background: rgba(255,255,255,0.03); }

  /* Waterfall */
  .waterfall-grid { display: grid; grid-template-columns: repeat(5, 1fr); gap: 12px; }
  .waterfall-item { text-align: center; padding: 16px 8px; border-radius: 12px; border: 1px solid var(--border); background: var(--card); }
  .waterfall-item .wf-label { font-size: 10px; font-weight: 700; text-transform: uppercase; color: var(--text-muted); letter-spacing: 0.5px; margin-bottom: 8px; }
  .waterfall-item .wf-count { font-size: 28px; font-weight: 800; line-height: 1; margin-bottom: 4px; font-variant-numeric: tabular-nums; }
  .waterfall-item .wf-revenue { font-size: 13px; font-weight: 700; font-variant-numeric: tabular-nums; }
  .waterfall-item.wf-new { border-color: var(--blue); }
  .waterfall-item.wf-new .wf-count { color: var(--blue); }
  .waterfall-item.wf-expansion { border-color: var(--green); }
  .waterfall-item.wf-expansion .wf-count { color: var(--green); }
  .waterfall-item.wf-stable .wf-count { color: var(--text-secondary); }
  .waterfall-item.wf-contraction { border-color: var(--orange); }
  .waterfall-item.wf-contraction .wf-count { color: var(--orange); }
  .waterfall-item.wf-churned { border-color: var(--red); }
  .waterfall-item.wf-churned .wf-count { color: var(--red); }
  [data-theme="dark"] .waterfall-item { background: rgba(255,255,255,0.02); }
  [data-theme="dark"] .waterfall-item .wf-count { font-family: 'SF Mono','Fira Code','Consolas',monospace; text-shadow: 0 0 8px currentColor; }

  /* Cross-sell & Maturity */
  .segment-grid { display: grid; grid-template-columns: 1fr 1fr; gap: 20px; margin-bottom: 28px; }
  .segment-card { border-radius: 16px; padding: 24px; background: var(--card); border: 1px solid var(--border); }
  .segment-card h3 { font-size: 14px; font-weight: 700; color: var(--text); margin-bottom: 16px; display: flex; align-items: center; gap: 8px; }
  .segment-bars { display: flex; flex-direction: column; gap: 10px; }
  .seg-row { display: flex; align-items: center; gap: 12px; }
  .seg-label { font-size: 12px; font-weight: 600; color: var(--text-secondary); min-width: 110px; }
  .seg-bar-wrap { flex: 1; height: 24px; border-radius: 6px; background: var(--bg); overflow: hidden; position: relative; }
  .seg-bar-fill { height: 100%; border-radius: 6px; transition: width 0.6s; display: flex; align-items: center; padding: 0 8px; min-width: 0; }
  .seg-bar-text { font-size: 10px; font-weight: 700; color: white; white-space: nowrap; }
  .seg-count { font-size: 13px; font-weight: 700; min-width: 50px; text-align: right; color: var(--text); font-variant-numeric: tabular-nums; }
  [data-theme="dark"] .segment-card { background: rgba(255,255,255,0.03); border-color: rgba(0,255,136,0.1); }

  /* Loading */
  .loading-overlay {
    position: absolute; inset: 0; background: rgba(255,255,255,0.8);
    display: flex; align-items: center; justify-content: center;
    border-radius: 16px; z-index: 10; font-size: 13px; color: var(--text-muted);
  }

  /* Responsive - Small Desktop */
  @media (max-width: 1200px) {
    .hero-grid { grid-template-columns: repeat(3, 1fr); }
    .hero-grid-4 { grid-template-columns: repeat(2, 1fr); }
    .hero-value { font-size: clamp(15px, 2.4vw, 22px); }
  }

  /* Responsive - Tablet */
  @media (max-width: 900px) {
    .trading-terminal { padding: 12px 16px; }
    .live-rate-bar { flex-wrap: wrap; gap: 12px; justify-content: center; }
    .terminal-title { display: none; }
    .rate-pair-group { padding: 6px 10px; }
    .live-rate-btn { min-width: 100px; padding: 6px 12px; }
    .live-rate-btn .rate-value { font-size: 16px; }
    .rate-separator { display: none; }
    .charts-row { grid-template-columns: 1fr; }
    .charts-row.equal { grid-template-columns: 1fr; }
    .charts-row.triple { grid-template-columns: 1fr 1fr; }
    .charts-row.triple > :last-child { grid-column: span 2; }
    .filter-divider { display: none; }
    .filter-bar { gap: 10px; }
  }

  /* Responsive - Mobile */
  @media (max-width: 768px) {
    /* Trading terminal */
    .trading-terminal { padding: 10px 12px; }
    .live-rate-bar { gap: 8px; justify-content: center; }
    .rate-pair-group { padding: 8px 10px; width: 100%; justify-content: center; }
    .live-rate-btn { min-width: 0; flex: 1; padding: 8px 10px; }
    .live-rate-btn .rate-value { font-size: 18px; }
    .live-rate-btn .rate-type { font-size: 8px; }
    .rate-flags { font-size: 8px; }
    .live-rate-time { width: 100%; text-align: center; font-size: 9px; }

    /* Filter bar - stack vertically */
    .filter-bar {
      padding: 14px 16px; gap: 10px;
      flex-direction: column; align-items: stretch;
    }
    .filter-bar-label { text-align: center; }
    .filter-presets { flex-wrap: wrap; justify-content: center; }
    .preset-btn { padding: 10px 14px; min-height: 44px; font-size: 13px; flex: 1; min-width: 70px; text-align: center; }
    .date-inputs {
      flex-wrap: wrap; justify-content: center; gap: 6px;
    }
    .date-inputs input[type="date"] { flex: 1; min-width: 130px; min-height: 44px; }
    .period-info { margin-left: 0; width: 100%; text-align: center; }

    /* Hero KPIs */
    .hero-grid { grid-template-columns: repeat(2, 1fr); gap: 12px; }
    .hero-grid-4 { grid-template-columns: repeat(2, 1fr); gap: 12px; }
    .hero-card { padding: 16px 18px; border-radius: 12px; }
    .hero-card:last-child { grid-column: span 2; }
    .hero-value { font-size: 22px; }
    .hero-label { font-size: 10px; }
    .hero-sub { font-size: 11px; }

    /* Charts - single column */
    .charts-row, .charts-row.equal, .charts-row.triple { grid-template-columns: 1fr; }
    .charts-row.triple > :last-child { grid-column: span 1; }
    .chart-card { padding: 18px; border-radius: 12px; }
    .chart-wrap { height: 250px; }

    /* Revenue controls */
    .revenue-controls { flex-direction: column; align-items: stretch; }
    .gran-selector { flex-wrap: wrap; justify-content: center; }
    .gran-btn { padding: 10px 16px; min-height: 44px; flex: 1; min-width: 60px; text-align: center; }
    .revenue-status { text-align: center; }

    /* Tables - horizontal scroll indicator */
    .chart-card:has(.data-table) { padding: 18px 0; }
    .chart-card:has(.data-table) > h3 { padding: 0 18px; }
    .data-table { font-size: 12px; }
    .data-table th { padding: 10px 10px; font-size: 10px; white-space: nowrap; }
    .data-table td { padding: 10px 10px; white-space: nowrap; }
    [style*="overflow-x:auto"], [style*="overflow:auto"] {
      -webkit-overflow-scrolling: touch;
      scrollbar-width: thin;
    }

    /* Section titles */
    .section-title { font-size: 13px; margin-bottom: 12px; }

    /* Metric / Gauge */
    .gauge-value { font-size: 40px; }
    .metric-card { padding: 16px; }

    /* Netting */
    .netting-label { font-size: 12px; }
    .netting-value { font-size: 14px; }

    /* Strategic sections */
    .waterfall-grid { grid-template-columns: repeat(3, 1fr); }
    .segment-grid { grid-template-columns: 1fr; }
    .cohort-table { font-size: 10px; }
    .cohort-table th, .cohort-table td { padding: 4px 6px; min-width: 40px; }
  }

  /* Responsive - Small Mobile */
  @media (max-width: 480px) {
    /* Trading terminal ultra-compact */
    .trading-terminal { padding: 8px 10px; }
    .live-rate-bar { flex-direction: column; align-items: center; gap: 6px; }
    .rate-pair-group { padding: 8px; gap: 4px; }
    .rate-pair-label { writing-mode: horizontal-tb; font-size: 10px; }
    .live-rate-btn .rate-value { font-size: 16px; }
    .live-rate-btn .rate-type { font-size: 7px; }

    /* Filter compact */
    .filter-bar { padding: 12px; }
    .preset-btn { padding: 8px 10px; font-size: 12px; min-height: 40px; }
    .date-inputs input[type="date"] { font-size: 12px; padding: 8px 10px; min-height: 40px; }

    /* Hero - single column */
    .hero-grid, .hero-grid-4 { grid-template-columns: 1fr; gap: 10px; }
    .hero-card { padding: 14px 16px; }
    .hero-card:last-child { grid-column: span 1; }
    .hero-value { font-size: 20px; }
    .hero-badge { font-size: 10px; padding: 2px 8px; }

    /* Charts compact */
    .chart-card { padding: 14px; }
    .chart-wrap { height: 200px; }
    .chart-wrap.short { height: 160px; }
    .chart-card h3 { font-size: 13px; }

    /* Tables even more compact */
    .data-table { font-size: 11px; }
    .data-table th { padding: 8px 6px; font-size: 9px; }
    .data-table td { padding: 8px 6px; }
    .data-table .rank { width: 26px; height: 26px; font-size: 10px; }

    /* Gauge */
    .gauge-value { font-size: 32px; }
    .gauge-label { font-size: 11px; }

    /* Granularity buttons */
    .gran-btn { padding: 8px 12px; font-size: 12px; min-height: 40px; }

    /* Section titles */
    .section-title { font-size: 12px; letter-spacing: 0.5px; }
    .section-title .icon { width: 24px; height: 24px; font-size: 12px; }

    /* Strategic */
    .waterfall-grid { grid-template-columns: repeat(2, 1fr); }
    .waterfall-item .wf-count { font-size: 22px; }
    .seg-label { min-width: 80px; font-size: 11px; }
  }

  /* Dark Mode overrides */
  [data-theme="dark"] .rank-1 { background: rgba(249,168,37,0.15); color: #F9A825; }
  [data-theme="dark"] .rank-2 { background: rgba(255,255,255,0.08); color: #9AA0A6; }
  [data-theme="dark"] .rank-3 { background: rgba(216,67,21,0.15); color: #FF7043; }
  [data-theme="dark"] .rank-default { background: var(--bg); }
  [data-theme="dark"] .loading-overlay { background: rgba(13,17,23,0.85); }
  [data-theme="dark"] .preset-btn { background: var(--card); color: var(--text-secondary); border-color: var(--border); }
  [data-theme="dark"] .preset-btn:hover { border-color: var(--admin-accent); color: var(--green); }
  [data-theme="dark"] .gran-btn { background: var(--card); color: var(--text-secondary); border-color: var(--border); }
  [data-theme="dark"] .gran-btn:hover { border-color: #F9A825; color: #F9A825; }
  [data-theme="dark"] .date-inputs input[type="date"] { background: var(--card); color: var(--text); border-color: var(--border); }
  [data-theme="dark"] .data-table tr:hover td { background: rgba(255,255,255,0.03); }

  /* === Skeleton Loading Shimmer === */
  @keyframes shimmer {
    0% { background-position: -400px 0; }
    100% { background-position: 400px 0; }
  }
  .skel {
    background: linear-gradient(90deg, var(--card-bg,var(--card)) 25%, var(--border) 50%, var(--card-bg,var(--card)) 75%);
    background-size: 800px 100%;
    animation: shimmer 1.5s infinite ease-in-out;
    border-radius: 6px;
    display: inline-block;
  }
  .skel-value { height: 32px; width: 55%; }
  .skel-badge { height: 18px; width: 70px; }
  .skel-text  { height: 14px; width: 80%; margin: 4px 0; }
  .skel-chart { height: 100%; width: 100%; min-height: 180px; border-radius: 12px; position: absolute; top: 0; left: 0; z-index: 2; }
  .skel-row   { height: 32px; margin: 6px 0; width: 100%; }
  .skel-gauge { height: 40px; width: 90px; }
  `;

  return `<!DOCTYPE html>
<html lang="pt-BR">
<head>
${buildHead('BI Executive', pageCSS, pageScripts)}
</head>
<body class="trading-console">

${buildHeader({ role: role, userName: user.nome, activePage: 'bi', permissions: user.permissions || [] })}

<div class="trading-terminal">
  <div class="live-rate-bar">
    <span class="live-rate-dot"></span>
    <span class="terminal-title">Live Rates</span>
    <div class="rate-pair-group">
      <span class="rate-pair-label">USD</span>
      <button class="live-rate-btn compra">
        <span class="rate-flags">\uD83C\uDDFA\uD83C\uDDF8 \u2192 \uD83C\uDDE7\uD83C\uDDF7</span>
        <span class="rate-type">Compra</span>
        <span class="rate-value" id="rateUsdCompra">--</span>
      </button>
      <button class="live-rate-btn venda">
        <span class="rate-flags">\uD83C\uDDE7\uD83C\uDDF7 \u2192 \uD83C\uDDFA\uD83C\uDDF8</span>
        <span class="rate-type">Venda</span>
        <span class="rate-value" id="rateUsdVenda">--</span>
      </button>
    </div>
    <span class="live-rate-time" id="rateTime">--</span>
  </div>
</div>

<div class="app-container">

  <!-- Filter Bar -->
  <div class="filter-bar" id="filterBar">
    <span class="filter-bar-label">Periodo:</span>
    <div class="filter-presets">
      <button class="preset-btn" data-preset="7d">7 Dias</button>
      <button class="preset-btn active" data-preset="30d">30 Dias</button>
      <button class="preset-btn" data-preset="90d">90 Dias</button>
      <button class="preset-btn" data-preset="thisMonth">Este Mes</button>
    </div>
    <div class="filter-divider"></div>
    <div class="date-inputs">
      <label>De:</label>
      <input type="date" id="dateStart" value="${thirtyDaysAgo}">
      <label>Ate:</label>
      <input type="date" id="dateEnd" value="${today}">
    </div>
    <span class="period-info" id="periodInfo">Carregando...</span>
    <button class="export-btn" onclick="exportBIExcel()" title="Export to Excel">Export Excel</button>
  </div>

  <!-- Hero KPI Cards -->
  <div class="hero-grid" id="heroGrid">
    <div class="hero-card spread">
      <div class="hero-label">Receita USD (Spread)</div>
      <div class="hero-value" id="kpiSpreadRevenue"><div class="skel skel-value"></div></div>
      <span class="hero-badge neutral" id="kpiSpreadBadge"><div class="skel skel-badge"></div></span>
      <div class="hero-sub" id="kpiSpreadSub">vs periodo anterior</div>
    </div>
    <div class="hero-card volume">
      <div class="hero-label">Volume Processado</div>
      <div class="hero-value" id="kpiVolume"><div class="skel skel-value"></div></div>
      <span class="hero-badge neutral" id="kpiVolumeBadge"><div class="skel skel-badge"></div></span>
      <div class="hero-sub" id="kpiVolumeSub">USD total movimentado</div>
    </div>
    <div class="hero-card transactions">
      <div class="hero-label">Transacoes</div>
      <div class="hero-value" id="kpiTransactions"><div class="skel skel-value"></div></div>
      <span class="hero-badge neutral" id="kpiTransBadge"><div class="skel skel-badge"></div></span>
      <div class="hero-sub" id="kpiTransSub">operacoes no periodo</div>
    </div>
    <div class="hero-card clients">
      <div class="hero-label">Clientes Ativos</div>
      <div class="hero-value" id="kpiClients"><div class="skel skel-value"></div></div>
      <div class="hero-sub">clientes unicos no periodo</div>
    </div>
    <div class="hero-card ticket">
      <div class="hero-label">Ticket Medio</div>
      <div class="hero-value" id="kpiTicket"><div class="skel skel-value"></div></div>
      <div class="hero-sub">USD por operacao</div>
    </div>
  </div>

  <!-- Section: Revenue & Spread -->
  <div class="section-title" id="sectionRevSpread">
    <span class="icon">$</span>
    Revenue & Spread
  </div>
  <div class="charts-row">
    <div class="chart-card">
      <h3>Revenue por Corredor</h3>
      <div class="chart-wrap short"><div class="skel skel-chart" id="skelDonut"></div><canvas id="chartDonut"></canvas></div>
    </div>
    <div class="chart-card">
      <h3>Spread Medio + Volume Diario <span class="badge" id="spreadBadge">--</span></h3>
      <div class="chart-wrap"><div class="skel skel-chart" id="skelSpreadTrend"></div><canvas id="chartSpreadTrend"></canvas></div>
    </div>
  </div>

  <!-- Section: Client Intelligence -->
  <div class="section-title" id="sectionClients">
    <span class="icon">&#x1F465;</span>
    Inteligencia de Clientes
  </div>
  <div class="charts-row equal">
    <div class="chart-card">
      <h3>Top 10 Clientes por Volume
        <button id="btnResetClients" style="display:none;margin-left:auto;" class="preset-btn"
          onclick="_resetClientFilter()">Mostrar Todos</button>
      </h3>
      <div class="chart-wrap"><div class="skel skel-chart" id="skelTopClients"></div><canvas id="chartTopClients"></canvas></div>
    </div>
    <div class="chart-card" style="display:flex;flex-direction:column;gap:20px;">
      <div class="metric-card" style="box-shadow:none;border:1px solid var(--border);padding:16px;">
        <h3 style="margin-bottom:8px;">Taxa de Retencao</h3>
        <div class="gauge-value green" id="retentionValue"><div class="skel skel-gauge"></div></div>
        <div class="gauge-bar"><div class="gauge-bar-fill green" id="retentionBar" style="width:0%"></div></div>
        <div class="gauge-label" id="retentionLabel"><div class="skel skel-text"></div></div>
        <div class="retention-breakdown" id="retentionBreakdown" style="display:flex;justify-content:center;gap:16px;margin-top:10px;">
          <span class="ret-stat" style="font-size:13px;font-weight:700;color:var(--green);" id="retNovos">+0 novos</span>
          <span class="ret-stat" style="font-size:13px;font-weight:700;color:var(--red);" id="retPerdidos">-0 perdidos</span>
        </div>
      </div>
      <div style="flex:1;overflow:auto;">
        <h3 style="font-size:14px;font-weight:700;margin-bottom:8px;color:var(--text);">
          Clientes em Risco
        </h3>
        <div class="risk-filters" style="display:flex;align-items:center;gap:6px;margin-bottom:10px;flex-wrap:wrap;">
          <span style="font-size:11px;color:var(--text-muted);">Inativos ha:</span>
          <button class="preset-btn risk-threshold-btn" data-risk="15" style="padding:4px 10px;font-size:11px;">15d</button>
          <button class="preset-btn risk-threshold-btn active" data-risk="30" style="padding:4px 10px;font-size:11px;">30d</button>
          <button class="preset-btn risk-threshold-btn" data-risk="60" style="padding:4px 10px;font-size:11px;">60d</button>
          <button class="preset-btn risk-threshold-btn" data-risk="90" style="padding:4px 10px;font-size:11px;">90d</button>
        </div>
        <table class="data-table" id="riskTable">
          <thead><tr><th>Cliente</th><th>Ultima Op</th><th>Dias</th><th>Volume USD</th></tr></thead>
          <tbody id="riskTableBody"><tr class="skel-tr"><td colspan="4"><div class="skel skel-row"></div></td></tr><tr class="skel-tr"><td colspan="4"><div class="skel skel-row"></div></td></tr><tr class="skel-tr"><td colspan="4"><div class="skel skel-row"></div></td></tr></tbody>
        </table>
      </div>
    </div>
  </div>

  <!-- Section: Operational -->
  <div class="section-title" id="sectionOps">
    <span class="icon">&#x2699;</span>
    Operacional
  </div>
  <div class="charts-row equal">
    <div class="chart-card">
      <h3>Volume por Corredor</h3>
      <div class="chart-wrap"><div class="skel skel-chart" id="skelVolFlow"></div><canvas id="chartVolFlow"></canvas></div>
    </div>
    <div class="chart-card">
      <h3>Ranking Agentes</h3>
      <div style="overflow-x:auto;-webkit-overflow-scrolling:touch;">
        <table class="data-table">
          <thead><tr><th>#</th><th>Agente</th><th>Volume</th><th>Ops</th><th>Spread R$</th><th>Clientes</th></tr></thead>
          <tbody id="agentTableBody"><tr class="skel-tr"><td colspan="6"><div class="skel skel-row"></div></td></tr><tr class="skel-tr"><td colspan="6"><div class="skel skel-row"></div></td></tr><tr class="skel-tr"><td colspan="6"><div class="skel skel-row"></div></td></tr></tbody>
        </table>
      </div>
    </div>
  </div>

  <!-- Section: Volume Forecast -->
  <div class="section-title" id="sectionForecast">
    <span class="icon">&#x1F4C8;</span>
    Volume Forecast (30 Days)
  </div>
  <div class="chart-card" style="margin-bottom:28px;">
    <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;">
      <h3 style="margin:0;">Forecast: Historical + Predicted Volume</h3>
      <span class="period-info" id="forecastInfo">Loading forecast...</span>
    </div>
    <div style="height:300px;position:relative;"><div class="skel skel-chart" id="skelForecast"></div><canvas id="forecastChart"></canvas></div>
  </div>

  <!-- Section: Netting & Balanco -->
  <div class="section-title" id="sectionNetting">
    <span class="icon">&#x2696;</span>
    Netting & Balanco
  </div>
  <div class="charts-row equal">
    <div class="chart-card">
      <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:12px;">
        <h3 style="margin:0;">Fluxo Entrada vs Saida</h3>
        <div class="gran-selector">
          <button class="netting-gran-btn active" data-netting-gran="D">D</button>
          <button class="netting-gran-btn" data-netting-gran="W">W</button>
          <button class="netting-gran-btn" data-netting-gran="M">M</button>
        </div>
      </div>
      <div class="chart-wrap"><div class="skel skel-chart" id="skelNetting"></div><canvas id="chartNetting"></canvas></div>
    </div>
    <div class="chart-card" style="display:flex;flex-direction:column;gap:16px;">
      <h3 style="font-size:14px;font-weight:700;color:var(--text);margin:0;">Resumo Netting</h3>
      <div id="nettingContent">
        <div class="netting-row">
          <span class="netting-label">Saida (BRL&#x2192;USD)</span>
          <span class="netting-value red" id="nettingSaida"><div class="skel skel-badge"></div></span>
        </div>
        <div class="netting-row">
          <span class="netting-label">Entrada (USD&#x2192;BRL)</span>
          <span class="netting-value green" id="nettingEntrada"><div class="skel skel-badge"></div></span>
        </div>
        <div class="netting-row" style="border-top:2px solid var(--border);padding-top:12px;">
          <span class="netting-label" style="font-weight:700;">Posicao Liquida</span>
          <span class="netting-value" id="nettingPosicao"><div class="skel skel-badge"></div></span>
        </div>
        <div style="margin-top:16px;">
          <div style="font-size:12px;color:var(--text-muted);margin-bottom:4px;">Eficiencia Netting</div>
          <div class="gauge-value blue" id="nettingEficiencia" style="font-size:36px;margin:4px 0;"><div class="skel skel-gauge"></div></div>
          <div class="gauge-bar"><div class="gauge-bar-fill blue" id="nettingBar" style="width:0%"></div></div>
        </div>
      </div>
    </div>
  </div>

  <!-- Section: Revenue Analytics -->
  <div class="section-title" id="sectionPnL" style="margin-top:12px;">
    <span class="icon">&#x1F4B0;</span>
    Revenue Analytics (P&L Real)
  </div>

  <div class="revenue-controls">
    <div class="gran-selector">
      <span class="gran-label">Granulacao:</span>
      <button class="gran-btn active" data-gran="dia">Dia</button>
      <button class="gran-btn" data-gran="mes">Mes</button>
      <button class="gran-btn" data-gran="ano">Ano</button>
    </div>
    <span class="revenue-status" id="revenueStatus">Carregando...</span>
  </div>

  <div class="hero-grid hero-grid-4" id="revenueKpis">
    <div class="hero-card" style="--top-color:linear-gradient(90deg,#F9A825,#FFD54F);">
      <div class="hero-label">Receita Total (P&L)</div>
      <div class="hero-value" id="revTotal"><div class="skel skel-value"></div></div>
      <div class="hero-sub" id="revTotalQtd"><div class="skel skel-text"></div></div>
    </div>
    <div class="hero-card" style="--top-color:linear-gradient(90deg,var(--blue),#42A5F5);">
      <div class="hero-label">BR &#x2192; US</div>
      <div class="hero-value" id="revBrUs"><div class="skel skel-value"></div></div>
      <div class="hero-sub">Checkout + CambioTransfer</div>
    </div>
    <div class="hero-card" style="--top-color:linear-gradient(90deg,var(--green),#4CAF50);">
      <div class="hero-label">US &#x2192; BR</div>
      <div class="hero-value" id="revUsBr"><div class="skel skel-value"></div></div>
      <div class="hero-sub">Spread + Fees</div>
    </div>
    <div class="hero-card" style="--top-color:linear-gradient(90deg,var(--purple),#AB47BC);">
      <div class="hero-label">Receita / Operacao</div>
      <div class="hero-value" id="revTicket"><div class="skel skel-value"></div></div>
      <div class="hero-sub">ticket medio de receita</div>
    </div>
  </div>

  <div class="charts-row equal">
    <div class="chart-card">
      <h3>Receita por Produto ao Longo do Tempo</h3>
      <div class="chart-wrap"><div class="skel skel-chart" id="skelRevTimeline"></div><canvas id="chartRevTimeline"></canvas></div>
    </div>
    <div class="chart-card">
      <h3>Composicao de Receita por Produto</h3>
      <div class="chart-wrap short"><div class="skel skel-chart" id="skelRevDonut"></div><canvas id="chartRevDonut"></canvas></div>
    </div>
  </div>

  <div class="chart-card" style="margin-bottom:28px;">
    <h3>Detalhamento por Periodo <span class="badge" id="revGranBadge">dia</span></h3>
    <div style="overflow-x:auto;">
      <table class="data-table" id="revTable">
        <thead><tr><th>Periodo</th><th>Produto</th><th>Receita</th><th>Operacoes</th><th>Receita/Op</th></tr></thead>
        <tbody id="revTableBody"><tr class="skel-tr"><td colspan="5"><div class="skel skel-row"></div></td></tr><tr class="skel-tr"><td colspan="5"><div class="skel skel-row"></div></td></tr><tr class="skel-tr"><td colspan="5"><div class="skel skel-row"></div></td></tr></tbody>
      </table>
    </div>
  </div>

  <!-- Section: Revenue Expansion / Contraction -->
  <div class="section-title" id="sectionExpansion" style="margin-top:12px;">
    <span class="icon">&#x1F4C9;</span>
    Revenue Expansion &amp; Contraction
  </div>
  <div class="waterfall-grid" id="waterfallGrid" style="margin-bottom:28px;">
    <div class="waterfall-item wf-new">
      <div class="wf-label">Novos</div>
      <div class="wf-count" id="wfNewCount"><div class="skel skel-badge"></div></div>
      <div class="wf-revenue" id="wfNewRev" style="color:var(--blue);"><div class="skel skel-text"></div></div>
    </div>
    <div class="waterfall-item wf-expansion">
      <div class="wf-label">Expansao</div>
      <div class="wf-count" id="wfExpCount"><div class="skel skel-badge"></div></div>
      <div class="wf-revenue" id="wfExpRev" style="color:var(--green);"><div class="skel skel-text"></div></div>
    </div>
    <div class="waterfall-item wf-stable">
      <div class="wf-label">Estavel</div>
      <div class="wf-count" id="wfStaCount"><div class="skel skel-badge"></div></div>
      <div class="wf-revenue" id="wfStaRev" style="color:var(--text-secondary);"><div class="skel skel-text"></div></div>
    </div>
    <div class="waterfall-item wf-contraction">
      <div class="wf-label">Contracao</div>
      <div class="wf-count" id="wfConCount"><div class="skel skel-badge"></div></div>
      <div class="wf-revenue" id="wfConRev" style="color:var(--orange);"><div class="skel skel-text"></div></div>
    </div>
    <div class="waterfall-item wf-churned">
      <div class="wf-label">Churned</div>
      <div class="wf-count" id="wfChurnCount"><div class="skel skel-badge"></div></div>
      <div class="wf-revenue" id="wfChurnRev" style="color:var(--red);"><div class="skel skel-text"></div></div>
    </div>
  </div>

  <div class="charts-row equal" style="margin-bottom:28px;">
    <div class="chart-card">
      <h3>Waterfall de Receita</h3>
      <div class="chart-wrap"><div class="skel skel-chart" id="skelWaterfall"></div><canvas id="chartWaterfall"></canvas></div>
    </div>
    <div class="chart-card">
      <h3>Distribuicao por Segmento</h3>
      <div class="chart-wrap"><div class="skel skel-chart" id="skelExpDonut"></div><canvas id="chartExpDonut"></canvas></div>
    </div>
  </div>

  <!-- Section: Cross-sell & Maturity -->
  <div class="section-title" id="sectionSegments">
    <span class="icon">&#x1F3AF;</span>
    Segmentacao Estrategica
  </div>
  <div class="segment-grid">
    <div class="segment-card">
      <h3>Cross-sell <span class="badge">CambioPay vs Checkout</span></h3>
      <div class="chart-wrap short"><div class="skel skel-chart" id="skelCrossSell"></div><canvas id="chartCrossSell"></canvas></div>
      <div class="segment-bars" id="crossSellBars" style="margin-top:16px;"></div>
    </div>
    <div class="segment-card">
      <h3>Maturidade de Clientes</h3>
      <div class="chart-wrap short"><div class="skel skel-chart" id="skelMaturity"></div><canvas id="chartMaturity"></canvas></div>
      <div class="segment-bars" id="maturityBars" style="margin-top:16px;"></div>
    </div>
  </div>

  <!-- Section: Cohort Retention -->
  <div class="section-title" id="sectionCohort">
    <span class="icon">&#x1F4CA;</span>
    Retencao por Cohort
  </div>
  <div class="chart-card" style="margin-bottom:28px;">
    <h3>Cohort Retention Heatmap <span class="badge">ultimos 12 meses</span></h3>
    <div style="overflow-x:auto;-webkit-overflow-scrolling:touch;">
      <table class="cohort-table" id="cohortTable">
        <thead id="cohortHead"><tr><th>Cohort</th><th>Clientes</th></tr></thead>
        <tbody id="cohortBody"><tr class="skel-tr"><td colspan="14"><div class="skel skel-row"></div></td></tr><tr class="skel-tr"><td colspan="14"><div class="skel skel-row"></div></td></tr><tr class="skel-tr"><td colspan="14"><div class="skel skel-row"></div></td></tr></tbody>
      </table>
    </div>
  </div>

</div>

${buildFooter()}

<!-- Floating Console Navigation -->
<nav class="console-nav" id="consoleNav">
  <a class="console-nav-btn" href="#filterBar" title="Filtros">
    <span class="nav-icon">\uD83D\uDD0D</span><span class="nav-label">Filtros</span>
  </a>
  <a class="console-nav-btn" href="#heroGrid" title="KPIs">
    <span class="nav-icon">\uD83D\uDCCA</span><span class="nav-label">KPIs</span>
  </a>
  <a class="console-nav-btn" href="#sectionRevSpread" title="Revenue">
    <span class="nav-icon">$</span><span class="nav-label">Revenue</span>
  </a>
  <a class="console-nav-btn" href="#sectionClients" title="Clientes">
    <span class="nav-icon">\uD83D\uDC65</span><span class="nav-label">Clientes</span>
  </a>
  <a class="console-nav-btn" href="#sectionOps" title="Operacional">
    <span class="nav-icon">\u2699</span><span class="nav-label">Ops</span>
  </a>
  <a class="console-nav-btn" href="#sectionNetting" title="Netting">
    <span class="nav-icon">\u2696</span><span class="nav-label">Netting</span>
  </a>
  <a class="console-nav-btn" href="#sectionPnL" title="P&L">
    <span class="nav-icon">\uD83D\uDCB0</span><span class="nav-label">P&L</span>
  </a>
  <a class="console-nav-btn" href="#sectionExpansion" title="Expansion">
    <span class="nav-icon">\uD83D\uDCC9</span><span class="nav-label">Exp</span>
  </a>
  <a class="console-nav-btn" href="#sectionSegments" title="Segments">
    <span class="nav-icon">\uD83C\uDFAF</span><span class="nav-label">Seg</span>
  </a>
  <a class="console-nav-btn" href="#sectionCohort" title="Cohort">
    <span class="nav-icon">\uD83D\uDCCA</span><span class="nav-label">Cohort</span>
  </a>
</nav>

<script>
// Global error handler - shows JS errors on screen for debugging
window.onerror = function(msg, url, line, col, err) {
  var d = document.createElement('div');
  d.style.cssText = 'position:fixed;top:0;left:0;right:0;padding:12px 16px;background:#FF4444;color:white;font-size:13px;z-index:99999;font-family:monospace;word-break:break-all;';
  d.textContent = 'JS ERROR: ' + msg + ' (line ' + line + ')';
  document.body.appendChild(d);
};
</script>

<script>
// === Formatters ===
const fmtUSD = v => '$' + Number(v).toLocaleString('en-US', {minimumFractionDigits:0, maximumFractionDigits:0});
const fmtNum = v => v.toLocaleString('pt-BR');
const fmtPct = (curr, prev) => {
  if (!prev || prev === 0) return { text: 'N/A', cls: 'neutral' };
  const pct = ((curr - prev) / prev * 100).toFixed(1);
  return { text: (pct > 0 ? '+' : '') + pct + '%', cls: pct >= 0 ? 'up' : 'down' };
};

// === Skeleton helpers ===
function showChart(skelId) {
  var s = document.getElementById(skelId);
  if (s) s.remove();
}

// === Date & Filter Logic ===
let currentStart = '${thirtyDaysAgo}';
let currentEnd = '${today}';

function setPreset(preset) {
  const now = new Date();
  const today = now.toISOString().slice(0, 10);
  let start;
  switch(preset) {
    case '7d':
      start = new Date(now.getTime() - 7 * 86400000).toISOString().slice(0, 10); break;
    case '30d':
      start = new Date(now.getTime() - 30 * 86400000).toISOString().slice(0, 10); break;
    case '90d':
      start = new Date(now.getTime() - 90 * 86400000).toISOString().slice(0, 10); break;
    case 'thisMonth':
      start = new Date(now.getFullYear(), now.getMonth(), 1).toISOString().slice(0, 10); break;
    default:
      start = new Date(now.getTime() - 30 * 86400000).toISOString().slice(0, 10);
  }
  document.getElementById('dateStart').value = start;
  document.getElementById('dateEnd').value = today;
  document.querySelectorAll('.preset-btn[data-preset]').forEach(b => b.classList.remove('active'));
  var _pb = document.querySelector('[data-preset="'+preset+'"]');
  if (_pb) _pb.classList.add('active');
  currentStart = start; currentEnd = today;
  loadAll();
}

function loadAll() { loadBI(); if (typeof loadRevenue === 'function') loadRevenue(); loadStrategic(); }

document.querySelectorAll('.preset-btn').forEach(btn => {
  btn.addEventListener('click', () => setPreset(btn.dataset.preset));
});
document.getElementById('dateStart').addEventListener('change', () => {
  currentStart = document.getElementById('dateStart').value;
  document.querySelectorAll('.preset-btn').forEach(b => b.classList.remove('active'));
  loadAll();
});
document.getElementById('dateEnd').addEventListener('change', () => {
  currentEnd = document.getElementById('dateEnd').value;
  document.querySelectorAll('.preset-btn').forEach(b => b.classList.remove('active'));
  loadAll();
});

// === Theme-aware Chart.js ===
function getChartTheme() {
  var isDark = document.documentElement.getAttribute('data-theme') === 'dark';
  return isDark ? {
    text: '#94A3B8', grid: 'rgba(0,255,136,0.06)',
    tooltipBg: '#1A2332', tooltipTitle: '#E2E8F0', tooltipBody: '#94A3B8',
    tooltipBorder: 'rgba(0,255,136,0.15)',
    donutColors: ['#58A6FF', '#00FF88'],
    volumeBar: 'rgba(88,166,255,0.15)', volumeBorder: 'rgba(88,166,255,0.4)',
    spreadLine: '#00FF88', spreadFill: 'rgba(0,255,136,0.1)',
    clientBar: 'rgba(188,140,255,0.15)', clientBorder: 'rgba(188,140,255,0.5)',
    flowColors: ['#58A6FF', '#00FF88', '#BC8CFF'],
    products: {
      'BR\\u2192US: Checkout': '#58A6FF', 'BR\\u2192US: CambioTransfer': '#82BFFF',
      'US\\u2192BR: balance': '#00FF88', 'US\\u2192BR: desconhecido': '#66FFB2',
      'US\\u2192BR: swift': '#00BFA5', 'US\\u2192BR: wire': '#4DD0A0', 'US\\u2192BR: pix': '#33FF99'
    },
    productFallback: ['#BC8CFF','#D4A5FF','#F9A825','#FF7043','#78909C','#FF6B9D','#7C8CFF','#A1887F']
  } : {
    text: '#5F6368', grid: 'rgba(0,0,0,0.06)',
    tooltipBg: '#FFFFFF', tooltipTitle: '#1A1D23', tooltipBody: '#5F6368',
    tooltipBorder: 'rgba(0,0,0,0.1)',
    donutColors: ['#1A73E8', '#1E8E3E'],
    volumeBar: 'rgba(26,115,232,0.12)', volumeBorder: 'rgba(26,115,232,0.4)',
    spreadLine: '#1E8E3E', spreadFill: 'rgba(30,142,62,0.08)',
    clientBar: 'rgba(123,31,162,0.12)', clientBorder: 'rgba(123,31,162,0.5)',
    flowColors: ['#1A73E8', '#1E8E3E', '#7B1FA2'],
    products: {
      'BR\\u2192US: Checkout': '#1A73E8', 'BR\\u2192US: CambioTransfer': '#4A9AF5',
      'US\\u2192BR: balance': '#1E8E3E', 'US\\u2192BR: desconhecido': '#43A047',
      'US\\u2192BR: swift': '#00897B', 'US\\u2192BR: wire': '#26A69A', 'US\\u2192BR: pix': '#2E7D32'
    },
    productFallback: ['#7B1FA2','#AB47BC','#F57C00','#E64A19','#546E7A','#D81B60','#3F51B5','#6D4C41']
  };
}

function applyChartDefaults(t) {
  if (typeof Chart === 'undefined') return;
  Chart.defaults.color = t.text;
  Chart.defaults.borderColor = t.grid;
  Chart.defaults.plugins.legend.labels.color = t.text;
  Chart.defaults.plugins.tooltip.backgroundColor = t.tooltipBg;
  Chart.defaults.plugins.tooltip.titleColor = t.tooltipTitle;
  Chart.defaults.plugins.tooltip.bodyColor = t.tooltipBody;
  Chart.defaults.plugins.tooltip.borderColor = t.tooltipBorder;
  Chart.defaults.plugins.tooltip.borderWidth = 1;
}

function getProductColor(produto, i) {
  var t = getChartTheme();
  return t.products[produto] || t.productFallback[i % t.productFallback.length];
}

// === Chart instances ===
let chartDonut, chartSpreadTrend, chartTopClients, chartVolFlow, chartNetting;

// === Cached data for theme re-render ===
let _biData = null, _revenueData = null;
var _hiddenClients = new Set();
var _riskThreshold = 30;
var currentNettingGran = 'D';

function destroyCharts() {
  [chartDonut, chartSpreadTrend, chartTopClients, chartVolFlow, chartNetting].forEach(c => { if (c) c.destroy(); });
}

function _renderBICharts(d) {
  if (typeof Chart === 'undefined') return;
  var _ct = getChartTheme();
  try { destroyCharts(); } catch(e) {}
  showChart('skelDonut', 'chartDonut');
  showChart('skelSpreadTrend', 'chartSpreadTrend');
  showChart('skelTopClients', 'chartTopClients');
  showChart('skelVolFlow', 'chartVolFlow');
  showChart('skelNetting', 'chartNetting');

  // Donut: Revenue por Corredor
  try {
  chartDonut = new Chart(document.getElementById('chartDonut'), {
    type: 'doughnut',
    data: {
      labels: ['BRL \\u2192 USD', 'USD \\u2192 BRL'],
      datasets: [{
        data: [d.kpis.brlUsd.spread_revenue, d.kpis.usdBrl.spread_revenue],
        backgroundColor: _ct.donutColors,
        borderWidth: 0, hoverOffset: 8
      }]
    },
    options: {
      responsive: true, maintainAspectRatio: false,
      plugins: {
        legend: { position: 'bottom', labels: { padding: 16, font: { size: 12, weight: 600 } } },
        tooltip: { callbacks: { label: function(ctx) { return ctx.label + ': ' + fmtUSD(ctx.raw); } } }
      },
      cutout: '65%'
    }
  });
  } catch(e) { console.warn('Chart donut:', e.message); }

  // Prepare trend data
  var allDays = new Set();
  d.trend.brlUsd.forEach(function(t) { allDays.add(t.dia); });
  d.trend.usdBrl.forEach(function(t) { allDays.add(t.dia); });
  d.trend.usdUsd.forEach(function(t) { allDays.add(t.dia); });
  var days = [...allDays].sort();
  var labels = days.map(function(x) { var p = x.split('-'); return p[2] + '/' + p[1]; });

  var spreadByDay = {}, volByDay = {};
  days.forEach(function(day) { spreadByDay[day] = []; volByDay[day] = 0; });
  d.trend.brlUsd.forEach(function(t) { spreadByDay[t.dia].push(t.avg_spread); volByDay[t.dia] += t.vol_usd; });
  d.trend.usdBrl.forEach(function(t) { spreadByDay[t.dia].push(t.avg_spread); volByDay[t.dia] += t.vol_usd; });
  d.trend.usdUsd.forEach(function(t) { volByDay[t.dia] += t.vol_usd; });

  var avgSpreads = days.map(function(day) {
    var vals = spreadByDay[day];
    return vals.length > 0 ? vals.reduce(function(a,b){return a+b;}, 0) / vals.length : null;
  });
  var volumes = days.map(function(day) { return volByDay[day]; });

  // Spread Trend + Volume
  try {
  chartSpreadTrend = new Chart(document.getElementById('chartSpreadTrend'), {
    type: 'bar',
    data: {
      labels: labels,
      datasets: [
        {
          label: 'Volume USD', data: volumes, type: 'bar',
          backgroundColor: _ct.volumeBar, borderColor: _ct.volumeBorder,
          borderWidth: 1, borderRadius: 4, yAxisID: 'y', order: 2
        },
        {
          label: 'Spread Medio %', data: avgSpreads, type: 'line',
          borderColor: _ct.spreadLine, backgroundColor: _ct.spreadFill,
          borderWidth: 2, pointRadius: 2, pointHoverRadius: 5, fill: true,
          tension: 0.3, yAxisID: 'y1', order: 1, spanGaps: true
        }
      ]
    },
    options: {
      responsive: true, maintainAspectRatio: false, interaction: { mode: 'index', intersect: false },
      plugins: {
        legend: { position: 'top', labels: { font: { size: 11, weight: 600 }, padding: 12 } },
        tooltip: {
          callbacks: {
            label: function(ctx) {
              return ctx.dataset.label === 'Volume USD'
                ? 'Volume: ' + fmtUSD(ctx.raw)
                : 'Spread: ' + (ctx.raw !== null ? ctx.raw.toFixed(2) + '%' : 'N/A');
            }
          }
        }
      },
      scales: {
        y: { position: 'left', grid: { color: _ct.grid }, ticks: { callback: function(v){return fmtUSD(v);}, font: { size: 10 } } },
        y1: { position: 'right', grid: { display: false }, ticks: { callback: function(v){return v.toFixed(1) + '%';}, font: { size: 10 } }, min: 0 },
        x: { grid: { display: false }, ticks: { font: { size: 10 }, maxRotation: 45 } }
      }
    }
  });
  } catch(e) { console.warn('Chart spread:', e.message); }

  // Top 10 Clients (with click-to-hide)
  _updateClientChart(d);
  document.getElementById('btnResetClients').style.display = _hiddenClients.size ? '' : 'none';

  // Volume by Flow Stacked
  var volBrlUsd = days.map(function(day) { var t = d.trend.brlUsd.find(function(x){return x.dia === day;}); return t ? t.vol_usd : 0; });
  var volUsdBrl = days.map(function(day) { var t = d.trend.usdBrl.find(function(x){return x.dia === day;}); return t ? t.vol_usd : 0; });
  var volUsdUsd = days.map(function(day) { var t = d.trend.usdUsd.find(function(x){return x.dia === day;}); return t ? t.vol_usd : 0; });
  try {
  chartVolFlow = new Chart(document.getElementById('chartVolFlow'), {
    type: 'bar',
    data: {
      labels: labels,
      datasets: [
        { label: 'BRL\\u2192USD', data: volBrlUsd, backgroundColor: _ct.flowColors[0], borderRadius: 2 },
        { label: 'USD\\u2192BRL', data: volUsdBrl, backgroundColor: _ct.flowColors[1], borderRadius: 2 },
        { label: 'USD\\u2192USD', data: volUsdUsd, backgroundColor: _ct.flowColors[2], borderRadius: 2 }
      ]
    },
    options: {
      responsive: true, maintainAspectRatio: false,
      plugins: {
        legend: { position: 'top', labels: { font: { size: 11, weight: 600 }, padding: 12 } },
        tooltip: { callbacks: { label: function(ctx) { return ctx.dataset.label + ': ' + fmtUSD(ctx.raw); } } }
      },
      scales: {
        x: { stacked: true, grid: { display: false }, ticks: { font: { size: 10 }, maxRotation: 45 } },
        y: { stacked: true, grid: { color: _ct.grid }, ticks: { callback: function(v){return fmtUSD(v);}, font: { size: 10 } } }
      }
    }
  });
  } catch(e) { console.warn('Chart volFlow:', e.message); }

  // Netting timeline chart
  _renderNettingChart(d, currentNettingGran);
}

// === Feature 1: Click-to-hide Client Chart ===
function _updateClientChart(d) {
  if (typeof Chart === 'undefined') return;
  var _ct = getChartTheme();
  if (chartTopClients) { try { chartTopClients.destroy(); } catch(e) {} }
  var visible = d.topClients.filter(function(_, i) { return !_hiddenClients.has(i); });
  var clientNames = visible.map(function(c) { return c.nome.length > 25 ? c.nome.slice(0, 22) + '...' : c.nome; });
  var clientVols = visible.map(function(c) { return c.vol_usd; });
  try {
  chartTopClients = new Chart(document.getElementById('chartTopClients'), {
    type: 'bar',
    data: {
      labels: clientNames,
      datasets: [{
        label: 'Volume USD', data: clientVols,
        backgroundColor: _ct.clientBar, borderColor: _ct.clientBorder,
        borderWidth: 1, borderRadius: 4
      }]
    },
    options: {
      responsive: true, maintainAspectRatio: false, indexAxis: 'y',
      onClick: function(evt, elements) {
        if (!elements.length) return;
        var clickedVisIdx = elements[0].index;
        // Map back to original index
        var origIdx = -1, visCount = -1;
        for (var i = 0; i < d.topClients.length; i++) {
          if (!_hiddenClients.has(i)) visCount++;
          if (visCount === clickedVisIdx) { origIdx = i; break; }
        }
        if (origIdx >= 0) {
          _hiddenClients.add(origIdx);
          _updateClientChart(d);
          document.getElementById('btnResetClients').style.display = _hiddenClients.size ? '' : 'none';
        }
      },
      plugins: {
        legend: { display: false },
        tooltip: { callbacks: { label: function(ctx) { return fmtUSD(ctx.raw) + ' (' + visible[ctx.dataIndex].qtd + ' ops)'; } } }
      },
      scales: {
        x: { grid: { color: _ct.grid }, ticks: { callback: function(v){return fmtUSD(v);}, font: { size: 10 } } },
        y: { grid: { display: false }, ticks: { font: { size: 11, weight: 600 } } }
      }
    }
  });
  } catch(e) { console.warn('Chart clients:', e.message); }
}

function _resetClientFilter() {
  _hiddenClients.clear();
  if (_biData) _updateClientChart(_biData);
  document.getElementById('btnResetClients').style.display = 'none';
}
// Expose to onclick
window._resetClientFilter = _resetClientFilter;

// === Feature 2: Risk Table Filter ===
function _filterRiskTable(threshold) {
  _riskThreshold = threshold;
  if (!_biData) return;
  var filtered = _biData.clientsAtRisk.filter(function(c) { return c.days_inactive >= threshold; });
  var riskBody = document.getElementById('riskTableBody');
  if (filtered.length === 0) {
    riskBody.innerHTML = '<tr><td colspan="4" style="text-align:center;color:var(--green);font-weight:600;">Nenhum cliente em risco (' + threshold + 'd+)</td></tr>';
  } else {
    riskBody.innerHTML = filtered.map(function(c) {
      return '<tr><td style="font-weight:600;">' + (c.nome.length > 30 ? c.nome.slice(0,27)+'...' : c.nome) + '</td>' +
        '<td style="color:var(--red);">' + c.last_op.slice(0,10) + '</td>' +
        '<td style="color:var(--text-muted);">' + c.days_inactive + 'd</td>' +
        '<td>' + fmtUSD(c.vol_usd) + '</td></tr>';
    }).join('');
  }
  // Update button active state
  document.querySelectorAll('.risk-threshold-btn').forEach(function(b) {
    b.classList.toggle('active', Number(b.dataset.risk) === threshold);
  });
}

// === Feature 3: Netting Timeline Chart ===
function _aggregateNetting(trendBrlUsd, trendUsdBrl, gran) {
  // Build daily map: saida (BRL->USD) and entrada (USD->BRL)
  var dayMap = {};
  trendBrlUsd.forEach(function(t) {
    if (!dayMap[t.dia]) dayMap[t.dia] = { saida: 0, entrada: 0 };
    dayMap[t.dia].saida += t.vol_usd;
  });
  trendUsdBrl.forEach(function(t) {
    if (!dayMap[t.dia]) dayMap[t.dia] = { saida: 0, entrada: 0 };
    dayMap[t.dia].entrada += t.vol_usd;
  });

  var days = Object.keys(dayMap).sort();
  if (gran === 'D') {
    return days.map(function(day) {
      var p = day.split('-');
      return { label: p[2] + '/' + p[1], saida: dayMap[day].saida, entrada: dayMap[day].entrada, posicao: dayMap[day].entrada - dayMap[day].saida };
    });
  }

  // Group by week or month
  var grouped = {};
  days.forEach(function(day) {
    var key;
    if (gran === 'W') {
      var dt = new Date(day);
      var thu = new Date(dt); thu.setDate(dt.getDate() - ((dt.getDay() + 6) % 7) + 3);
      var y = thu.getFullYear();
      var w = Math.ceil((((thu - new Date(y,0,4)) / 86400000) + new Date(y,0,4).getDay() + 1) / 7);
      key = 'W' + (w < 10 ? '0' : '') + w + '/' + String(y).slice(2);
    } else {
      var p = day.split('-');
      key = p[1] + '/' + p[0].slice(2);
    }
    if (!grouped[key]) grouped[key] = { saida: 0, entrada: 0 };
    grouped[key].saida += dayMap[day].saida;
    grouped[key].entrada += dayMap[day].entrada;
  });

  return Object.keys(grouped).map(function(key) {
    return { label: key, saida: grouped[key].saida, entrada: grouped[key].entrada, posicao: grouped[key].entrada - grouped[key].saida };
  });
}

function _renderNettingChart(d, gran) {
  if (typeof Chart === 'undefined') return;
  var _ct = getChartTheme();
  if (chartNetting) { try { chartNetting.destroy(); } catch(e) {} }

  var data = _aggregateNetting(d.trend.brlUsd, d.trend.usdBrl, gran);
  var labels = data.map(function(r) { return r.label; });
  var saidaData = data.map(function(r) { return r.saida; });
  var entradaData = data.map(function(r) { return r.entrada; });
  var posicaoData = data.map(function(r) { return r.posicao; });

  var isDark = document.documentElement.getAttribute('data-theme') === 'dark';

  try {
  chartNetting = new Chart(document.getElementById('chartNetting'), {
    type: 'bar',
    data: {
      labels: labels,
      datasets: [
        {
          label: 'Saida (BRL\\u2192USD)', data: saidaData, type: 'bar',
          backgroundColor: isDark ? 'rgba(255,68,68,0.2)' : 'rgba(217,48,37,0.15)',
          borderColor: isDark ? 'rgba(255,68,68,0.5)' : 'rgba(217,48,37,0.4)',
          borderWidth: 1, borderRadius: 3, stack: 'flow', order: 2
        },
        {
          label: 'Entrada (USD\\u2192BRL)', data: entradaData, type: 'bar',
          backgroundColor: isDark ? 'rgba(0,255,136,0.2)' : 'rgba(30,142,62,0.15)',
          borderColor: isDark ? 'rgba(0,255,136,0.5)' : 'rgba(30,142,62,0.4)',
          borderWidth: 1, borderRadius: 3, stack: 'flow', order: 2
        },
        {
          label: 'Posicao Liquida', data: posicaoData, type: 'line',
          borderColor: isDark ? '#58A6FF' : '#1A73E8',
          backgroundColor: 'transparent',
          borderWidth: 2, pointRadius: 3, pointHoverRadius: 6,
          tension: 0.3, order: 1
        }
      ]
    },
    options: {
      responsive: true, maintainAspectRatio: false, interaction: { mode: 'index', intersect: false },
      plugins: {
        legend: { position: 'top', labels: { font: { size: 11, weight: 600 }, padding: 10, boxWidth: 12 } },
        tooltip: {
          callbacks: {
            label: function(ctx) { return ctx.dataset.label + ': ' + fmtUSD(ctx.raw); }
          }
        }
      },
      scales: {
        x: { stacked: false, grid: { display: false }, ticks: { font: { size: 10 }, maxRotation: 45 } },
        y: { grid: { color: _ct.grid }, ticks: { callback: function(v){return fmtUSD(v);}, font: { size: 10 } } }
      }
    }
  });
  } catch(e) { console.warn('Chart netting:', e.message); }
}

// === Main Data Loader ===
async function loadBI() {
  document.getElementById('periodInfo').textContent = 'Carregando BI...';
  const periodDays = Math.round((new Date(currentEnd) - new Date(currentStart)) / 86400000) + 1;

  try {
    const resp = await fetch('/admin/api/bi?start=' + currentStart + '&end=' + currentEnd);
    if (!resp.ok) { document.getElementById('periodInfo').textContent = 'Erro HTTP ' + resp.status; return; }
    const d = await resp.json();
    if (d.error) { document.getElementById('periodInfo').textContent = 'Erro: ' + d.error; return; }
    _biData = d;

    // Hero KPIs
    document.getElementById('kpiSpreadRevenue').textContent = fmtUSD(d.kpis.total.spread_revenue);
    const sBadge = fmtPct(d.kpis.total.spread_revenue, d.comparison.prev_spread);
    document.getElementById('kpiSpreadBadge').textContent = sBadge.text;
    document.getElementById('kpiSpreadBadge').className = 'hero-badge ' + sBadge.cls;

    document.getElementById('kpiVolume').textContent = fmtUSD(d.kpis.total.vol_usd);
    const vBadge = fmtPct(d.kpis.total.vol_usd, d.comparison.prev_vol_usd);
    document.getElementById('kpiVolumeBadge').textContent = vBadge.text;
    document.getElementById('kpiVolumeBadge').className = 'hero-badge ' + vBadge.cls;

    document.getElementById('kpiTransactions').textContent = fmtNum(d.kpis.total.qtd);
    const tBadge = fmtPct(d.kpis.total.qtd, d.comparison.prev_qtd);
    document.getElementById('kpiTransBadge').textContent = tBadge.text;
    document.getElementById('kpiTransBadge').className = 'hero-badge ' + tBadge.cls;

    document.getElementById('kpiClients').textContent = fmtNum(d.kpis.total.clientes);
    document.getElementById('kpiTicket').textContent = fmtUSD(d.kpis.total.ticket_medio);

    // Spread badge
    const avgSpread = d.kpis.brlUsd.avg_spread_pct || d.kpis.usdBrl.avg_spread_pct || 0;
    document.getElementById('spreadBadge').textContent = 'Media: ' + avgSpread.toFixed(2) + '%';

    // === Charts ===
    _renderBICharts(d);

    // Retention
    document.getElementById('retentionValue').textContent = d.retention.rate + '%';
    document.getElementById('retentionBar').style.width = d.retention.rate + '%';
    document.getElementById('retentionLabel').textContent = d.retention.retained + ' de ' + d.retention.prev_clients + ' clientes retidos';
    const retEl = document.getElementById('retentionValue');
    retEl.className = 'gauge-value ' + (d.retention.rate >= 70 ? 'green' : d.retention.rate >= 40 ? 'blue' : 'red');
    document.getElementById('retentionBar').className = 'gauge-bar-fill ' + (d.retention.rate >= 70 ? 'green' : d.retention.rate >= 40 ? 'blue' : 'red');

    // Retention breakdown: novos and perdidos
    var retNovos = d.kpis.total.clientes - d.retention.retained;
    var retPerdidos = d.retention.prev_clients - d.retention.retained;
    document.getElementById('retNovos').textContent = '+' + Math.max(0, retNovos) + ' novos';
    document.getElementById('retPerdidos').textContent = '-' + Math.max(0, retPerdidos) + ' perdidos';

    // Clients at risk table (filtered by threshold)
    _filterRiskTable(_riskThreshold);

    // Netting
    document.getElementById('nettingSaida').textContent = fmtUSD(d.netting.saida_usd);
    document.getElementById('nettingEntrada').textContent = fmtUSD(d.netting.entrada_usd);
    const posEl = document.getElementById('nettingPosicao');
    posEl.textContent = fmtUSD(Math.abs(d.netting.posicao_liquida));
    posEl.className = 'netting-value ' + (d.netting.posicao_liquida >= 0 ? 'green' : 'red');
    posEl.textContent = (d.netting.posicao_liquida >= 0 ? '+' : '-') + fmtUSD(Math.abs(d.netting.posicao_liquida));
    document.getElementById('nettingEficiencia').textContent = d.netting.eficiencia + '%';
    document.getElementById('nettingBar').style.width = d.netting.eficiencia + '%';

    // Agent ranking table
    const agentBody = document.getElementById('agentTableBody');
    if (d.agentRanking.length === 0) {
      agentBody.innerHTML = '<tr><td colspan="6" style="text-align:center;color:var(--text-muted);">Sem dados</td></tr>';
    } else {
      agentBody.innerHTML = d.agentRanking.map(a => {
        const rankCls = a.rank <= 3 ? 'rank-' + a.rank : 'rank-default';
        return '<tr>' +
          '<td><span class="rank ' + rankCls + '">' + a.rank + '</span></td>' +
          '<td style="font-weight:600;">' + a.nome + '</td>' +
          '<td>' + fmtUSD(a.vol_usd) + '</td>' +
          '<td>' + fmtNum(a.qtd) + '</td>' +
          '<td style="color:var(--green);font-weight:600;">' + fmtUSD(a.spread_revenue) + '</td>' +
          '<td>' + a.clientes + '</td></tr>';
      }).join('');
    }

    // Show period info after successful load
    const periodDaysLabel = Math.round((new Date(currentEnd) - new Date(currentStart)) / 86400000) + 1;
    var _chartInfo = typeof Chart !== 'undefined' ? '' : ' | Charts: OFF' + (window._chartError ? ' (' + window._chartError + ')' : '');
    document.getElementById('periodInfo').textContent = periodDaysLabel + ' dias | ' + currentStart.split('-').reverse().join('/') + ' a ' + currentEnd.split('-').reverse().join('/') + _chartInfo;

  } catch (err) {
    console.error('BI load error:', err);
    document.getElementById('periodInfo').textContent = 'Erro: ' + (err.message || err);
  }
}

// === Live Rates ===
let _lastUsdBid = null, _lastUsdAsk = null;
function pulseEl(el) { el.closest('.live-rate-btn').classList.add('pulse'); setTimeout(() => el.closest('.live-rate-btn').classList.remove('pulse'), 500); }
async function fetchLiveRate() {
  try {
    const resp = await fetch('/api/cotacao');
    const json = await resp.json();
    const usd = json.USDBRL;
    if (usd) {
      const bidRaw = parseFloat(usd.bid), askRaw = parseFloat(usd.ask);
      const bid = bidRaw * (1 - 0.0043);
      const ask = askRaw * (1 + 0.0005);
      const elC = document.getElementById('rateUsdCompra'), elV = document.getElementById('rateUsdVenda');
      elC.textContent = bid.toFixed(4); elV.textContent = ask.toFixed(4);
      if (_lastUsdBid !== null && bidRaw !== _lastUsdBid) pulseEl(elC);
      if (_lastUsdAsk !== null && askRaw !== _lastUsdAsk) pulseEl(elV);
      _lastUsdBid = bidRaw; _lastUsdAsk = askRaw;
    }
    document.getElementById('rateTime').textContent = new Date().toLocaleTimeString('pt-BR');
  } catch (e) { /* retry next cycle */ }
}

// === Revenue Analytics ===
let currentGran = 'dia';
let chartRevTimeline, chartRevDonut;

function destroyRevCharts() {
  [chartRevTimeline, chartRevDonut].forEach(c => { if (c) c.destroy(); });
}

function _renderRevCharts(d) {
  if (typeof Chart === 'undefined' || !d.timeline || !d.totals) return;
  var _ct = getChartTheme();
  try { destroyRevCharts(); } catch(e) {}
  showChart('skelRevTimeline', 'chartRevTimeline');
  showChart('skelRevDonut', 'chartRevDonut');

  var periods = [...new Set(d.timeline.map(function(r){return r.periodo_label;}))].sort();
  var products = [...new Set(d.timeline.map(function(r){return r.produto;}))].sort();

  var datasets = products.map(function(prod, i) {
    return {
      label: prod,
      data: periods.map(function(p) {
        var match = d.timeline.find(function(r){return r.periodo_label === p && r.produto === prod;});
        return match ? match.receita : 0;
      }),
      backgroundColor: getProductColor(prod, i),
      borderRadius: 3
    };
  });

  var labels = periods.map(function(p) {
    if (currentGran === 'dia') { var parts = p.split('-'); return parts[2] + '/' + parts[1]; }
    if (currentGran === 'mes') { var parts = p.split('-'); return parts[1] + '/' + parts[0]; }
    return p;
  });

  try {
  chartRevTimeline = new Chart(document.getElementById('chartRevTimeline'), {
    type: 'bar',
    data: { labels: labels, datasets: datasets },
    options: {
      responsive: true, maintainAspectRatio: false,
      plugins: {
        legend: { position: 'top', labels: { font: { size: 11, weight: 600 }, padding: 10, boxWidth: 12 } },
        tooltip: { callbacks: { label: function(ctx) { return ctx.dataset.label + ': ' + fmtUSD(ctx.raw); } } }
      },
      scales: {
        x: { stacked: true, grid: { display: false }, ticks: { font: { size: 10 }, maxRotation: 45 } },
        y: { stacked: true, grid: { color: _ct.grid }, ticks: { callback: function(v){return fmtUSD(v);}, font: { size: 10 } } }
      }
    }
  });
  } catch(e) { console.warn('Chart revTimeline:', e.message); }

  var donutData = d.totals.map(function(t){return t.receita;});
  var donutLabels = d.totals.map(function(t){return t.produto;});
  var donutColors = d.totals.map(function(t, i){return getProductColor(t.direcao + ': ' + t.tipo, i);});

  try {
  chartRevDonut = new Chart(document.getElementById('chartRevDonut'), {
    type: 'doughnut',
    data: {
      labels: donutLabels,
      datasets: [{ data: donutData, backgroundColor: donutColors, borderWidth: 0, hoverOffset: 8 }]
    },
    options: {
      responsive: true, maintainAspectRatio: false,
      plugins: {
        legend: { position: 'bottom', labels: { padding: 12, font: { size: 11, weight: 600 }, boxWidth: 12 } },
        tooltip: { callbacks: { label: function(ctx) { return ctx.label + ': ' + fmtUSD(ctx.raw) + ' (' + d.totals[ctx.dataIndex].qtd + ' ops)'; } } }
      },
      cutout: '60%'
    }
  });
  } catch(e) { console.warn('Chart revDonut:', e.message); }
}

async function loadRevenue() {
  document.getElementById('revenueStatus').textContent = 'Carregando...';
  try {
    const resp = await fetch('/admin/api/bi/revenue?start=' + currentStart + '&end=' + currentEnd + '&granularity=' + currentGran);
    if (!resp.ok) { document.getElementById('revenueStatus').textContent = 'Erro HTTP ' + resp.status; return; }
    const d = await resp.json();

    if (d.error) { document.getElementById('revenueStatus').textContent = 'Erro: ' + d.error; return; }
    if (!d.summary || !d.timeline) { document.getElementById('revenueStatus').textContent = 'Dados incompletos'; return; }
    _revenueData = d;

    // KPI cards
    document.getElementById('revTotal').textContent = fmtUSD(d.summary.total_receita);
    document.getElementById('revTotalQtd').textContent = fmtNum(d.summary.total_qtd) + ' operacoes';
    document.getElementById('revBrUs').textContent = fmtUSD(d.summary.receita_br_us);
    document.getElementById('revUsBr').textContent = fmtUSD(d.summary.receita_us_br);
    document.getElementById('revTicket').textContent = fmtUSD(d.summary.ticket_medio_receita);
    document.getElementById('revGranBadge').textContent = currentGran;

    // Charts
    _renderRevCharts(d);

    // Detailed table
    const tbody = document.getElementById('revTableBody');
    if (d.timeline.length === 0) {
      tbody.innerHTML = '<tr><td colspan="5" style="text-align:center;color:var(--text-muted);">Sem dados no periodo</td></tr>';
    } else {
      // Group by period for subtotals
      const byPeriod = {};
      d.timeline.forEach(r => {
        if (!byPeriod[r.periodo_label]) byPeriod[r.periodo_label] = [];
        byPeriod[r.periodo_label].push(r);
      });

      let html = '';
      for (const [periodo, rows] of Object.entries(byPeriod)) {
        const periodTotal = rows.reduce((s, r) => s + r.receita, 0);
        const periodQtd = rows.reduce((s, r) => s + r.qtd, 0);
        rows.forEach(r => {
          const ticketOp = r.qtd > 0 ? r.receita / r.qtd : 0;
          html += '<tr>' +
            '<td style="font-weight:600;">' + periodo + '</td>' +
            '<td>' + r.produto + '</td>' +
            '<td style="color:' + (r.receita >= 0 ? 'var(--green)' : 'var(--red)') + ';font-weight:600;">' + fmtUSD(r.receita) + '</td>' +
            '<td>' + fmtNum(r.qtd) + '</td>' +
            '<td>' + fmtUSD(ticketOp) + '</td></tr>';
        });
        if (rows.length > 1) {
          html += '<tr style="background:var(--bg);font-weight:700;">' +
            '<td>' + periodo + '</td><td>TOTAL</td>' +
            '<td style="color:' + (periodTotal >= 0 ? 'var(--green)' : 'var(--red)') + ';">' + fmtUSD(periodTotal) + '</td>' +
            '<td>' + fmtNum(periodQtd) + '</td>' +
            '<td>' + fmtUSD(periodQtd > 0 ? periodTotal / periodQtd : 0) + '</td></tr>';
        }
      }
      tbody.innerHTML = html;
    }

    document.getElementById('revenueStatus').textContent = d.timeline.length + ' registros | ' + currentGran;
  } catch (err) {
    console.error('Revenue load error:', err);
    document.getElementById('revenueStatus').textContent = 'Erro ao carregar';
  }
}

// Granularity buttons (Revenue)
document.querySelectorAll('.gran-btn').forEach(btn => {
  btn.addEventListener('click', () => {
    document.querySelectorAll('.gran-btn').forEach(b => b.classList.remove('active'));
    btn.classList.add('active');
    currentGran = btn.dataset.gran;
    loadRevenue();
  });
});

// Risk threshold buttons
document.querySelectorAll('.risk-threshold-btn').forEach(btn => {
  btn.addEventListener('click', () => {
    _filterRiskTable(Number(btn.dataset.risk));
  });
});

// Netting granularity buttons
document.querySelectorAll('.netting-gran-btn').forEach(btn => {
  btn.addEventListener('click', () => {
    document.querySelectorAll('.netting-gran-btn').forEach(b => b.classList.remove('active'));
    btn.classList.add('active');
    currentNettingGran = btn.dataset.nettingGran;
    if (_biData) _renderNettingChart(_biData, currentNettingGran);
  });
});

// === STRATEGIC DATA (Cohorts, Expansion, Cross-sell, Maturity) ===
var _strategicData = null;
var chartWaterfall, chartExpDonut, chartCrossSell, chartMaturity;

function destroyStrategicCharts() {
  [chartWaterfall, chartExpDonut, chartCrossSell, chartMaturity].forEach(function(c){ if(c) c.destroy(); });
  chartWaterfall = chartExpDonut = chartCrossSell = chartMaturity = null;
}

async function loadStrategic() {
  try {
    var resp = await fetch('/admin/api/bi/strategic?start=' + currentStart + '&end=' + currentEnd);
    if (!resp.ok) return;
    var d = await resp.json();
    if (d.error) return;
    _strategicData = d;
    renderStrategic(d);
  } catch(e) { console.warn('Strategic load:', e.message); }
}

function renderStrategic(d) {
  var t = getChartTheme();
  renderExpansion(d.expansion, t);
  renderCrossSell(d.crossSell, t);
  renderMaturity(d.maturity, t);
  renderCohort(d.cohorts, t);
}

// --- Expansion / Contraction ---
function renderExpansion(exp, t) {
  showChart('skelWaterfall', 'chartWaterfall');
  showChart('skelExpDonut', 'chartExpDonut');
  document.getElementById('wfNewCount').textContent = exp.new_clients.count;
  document.getElementById('wfNewRev').textContent = '+' + fmtUSD(exp.new_clients.revenue);
  document.getElementById('wfExpCount').textContent = exp.expansion.count;
  document.getElementById('wfExpRev').textContent = '+' + fmtUSD(exp.expansion.revenue);
  document.getElementById('wfStaCount').textContent = exp.stable.count;
  document.getElementById('wfStaRev').textContent = fmtUSD(exp.stable.revenue);
  document.getElementById('wfConCount').textContent = exp.contraction.count;
  document.getElementById('wfConRev').textContent = fmtUSD(exp.contraction.revenue);
  document.getElementById('wfChurnCount').textContent = exp.churned.count;
  document.getElementById('wfChurnRev').textContent = fmtUSD(exp.churned.revenue);

  if (typeof Chart === 'undefined') return;
  try { if (chartWaterfall) chartWaterfall.destroy(); } catch(e){}
  try { if (chartExpDonut) chartExpDonut.destroy(); } catch(e){}

  var labels = ['Novos','Expansao','Estavel','Contracao','Churned'];
  var values = [exp.new_clients.revenue, exp.expansion.revenue, exp.stable.revenue, exp.contraction.revenue, exp.churned.revenue];
  var colors = [t.blue || '#58A6FF', t.healthGreen || '#00FF88', t.text || '#94A3B8', t.healthOrange || '#F0883E', t.healthRed || '#FF4444'];
  var bgColors = colors.map(function(c,i){ return i===2 ? (t.grid || 'rgba(0,0,0,0.1)') : c; });

  try {
  chartWaterfall = new Chart(document.getElementById('chartWaterfall'), {
    type: 'bar', data: {
      labels: labels,
      datasets: [{ label: 'Receita R$', data: values, backgroundColor: bgColors, borderColor: colors, borderWidth: 1, borderRadius: 6 }]
    }, options: {
      responsive: true, maintainAspectRatio: false,
      plugins: { legend:{display:false}, tooltip:{callbacks:{label:function(ctx){ return ctx.label+': '+fmtUSD(ctx.raw); }}} },
      scales: { y:{grid:{color:t.grid}, ticks:{callback:function(v){return fmtUSD(v);}, font:{size:10}}}, x:{grid:{display:false}, ticks:{font:{size:11,weight:600}}} }
    }
  }); } catch(e){ console.warn('chartWaterfall:', e.message); }

  var counts = [exp.new_clients.count, exp.expansion.count, exp.stable.count, exp.contraction.count, exp.churned.count];
  try {
  chartExpDonut = new Chart(document.getElementById('chartExpDonut'), {
    type: 'doughnut', data: {
      labels: labels, datasets: [{ data: counts, backgroundColor: colors, borderWidth: 0, hoverOffset: 8 }]
    }, options: {
      responsive: true, maintainAspectRatio: false, cutout: '60%',
      plugins: { legend:{position:'bottom', labels:{padding:12, font:{size:11,weight:600}}},
        tooltip:{callbacks:{label:function(ctx){ var total=ctx.dataset.data.reduce(function(a,b){return a+b;},0); return ctx.label+': '+ctx.raw+' ('+(total>0?(ctx.raw/total*100).toFixed(0)+'%':'0%')+')'; }}} }
    }
  }); } catch(e){ console.warn('chartExpDonut:', e.message); }
}

// --- Cross-sell ---
function renderCrossSell(cs, t) {
  showChart('skelCrossSell', 'chartCrossSell');
  if (typeof Chart === 'undefined') return;
  try { if (chartCrossSell) chartCrossSell.destroy(); } catch(e){}

  var labels = ['CambioPay Only','CambioCheckout Only','Ambos'];
  var counts = [cs.pay_only.count, cs.checkout_only.count, cs.both.count];
  var vols = [cs.pay_only.vol, cs.checkout_only.vol, cs.both.vol];
  var colors = [t.blue || '#58A6FF', t.healthGreen || '#00FF88', t.purple || '#BC8CFF'];

  try {
  chartCrossSell = new Chart(document.getElementById('chartCrossSell'), {
    type: 'doughnut', data: {
      labels: labels, datasets: [{ data: counts, backgroundColor: colors, borderWidth: 0, hoverOffset: 8 }]
    }, options: {
      responsive: true, maintainAspectRatio: false, cutout: '60%',
      plugins: { legend:{position:'bottom', labels:{padding:10, font:{size:11,weight:600}}},
        tooltip:{callbacks:{label:function(ctx){ return ctx.label+': '+ctx.raw+' clientes'; }}} }
    }
  }); } catch(e){}

  var total = counts.reduce(function(a,b){return a+b;},0) || 1;
  var barsHtml = '';
  var segLabels = ['CambioPay','Checkout','Ambos'];
  counts.forEach(function(cnt, i) {
    var pct = Math.round(cnt / total * 100);
    barsHtml += '<div class="seg-row"><span class="seg-label">'+segLabels[i]+'</span>' +
      '<div class="seg-bar-wrap"><div class="seg-bar-fill" style="width:'+pct+'%;background:'+colors[i]+';"><span class="seg-bar-text">'+pct+'%</span></div></div>' +
      '<span class="seg-count">'+cnt+' | '+fmtUSD(vols[i])+'</span></div>';
  });
  document.getElementById('crossSellBars').innerHTML = barsHtml;
}

// --- Client Maturity ---
function renderMaturity(mat, t) {
  showChart('skelMaturity', 'chartMaturity');
  if (typeof Chart === 'undefined') return;
  try { if (chartMaturity) chartMaturity.destroy(); } catch(e){}

  var labels = ['Novo (<3m)','Crescendo (3-12m)','Maduro (12m+)','Declinando'];
  var counts = [mat.new_client.count, mat.growing.count, mat.mature.count, mat.declining.count];
  var vols = [mat.new_client.vol, mat.growing.vol, mat.mature.vol, mat.declining.vol];
  var colors = [t.blue || '#58A6FF', t.healthGreen || '#00FF88', t.purple || '#BC8CFF', t.healthOrange || '#F0883E'];

  try {
  chartMaturity = new Chart(document.getElementById('chartMaturity'), {
    type: 'doughnut', data: {
      labels: labels, datasets: [{ data: counts, backgroundColor: colors, borderWidth: 0, hoverOffset: 8 }]
    }, options: {
      responsive: true, maintainAspectRatio: false, cutout: '60%',
      plugins: { legend:{position:'bottom', labels:{padding:10, font:{size:11,weight:600}}},
        tooltip:{callbacks:{label:function(ctx){ return ctx.label+': '+ctx.raw+' clientes'; }}} }
    }
  }); } catch(e){}

  var total = counts.reduce(function(a,b){return a+b;},0) || 1;
  var barsHtml = '';
  var segLabels = ['Novo','Crescendo','Maduro','Declinando'];
  counts.forEach(function(cnt, i) {
    var pct = Math.round(cnt / total * 100);
    barsHtml += '<div class="seg-row"><span class="seg-label">'+segLabels[i]+'</span>' +
      '<div class="seg-bar-wrap"><div class="seg-bar-fill" style="width:'+pct+'%;background:'+colors[i]+';"><span class="seg-bar-text">'+pct+'%</span></div></div>' +
      '<span class="seg-count">'+cnt+' | '+fmtUSD(vols[i])+'</span></div>';
  });
  document.getElementById('maturityBars').innerHTML = barsHtml;
}

// --- Cohort Retention Heatmap ---
function renderCohort(cohorts, t) {
  if (!cohorts || !cohorts.length) return;
  var maxCols = 0;
  cohorts.forEach(function(c) { if (c.retention.length > maxCols) maxCols = c.retention.length; });
  maxCols = Math.min(maxCols, 13);

  var headHtml = '<tr><th>Cohort</th><th>Clientes</th>';
  for (var i = 0; i < maxCols; i++) headHtml += '<th>M' + i + '</th>';
  headHtml += '</tr>';
  document.getElementById('cohortHead').innerHTML = headHtml;

  var isDark = document.documentElement.getAttribute('data-theme') === 'dark';
  var bodyHtml = '';
  cohorts.forEach(function(c) {
    bodyHtml += '<tr><td style="font-weight:700;">' + c.month + '</td><td>' + c.size + '</td>';
    for (var i = 0; i < maxCols; i++) {
      var val = c.retention[i] != null ? c.retention[i] : '';
      if (val === '') { bodyHtml += '<td></td>'; continue; }
      var bg, fg;
      if (val >= 80) { bg = isDark ? 'rgba(0,255,136,0.35)' : 'rgba(30,142,62,0.25)'; fg = isDark ? '#00FF88' : '#1E8E3E'; }
      else if (val >= 50) { bg = isDark ? 'rgba(88,166,255,0.25)' : 'rgba(26,115,232,0.18)'; fg = isDark ? '#58A6FF' : '#1A73E8'; }
      else if (val >= 25) { bg = isDark ? 'rgba(240,136,62,0.25)' : 'rgba(240,136,62,0.15)'; fg = isDark ? '#F0883E' : '#E8710A'; }
      else { bg = isDark ? 'rgba(255,68,68,0.2)' : 'rgba(217,48,37,0.12)'; fg = isDark ? '#FF4444' : '#D93025'; }
      bodyHtml += '<td class="cohort-cell" style="background:'+bg+';color:'+fg+';">'+val+'%</td>';
    }
    bodyHtml += '</tr>';
  });
  document.getElementById('cohortBody').innerHTML = bodyHtml;
}

// === Console Nav: Scroll Spy (highlight active section) ===
(function() {
  var links = document.querySelectorAll('.console-nav-btn');
  var ids = [];
  links.forEach(function(a) {
    var h = a.getAttribute('href');
    if (h && h.charAt(0) === '#') ids.push(h.substring(1));
  });
  var ticking = false;
  function update() {
    var active = ids[0];
    for (var i = 0; i < ids.length; i++) {
      var el = document.getElementById(ids[i]);
      if (el && el.getBoundingClientRect().top <= 150) active = ids[i];
    }
    links.forEach(function(a) {
      var h = a.getAttribute('href');
      if (h === '#' + active) a.classList.add('active');
      else a.classList.remove('active');
    });
    ticking = false;
  }
  window.addEventListener('scroll', function() {
    if (!ticking) { requestAnimationFrame(update); ticking = true; }
  }, { passive: true });
  update();
})();

var _forecastChart = null;
async function loadForecast() {
  try {
    var resp = await fetch('/admin/api/bi/forecast?metric=volume&days=30');
    var data = await resp.json();
    if (!data.historical || data.historical.length === 0) {
      showChart('skelForecast', 'forecastChart');
      document.getElementById('forecastInfo').textContent = 'No data';
      return;
    }
    var theme = getChartTheme();
    var histLabels = data.historical.map(function(d){return d.dia;});
    var predLabels = data.predicted.map(function(d){return d.dia;});
    var allLabels = histLabels.concat(predLabels);
    var histValues = data.historical.map(function(d){return d.vol_usd;});
    var predValues = new Array(histLabels.length).fill(null).concat(data.predicted.map(function(d){return d.vol_usd;}));
    var upperValues = new Array(histLabels.length).fill(null).concat(data.confidence_upper.map(function(d){return d.vol_usd;}));
    var lowerValues = new Array(histLabels.length).fill(null).concat(data.confidence_lower.map(function(d){return d.vol_usd;}));
    // Extend historical with nulls for prediction period
    var histFull = histValues.concat(new Array(predLabels.length).fill(null));

    showChart('skelForecast', 'forecastChart');
    if (_forecastChart) _forecastChart.destroy();
    var ctx = document.getElementById('forecastChart');
    if (!ctx) return;
    _forecastChart = new Chart(ctx, {
      type: 'line',
      data: {
        labels: allLabels,
        datasets: [
          { label: 'Confidence 95%', data: upperValues, borderColor: 'transparent', backgroundColor: theme.green + '15', fill: { target: 3, above: theme.green + '15' }, pointRadius: 0, tension: 0.3 },
          { label: 'Historical', data: histFull, borderColor: theme.blue, backgroundColor: 'transparent', borderWidth: 2, pointRadius: 0, tension: 0.3, fill: false },
          { label: 'Forecast', data: predValues, borderColor: theme.green, backgroundColor: 'transparent', borderWidth: 2, borderDash: [6,3], pointRadius: 0, tension: 0.3, fill: false },
          { data: lowerValues, borderColor: 'transparent', backgroundColor: 'transparent', pointRadius: 0, tension: 0.3, fill: false }
        ]
      },
      options: {
        responsive: true, maintainAspectRatio: false,
        plugins: {
          legend: { position: 'top', labels: { color: theme.text, usePointStyle: true, pointStyle: 'line', font: { size: 11 }, filter: function(item) { return item.text !== undefined; } } },
          tooltip: { filter: function(item) { return item.dataset.label !== undefined; } },
          filler: { propagate: false }
        },
        scales: {
          x: { ticks: { color: theme.text, maxTicksLimit: 15, font: { size: 10 } }, grid: { color: theme.grid } },
          y: { ticks: { color: theme.text, callback: function(v){return '$' + (v>=1000 ? Math.round(v/1000)+'K' : v);} }, grid: { color: theme.grid } }
        }
      }
    });
    document.getElementById('forecastInfo').textContent = data.predicted.length + '-day forecast';
  } catch (e) {
    console.error('Forecast error:', e);
    showChart('skelForecast', 'forecastChart');
    document.getElementById('forecastInfo').textContent = 'Forecast error';
  }
}

function exportBIExcel() {
  var s = document.getElementById('dateStart').value;
  var e = document.getElementById('dateEnd').value;
  if (s && e) window.location.href = '/admin/api/export/bi-excel?start=' + s + '&end=' + e;
}

// Init - runs immediately (script is at bottom of body, DOM is ready)
// Also handles case where DOMContentLoaded already fired
function _startBI() {
  try {
    // Diagnostic: show Chart.js status
    var chartStatus = typeof Chart !== 'undefined' ? 'Chart.js v' + (Chart.version || '?') : 'Chart.js FALHOU' + (window._chartError ? ': ' + window._chartError : '');
    console.log(chartStatus);

    // Apply theme-aware Chart.js defaults
    applyChartDefaults(getChartTheme());

    loadBI(); loadRevenue(); loadStrategic(); loadForecast(); fetchLiveRate();
    setInterval(fetchLiveRate, 3000);

    // Re-render charts on theme toggle
    window.addEventListener('themechange', function(e) {
      requestAnimationFrame(function() {
        applyChartDefaults(getChartTheme());
        if (_biData) { destroyCharts(); _renderBICharts(_biData); }
        if (_revenueData) { destroyRevCharts(); _renderRevCharts(_revenueData); }
        if (_strategicData) { destroyStrategicCharts(); renderStrategic(_strategicData); }
      });
    });
  } catch(e) {
    document.getElementById('periodInfo').textContent = 'Init erro: ' + e.message;
  }
}
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', _startBI);
} else {
  _startBI();
}
<\/script>
</body>
</html>`;
}

module.exports = { buildAdminBIHTML };
