/* global React, YUNO_DATA, YUNO_COMPONENTS */
(function () {
const { useState, useMemo, useEffect, useRef } = React;
const D = window.YUNO_DATA;
const { C, TrendChart, ComparisonBar, computeFiltered, effectiveRegions, ContextualFilters } = window.YUNO_COMPONENTS;

// ============================================================================
// Sidebar — 2-level: Teams (top) + active-team pages (below) with collapsible functionality
// ============================================================================
function Sidebar({ activeTeam, onTeam, activePage, onPage, onOpenSidebar, sidebarContent, selectedTeam, onSelectTeam }) {
  const [isCollapsed, setIsCollapsed] = useState(false);
  const [teamsExpanded, setTeamsExpanded] = useState(activePage === 'teams');

  const TEAM_CLUSTERS = D.TEAM_CLUSTERS || [];
  const currentSel = selectedTeam || 'all';

  // Which cluster does the current selection belong to (if any)?
  const activeClusterId = (() => {
    for (const c of TEAM_CLUSTERS) {
      if (c.id === currentSel) return c.id;
      if (c.children && c.children.some(s => s.id === currentSel)) return c.id;
    }
    return null;
  })();

  // Track which clusters are expanded (auto-expand the active one)
  const [expandedClusters, setExpandedClusters] = useState(() => {
    const s = new Set();
    if (activeClusterId) s.add(activeClusterId);
    return s;
  });

  function toggleCluster(id) {
    setExpandedClusters(prev => {
      const next = new Set(prev);
      next.has(id) ? next.delete(id) : next.add(id);
      return next;
    });
  }

  // Auto-expand the Teams group + the cluster containing the active selection
  useEffect(() => {
    if (activePage === 'teams') setTeamsExpanded(true);
    if (activeClusterId) {
      setExpandedClusters(prev => prev.has(activeClusterId) ? prev : new Set([...prev, activeClusterId]));
    }
  }, [activePage, activeClusterId]);

  function selectNode(id) {
    onPage('teams');
    onSelectTeam && onSelectTeam(id);
  }

  return (
    <aside className={`sidebar ${isCollapsed ? 'collapsed' : ''}`}>
      <div className="brand">
        {!isCollapsed && (
          <img src="assets/yuno_wordmark.svg" alt="Yuno Executive Dashboard"
               onError={(e) => { e.target.src = 'assets/yuno_fulllogo.svg'; }}/>
        )}
        {isCollapsed && (
          <span style={{
            fontSize: '24px',
            fontWeight: 'bold',
            color: '#5B6EF7',
            fontFamily: 'Inter, system-ui, sans-serif'
          }}>Y</span>
        )}
        <button
          className="sidebar-toggle"
          onClick={() => setIsCollapsed(!isCollapsed)}
          style={{
            background: 'none',
            border: 'none',
            color: isCollapsed ? '#6B7280' : '#FFFFFF',
            cursor: 'pointer',
            padding: '8px',
            borderRadius: '6px',
            fontSize: '18px',
            marginLeft: isCollapsed ? '0' : 'auto',
            transition: 'all 0.2s ease',
            display: 'flex',
            alignItems: 'center',
            justifyContent: 'center',
            width: '36px',
            height: '36px'
          }}
          onMouseEnter={(e) => {
            e.target.style.backgroundColor = isCollapsed ? 'rgba(107, 114, 128, 0.1)' : 'rgba(255, 255, 255, 0.1)';
          }}
          onMouseLeave={(e) => {
            e.target.style.backgroundColor = 'transparent';
          }}
        >
          {isCollapsed ? (
            // Hamburger menu icon when collapsed
            <svg
              width="20"
              height="20"
              viewBox="0 0 24 24"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d="M3 12H21"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
              <path
                d="M3 6H21"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
              <path
                d="M3 18H21"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
            </svg>
          ) : (
            // Close X icon when expanded
            <svg
              width="20"
              height="20"
              viewBox="0 0 24 24"
              fill="none"
              xmlns="http://www.w3.org/2000/svg"
            >
              <path
                d="M18 6L6 18"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
              <path
                d="M6 6L18 18"
                stroke="currentColor"
                strokeWidth="2"
                strokeLinecap="round"
                strokeLinejoin="round"
              />
            </svg>
          )}
        </button>
        {!isCollapsed && (
          <div className="brand-subtitle">KPI DASHBOARD · 2026</div>
        )}
      </div>

      {!isCollapsed && (
        <>
          <div className="nav-section">Pages</div>

          {/* Executive Overview */}
          <div
            className={`nav-item page ${activePage === 'overview' ? 'active' : ''}`}
            onClick={() => onPage('overview')}>
            <span>Executive Overview</span>
          </div>

          {/* Teams (expandable group). Clicking opens the Teams picker page —
              a tile grid of all leaf teams. Clusters (CRO, Product & Tech) don't
              have their own page anymore; their headers below only toggle expand. */}
          <div
            className={`nav-item page ${activePage === 'teams' && (currentSel === 'picker' || currentSel === 'all') ? 'active' : ''}`}
            onClick={() => {
              setTeamsExpanded(prev => !prev);
              selectNode('picker');
            }}
            style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', cursor: 'pointer' }}>
            <span>Teams</span>
            <svg
              width="12" height="12" viewBox="0 0 24 24" fill="none"
              style={{
                transform: teamsExpanded ? 'rotate(180deg)' : 'rotate(0deg)',
                transition: 'transform 0.15s ease',
                opacity: 0.7
              }}>
              <path d="M7 9L12 14L17 9" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
            </svg>
          </div>

          {teamsExpanded && (
            <div style={{ paddingLeft: 10, marginTop: 2, marginBottom: 6 }}>
              {/* Skip the synthetic "All Teams" cluster — the parent Teams item already
                  navigates to it, so listing it here is redundant. */}
              {TEAM_CLUSTERS.filter(c => c.id !== 'all').map(cluster => {
                const hasChildren = !!(cluster.children && cluster.children.length);
                const isExpanded = expandedClusters.has(cluster.id);
                // Cluster header is "active" only for standalone clusters that
                // are also a leaf navigation target (Finance, AI, HR, …). Clusters
                // WITH children (CRO, Product & Tech) are toggle-only — never
                // active themselves.
                const isClusterActive = !hasChildren && activePage === 'teams' && currentSel === cluster.id;

                return (
                  <div key={cluster.id}>
                    <div
                      className={`nav-item page ${isClusterActive ? 'active' : ''}`}
                      onClick={(e) => {
                        e.stopPropagation();
                        if (hasChildren) {
                          // Cluster with children → toggle-only, no navigation
                          toggleCluster(cluster.id);
                        } else {
                          // Leaf cluster (Finance, AI, HR, CEO Office, Legal, Banking & FI) → navigate
                          selectNode(cluster.id);
                        }
                      }}
                      style={{
                        fontSize: 13,
                        padding: '6px 10px',
                        display: 'flex',
                        alignItems: 'center',
                        justifyContent: 'space-between'
                      }}>
                      <span>{cluster.label}</span>
                      {hasChildren && (
                        <svg width="10" height="10" viewBox="0 0 24 24" fill="none"
                          style={{
                            transform: isExpanded ? 'rotate(180deg)' : 'rotate(0deg)',
                            transition: 'transform 0.15s ease',
                            opacity: 0.6
                          }}>
                          <path d="M7 9L12 14L17 9" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
                        </svg>
                      )}
                    </div>

                    {hasChildren && isExpanded && (
                      <div style={{ paddingLeft: 14, marginBottom: 4 }}>
                        {cluster.children.map(sub => {
                          const isSubActive = activePage === 'teams' && currentSel === sub.id;
                          return (
                            <div
                              key={sub.id}
                              className={`nav-item page ${isSubActive ? 'active' : ''}`}
                              onClick={(e) => {
                                e.stopPropagation();
                                selectNode(sub.id);
                              }}
                              style={{
                                fontSize: 12,
                                padding: '5px 10px',
                                opacity: isSubActive ? 1 : 0.75
                              }}>
                              <span>{sub.label}</span>
                            </div>
                          );
                        })}
                      </div>
                    )}
                  </div>
                );
              })}
            </div>
          )}
        </>
      )}

      {isCollapsed && (
        <div style={{ marginTop: 'auto', fontSize: 10, color: '#6A6F83', padding: 8, borderTop: '1px solid rgba(255,255,255,0.06)', textAlign: 'center' }}>
          W{D.WEEK_OF_QUARTER}
        </div>
      )}

      {/* Data freshness — pulled from cascade-data.js metadata.generated_at.
          Sourced once at module-eval time and rendered as a small footer so
          "is this dashboard fresh?" stops being a recurring exec question. */}
      {!isCollapsed && (() => {
        const meta = (window.YUNO_CASCADE_DATA && window.YUNO_CASCADE_DATA.metadata) || {};
        const gen = meta.generated_at;
        const src = meta.source_file_mtime;
        if (!gen && !src) return null;
        // Use whichever timestamp is more meaningful to executives: the
        // spreadsheet mtime (when an owner last edited values) is more
        // representative than the ETL run time. Fall back to generated_at.
        const ts = src || gen;
        let display;
        try {
          const d = new Date(ts);
          // Short ISO date — "2026-05-10" beats "May 10, 2026, 12:55:02 PM" for
          // executive scanning.
          display = d.toISOString().slice(0, 10);
        } catch (e) {
          display = String(ts).slice(0, 10);
        }
        return (
          <div
            className="sidebar-data-as-of"
            style={{ marginTop: 'auto', fontSize: 11, color: '#6A6F83',
                     padding: '10px 16px', borderTop: '1px solid rgba(255,255,255,0.06)',
                     letterSpacing: '0.02em' }}
            title={`Spreadsheet last edited: ${src || '—'}\nETL run: ${gen || '—'}`}>
            Data as of {display}
          </div>
        );
      })()}
    </aside>
  );
}

// ============================================================================
// Exec Summary (Overview header)
// ============================================================================
function ExecSummary({ view, filters, onKpiClick }) {
  const summary = useMemo(() => {
    const items = D.STRATEGIC.map(k => {
      const actual = computeFiltered(k, view, filters, 'actual');
      const target = computeFiltered(k, view, filters, 'target');
      const pace = view === 'qtd' && (k.format === 'currencyMM' || k.format === 'currencyK')
        ? target * D.QUARTER_PROGRESS : target;
      const pct = D.pctToTarget(actual, pace, k.higherIsBetter);
      return { kpi: k, actual, target, pace, pct, status: D.health(actual, pace, k.higherIsBetter) };
    });
    const onTrack = items.filter(i => i.status === 'good').length;
    const warn = items.filter(i => i.status === 'warn').length;
    const bad = items.filter(i => i.status === 'bad').length;
    const sorted = [...items].sort((a, b) => a.pct - b.pct);
    const worst = sorted.slice(0, 3);
    const best = [...items].sort((a, b) => b.pct - a.pct).slice(0, 3);
    const overallPct = items.reduce((s, i) => s + i.pct, 0) / items.length;
    const overallStatus = overallPct >= 0 ? 'good' : overallPct >= -15 ? 'warn' : 'bad';
    return { items, onTrack, warn, bad, worst, best, overallPct, overallStatus };
  }, [view, filters]);

  const scope = describeScope(filters);

  return (
    <div className={`exec-summary exec-${summary.overallStatus}`}>
      <div className="exec-left">
        <div className="exec-eyebrow">
          Executive summary · {D.CURRENT_QUARTER} · W{D.WEEK_OF_QUARTER}/{D.WEEKS_IN_QUARTER}
          {scope && <span className="exec-scope"> · {scope}</span>}
        </div>
        <div className="exec-headline">
          BD is{' '}
          <span className={`exec-state state-${summary.overallStatus}`}>
            {summary.overallStatus === 'good' ? 'on track' : summary.overallStatus === 'warn' ? 'slightly behind' : 'behind pace'}
          </span>
          {' '}— {summary.onTrack} of {summary.items.length} KPIs on target,
          {' '}<span className="text-warn">{summary.warn} watch</span>,
          {' '}<span className="text-bad">{summary.bad} at risk</span>.
        </div>
        <div className="exec-row">
          <div className="exec-block">
            <div className="exec-label">Overall pace vs target</div>
            <div className={`exec-big text-${summary.overallStatus}`}>
              {summary.overallPct >= 0 ? '+' : ''}{summary.overallPct.toFixed(1)}%
            </div>
          </div>
          <div className="exec-block">
            <div className="exec-label">Top 3 at risk</div>
            <div className="exec-pills">
              {summary.worst.map(w => (
                <button key={w.kpi.id} className="exec-pill bad" onClick={() => onKpiClick(w.kpi)}>
                  {w.kpi.name} <span>{w.pct.toFixed(0)}%</span>
                </button>
              ))}
            </div>
          </div>
          <div className="exec-block">
            <div className="exec-label">Top 3 outperforming</div>
            <div className="exec-pills">
              {summary.best.map(w => (
                <button key={w.kpi.id} className="exec-pill good" onClick={() => onKpiClick(w.kpi)}>
                  {w.kpi.name} <span>+{Math.abs(w.pct).toFixed(0)}%</span>
                </button>
              ))}
            </div>
          </div>
        </div>
      </div>
    </div>
  );
}

function describeScope(filters) {
  const parts = [];
  if (filters.region?.length) parts.push(filters.region.join('·'));
  if (filters.owner?.length) parts.push(filters.owner.join('·'));
  if (filters.source?.length) parts.push(filters.source.join('·'));
  if (filters.vertical?.length) parts.push(filters.vertical.join('·'));
  if (filters.stage?.length) parts.push(filters.stage.join('·'));
  return parts.length ? 'Filtered: ' + parts.join(' / ') : null;
}

// ============================================================================
// PageFilterBar — cascades to every chart on the page
// Shows only filters applicable to the active page (via `dims` prop)
// ============================================================================
function PageFilterBar({ dims, filters, setFilters, view, setView, granularity, setGranularity }) {
  const [openKey, setOpenKey] = useState(null);
  const popRef = useRef(null);
  useEffect(() => {
    function close(e) { if (popRef.current && !popRef.current.contains(e.target)) setOpenKey(null); }
    document.addEventListener('click', close);
    return () => document.removeEventListener('click', close);
  }, []);

  const DEFS = {
    region:   { label: 'Region',   options: D.REGIONS },
    owner:    { label: 'Owner',    options: D.OWNERS },
    source:   { label: 'Source',   options: D.SOURCES },
    vertical: { label: 'Vertical', options: D.VERTICALS },
    stage:    { label: 'Stage',    options: D.STAGES },
  };

  function toggle(key, val) {
    const arr = filters[key] || [];
    setFilters({ ...filters, [key]: arr.includes(val) ? arr.filter(x => x !== val) : [...arr, val] });
  }
  function clearKey(key) { setFilters({ ...filters, [key]: [] }); }

  const activeDims = dims || Object.keys(DEFS);
  const hasAny = activeDims.some(d => (filters[d] || []).length > 0);
  function clearAll() {
    const next = { ...filters };
    activeDims.forEach(d => { next[d] = []; });
    setFilters(next);
  }

  return (
    <div className="page-filterbar">
      <div className="pfb-left">
        <div className="pfb-group">
          <span className="pfb-label">Period</span>
          <div className="view-toggle">
            <button className={view === 'qtd' ? 'active' : ''} onClick={() => setView('qtd')}>Q2 QTD</button>
            <button className={view === 'fy' ? 'active' : ''} onClick={() => setView('fy')}>YTD</button>
          </div>
        </div>
        {granularity && setGranularity && (
          <div className="pfb-group">
            <span className="pfb-label">Granularity</span>
            <div className="view-toggle">
              <button className={granularity === 'quarter' ? 'active' : ''} onClick={() => setGranularity('quarter')}>Quarterly</button>
              {/* Monthly option only for KPIs with monthly data (New Logo ARR, CAC Payback) */}
              <button className={granularity === 'month' ? 'active' : ''} onClick={() => setGranularity('month')}>Monthly</button>
            </div>
          </div>
        )}
        <div className="pfb-divider"/>
        <div className="pfb-group">
          <span className="pfb-label">Filter</span>
          <div className="pfb-chips">
            {activeDims.map(key => {
              const def = DEFS[key];
              if (!def) return null;
              const sel = filters[key] || [];
              return (
                <div key={key} style={{ position: 'relative' }} ref={openKey === key ? popRef : null}>
                  <button
                    className={`filter-chip ${sel.length > 0 ? 'active' : ''}`}
                    onClick={(e) => { e.stopPropagation(); setOpenKey(openKey === key ? null : key); }}>
                    {def.label}
                    {sel.length > 0 && <span className="chip-count">{sel.length}</span>}
                    <svg className="caret" width="12" height="12" viewBox="0 0 24 24" fill="none">
                      <path d="M7 9L12 14L17 9" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"/>
                    </svg>
                  </button>
                  {openKey === key && (
                    <div className="filter-popover">
                      {def.options.map(opt => (
                        <label key={opt} className="opt">
                          <input type="checkbox" checked={sel.includes(opt)} onChange={() => toggle(key, opt)}/>
                          <span>{opt}</span>
                        </label>
                      ))}
                      {sel.length > 0 && (
                        <div style={{ borderTop: '1px solid var(--border)', marginTop: 4, paddingTop: 4 }}>
                          <button className="btn btn-ghost" style={{ width: '100%', justifyContent: 'flex-start' }}
                            onClick={() => clearKey(key)}>Clear {def.label}</button>
                        </div>
                      )}
                    </div>
                  )}
                </div>
              );
            })}
            {hasAny && <button className="filter-clear" onClick={clearAll}>Clear all</button>}
          </div>
        </div>
      </div>
      <div className="pfb-right">
        <span className="meta-chip"><span className="pulse"/>Live · {D.LAST_UPDATED}</span>
      </div>
    </div>
  );
}

function AtRiskStrip({ items, onItemClick }) {
  if (!items.length) return null;
  return (
    <div className="atrisk-strip">
      <div className="icon">!</div>
      <div className="copy">
        <strong>{items.length} headline KPI{items.length > 1 ? 's' : ''} at risk</strong>
        {' '}— below 80% of pace-to-target this quarter.
      </div>
      <div className="pills">
        {items.slice(0, 6).map(it => (
          <button key={it.id} className="atrisk-pill" onClick={() => onItemClick(it)}>
            {it.name} <span className="x">{it.pct.toFixed(0)}%</span>
          </button>
        ))}
      </div>
    </div>
  );
}

// ============================================================================
// New Expandable Sidebar for drill-down views
// ============================================================================
function ExpandableSidebar({ content, expanded, onToggleExpand, onClose, monthKey = 'mar' }) {
  const [localFilters, setLocalFilters] = useState({});
  const [view, setView] = useState('qtd');
  const [granularity, setGranularity] = useState('quarter');
  const [navigationHistory, setNavigationHistory] = useState([]);

  // Auto-expand to full-screen if triggered from left sidebar
  const isFullScreen = expanded || (content && content.data && content.data.fullScreen);

  // Prevent background scrolling when sidebar is open
  React.useEffect(() => {
    if (content) {
      document.body.classList.add('sidebar-open');
      // Auto-expand if fullScreen flag is set
      if (content.data && content.data.fullScreen && onToggleExpand && !expanded) {
        onToggleExpand();
      }
    } else {
      document.body.classList.remove('sidebar-open');
      // Clear navigation history when sidebar is closed
      setNavigationHistory([]);
    }

    // Cleanup on unmount
    return () => {
      document.body.classList.remove('sidebar-open');
    };
  }, [content, expanded, onToggleExpand]);

  if (!content) return null;

  const renderContent = () => {

    switch (content.content) {
      case 'strategic_kpis':
        return <StrategicKpisDrillDown data={content.data} filters={localFilters} view={view} onKpiClick={onKpiClick}/>;
      case 'strategic_deep_dive':
        if (!content.data) {
          return <div>Error: No data provided for strategic deep dive</div>;
        }
        return <StrategicDeepDive data={content.data} filters={localFilters} view={view} onKpiClick={onKpiClick}/>;
      // case 'department_deep_dive':  // TEMPORARILY DISABLED
      //   return <DepartmentDeepDive department={content.data?.department} filters={localFilters} view={view}/>;
      case 'headline_kpis':
        return <HeadlineKpisDrillDown data={content.data} filters={localFilters} view={view}/>;
      // case 'department':  // TEMPORARILY DISABLED
      //   return <DepartmentDrillDown department={content.department} filters={localFilters} view={view}/>;
      case 'kpi':
        return <KpiDrillDown kpi={content.kpi} filters={localFilters} view={view} granularity={granularity} monthKey={monthKey}/>;
      case 'pillar_insights':
        return <PillarInsightsDrillDown pillar={content.pillar} anchor={content.anchor} monthKey={content.monthKey || monthKey}/>;
      case 'region':
        return <RegionDrillDown region={content.region} filters={localFilters} view={view}/>;
      default:
        return <div>Unknown content type: {content.content}</div>;
    }
  };

  // Handle Strategic KPI click to show its detailed drill-down with chart
  const onKpiClick = (strategicKpi) => {

    // Store current content in navigation history
    if (content) {
      setNavigationHistory(prev => [...prev, content]);
    }

    // Update sidebar content to show KPI drill-down with trend chart
    const newContent = {
      type: 'kpi',
      content: 'kpi',
      kpi: strategicKpi,
      category: 'KPI Deep-Dive',
      title: strategicKpi.name,
      subtitle: `${strategicKpi.owner} • Q2 2026 Performance Analysis`,
    };


    // We need to communicate this back to the App component
    // For now, we'll trigger a custom event that the App can listen to
    window.dispatchEvent(new CustomEvent('updateSidebarContent', {
      detail: newContent
    }));
  };

  // Handle back navigation
  const handleBackNavigation = () => {
    if (navigationHistory.length > 0) {
      const previousContent = navigationHistory[navigationHistory.length - 1];
      const newHistory = navigationHistory.slice(0, -1);

      setNavigationHistory(newHistory);

      // Dispatch event to restore previous content
      window.dispatchEvent(new CustomEvent('updateSidebarContent', {
        detail: previousContent
      }));
    }
  };

  const getContextualFilters = () => {
    const availableFilters = [];
    switch (content.type) {
      case 'department':
        availableFilters.push('region', 'source');
        if (['sales', 'marketing'].includes(content.department)) availableFilters.push('stage');
        break;
      case 'kpi':
        if (content.kpi.byRegion) availableFilters.push('region');
        if (content.kpi.bySource) availableFilters.push('source');
        if (content.kpi.byStage) availableFilters.push('stage');
        break;
      case 'region':
        availableFilters.push('source', 'stage', 'vertical');
        break;
    }
    return availableFilters;
  };

  return (
    <>
      <div className={`sidebar-backdrop ${content ? 'open' : ''}`} onClick={onClose}/>
      <div className={`expandable-sidebar ${content ? 'open' : ''} ${isFullScreen ? 'expanded' : ''}`}>
        <div className="sidebar-header">
          <div className="sidebar-title-area">
            <div className="sidebar-eyebrow">{content.category || 'Drill-down'}</div>
            <h2 className="sidebar-title">{content.title}</h2>
            <div className="sidebar-subtitle">{content.subtitle}</div>
          </div>
          <div className="sidebar-actions">
            {navigationHistory.length > 0 && (
              <button className="icon-btn back-btn" onClick={handleBackNavigation} title="Go back">
                <svg
                  width="16"
                  height="16"
                  viewBox="0 0 24 24"
                  fill="none"
                  xmlns="http://www.w3.org/2000/svg"
                >
                  <path
                    d="M19 12H5"
                    stroke="currentColor"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  />
                  <path
                    d="M12 19L5 12L12 5"
                    stroke="currentColor"
                    strokeWidth="2"
                    strokeLinecap="round"
                    strokeLinejoin="round"
                  />
                </svg>
              </button>
            )}
            <button className="icon-btn" onClick={onToggleExpand} title={expanded ? 'Collapse' : 'Expand full-screen'}>
              {isFullScreen ? '⤡' : '⤢'}
            </button>
            <button className="close" onClick={onClose}>×</button>
          </div>
        </div>


        <div className="sidebar-content">
          {renderContent()}
        </div>
      </div>
    </>
  );
}


// ============================================================================
// Department Deep Dive Component (triggered from left sidebar)
// ============================================================================
function DepartmentDeepDive({ department, filters, view }) {

  // Get department-specific KPIs
  const departmentKpis = D.getStrategicKpisByDepartment(department);

  if (!departmentKpis || departmentKpis.length === 0) {
    return (
      <div style={{ padding: '40px', textAlign: 'center' }}>
        <h3>No KPIs available for {department}</h3>
        <p>This department's KPI structure is being developed.</p>
      </div>
    );
  }

  return (
    <div className="department-deep-dive">
      <div className="department-overview">
        <h3>{department} Performance</h3>
        <p>{departmentKpis.length} Strategic KPIs</p>
      </div>

      <div className="department-kpis">
        {departmentKpis.map(kpi => {
          const value = kpi.q2Progress || 0;
          const target = kpi.q2Target || 0;
          const pct = D.pctToTarget(value, target, kpi.higherIsBetter);
          const status = D.health(value, target, kpi.higherIsBetter);

          return (
            <div key={kpi.id} className="dept-kpi-card">
              <div className="dept-kpi-header">
                <div className="dept-kpi-name">{kpi.name}</div>
                <div className={`dept-kpi-status status-${status}`}>
                  {status === 'good' ? '✓' : status === 'warn' ? '!' : '⚠'}
                </div>
              </div>

              <div className="dept-kpi-metrics">
                <div className="dept-metric">
                  <span className="dept-metric-label">Current</span>
                  <span className={`dept-metric-value status-${status}`}>
                    {D.fmt(value, kpi.format)}
                  </span>
                </div>
                <div className="dept-metric">
                  <span className="dept-metric-label">Target</span>
                  <span className="dept-metric-value">
                    {D.fmt(target, kpi.format)}
                  </span>
                </div>
                <div className="dept-metric">
                  <span className="dept-metric-label">vs Target</span>
                  <span className={`dept-metric-value text-${status}`}>
                    {pct >= 0 ? '+' : ''}{pct.toFixed(1)}%
                  </span>
                </div>
              </div>

              <div className="dept-kpi-owner">
                <span>Owner: {kpi.owner}</span>
              </div>
            </div>
          );
        })}
      </div>
    </div>
  );
}

// ============================================================================
// Strategic KPIs Drill-down Component
// ============================================================================
function StrategicKpisDrillDown({ data, filters, view, onKpiClick }) {
  const { departmentId, strategicKpis, department } = data;

  // Helper function for clean percentage formatting
  const formatPercentage = (actual, target, higherIsBetter) => {
    const pct = D.pctToTarget(actual, target, higherIsBetter);
    if (isNaN(pct) || !isFinite(pct)) return '0';
    return Math.round(pct).toString();
  };

  return (
    <div className="strategic-kpis-drilldown">
      <div className="drilldown-header">
        <h3>{department?.label || departmentId} Strategic KPIs</h3>
        <p className="drilldown-description">
          {strategicKpis.length} strategic KPIs for Q2 2026 performance tracking.
        </p>
      </div>

      <div className="strategic-kpis-grid">
        {strategicKpis.map(kpi => {
          const actual = kpi.q2Progress || 0;
          const target = kpi.q2Target || 0;
          const healthStatus = D.health(actual, target, kpi.higherIsBetter);

          return (
            <div
              key={kpi.id}
              className={`strategic-kpi-card status-${healthStatus}`}
              onClick={() => onKpiClick(kpi)}
              style={{ cursor: 'pointer' }}
            >
              <div className="kpi-header">
                <h4 className="kpi-name">{kpi.name}</h4>
                <span className="kpi-unit">{kpi.unit}</span>
              </div>
              <div className="kpi-metrics">
                <div className="kpi-metric-row">
                  <div className="metric-group">
                    <span className="metric-label">Progress</span>
                    <span className="metric-value">{D.fmt(actual, kpi.format)}</span>
                  </div>
                  <div className="metric-group">
                    <span className="metric-label">Target</span>
                    <span className="metric-value">{D.fmt(target, kpi.format)}</span>
                  </div>
                  <div className="metric-group">
                    <span className="metric-label">vs Target</span>
                    <span className={`metric-value status-${healthStatus}`}>
                      {formatPercentage(actual, target, kpi.higherIsBetter)}%
                    </span>
                  </div>
                </div>
              </div>
              <div className="kpi-owner">
                <span className="owner-label">Owner:</span>
                <span className="owner-name">{kpi.owner}</span>
              </div>
            </div>
          );
        })}
      </div>

      {strategicKpis.length === 0 && (
        <div className="empty-state">
          <p>No strategic KPIs found for this department.</p>
        </div>
      )}
    </div>
  );
}

// ============================================================================
// Headline KPIs Drill-down Component - Enhanced for comprehensive deepdive
// ============================================================================
function HeadlineKpisDrillDown({ data, filters, view }) {
  const { strategicKpi, headlineKpis, category } = data;
  const [activeSection, setActiveSection] = useState('all');

  // Get all relevant Headline KPI arrays based on the Strategic KPI or category
  const getRelevantHeadlineKpis = () => {
    const relevantKpis = [];

    // If specific headlineKpis provided, use those
    if (headlineKpis && headlineKpis.length > 0) {
      return headlineKpis;
    }

    // Otherwise, determine relevant Headline KPIs based on Strategic KPI or category
    const kpiId = strategicKpi?.id;
    const categoryName = category || strategicKpi?.pillar;

    // Business Development related KPIs
    if (kpiId?.includes('arr') || kpiId?.includes('pipeline') || categoryName?.includes('Growth')) {
      relevantKpis.push(
        ...D.SALES_DEVELOPMENT,
        ...D.PIPELINE_METRICS,
        ...D.LEAD_GENERATION,
        ...D.WIN_RATE_CONVERSION,
        ...D.ACV_SALES_CYCLE
      );
    }

    // Customer Success related KPIs
    if (kpiId?.includes('ndr') || kpiId?.includes('satisfaction') || categoryName?.includes('Value')) {
      relevantKpis.push(
        ...D.CUSTOMER_SUCCESS_SUPPORT,
        ...D.TECH_SUPPORT_METRICS
      );
    }

    // Finance related KPIs
    if (kpiId?.includes('ebitda') || kpiId?.includes('revenue') || categoryName?.includes('Leverage')) {
      relevantKpis.push(...D.FINANCE_METRICS);
    }

    // HR related KPIs
    if (kpiId?.includes('enps') || kpiId?.includes('turnover') || categoryName?.includes('Culture')) {
      relevantKpis.push(...D.HR_METRICS);
    }

    // If no specific matches, show all Headline KPIs
    if (relevantKpis.length === 0) {
      relevantKpis.push(
        ...D.SALES_DEVELOPMENT,
        ...D.PIPELINE_METRICS,
        ...D.LEAD_GENERATION,
        ...D.WIN_RATE_CONVERSION,
        ...D.ACV_SALES_CYCLE,
        ...D.CUSTOMER_SUCCESS_SUPPORT,
        ...D.TECH_SUPPORT_METRICS,
        ...D.HR_METRICS,
        ...D.FINANCE_METRICS
      );
    }

    return relevantKpis;
  };

  const allHeadlineKpis = getRelevantHeadlineKpis();

  // Group KPIs by category for better organization
  const groupedKpis = {
    'Sales Development': D.SALES_DEVELOPMENT.filter(kpi => allHeadlineKpis.includes(kpi)),
    'Pipeline & Funnel': D.PIPELINE_METRICS.filter(kpi => allHeadlineKpis.includes(kpi)),
    'Lead Generation': D.LEAD_GENERATION.filter(kpi => allHeadlineKpis.includes(kpi)),
    'Win Rate & Conversion': D.WIN_RATE_CONVERSION.filter(kpi => allHeadlineKpis.includes(kpi)),
    'ACV & Sales Cycle': D.ACV_SALES_CYCLE.filter(kpi => allHeadlineKpis.includes(kpi)),
    'Customer Success': D.CUSTOMER_SUCCESS_SUPPORT.filter(kpi => allHeadlineKpis.includes(kpi)),
    'Technical Support': D.TECH_SUPPORT_METRICS.filter(kpi => allHeadlineKpis.includes(kpi)),
    'HR Metrics': D.HR_METRICS.filter(kpi => allHeadlineKpis.includes(kpi)),
    'Finance Metrics': D.FINANCE_METRICS.filter(kpi => allHeadlineKpis.includes(kpi))
  };

  // Filter out empty groups
  const nonEmptyGroups = Object.entries(groupedKpis).filter(([_, kpis]) => kpis.length > 0);

  const filteredKpis = activeSection === 'all'
    ? allHeadlineKpis
    : groupedKpis[activeSection] || [];

  return (
    <div className="headline-kpis-drilldown">
      <div className="drilldown-header">
        <h3>{strategicKpi?.name ? `${strategicKpi.name} Breakdown` : 'Headline KPIs Deep Dive'}</h3>
        <p className="drilldown-description">
          {strategicKpi
            ? `Detailed breakdowns and contributing factors for ${strategicKpi.name}`
            : `Comprehensive view of ${allHeadlineKpis.length} headline KPIs across all business functions`
          }
        </p>
      </div>

      {strategicKpi && (
        <div className="parent-kpi-summary">
          <div className="parent-kpi-card">
            <div className="parent-kpi-value">
              {D.fmt(strategicKpi.q2Progress, strategicKpi.format)} {strategicKpi.unit}
            </div>
            <div className="parent-kpi-target">
              Target: {D.fmt(strategicKpi.q2Target, strategicKpi.format)}
            </div>
            <div className={`parent-kpi-health ${D.health(strategicKpi.q2Progress, strategicKpi.q2Target, strategicKpi.higherIsBetter)}`}>
              {D.pctToTarget(strategicKpi.q2Progress, strategicKpi.q2Target, strategicKpi.higherIsBetter)}% vs Target
            </div>
          </div>
        </div>
      )}

      {/* Category Filter Tabs */}
      {nonEmptyGroups.length > 1 && (
        <div className="headline-category-tabs">
          <button
            className={`tab ${activeSection === 'all' ? 'active' : ''}`}
            onClick={() => setActiveSection('all')}
          >
            All ({allHeadlineKpis.length})
          </button>
          {nonEmptyGroups.map(([groupName, kpis]) => (
            <button
              key={groupName}
              className={`tab ${activeSection === groupName ? 'active' : ''}`}
              onClick={() => setActiveSection(groupName)}
            >
              {groupName} ({kpis.length})
            </button>
          ))}
        </div>
      )}

      {/* Display KPIs by section or all */}
      {activeSection === 'all' ? (
        // Show all KPIs grouped by category
        <div className="headline-kpis-grouped">
          {nonEmptyGroups.map(([groupName, kpis]) => (
            <div key={groupName} className="headline-kpi-group">
              <div className="group-header">
                <h4 className="group-title">{groupName}</h4>
                <span className="group-count">{kpis.length} KPIs</span>
              </div>
              <div className="headline-kpis-grid">
                {kpis.map(kpi => (
                  <HeadlineKpiCard key={kpi.id} kpi={kpi} filters={filters} view={view} />
                ))}
              </div>
            </div>
          ))}
        </div>
      ) : (
        // Show KPIs for specific category
        <div className="headline-kpis-grid">
          {filteredKpis.map(kpi => (
            <HeadlineKpiCard key={kpi.id} kpi={kpi} filters={filters} view={view} />
          ))}
        </div>
      )}

      {filteredKpis.length === 0 && (
        <div className="empty-state">
          <p>No headline KPIs available for the selected category.</p>
        </div>
      )}
    </div>
  );
}

// ============================================================================
// Headline KPI Card Component
// ============================================================================
function HeadlineKpiCard({ kpi, filters, view }) {
  const actual = kpi.q2Progress || 0;
  // Q1 target only — no Q2 fallback so KPIs without a Q1 target render '—' honestly.
  const target = (kpi.q1Target === null || kpi.q1Target === undefined) ? null : kpi.q1Target;
  const baseline = kpi.baseline || 0;
  const hasTarget = target !== null;
  // pctToTarget doesn't guard against null (only 0), and null coerces to 0 in division
  // → Infinity. Guard explicitly so KPIs without a Q1 target render '—' instead.
  const status = window.YUNO_KPI_STATUS
    ? window.YUNO_KPI_STATUS(kpi, hasTarget ? D.health(actual, target, kpi.higherIsBetter) : 'neutral')
    : (hasTarget ? D.health(actual, target, kpi.higherIsBetter) : 'neutral');
  const pct = hasTarget ? D.pctToTarget(actual, target, kpi.higherIsBetter) : null;

  // Determine trend from baseline to current
  const trend = actual > baseline ? 'up' : actual < baseline ? 'down' : 'flat';
  const trendPct = baseline !== 0 ? ((actual - baseline) / baseline * 100) : 0;

  return (
    <div className={`headline-kpi-card status-${status}`}>
      <div className="headline-kpi-header">
        <div className="headline-kpi-info">
          <h4 className="headline-kpi-name">
            {kpi.name}
            {kpi.cascade && kpi.cascade.warning && (
              <span className="cascade-warning-badge" title={`Cascade data note: ${kpi.cascade.warning}`}>!</span>
            )}
          </h4>
          <span className="headline-kpi-owner">{kpi.owner}</span>
        </div>
        <div className={`headline-kpi-status status-${status}`}>
          {status === 'good' ? '✓' : status === 'warn' ? '!' : '⚠'}
        </div>
      </div>

      <div className="headline-kpi-metrics">
        <div className="headline-kpi-main">
          <div className="metric-value">
            <span className={`value-primary status-${status}`}>
              {D.fmt(actual, kpi.format)}
            </span>
            <span className="value-unit">{kpi.unit}</span>
          </div>
          <div className="metric-trend">
            <span className={`trend-indicator trend-${trend}`}>
              <svg
                width="16"
                height="16"
                viewBox="0 0 24 24"
                fill="none"
                xmlns="http://www.w3.org/2000/svg"
                style={{
                  transform: trend === 'up' ? 'rotate(-45deg)' : trend === 'down' ? 'rotate(135deg)' : 'rotate(0deg)',
                  transition: 'transform 0.2s ease'
                }}
              >
                <path
                  d="M5 12H19"
                  stroke="currentColor"
                  strokeWidth="2"
                  strokeLinecap="round"
                  strokeLinejoin="round"
                />
                <path
                  d="M12 5L19 12L12 19"
                  stroke="currentColor"
                  strokeWidth="2"
                  strokeLinecap="round"
                  strokeLinejoin="round"
                />
              </svg>
            </span>
            <span className="trend-value">
              {trendPct >= 0 ? '+' : ''}{trendPct.toFixed(0)}%
            </span>
          </div>
        </div>

        <div className="headline-kpi-targets">
          <div className="target-row">
            <span className="target-label">Q1 Target:</span>
            <span className="target-value">{hasTarget ? D.fmt(target, kpi.format) : '—'}</span>
          </div>
          <div className="target-row">
            <span className="target-label">vs Target:</span>
            <span className={`target-pct status-${status}`}>
              {pct !== null ? `${pct >= 0 ? '+' : ''}${pct.toFixed(0)}%` : '—'}
            </span>
          </div>
          <div className="target-row">
            <span className="target-label">Baseline:</span>
            <span className="target-value">{D.fmt(baseline, kpi.format)}</span>
          </div>
        </div>
      </div>

      {/* Show regional breakdown if available */}
      {kpi.byRegion && (
        <div className="headline-kpi-breakdown">
          <div className="breakdown-title">Regional Performance</div>
          <div className="breakdown-items">
            {Object.entries(kpi.byRegion).slice(0, 3).map(([region, data]) => (
              <div key={region} className="breakdown-item">
                <span className="breakdown-label">{region}:</span>
                <span className="breakdown-value">
                  {D.fmt(data.q2Progress || data.baseline, kpi.format)}
                </span>
              </div>
            ))}
            {Object.keys(kpi.byRegion).length > 3 && (
              <div className="breakdown-more">
                +{Object.keys(kpi.byRegion).length - 3} more
              </div>
            )}
          </div>
        </div>
      )}
    </div>
  );
}

function DepartmentDrillDown({ department, filters, view }) {
  const dept = D.DEPARTMENTS.find(d => d.id === department);
  if (!dept) return <div>Department not found</div>;

  const kpis = dept.members.flatMap(member => member.kpiIds || [])
    .filter((id, index, arr) => arr.indexOf(id) === index)
    .map(id => D.STRATEGIC.find(k => k.id === id) || D.CUSTOMER_VALUE.find(k => k.id === id) || D.MAYA.find(k => k.id === id))
    .filter(Boolean);

  return (
    <div className="department-drilldown">
      <div className="panel">
        <div className="panel-head">
          <div className="panel-title">{dept.label} KPI Performance</div>
          <div className="panel-subtitle">{kpis.length} KPIs across {dept.members.length} team members</div>
        </div>
        <div className="kpi-performance-grid">
          {kpis.map(kpi => {
            const actual = computeFiltered(kpi, view, filters, 'actual');
            const target = computeFiltered(kpi, view, filters, 'target');
            const pct = D.pctToTarget(actual, target, kpi.higherIsBetter);
            const localStatus = D.health(actual, target, kpi.higherIsBetter);
            const status = window.YUNO_KPI_STATUS ? window.YUNO_KPI_STATUS(kpi, localStatus) : localStatus;

            return (
              <div key={kpi.id} className={`dept-kpi-card status-${status}`}>
                <div className="dept-kpi-name">{kpi.name}</div>
                <div className="dept-kpi-value">{D.fmt(actual, kpi.format)}</div>
                <div className="dept-kpi-target">Target: {D.fmt(target, kpi.format)}</div>
                <div className={`dept-kpi-pct text-${status}`}>
                  {pct >= 0 ? '+' : ''}{pct.toFixed(0)}%
                </div>
              </div>
            );
          })}
        </div>
      </div>

      {/* DepartmentInsights was removed (it rendered hardcoded prose). If
          this scaffolding is ever wired up, source insights from
          cascade.insights instead of static strings. */}
    </div>
  );
}

// Three-line trend chart inside KpiDrillDown — mirrors TrendAreaChart in sections.jsx.
//   - Actual:     thick solid status-color line, real actuals only (Mar/Apr today)
//   - Projected:  thinner dashed status-color line, projection forward from current pace
//   - Target pace: very thin dotted gray line, linear pacing to FY target
// Each line is visually distinct (weight + dash style + color) so the three series
// are unmistakable at small sizes — the prior treatment had Actual+Projected reading
// as one continuous line.
function KddTrendChart({ kpi, status }) {
  const STATUS_FILL = { good: '#ECFDF5', warn: '#FFFBEB', bad: '#FEF2F2', neutral: '#F1F5F9' };
  const STATUS_LINE = { good: '#10B981', warn: '#F59E0B', bad: '#DC2626', neutral: '#94A3B8' };
  // Pull monthly actuals from the cascade when available, fall back to the
  // dashboard's hand-curated kpi.<month>.actual otherwise. All 12 months are
  // slotted; quarter-end months (Mar/Jun/Sep/Dec) get the quarter label.
  const ca = (kpi.cascade && kpi.cascade.monthlyActuals) || {};
  const hasBaseline = kpi.cascade && typeof kpi.cascade.jan1 === 'number';
  const slots = [];
  if (hasBaseline) slots.push({ label: 'Jan-1', actual: kpi.cascade.jan1, monthIdx: 0, isBaseline: true });
  const QUARTER_LABEL_KDD = { mar: 'Q1', jun: 'Q2', sep: 'Q3', dec: 'Q4' };
  MONTH_KEYS_ORDERED.forEach((mk, i) => {
    const monthIdx = i + 1;
    const cAct = ca[mk];
    const handAct = kpi[mk] && kpi[mk].actual;
    const actual = (cAct !== undefined && cAct !== null) ? cAct : (handAct ?? null);
    // Suppress the JAN label when Jan-1 baseline is also rendered — they sit
    // visually adjacent and overlap. See sibling TrendAreaChart in sections.jsx.
    const label = (mk === 'jan' && hasBaseline) ? '' : (QUARTER_LABEL_KDD[mk] || mk.toUpperCase());
    slots.push({ label, actual, monthIdx });
  });
  let lastActualIdx = -1;
  slots.forEach((s, i) => { if (s.actual !== null && s.actual !== undefined) lastActualIdx = i; });
  if (lastActualIdx < 0) return null;
  const lastActual = slots[lastActualIdx].actual;
  // Per-month slope (time-honest): walk back to the previous slot with a real
  // actual and compute (lastActual - prevActual) / (months between).
  let slopePerMonth = 0;
  for (let i = lastActualIdx - 1; i >= 0; i--) {
    if (slots[i].actual !== null && slots[i].actual !== undefined) {
      const dt = slots[lastActualIdx].monthIdx - slots[i].monthIdx;
      if (dt > 0) slopePerMonth = (lastActual - slots[i].actual) / dt;
      break;
    }
  }
  const projected = slots.map((s, i) =>
    i <= lastActualIdx ? s.actual : lastActual + slopePerMonth * (s.monthIdx - slots[lastActualIdx].monthIdx)
  );
  // Prefer cascade FY target — falls back to the hand-curated kpi.fy when
  // there's no cascade data. Same 50× unit-scale guard as MarchCard so the
  // chart's pace line matches what the card shows.
  const fyTarget = (function() {
    const _cFy = kpi.cascade && kpi.cascade.monthlyTargets && kpi.cascade.monthlyTargets.fy;
    const handFy = (kpi.fy && kpi.fy.target !== undefined && kpi.fy.target !== null) ? kpi.fy.target : null;
    const cValid = (_cFy !== null && _cFy !== undefined);
    const hValid = (handFy !== null && handFy !== undefined);
    if (!cValid) return hValid ? handFy : null;
    if (!hValid) return _cFy;
    if (Math.abs(_cFy) > 0 && Math.abs(handFy) / Math.abs(_cFy) > 50) return handFy;
    return _cFy;
  })();
  // Target pace line: prefer cascade-truth (Jan-1 → FY linear pace) when present.
  // Cascade trend line has 13 points indexed 0=Jan-1, 1=end-Jan, …, 12=end-Dec.
  // Look up each slot's value via slot.monthIdx — works uniformly whether or not
  // the Jan-1 slot is included.
  const tl = kpi.cascade && kpi.cascade.trendLine;
  const tlValid = Array.isArray(tl) && tl.length === 13 && tl.every(v => typeof v === 'number');
  const startVal = slots[0].actual !== null && slots[0].actual !== undefined ? slots[0].actual : lastActual;
  const ideal = tlValid
    ? slots.map(s => tl[s.monthIdx])
    : (fyTarget !== null ? slots.map((_, i) => startVal + (fyTarget - startVal) * (i / (slots.length - 1))) : null);

  const w = 320, h = 150, padX = 14, padTop = 22, padBot = 14;
  // Time-proportional x: month 0 → padX, month 12 → w − padX.
  const xs = slots.map(s => padX + (s.monthIdx / 12) * (w - 2 * padX));
  const allValues = [...projected, ...(ideal || [])].filter(v => v !== null && v !== undefined);
  const min = Math.min(...allValues), max = Math.max(...allValues);
  const range = (max - min) || Math.abs(max) || 1;
  const yTop = padTop, yBot = h - padBot;
  const yFor = v => yBot - ((v - min) / range) * (yBot - yTop);

  const actualPath = slots.slice(0, lastActualIdx + 1)
    .map((s, i) => `${i === 0 ? 'M' : 'L'}${xs[i].toFixed(1)},${yFor(s.actual).toFixed(1)}`).join(' ');
  const projPath = lastActualIdx < slots.length - 1
    ? slots.slice(lastActualIdx).map((_, i) =>
        `${i === 0 ? 'M' : 'L'}${xs[lastActualIdx + i].toFixed(1)},${yFor(projected[lastActualIdx + i]).toFixed(1)}`
      ).join(' ')
    : '';
  const combinedY = projected.map(yFor);
  const areaPath = xs.map((x, i) => `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${combinedY[i].toFixed(1)}`).join(' ')
    + ` L${xs[xs.length - 1].toFixed(1)},${yBot.toFixed(1)} L${xs[0].toFixed(1)},${yBot.toFixed(1)} Z`;
  const idealPath = ideal ? xs.map((x, i) => `${i === 0 ? 'M' : 'L'}${x.toFixed(1)},${yFor(ideal[i]).toFixed(1)}`).join(' ') : '';

  const stroke = STATUS_LINE[status] || STATUS_LINE.neutral;
  const fill = STATUS_FILL[status] || STATUS_FILL.neutral;
  // Bottom strip reserved inside the SVG for x-axis labels (so they land
  // exactly under their data points regardless of slot count / spacing).
  const xLabelY = h - 2;
  // Format the baseline value compactly for the inline annotation.
  const fmtBaseline = (v) => {
    if (v === null || v === undefined) return '';
    if (kpi.format === 'currencyMM') return `$${Number(v).toFixed(1)}M`;
    if (kpi.format === 'currencyK')  return `$${Math.round(v)}K`;
    if (kpi.format === 'pct')        return `${Number(v).toFixed(0)}%`;
    if (kpi.format === 'months' || kpi.format === 'days') return `${Math.round(v)}`;
    return Number.isInteger(v) ? String(v) : Number(v).toFixed(1);
  };
  return (
    <div className="kdd-trend">
      <svg viewBox={`0 0 ${w} ${h + 14}`} preserveAspectRatio="none" width="100%" height={h + 14} aria-hidden="true">
        <path d={areaPath} fill={fill} opacity="0.5" />
        {/* Target pace: very thin dotted gray, linear to FY target */}
        {idealPath && <path d={idealPath} fill="none" stroke="#94A3B8" strokeWidth="1" strokeDasharray="2 3" strokeLinecap="round" opacity="0.7" />}
        {/* Projected: thinner dashed status color */}
        {projPath && <path d={projPath} fill="none" stroke={stroke} strokeWidth="1.75" strokeDasharray="6 4" strokeLinecap="round" opacity="0.9" />}
        {/* Actual: thick solid status color */}
        {actualPath && <path d={actualPath} fill="none" stroke={stroke} strokeWidth="3" strokeLinejoin="round" strokeLinecap="round" />}
        {/* Data point markers — baseline is hollow (white fill) to read as a starting reference; real actuals are solid. */}
        {slots.slice(0, lastActualIdx + 1).map((s, i) => s.isBaseline ? (
          <g key={i}>
            <circle cx={xs[i]} cy={yFor(s.actual)} r="4" fill="#FFFFFF" stroke={stroke} strokeWidth="1.75" />
            <text x={xs[i]} y={yFor(s.actual) - 9} fontSize="9" fontWeight="700" fill="#475569" textAnchor="middle">{fmtBaseline(s.actual)}</text>
          </g>
        ) : (
          <circle key={i} cx={xs[i]} cy={yFor(s.actual)} r="4" fill={stroke} stroke="#FFFFFF" strokeWidth="1.5" />
        ))}
        {/* X-axis labels — only at year-anchors + quarter-end checkpoints.
            Was rendering 12-13 labels in 320px viewBox; cramped, "all over the
            place" per user feedback. Hide everything except Jan-1 (start) and
            the four quarter-end markers. */}
        {slots.map((s, i) => {
          const isQuarterEnd = ['Q1', 'Q2', 'Q3', 'Q4'].includes(s.label);
          const isYearStart = s.isBaseline || (i === 0 && !hasBaseline && s.label);
          if (!isQuarterEnd && !isYearStart) return null;
          const label = isYearStart ? (s.label || 'Jan') : s.label;
          return (
            <text key={i}
              x={xs[i]}
              y={h + 11}
              fontSize="9"
              fontWeight="700"
              letterSpacing="0.04em"
              fill={i <= lastActualIdx ? '#0F172A' : '#94A3B8'}
              textAnchor={i === 0 ? 'start' : (i === slots.length - 1 ? 'end' : 'middle')}>
              {label}
            </text>
          );
        })}
      </svg>
      <div className="kdd-trend-legend">
        <span className="kdd-trend-legend-item">
          <span className="kdd-trend-swatch solid-thick" style={{ background: stroke }} />Actual
        </span>
        <span className="kdd-trend-legend-item">
          <span className="kdd-trend-swatch dashed-color" style={{ '--c': stroke }} />Projected
        </span>
        {ideal && (
          <span className="kdd-trend-legend-item">
            <span className="kdd-trend-swatch dotted-gray" />Target pace
          </span>
        )}
      </div>
    </div>
  );
}

// TREND + DRIVERS captions below the chart. TREND reads "Projected to miss/beat
// FY by X%" using the projected EOY value vs FY target.
//
// Polarity-aware: for lower-is-better KPIs (CAC Payback, Sales Cycle, Bugs/Month,
// Latency, Voluntary Turnover, Time to Fill, Burn Multiple, …) the verb flips.
// E.g. CAC Payback Period actual 13mo, projected EOY 32mo, FY target 7mo:
//   Before:  pct = +357% → "Projected to beat FY by 357%"   (wrong direction)
//   After:   fav = -357% → "Projected to miss FY by 357%"
//
// Prefers cascade.projectedLine (computed deterministically by the ETL) so the
// caption matches what the chart's dashed projected line draws. Falls back to a
// chart-local Mar→Apr slope projection when cascade is unavailable.
function KddTrendCaption({ kpi, status }) {
  const STATUS_TXT = { good: '#10B981', warn: '#F59E0B', bad: '#DC2626', neutral: '#1E293B' };
  const c = kpi.cascade;
  const cascadeProj = c && c.projectedLine && Array.isArray(c.projectedLine.values) && c.projectedLine.values.length
    ? c.projectedLine.values[c.projectedLine.values.length - 1]
    : null;
  let projectedEoy = cascadeProj;
  if (projectedEoy === null) {
    const marActual = kpi.mar && kpi.mar.actual;
    const aprActual = kpi.apr && kpi.apr.actual;
    if (marActual !== null && marActual !== undefined) {
      if (aprActual !== null && aprActual !== undefined) {
        const slope = aprActual - marActual;
        projectedEoy = aprActual + slope * 8;
      } else {
        projectedEoy = marActual;
      }
    }
  }
  const fyTarget = (c && c.monthlyTargets && c.monthlyTargets.fy) || (kpi.fy && kpi.fy.target);
  const isLowerBetter = (c && c.polarity === 'lower_is_better') || kpi.higherIsBetter === false;
  let trendStr = '—';
  // Trend-specific status — see sibling TrendCaption in sections.jsx for full
  // rationale. Color must reflect the PROJECTION, not the latest-month RAG.
  let trendStatus = 'neutral';
  if (projectedEoy !== null && fyTarget !== null && fyTarget !== undefined && fyTarget !== 0) {
    const rawPct = ((projectedEoy - fyTarget) / Math.abs(fyTarget)) * 100;
    const fav = isLowerBetter ? -rawPct : rawPct;
    const absFav = Math.abs(fav);
    if (absFav < 1) {
      trendStr = 'Projected to reach FY target';
      trendStatus = 'good';
    } else {
      const verb = fav >= 0 ? 'beat' : 'miss';
      // See sibling TrendCaption in sections.jsx for the full rationale.
      // "On current pace, would ..." with "~" makes the model + imprecision
      // explicit. Sub-line spells out the linear extrapolation so an
      // executive reading the integer pct doesn't take it as a forecast.
      trendStr = `On current pace, would ${verb} FY by ~${Math.round(absFav)}%`;
      if (fav >= 0)        trendStatus = 'good';
      else if (fav >= -30) trendStatus = 'warn';
      else                 trendStatus = 'bad';
    }
  }
  const actualMonths = c && c.monthlyActuals
    ? Object.values(c.monthlyActuals).filter(v => typeof v === 'number').length
    : 0;
  const lowData = actualMonths > 0 && actualMonths < 3;
  const modelNote = projectedEoy !== null && fyTarget !== null && fyTarget !== undefined && fyTarget !== 0
    ? `Linear extrapolation from Jan-1 baseline · ${actualMonths || 'no'} actual month${actualMonths === 1 ? '' : 's'}${lowData ? ' · limited data' : ''}`
    : null;
  return (
    <div className="kdd-trend-meta">
      <div className="kdd-trend-meta-row">
        <span className="kdd-trend-meta-label">TREND</span>
        <span className="kdd-trend-meta-value"
              style={{ color: STATUS_TXT[trendStatus] || STATUS_TXT.neutral }}
              title="Projection is a linear extrapolation — assumes current rate continues. Not a forecast.">
          {trendStr}
        </span>
      </div>
      {modelNote && (
        <div className="kdd-trend-meta-row" style={{ marginTop: 2 }}>
          <span className="kdd-trend-meta-label" style={{ visibility: 'hidden' }}>TREND</span>
          <span style={{ fontSize: 11, color: '#94A3B8', letterSpacing: '0.02em', fontStyle: 'italic' }}>
            {modelNote}
          </span>
        </div>
      )}
      <div className="kdd-trend-meta-row">
        <span className="kdd-trend-meta-label">DRIVERS</span>
        <span className="kdd-trend-meta-value muted">— No driver notes</span>
      </div>
    </div>
  );
}

// Quarter-end months keep "vs FY target" framing (they're the checkpoint).
// Mid-quarter months get "vs <Month> target" framing.
const QUARTER_END_MONTHS = new Set(['mar', 'jun', 'sep', 'dec']);
const MONTH_NAME_FULL = {
  jan: 'January', feb: 'February', mar: 'March',     apr: 'April',
  may: 'May',     jun: 'June',     jul: 'July',      aug: 'August',
  sep: 'September', oct: 'October', nov: 'November', dec: 'December'
};
const MONTH_KEYS_ORDERED = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'];

function KpiDrillDown({ kpi, filters, view, granularity = 'quarter', monthKey = 'mar' }) {
  const M = window.YUNO_MARCH_2026;
  // Look up the cascade-truth record by id so the deep dive matches the cards exactly.
  // (Fall back to the legacy data.js record if the id isn't in march-data, e.g. for a few headlines.)
  const mk = M && M.STRATEGIC_BY_ID && M.STRATEGIC_BY_ID[kpi.id];
  const headlineMK = !mk && M && M.HEADLINES
    ? Object.values(M.HEADLINES).flat().find(h => h.id === kpi.id)
    : null;
  const k = mk || headlineMK;
  // Period bucket resolution: prefer cascade (spreadsheet truth, refreshed
  // monthly via ETL) over k[monthKey] (hand-curated in march-data.js, drifts
  // the moment owners edit the spreadsheet). See periodBucket() in sections.jsx
  // for the full rationale.
  const periodBucketOf = (mkey) => {
    if (!k || !mkey) return null;
    const c = k.cascade || {};
    const cA = c.monthlyActuals && c.monthlyActuals[mkey];
    const cT = c.monthlyTargets && c.monthlyTargets[mkey];
    if (cA != null || cT != null) {
      return { actual: cA ?? null, target: cT ?? null };
    }
    return k[mkey] || null;
  };
  const cur = periodBucketOf(monthKey);
  // Walk back chronologically to find the last month with a real actual.
  // currentPeriodActual = ONLY the active month's actual (null when not yet
  // reported). value = currentPeriodActual ?? carry-over from last known month.
  // This split matters: pct/variance must use currentPeriodActual, NOT the
  // carried value, otherwise we get nonsense like "March $90K vs April target
  // $97K = -8%" when there's no April actual yet.
  const currentPeriodActual = (cur && cur.actual !== null && cur.actual !== undefined) ? cur.actual : null;
  let carriedFromMonth = null;
  let carriedValue = null;
  if (currentPeriodActual === null && monthKey && k) {
    const idx = MONTH_KEYS_ORDERED.indexOf(monthKey);
    for (let i = idx - 1; i >= 0; i--) {
      const mk2 = MONTH_KEYS_ORDERED[i];
      const b = periodBucketOf(mk2);
      if (b && b.actual !== null && b.actual !== undefined) {
        carriedFromMonth = mk2;
        carriedValue = b.actual;
        break;
      }
    }
  }
  const value = currentPeriodActual !== null ? currentPeriodActual
              : (carriedValue !== null ? carriedValue
                 : (k && k.mar && k.mar.actual !== undefined ? k.mar.actual : kpi.q2Progress));
  const isCarriedOver = currentPeriodActual === null && carriedValue !== null;
  const periodTarget = cur ? cur.target : null;
  // Prefer the cascade FY target — see sections.jsx::preferCascadeFy for
  // rationale + the 50× unit-scale guard. The drill-in needs the same logic
  // as MarchCard so card + drill-in show the same target.
  const fyTarget = (function() {
    const cFy = kpi.cascade && kpi.cascade.monthlyTargets && kpi.cascade.monthlyTargets.fy;
    const handFy = (k && k.fy && k.fy.target !== undefined && k.fy.target !== null) ? k.fy.target
                   : ((kpi.fyTarget !== null && kpi.fyTarget !== undefined && kpi.fyTarget !== 'TBD') ? kpi.fyTarget : null);
    const cValid = (cFy !== null && cFy !== undefined);
    const hValid = (handFy !== null && handFy !== undefined);
    if (!cValid) return hValid ? handFy : null;
    if (!hValid) return cFy;
    if (Math.abs(cFy) > 0 && Math.abs(handFy) / Math.abs(cFy) > 50) return handFy;
    return cFy;
  })();
  const fyPending = !!(k && k.fy && k.fy.pending);
  const fmt = M ? M.formatValue : (v, f) => D.fmt(v, f);
  // Color logic must match what MarchCard renders so clicking a card and
  // seeing the drill-in doesn't show two different statuses for the same KPI.
  // MarchCard prefers cascade.latestRag (via window.YUNO_KPI_STATUS) and only
  // falls back to local computation when no cascade RAG is available.
  // This drill-in previously used M.healthVsFY exclusively, so a card showing
  // green (above month target) could open a drill-in showing red (far from
  // FY target) — confusing.
  // Same status-fallback ladder as resolveKpiForMonth + MarchCard. When cascade
  // RAG isn't available, mid-quarter months prefer the monthly target if it
  // exists, else fall back to FY-pace. Without this fallback, KPIs with
  // quarterly-only targets (e.g. Qualified Pipeline Stage Demo) rendered the
  // CARD as 'neutral' (gray, M.health returns neutral when monthly target is
  // null) and the DRILL-IN as warn/bad (M.healthVsFY against FY gap). The
  // two surfaces now agree on color.
  const localStatus = !(M && value !== null && value !== undefined)
    ? 'neutral'
    : (QUARTER_END_MONTHS.has(monthKey)
        ? (fyTarget !== null && fyTarget !== undefined
            ? M.healthVsFY(value, fyTarget, kpi.higherIsBetter)
            : 'neutral')
        : (periodTarget !== null && periodTarget !== undefined
            ? M.health(value, periodTarget, kpi.higherIsBetter)
            : (fyTarget !== null && fyTarget !== undefined
                ? M.healthVsFY(value, fyTarget, kpi.higherIsBetter)
                : 'neutral')));
  const status = window.YUNO_KPI_STATUS ? window.YUNO_KPI_STATUS(k || kpi, localStatus) : localStatus;
  // Variance pill framing: quarter-end months → vs FY target. Mid-quarter months → vs <Month> target.
  // SUPPRESS variance when value is carried over from a prior month — comparing
  // (say) a March actual against an April target produces a misleading number
  // and the panel ends up showing three different unrelated comparisons.
  const isQuarterEnd = QUARTER_END_MONTHS.has(monthKey);
  const pillTarget = isQuarterEnd ? fyTarget : periodTarget;
  const pct = (M && !isCarriedOver && pillTarget !== null && pillTarget !== undefined && currentPeriodActual !== null)
    ? M.variancePct(currentPeriodActual, pillTarget, kpi.higherIsBetter)
    : null;
  const pillLabel = isQuarterEnd ? 'vs FY target' : `vs ${MONTH_NAME_FULL[monthKey] || monthKey} target`;

  // Are there any curated insights for this KPI? Drives whether we render
  // the Insights section below — no fake content for KPIs without real data.
  const hasInsights = (() => {
    const cd = window.YUNO_CASCADE_DATA || {};
    const byKpi = (cd.insights && cd.insights.byKpi) || {};
    return Array.isArray(byKpi[kpi.id]) && byKpi[kpi.id].length > 0;
  })();

  return (
    <div className="kpi-deepdive">
      {/* Hero — clean white card. Color comes from FY-target health (same as cards). */}
      <div className={`kdd-hero status-${status}`}>
        <div className="kdd-hero-meta">
          <span className="kdd-hero-pillar">{(kpi.pillar || '').toUpperCase()}</span>
          {kpi.team && <span className="kdd-hero-sep">·</span>}
          {kpi.team && <span className="kdd-hero-team">{kpi.team}</span>}
        </div>
        <div className="kdd-hero-name">
          {kpi.name}
          {kpi.cascade && kpi.cascade.warning && (
            <span className="cascade-warning-badge" title={`Cascade data note: ${kpi.cascade.warning}`}>!</span>
          )}
        </div>
        <div className="kdd-hero-stat-row">
          <div className={`kdd-hero-value status-${status}`}>{fmt(value, kpi.format)}</div>
          {pct !== null && (
            <div className={`kdd-hero-pct status-${status}`}>
              {pct >= 0 ? '+' : ''}{pct}% {pillLabel}
            </div>
          )}
          {isCarriedOver && (
            <div style={{ fontSize: 12, color: '#94A3B8', letterSpacing: '0.02em' }}>
              latest: {MONTH_NAME_FULL[carriedFromMonth] || carriedFromMonth}
              &nbsp;·&nbsp; {MONTH_NAME_FULL[monthKey] || monthKey} actual pending
            </div>
          )}
        </div>
        {/* Period-context block: mid-quarter months add Month target + Quarter-end
            target rows on top. Quarter-end months (Mar/Jun/Sep/Dec) skip these rows
            because their pill already shows "vs FY". The trend chart always renders. */}
        {k && (
          <div className="kdd-apr-context">
            {!isQuarterEnd && (
              <>
                <div className="kdd-apr-row">
                  <span className="kdd-apr-label">{MONTH_NAME_FULL[monthKey] || monthKey} target</span>
                  <span className="kdd-apr-value">{fmt(periodTarget, kpi.format)}</span>
                </div>
                {(() => {
                  // Which quarter does this mid-quarter month belong to?
                  const Q_OF = { apr: 'q2', may: 'q2', jun: 'q2',
                                 jul: 'q3', aug: 'q3', sep: 'q3',
                                 oct: 'q4', nov: 'q4', dec: 'q4',
                                 jan: 'q1', feb: 'q1', mar: 'q1' };
                  const qKey = Q_OF[monthKey];
                  const qLabel = qKey ? qKey.toUpperCase() : '';
                  const qt = k[qKey] && k[qKey].target;
                  const qPending = k[qKey] && k[qKey].pending;
                  const hasQ = qt !== null && qt !== undefined;
                  const qStatus = hasQ ? M.health(value, qt, kpi.higherIsBetter) : 'neutral';
                  // Same carry-over guard as the headline pill: don't compute
                  // a Q-target variance against a value carried over from a
                  // prior month — the panel ends up showing two different
                  // misleading numbers that don't reconcile with the chart.
                  const qPct = (hasQ && !isCarriedOver) ? M.variancePct(currentPeriodActual, qt, kpi.higherIsBetter) : null;
                  return (
                    <div className={`kdd-apr-row${qPending ? ' is-pending' : ''}`}>
                      <span className="kdd-apr-label">{qLabel} target</span>
                      <span className="kdd-apr-value">{hasQ ? fmt(qt, kpi.format) : (qPending ? 'TBC' : '—')}</span>
                      {qPct !== null && (
                        <span className={`kdd-apr-pct status-${qStatus}`}>{qPct >= 0 ? '+' : ''}{qPct}% vs {qLabel}</span>
                      )}
                    </div>
                  );
                })()}
              </>
            )}
            <KddTrendChart kpi={k} status={status} />
            <KddTrendCaption kpi={k} status={status} />
          </div>
        )}
        <div className={`kdd-hero-status-bar status-${status}`}>
          <span className={`kdd-hero-status-dot status-${status}`}></span>
          <span className="kdd-hero-status-label">
            FY target: {fyTarget !== null && fyTarget !== undefined ? fmt(fyTarget, kpi.format) : (fyPending ? 'TBC' : '—')}
          </span>
          <span className="kdd-hero-status-sep">·</span>
          <span className="kdd-hero-owner">Owner: {kpi.owner || kpi.team || '—'}</span>
        </div>
      </div>

      {/* "What's driving it" placeholder block was removed — it rendered four
          hardcoded driver chips ("LATAM region +18% QoQ" etc.) for every
          KPI regardless of whether they applied. Real drivers live in the
          spreadsheet's Insights tab and now render in the "Insights" section
          below via cascade.insights.byKpi[kpi.id]. */}

      {/* Headlines breakdown — only render when real data exists */}
      {kpi.byRegion && (
        <div className="kdd-section">
          <div className="kdd-section-head">
            <div className="kdd-section-title">By region</div>
          </div>
          <ComparisonBar
            data={D.REGIONS.map(r => ({
              name: r,
              actual: kpi.byRegion[r]?.q2Progress ?? 0,
              target: kpi.byRegion[r]?.q2Target ?? 0
            }))}
            dataKey="actual"
            targetKey="target"
            format={kpi.format}
            height={150}
          />
        </div>
      )}

      {kpi.byTeam && (
        <div className="kdd-section">
          <div className="kdd-section-head">
            <div className="kdd-section-title">By team</div>
            <span className="kdd-section-tag">April pulse</span>
          </div>
          <ComparisonBar
            data={Object.keys(kpi.byTeam).map(team => ({
              name: team.replace('Engineering — ', 'Eng ').replace('Customer Success', 'CS').replace('Tech — Core/SecOps/SRE', 'Tech Core'),
              actual: kpi.byTeam[team]?.q2Progress ?? 0,
              target: kpi.byTeam[team]?.q2Target ?? 0,
              respondents: kpi.byTeam[team]?.respondents ?? 0
            }))}
            dataKey="actual"
            targetKey="target"
            format={kpi.format}
            height={200}
          />
        </div>
      )}

      {/* Insights — only render when cascade.insights actually has prose for
          this KPI id. KpiInsights returns null for KPIs without any curated
          text (e.g. Bugs/Month sub-cats) so the section disappears cleanly
          instead of showing the old generic "performing within expected
          range" placeholder. */}
      {hasInsights && (
        <div className="kdd-section">
          <div className="kdd-section-head">
            <div className="kdd-section-title">Insights</div>
          </div>
          <KpiInsights kpi={kpi} />
        </div>
      )}

      {/* Owner / Pillar footer */}
      <div className="kdd-footer">
        <div className="kdd-footer-col">
          <div className="kdd-footer-label">Owner</div>
          <div className="kdd-footer-value">{kpi.owner || kpi.team || '—'}</div>
        </div>
        <div className="kdd-footer-col">
          <div className="kdd-footer-label">Pillar</div>
          <div className="kdd-footer-value">{kpi.pillar || '—'}</div>
        </div>
      </div>
    </div>
  );
}

// ============================================================================
// PillarInsightsDrillDown — sidebar contents when a user clicks the bottom
// half of an Anchor card on the Executive Overview. Renders all curated
// `cascade.insights` for the pillar + the anchor KPI, grouped by month
// newest-first. Each insight gets a type chip (Driving / Watch / Risk / Note)
// and shows its source + last-updated date so the reader can trace it back
// to the spreadsheet.
//
// Data shape (from scripts/cascade_to_dashboard.py / extract_insights):
//   cascade.insights.byPillar['P1'] = [
//     { type: 'What's driving', text: '...', month: '2026-04',
//       last_updated: '2026-05-09', source: '...' },
//     ...
//   ]
//   cascade.insights.byKpi['arr']    = [ same shape ]
// Lists are pre-sorted newest-first by the ETL, so we just concat + group.
// ============================================================================
function PillarInsightsDrillDown({ pillar, anchor, monthKey }) {
  if (!pillar) return <div style={{ padding: 24, color: '#94A3B8' }}>No pillar selected.</div>;
  const cd = window.YUNO_CASCADE_DATA || {};
  const ins = cd.insights || {};
  const byKpi = ins.byKpi || {};
  const byPillar = ins.byPillar || {};

  // Tag each block with which dataset it came from so the sidebar can label
  // KPI-specific vs pillar-wide insights. KPI insights also get the anchor
  // name attached for display.
  const kpiBlocks = (anchor && anchor.id && byKpi[anchor.id] || []).map(i => ({
    ...i, _source: 'kpi', _label: (anchor && anchor.name) || 'KPI',
  }));
  const pillarBlocks = (byPillar[pillar.tag] || []).map(i => ({
    ...i, _source: 'pillar', _label: `${pillar.tag} pillar`,
  }));
  const all = [...kpiBlocks, ...pillarBlocks];

  // Group by month label. The ETL emits "YYYY-MM"; we expand to a human-
  // readable header like "APRIL 2026" for the sidebar.
  const MONTH_NAMES = ['January','February','March','April','May','June',
                       'July','August','September','October','November','December'];
  const monthLabel = (yyyyMm) => {
    if (!yyyyMm) return 'UNDATED';
    const [y, m] = yyyyMm.split('-');
    const idx = parseInt(m, 10) - 1;
    return `${(MONTH_NAMES[idx] || m).toUpperCase()} ${y}`;
  };

  const byMonth = {};
  for (const b of all) {
    const key = b.month || '';
    (byMonth[key] = byMonth[key] || []).push(b);
  }
  // Sort month keys newest-first (lexicographic works because YYYY-MM).
  const sortedKeys = Object.keys(byMonth).sort().reverse();

  // Normalize type to {driving, watch, risk, note} for icon + color picking.
  const normType = (t) => {
    const s = String(t || '').toLowerCase();
    if (s.includes('driv')) return 'driving';
    if (s.includes('watch')) return 'watch';
    if (s.includes('risk')) return 'risk';
    return 'note';
  };
  const iconByType = { driving: '↗', watch: '⚠', risk: '⚡', note: '·' };
  const labelByType = { driving: 'Driving', watch: 'Watch', risk: 'Risk', note: 'Note' };

  const totalCount = all.length;
  const currentMonthStr = (() => {
    // Mirror sections.jsx's insightMonthString so the "Current month" header
    // matches what the anchor card was showing. Year defaults to 2026.
    const MONTH_KEYS_LOCAL = ['jan','feb','mar','apr','may','jun','jul','aug','sep','oct','nov','dec'];
    const i = MONTH_KEYS_LOCAL.indexOf(monthKey);
    if (i < 0) return null;
    return `2026-${String(i + 1).padStart(2, '0')}`;
  })();

  return (
    <div className="pillar-insights-drilldown">
      {totalCount === 0 ? (
        <div style={{ padding: 24, color: '#64748B', lineHeight: 1.6 }}>
          <p style={{ margin: 0, fontSize: 14 }}>
            No curated insights yet for <b>{pillar.name}</b>.
          </p>
          <p style={{ margin: '12px 0 0', fontSize: 13, color: '#94A3B8' }}>
            Add insights in the spreadsheet's <code>Insights</code> tab —
            they'll flow into the dashboard on the next cascade refresh.
            Scope can be a pillar tag ({pillar.tag}) or a specific KPI id
            ({(anchor && anchor.id) || '—'}).
          </p>
        </div>
      ) : sortedKeys.map((mk, mi) => (
        <div key={mk} className="pillar-insights-month-block">
          <div className="pillar-insights-month-label">
            {monthLabel(mk)}
            {mk === currentMonthStr && (
              <span className="pillar-insights-month-current">CURRENT</span>
            )}
          </div>
          {byMonth[mk].map((b, i) => {
            const n = normType(b.type);
            return (
              <div key={i} className={`pillar-insights-block block-${n}`}>
                <div className={`pillar-insights-type type-${n}`}>
                  <span aria-hidden="true">{iconByType[n]}</span>
                  <span>{labelByType[n]}</span>
                  <span className="pillar-insights-scope">· {b._label}</span>
                </div>
                <div className="pillar-insights-text">{b.text}</div>
                {(b.source || b.last_updated) && (
                  <div className="pillar-insights-meta">
                    {b.source && <span>{b.source}</span>}
                    {b.source && b.last_updated && <span> · </span>}
                    {b.last_updated && <span>updated {b.last_updated}</span>}
                  </div>
                )}
              </div>
            );
          })}
        </div>
      ))}
    </div>
  );
}

function RegionDrillDown({ region, filters, view }) {
  const regionKpis = D.STRATEGIC.filter(kpi => kpi.byRegion && kpi.byRegion[region]);

  return (
    <div className="region-drilldown">
      <div className="panel">
        <div className="panel-head">
          <div className="panel-title">{region} Performance</div>
          <div className="panel-subtitle">Regional KPI overview</div>
        </div>
        <div className="region-kpi-grid">
          {regionKpis.map(kpi => {
            const actual = kpi.byRegion[region]?.q2Progress ?? 0;
            const target = kpi.byRegion[region]?.q2Target ?? 0;
            const pct = D.pctToTarget(actual, target, kpi.higherIsBetter);
            const localStatus = D.health(actual, target, kpi.higherIsBetter);
            const status = window.YUNO_KPI_STATUS ? window.YUNO_KPI_STATUS(kpi, localStatus) : localStatus;

            return (
              <div key={kpi.id} className={`region-kpi-card status-${status}`}>
                <div className="region-kpi-name">{kpi.name}</div>
                <div className="region-kpi-value">{D.fmt(actual, kpi.format)}</div>
                <div className={`region-kpi-pct text-${status}`}>
                  {pct >= 0 ? '+' : ''}{pct.toFixed(0)}%
                </div>
              </div>
            );
          })}
        </div>
      </div>

    </div>
  );
}

// RegionInsights and DepartmentInsights were removed: both rendered hardcoded
// prose ("LATAM continues to drive…", "Strong Department Performance") that
// had nothing to do with live data. RegionDrillDown still exists as
// scaffolding but no longer surfaces fake insights; DepartmentDrillDown
// remains commented out throughout the codebase. Real prose comes from
// `cascade.insights` — wire any future region/department surface to that.

// KpiInsights — renders curated insights for a specific KPI from
// `cascade.insights.byKpi[kpi.id]`. Returns null when no insights exist for
// the KPI so the parent can skip the section entirely (no canned filler).
//
// Previously this component generated hardcoded, made-up text for a handful
// of KPI ids ("LATAM leading growth", "Banking vertical engagement
// accelerating", etc.) and fell through to a generic template ("`${kpi.name}`
// performing within expected range") for everything else. That meant opening
// a KPI like Bugs/Month surfaced text that had nothing to do with the KPI.
// Now: read real prose from the Insights tab via the ETL — nothing else.
function KpiInsights({ kpi }) {
  const blocks = useMemo(() => {
    const cd = window.YUNO_CASCADE_DATA || {};
    const byKpi = (cd.insights && cd.insights.byKpi) || {};
    const list = byKpi[kpi.id] || [];
    // Already sorted newest-first by the ETL (extract_insights in
    // scripts/cascade_to_dashboard.py). Pass through as-is so the drill-in
    // and the pillar-insights sidebar both show the same order.
    return list;
  }, [kpi]);

  if (blocks.length === 0) return null;

  // Normalize the spreadsheet's free-form `type` column to a stable key for
  // icon + color + ordering. Mirrors normalizeInsightType in sections.jsx.
  const norm = (t) => {
    const s = String(t || '').toLowerCase();
    if (s.includes('driv')) return 'driving';
    if (s.includes('watch')) return 'watch';
    if (s.includes('risk')) return 'risk';
    return 'note';
  };
  const iconByType = { driving: '↗', watch: '⚠', risk: '⚡', note: '·' };
  const labelByType = { driving: 'Driving', watch: 'Watch', risk: 'Risk', note: 'Note' };

  // Format YYYY-MM → "APRIL 2026" for the per-insight chip. The ETL emits
  // a YYYY-MM string when the spreadsheet's Month column was a date; we
  // keep month grouping inside this component so KPIs that span months show
  // their chronology in-place (the pillar sidebar groups the same way).
  const MONTH_NAMES = ['January','February','March','April','May','June',
                       'July','August','September','October','November','December'];
  const monthLabel = (yyyyMm) => {
    if (!yyyyMm) return '';
    const [y, m] = yyyyMm.split('-');
    const idx = parseInt(m, 10) - 1;
    return `${(MONTH_NAMES[idx] || m).toUpperCase()} ${y}`;
  };

  // Group by month so the drill-in shows the same chronological structure
  // as the pillar sidebar (and the user's spreadsheet).
  const byMonth = {};
  for (const b of blocks) {
    const k = b.month || '';
    (byMonth[k] = byMonth[k] || []).push(b);
  }
  const sortedKeys = Object.keys(byMonth).sort().reverse();

  return (
    <div className="kpi-insights-list">
      {sortedKeys.map(mk => (
        <div key={mk} className="kpi-insights-month">
          {mk && <div className="kpi-insights-month-label">{monthLabel(mk)}</div>}
          {byMonth[mk].map((b, i) => {
            const n = norm(b.type);
            return (
              <div key={i} className={`kpi-insights-block block-${n}`}>
                <div className={`kpi-insights-type type-${n}`}>
                  <span aria-hidden="true">{iconByType[n]}</span>
                  <span>{labelByType[n]}</span>
                </div>
                <div className="kpi-insights-text">{b.text}</div>
                {(b.source || b.last_updated) && (
                  <div className="kpi-insights-meta">
                    {b.source && <span>{b.source}</span>}
                    {b.source && b.last_updated && <span> · </span>}
                    {b.last_updated && <span>updated {b.last_updated}</span>}
                  </div>
                )}
              </div>
            );
          })}
        </div>
      ))}
    </div>
  );
}

// ============================================================================
// Drawer (with fullscreen expand) - Legacy component
// ============================================================================
function Drawer({ kpi, view, filters, onClose }) {
  const [granularity, setGranularity] = useState('quarter');
  const [expanded, setExpanded] = useState(false);
  const open = !!kpi;

  useEffect(() => { if (!kpi) setExpanded(false); }, [kpi]);

  if (!kpi) return <div className="drawer-backdrop"/>;
  const value = computeFiltered(kpi, view, filters, 'actual');
  const target = computeFiltered(kpi, view, filters, 'target');
  const localStatus = D.health(value, target, kpi.higherIsBetter);
  const status = window.YUNO_KPI_STATUS ? window.YUNO_KPI_STATUS(kpi, localStatus) : localStatus;
  const pct = D.pctToTarget(value, target, kpi.higherIsBetter);
  const scope = describeScope(filters);

  const regionData = kpi.byRegion ? D.REGIONS.map(r => ({
    name: r,
    actual: view === 'qtd' ? (kpi.byRegion[r]?.q2Progress ?? kpi.byRegion[r]?.q1Actual ?? 0) : (kpi.byRegion[r]?.q1Actual ?? 0),
    target: kpi.byRegion[r]?.[view === 'qtd' ? 'q2Target' : 'q4Target'] || 0,
  })) : null;

  const sourceData = kpi.bySource ? Object.entries(kpi.bySource).map(([k, v]) => ({
    name: k, actual: v.current, target: v[view === 'qtd' ? 'q2Target' : 'q4Target'] || v.target,
  })) : null;

  const stageData = kpi.byStage ? Object.entries(kpi.byStage).map(([k, v]) => ({
    name: k, actual: v.current, target: v[view === 'qtd' ? 'q2Target' : 'q4Target'] || v.target,
  })) : null;

  return (
    <>
      <div className={`drawer-backdrop ${open ? 'open' : ''}`} onClick={onClose}/>
      <div className={`drawer ${open ? 'open' : ''} ${expanded ? 'expanded' : ''}`}>
        <div className="drawer-head">
          <div>
            <div className="text-xs text-muted" style={{ textTransform: 'uppercase', letterSpacing: '0.06em', fontWeight: 600 }}>
              Strategic KPI · {kpi.team || 'BD'}
            </div>
            <h2 style={{ fontSize: 22, fontWeight: 700, marginTop: 4 }}>{kpi.name}</h2>
            <div className="text-sm text-muted" style={{ marginTop: 2 }}>
              Owner: {kpi.owner}
              {scope && <span> · {scope}</span>}
            </div>
          </div>
          <div className="drawer-head-actions">
            <button className="icon-btn" title={expanded ? 'Collapse' : 'Expand full-screen'}
              onClick={() => setExpanded(!expanded)}>
              {expanded ? '⤡' : '⤢'}
            </button>
            <button className="close" onClick={onClose}>×</button>
          </div>
        </div>
        <div className="drawer-body">
          <div style={{ display: 'flex', gap: 24, alignItems: 'flex-end', marginBottom: 20 }}>
            <div>
              <div className="text-xs text-muted">Current ({view === 'qtd' ? `Q2 W${D.WEEK_OF_QUARTER}` : 'YTD'})</div>
              <div style={{ fontFamily: 'var(--font-display)', fontSize: 44, fontWeight: 700, lineHeight: 1, fontVariantNumeric: 'tabular-nums' }}>
                {D.fmt(value, kpi.format)}
              </div>
            </div>
            <div>
              <div className="text-xs text-muted">{view === 'qtd' ? 'Q1 Target' : 'FY Target'}</div>
              <div style={{ fontFamily: 'var(--font-display)', fontSize: 22, fontWeight: 600, color: C.n400, fontVariantNumeric: 'tabular-nums' }}>
                {D.fmt(target, kpi.format)}
              </div>
            </div>
            <div style={{ marginLeft: 'auto' }}>
              <span className={`badge badge-${status === 'good' ? 'good' : status === 'warn' ? 'warn' : 'bad'}`}>
                {pct >= 0 ? '+' : ''}{pct.toFixed(1)}% vs target
              </span>
            </div>
          </div>

          <div className="panel" style={{ marginBottom: 16 }}>
            <div className="panel-head">
              <div>
                <div className="panel-title">Trend</div>
                <div className="panel-subtitle">Actual · Target · Forecast</div>
              </div>
              <div className="view-toggle" style={{ padding: 2 }}>
                <button className={granularity === 'quarter' ? 'active' : ''} onClick={() => setGranularity('quarter')}>Quarterly</button>
              </div>
            </div>
            <TrendChart kpiId={kpi.id} format={kpi.format} height={expanded ? 360 : 220} granularity={granularity} higherIsBetter={kpi.higherIsBetter}/>
          </div>

          <div className={expanded ? 'drawer-grid-2' : ''}>
            {regionData && (
              <div className="panel" style={{ marginBottom: 16 }}>
                <div className="panel-head"><div className="panel-title">By region</div></div>
                <ComparisonBar data={regionData} dataKey="actual" targetKey="target" format={kpi.format} height={200}/>
              </div>
            )}
            {sourceData && (
              <div className="panel" style={{ marginBottom: 16 }}>
                <div className="panel-head"><div className="panel-title">By source</div></div>
                <ComparisonBar data={sourceData} dataKey="actual" targetKey="target" format={kpi.format} height={200}/>
              </div>
            )}
            {stageData && (
              <div className="panel" style={{ marginBottom: 16 }}>
                <div className="panel-head"><div className="panel-title">By pipeline stage</div></div>
                <ComparisonBar data={stageData} dataKey="actual" targetKey="target" format={kpi.format} height={200}/>
              </div>
            )}

            <div className="panel" style={{ marginBottom: 16 }}>
              <div className="panel-head"><div className="panel-title">Quarterly cascade</div></div>
              <dl className="kv">
                <dt>Baseline</dt><dd>{D.fmt(kpi.baseline, kpi.format)}</dd>
                <dt>Q1 Actual</dt><dd>{D.fmt(kpi.q1Actual, kpi.format)}</dd>
                <dt>Q2 Progress</dt><dd>{D.fmt(kpi.q2Progress, kpi.format)} <span className="text-xs text-muted">(W{D.WEEK_OF_QUARTER}/{D.WEEKS_IN_QUARTER})</span></dd>
                {kpi.q1Target !== undefined && kpi.q1Target !== null && (
                  <>
                    <dt>Q1 Target</dt><dd>{D.fmt(kpi.q1Target, kpi.format)}</dd>
                  </>
                )}
                <dt>Q2 Target</dt><dd>{D.fmt(kpi.q2Target, kpi.format)}</dd>
                <dt>Q3 Target</dt><dd>{D.fmt(kpi.q3Target, kpi.format)}</dd>
                <dt>Q4 Target</dt><dd>{D.fmt(kpi.q4Target, kpi.format)}</dd>
                <dt>FY Target</dt><dd>{D.fmt(kpi.fyTarget, kpi.format)}</dd>
                <dt>Direction</dt><dd style={{display: 'flex', alignItems: 'center', gap: '6px'}}>
                  {kpi.higherIsBetter ? 'Higher is better' : 'Lower is better'}
                  <svg
                    width="14"
                    height="14"
                    viewBox="0 0 24 24"
                    fill="none"
                    xmlns="http://www.w3.org/2000/svg"
                    style={{
                      transform: kpi.higherIsBetter ? 'rotate(0deg)' : 'rotate(180deg)',
                      transition: 'transform 0.2s ease'
                    }}
                  >
                    <path
                      d="M7 14L12 9L17 14"
                      stroke="currentColor"
                      strokeWidth="2"
                      strokeLinecap="round"
                      strokeLinejoin="round"
                    />
                  </svg>
                </dd>
              </dl>
            </div>

            <div className="panel">
              <div className="panel-head"><div className="panel-title">Data source</div></div>
              <div className="text-sm" style={{ lineHeight: 1.5 }}>
                <div><span className="badge badge-region">SOURCE</span> {kpi._source || 'Pending'}</div>
              </div>
            </div>
          </div>
        </div>
      </div>
    </>
  );
}

// Coming Soon page for teams without data yet
function ComingSoonPage({ team }) {
  const info = {
    marketing: { label: 'Marketing', desc: 'MQL → SQL, CAC, attribution, campaign ROI, brand awareness', source: 'HubSpot · Google Analytics · Salesforce' },
    cs:        { label: 'Customer Success', desc: 'NRR, GRR, churn, CSAT, health score, time-to-value', source: 'Gainsight · Salesforce · internal CSAT' },
    product:   { label: 'Product', desc: 'DAU/MAU, feature adoption, latency, error rate, NPS', source: 'Amplitude · Datadog · in-product surveys' },
    finance:   { label: 'Finance', desc: 'Revenue, burn, runway, margin, cash, AR/AP', source: 'NetSuite · Deel · internal Excel sheets' },
    hr:        { label: 'People',   desc: 'Headcount, attrition, time-to-hire, engagement, comp', source: 'Deel · Greenhouse · Culture Amp' },
  }[team] || { label: team, desc: '—', source: '—' };

  return (
    <div className="coming-soon">
      <div className="cs-badge">Coming Soon</div>
      <h2>{info.label} KPIs</h2>
      <p className="cs-desc">{info.desc}</p>
      <div className="cs-source">
        <span className="cs-source-label">Planned data sources</span>
        <span className="cs-source-val">{info.source}</span>
      </div>
      <p className="cs-cta">
        Once integrations land, this page gets the same treatment BD has today:
        page-level filters, drill-down drawer, fullscreen deep-dive.
      </p>
    </div>
  );
}

// ============================================================================
// Strategic Deep Dive - 4 strategic focus areas
// ============================================================================
function StrategicDeepDive({ data, filters, view, onKpiClick }) {
  if (!data) return React.createElement("div", null, "No data available");
  const { deepDive, config } = data;

  if (deepDive === "ai_maya") {
    return React.createElement("div", {style: {padding: "40px", textAlign: "center"}}, [
      React.createElement("h3", {key: "title", style: {fontSize: "24px", marginBottom: "8px"}}, "AI & Maya Analytics"),
      React.createElement("p", {key: "desc", style: {color: "#64748B"}}, "Enhanced analytics coming Q3 2026")
    ]);
  }

  if (deepDive === "pipeline") {
    return React.createElement("div", {style: {display: "flex", gap: "32px", padding: "20px"}}, [
      React.createElement("div", {
        key: "card",
        style: {
          backgroundColor: "#3E4FE0",
          color: "white",
          padding: "32px",
          borderRadius: "16px",
          minWidth: "300px"
        }
      }, [
        React.createElement("div", {key: "label", style: {fontSize: "12px", fontWeight: 600}}, "QUALIFIED PIPELINE"),
        React.createElement("div", {key: "value", style: {fontSize: "48px", fontWeight: 700}}, "$67.3M"),
        React.createElement("div", {key: "change", style: {fontSize: "14px", color: "#E2E8F0"}}, "-$2.7M vs target")
      ]),
      React.createElement("div", {key: "drivers", style: {flex: 1}}, [
        React.createElement("h3", {key: "title", style: {fontSize: "18px", fontWeight: 600, marginBottom: "16px"}}, "The drivers — why it moved"),
        React.createElement("div", {key: "content", style: {lineHeight: "1.6"}}, [
          React.createElement("div", {key: "p1", style: {marginBottom: "12px"}}, "LATAM continues to drive pipeline generation with $32M qualified (67% conversion). Banking vertical engagement accelerated 23% quarter-over-quarter with strong enterprise momentum."),
          React.createElement("div", {key: "p2", style: {marginBottom: "12px"}}, "APAC pipeline quality improved significantly - qualification velocity up 15% but total volume remains behind target. European expansion showing early traction with $8.2M qualified opportunities."),
          React.createElement("div", {key: "p3", style: {color: "#6B7280"}}, "Demo conversion rates improved to 67% vs 61% last quarter, indicating stronger product-market fit across verticals.")
        ])
      ])
    ]);
  }

  if (deepDive === "leverage") {
    return React.createElement("div", {style: {display: "flex", gap: "32px", padding: "20px"}}, [
      React.createElement("div", {
        key: "card",
        style: {
          backgroundColor: "#3E4FE0",
          color: "white",
          padding: "32px",
          borderRadius: "16px",
          minWidth: "300px"
        }
      }, [
        React.createElement("div", {key: "label", style: {fontSize: "12px", fontWeight: 600}}, "REVENUE PER EMPLOYEE"),
        React.createElement("div", {key: "value", style: {fontSize: "48px", fontWeight: 700}}, "$187K"),
        React.createElement("div", {key: "change", style: {fontSize: "14px", color: "#E2E8F0"}}, "+23% vs baseline")
      ]),
      React.createElement("div", {key: "drivers", style: {flex: 1}}, [
        React.createElement("h3", {key: "title", style: {fontSize: "18px", fontWeight: 600, marginBottom: "16px"}}, "The drivers — why it moved"),
        React.createElement("div", {key: "content", style: {lineHeight: "1.6"}}, [
          React.createElement("div", {key: "p1", style: {marginBottom: "12px"}}, "Operating leverage accelerating as ARR scales 23% faster than headcount growth. Revenue per employee increased from $152K baseline to $187K current, demonstrating improving unit economics."),
          React.createElement("div", {key: "p2", style: {marginBottom: "12px"}}, "EBITDA trajectory improving from -$1.66M baseline towards positive territory. Cost arbitrage through LATAM operations contributing $2.1M quarterly savings while maintaining service quality."),
          React.createElement("div", {key: "p3", style: {color: "#6B7280"}}, "Path to profitability clear with current efficiency gains - breakeven projected at $92M ARR run rate.")
        ])
      ])
    ]);
  }

  if (deepDive === "ndr_expansion") {
    return React.createElement("div", {style: {display: "flex", gap: "32px", padding: "20px"}}, [
      React.createElement("div", {
        key: "card",
        style: {
          backgroundColor: "#3E4FE0",
          color: "white",
          padding: "32px",
          borderRadius: "16px",
          minWidth: "300px"
        }
      }, [
        React.createElement("div", {key: "label", style: {fontSize: "12px", fontWeight: 600}}, "NET DOLLAR RETENTION"),
        React.createElement("div", {key: "value", style: {fontSize: "48px", fontWeight: 700}}, "125%"),
        React.createElement("div", {key: "change", style: {fontSize: "14px", color: "#E2E8F0"}}, "Controlled decline strategy")
      ]),
      React.createElement("div", {key: "drivers", style: {flex: 1}}, [
        React.createElement("h3", {key: "title", style: {fontSize: "18px", fontWeight: 600, marginBottom: "16px"}}, "The drivers — why it moved"),
        React.createElement("div", {key: "content", style: {lineHeight: "1.6"}}, [
          React.createElement("div", {key: "p1", style: {marginBottom: "12px"}}, "NDR progression follows strategic decline pattern: 141% → 125% → 135% → 130% → 125%. Controlled reduction as customer base scales while maintaining healthy expansion rates."),
          React.createElement("div", {key: "p2", style: {marginBottom: "12px"}}, "Enterprise customers driving expansion with average 34% upsell rate. Land-and-expand strategy proving effective across banking and fintech verticals with strong product adoption."),
          React.createElement("div", {key: "p3", style: {color: "#6B7280"}}, "Retention rates remain strong at 94% gross retention while expansion opportunities normalize to sustainable levels.")
        ])
      ])
    ]);
  }

  return React.createElement("div", {style: {padding: "20px"}}, [
    React.createElement("h3", {key: "title"}, config.title),
    React.createElement("p", {key: "subtitle"}, config.subtitle),
    React.createElement("div", {key: "content", style: {padding: "20px", backgroundColor: "#f8f9fa"}}, "Analytics available")
  ]);
}
window.YUNO_PANELS = {
  Sidebar, PageFilterBar, AtRiskStrip, Drawer, ExecSummary, ComingSoonPage, describeScope,
  ExpandableSidebar, ContextualFilters, KpiDrillDown, RegionDrillDown,
  StrategicKpisDrillDown, StrategicDeepDive, HeadlineKpisDrillDown,
  KpiInsights,
};
})();
