/* global React */
// ============================================================
// Inframind — Animated product mockup (enterprise SaaS)
// Cycles: Workspace + map → click → Overview dashboard →
//   click Generate → Bill of Quantities export
// Light theme, real brand colours, severity reds/oranges
// ============================================================

const { useState: useStateMockup, useEffect: useEffectMockup } = React;

// Animation timeline (seconds)
const TIMELINE = {
  total: 34,             // full cycle
  showMap:      [0, 6.2],
  clickAsset:   5.2,
  showOverview: [6.2, 12.2],
  clickListTab: 11.6,
  showList:     [12.2, 19.2],
  click3DTab:   18.6,
  show3D:       [19.2, 26.2],
  clickGenerate: 25.6,
  showBom:      [26.2, 32.0],
  fadeOut:      [32.0, 34.0],
};

function ProductMockup() {
  const [t, setT] = useStateMockup(0);

  useEffectMockup(() => {
    const start = performance.now();
    const id = setInterval(() => {
      const elapsed = ((performance.now() - start) / 1000) % TIMELINE.total;
      setT(elapsed);
    }, 1000 / 30);
    return () => clearInterval(id);
  }, []);

  // Stage opacities (cross-fade between stages)
  const inRange = (t, a, b, fadeIn = 0.4, fadeOut = 0.4) => {
    if (t < a) return 0;
    if (t < a + fadeIn) return (t - a) / fadeIn;
    if (t < b - fadeOut) return 1;
    if (t < b) return (b - t) / fadeOut;
    return 0;
  };

  const opMap      = inRange(t, ...TIMELINE.showMap);
  const opOverview = inRange(t, ...TIMELINE.showOverview);
  const opList     = inRange(t, ...TIMELINE.showList);
  const op3D       = inRange(t, ...TIMELINE.show3D);
  const opBom      = inRange(t, ...TIMELINE.showBom);

  // Active tab — drives the tab pill highlight
  const activeTab =
    t < TIMELINE.showOverview[0] ? "map" :
    t < TIMELINE.showList[0]     ? "overview" :
    t < TIMELINE.show3D[0]       ? "list" :
    t < TIMELINE.showBom[0]      ? "3d" :
    "list"; // BoQ opens over the list context

  // Sidebar highlight when clicking the asset
  const assetHighlight = t > 2.4 && t < 3.4;

  return (
    <div className="mockup-frame">
      <MockupTitleBar activeTab={activeTab}/>
      <div className="mockup-body">
        <MockupSidebar tab={activeTab} highlight={assetHighlight}/>
        <div className="mockup-main">
          <MockupBreadcrumb/>
          <div className="mockup-canvas">
            <div className="stage" style={{opacity: opMap}}><StageMap t={t}/></div>
            <div className="stage" style={{opacity: opOverview}}><StageOverview t={t}/></div>
            <div className="stage" style={{opacity: opList}}><StageList t={t} t0={TIMELINE.showList[0]}/></div>
            <div className="stage" style={{opacity: op3D}}><Stage3D t={t} t0={TIMELINE.show3D[0]}/></div>
            <div className="stage" style={{opacity: opBom, zIndex: 5}}><StageBom t={t}/></div>
          </div>
        </div>
      </div>
      {/* Click cursor — at frame level so it can reach the title-bar tabs */}
      <ClickCursor t={t}/>
    </div>
  );
}

// -------- Top title bar (browser-style + product header)
function MockupTitleBar({ activeTab }) {
  const tabs = [
    { id: "map",       label: "Map" },
    { id: "overview",  label: "Overview" },
    { id: "list",      label: "List View" },
    { id: "3d",        label: "3D View" },
    { id: "documents", label: "Documents" },
  ];
  return (
    <div className="mockup-titlebar">
      <div className="mockup-dots"><span></span><span></span><span></span></div>
      <div className="mockup-url">
        <span className="lock">⌥</span> inframind.app / workspace
      </div>
      <div className="mockup-tabs">
        {tabs.map(tab => (
          <span key={tab.id} className={`tab-pill ${activeTab === tab.id ? "active" : ""}`}>{tab.label}</span>
        ))}
      </div>
    </div>
  );
}

function MockupBreadcrumb() {
  return (
    <div className="mockup-breadcrumb">
      <span>InfraMind</span>
      <span className="sep">/</span>
      <span>England</span>
      <span className="sep">/</span>
      <span>West Yorkshire</span>
      <span className="sep">/</span>
      <span className="here">Demo Tunnel</span>
    </div>
  );
}

// -------- Left sidebar
function MockupSidebar({ tab, highlight }) {
  return (
    <aside className="mockup-sidebar">
      <div className="ms-section-label">Workspace</div>
      <div className="ms-control">
        <span>Demo Workspace</span>
        <span className="caret">▾</span>
      </div>
      <div className="ms-control">
        <span>All Asset Types</span>
        <span className="caret">▾</span>
      </div>
      <div className="ms-search">
        <span className="ic">⌕</span>
        <span>Search</span>
      </div>

      <div className="ms-tree">
        <div className="ms-tree-row">
          <span className="ms-caret">▾</span>
          <span className="ms-row-label">InfraMind</span>
          <span className="ms-row-count">1</span>
        </div>
        <div className="ms-tree-row indent">
          <span className="ms-caret">▾</span>
          <span className="ms-row-label">England</span>
          <span className="ms-row-count">1</span>
        </div>
        <div className="ms-section-label small">West Yorkshire</div>
        <div className={`ms-tree-row indent2 selected ${highlight ? "highlight" : ""}`}>
          <span className="ms-icon-asset">⌂</span>
          <span className="ms-row-label">Demo Tunnel</span>
        </div>
      </div>

      <div className="ms-foot">1 asset</div>
    </aside>
  );
}

// -------- Stage: Map
function StageMap({ t }) {
  // Marker pulse intensity grows toward click time
  const pulse = Math.max(0, Math.sin((t / 3.0) * Math.PI * 4) * 0.5 + 0.5);
  return (
    <div className="stage-map">
      <div className="stage-map-bg"></div>
      <svg className="stage-map-routes" viewBox="0 0 1200 700" preserveAspectRatio="xMidYMid slice">
        {/* abstract topo/road network */}
        <defs>
          <linearGradient id="mapGreen" x1="0" y1="0" x2="1" y2="1">
            <stop offset="0" stopColor="#E5EFE3"/>
            <stop offset="1" stopColor="#D6E2D2"/>
          </linearGradient>
          <pattern id="mapGrain" width="2" height="2" patternUnits="userSpaceOnUse">
            <rect width="2" height="2" fill="rgba(0,0,0,0.015)"/>
          </pattern>
        </defs>
        <rect width="1200" height="700" fill="url(#mapGreen)"/>
        <rect width="1200" height="700" fill="url(#mapGrain)"/>
        {/* hills (irregular shaded polygons) */}
        <path d="M0 380 L180 320 L320 360 L470 310 L640 340 L800 300 L980 340 L1200 320 L1200 700 L0 700 Z" fill="#CFDDC9" opacity="0.55"/>
        <path d="M0 460 L220 420 L380 450 L560 410 L760 440 L960 410 L1200 430 L1200 700 L0 700 Z" fill="#C2D2BB" opacity="0.5"/>
        {/* water bodies */}
        <ellipse cx="980" cy="220" rx="120" ry="50" fill="#A8C5D9" opacity="0.6"/>
        <ellipse cx="160" cy="540" rx="80" ry="30" fill="#A8C5D9" opacity="0.55"/>
        {/* roads */}
        <path d="M0 410 Q280 380 460 420 T820 400 T1200 420" stroke="#fff" strokeWidth="6" fill="none" opacity="0.85"/>
        <path d="M0 410 Q280 380 460 420 T820 400 T1200 420" stroke="#E8B96B" strokeWidth="2" fill="none"/>
        <path d="M100 200 Q260 280 460 240 T780 280 T1100 240" stroke="#fff" strokeWidth="4" fill="none" opacity="0.7"/>
        <path d="M620 0 Q580 200 640 360 T580 700" stroke="#fff" strokeWidth="3" fill="none" opacity="0.65"/>
        <path d="M860 0 Q820 180 880 360 T820 700" stroke="#fff" strokeWidth="2" fill="none" opacity="0.55"/>
        {/* tunnel asset line (highlight) */}
        <line x1="430" y1="395" x2="780" y2="378" stroke="#0A0A0A" strokeWidth="5"/>
        <circle cx="430" cy="395" r="6" fill="#0A0A0A"/>
        {/* place labels */}
        <text x="200" y="180" fontFamily="Inter, sans-serif" fontSize="11" fill="#525252">Godleybrook</text>
        <text x="430" y="200" fontFamily="Inter, sans-serif" fontSize="11" fill="#525252">Dilhorne</text>
        <text x="200" y="500" fontFamily="Inter, sans-serif" fontSize="11" fill="#525252">Caverswall</text>
        <text x="850" y="500" fontFamily="Inter, sans-serif" fontSize="11" fill="#525252">Brookhouses</text>
        <text x="1040" y="610" fontFamily="Inter, sans-serif" fontSize="11" fill="#525252">Draycott Cross</text>
      </svg>

      {/* Tunnel marker w/ pulse */}
      <div className="map-marker" style={{left: "39%", top: "55%"}}>
        <div className="marker-pulse" style={{transform: `scale(${1 + pulse * 1.5})`, opacity: 0.35 - pulse * 0.25}}></div>
        <div className="marker-pin">
          <svg width="20" height="26" viewBox="0 0 20 26">
            <path d="M10 0 C4 0 0 4 0 10 C0 17 10 26 10 26 C10 26 20 17 20 10 C20 4 16 0 10 0 Z" fill="#0A0A0A"/>
            <circle cx="10" cy="10" r="4" fill="#fff"/>
          </svg>
        </div>
      </div>

      {/* Map controls (right rail) */}
      <div className="map-controls">
        <div className="mc-btn">+</div>
        <div className="mc-btn">−</div>
        <div className="mc-btn">⤢</div>
        <div className="mc-btn">⚙</div>
      </div>

      {/* Style switcher (top left) */}
      <div className="map-styles">
        <span className="ms-pill">Default</span>
        <span className="ms-pill active">Terrain</span>
        <span className="ms-pill">Satellite</span>
        <span className="ms-pill">3D</span>
      </div>

      {/* Selected asset card (bottom center) */}
      <div className="map-selected-card">
        <div className="msc-row">
          <span className="msc-pin">📍</span>
          <span className="msc-title">Demo Tunnel</span>
          <span className="msc-clear">× Clear</span>
        </div>
        <div className="msc-sub">West Yorkshire, England</div>
        <div className="msc-nav">
          <div className="msc-label">Quick Navigation</div>
          <div className="msc-buttons">
            <button>Overview</button>
            <button>List View</button>
            <button>3D View</button>
          </div>
        </div>
      </div>

      {/* Elevation profile panel — slides in from right around t=2.8s */}
      <MapElevationPanel t={t}/>

      {/* Street View panel — fades in around t=4.0s */}
      <MapStreetViewPanel t={t}/>
    </div>
  );
}

// -------- Elevation profile panel (slides in on the right of the map)
function MapElevationPanel({ t }) {
  const inP = Math.max(0, Math.min(1, (t - 2.8) / 0.5));
  if (inP <= 0) return null;
  // Animated peak chart — single hill shape, like a tunnel elevation profile
  // Build a path with a peaked profile (gentle rise → peak → gentle fall)
  const pts = [];
  const N = 40;
  for (let i = 0; i <= N; i++) {
    const x = i / N;
    // Bell-ish curve with slight asymmetry
    const e = Math.exp(-Math.pow((x - 0.55) * 2.8, 2)) * 0.85 + 0.05;
    pts.push([20 + x * 240, 110 - e * 88]);
  }
  const linePath = "M " + pts.map(p => p.join(",")).join(" L ");
  const areaPath = linePath + ` L ${pts[pts.length-1][0]},110 L ${pts[0][0]},110 Z`;
  const elevAt = (frac) => {
    const idx = Math.min(N, Math.floor(frac * N));
    return pts[idx];
  };
  // Marker on the curve at ~55% chainage (highest point)
  const [mx, my] = elevAt(0.55);

  return (
    <div className="map-elev-panel" style={{
      opacity: inP,
      transform: `translateX(${(1 - inP) * 24}px)`,
    }}>
      <div className="mep-head">
        <div>
          <div className="mep-title">Elevation Profile</div>
          <div className="mep-sub">Demo Tunnel · 750 m route</div>
        </div>
        <span className="mep-x">⛶</span>
      </div>
      <svg viewBox="0 0 280 130" style={{width: "100%", height: "auto", display: "block"}}>
        <defs>
          <linearGradient id="elevFill" x1="0" y1="0" x2="0" y2="1">
            <stop offset="0" stopColor="#3B82F6" stopOpacity="0.4"/>
            <stop offset="1" stopColor="#3B82F6" stopOpacity="0.05"/>
          </linearGradient>
        </defs>
        {/* Y-axis grid lines */}
        {[0, 1, 2, 3].map(i => (
          <line key={i} x1="20" y1={20 + i * 22} x2="270" y2={20 + i * 22} stroke="#E5E5E5" strokeWidth="0.5"/>
        ))}
        {/* Filled area */}
        <path d={areaPath} fill="url(#elevFill)"/>
        {/* Line */}
        <path d={linePath} fill="none" stroke="#3B82F6" strokeWidth="1.4"/>
        {/* Highlighted marker */}
        <line x1={mx} y1={my} x2={mx} y2="110" stroke="#1E40AF" strokeWidth="1" strokeDasharray="2 2"/>
        <circle cx={mx} cy={my} r="3.5" fill="#1E40AF" stroke="#fff" strokeWidth="1.4"/>
        {/* Axis labels */}
        <text x="20"  y="125" fontFamily="JetBrains Mono, monospace" fontSize="8" fill="#737373">0m</text>
        <text x="145" y="125" fontFamily="JetBrains Mono, monospace" fontSize="8" fill="#737373" textAnchor="middle">375m</text>
        <text x="270" y="125" fontFamily="JetBrains Mono, monospace" fontSize="8" fill="#737373" textAnchor="end">750m</text>
        <text x="14"  y="22"  fontFamily="JetBrains Mono, monospace" fontSize="8" fill="#737373" textAnchor="end">180m</text>
        <text x="14"  y="110" fontFamily="JetBrains Mono, monospace" fontSize="8" fill="#737373" textAnchor="end">90m</text>
      </svg>
      <div className="mep-foot">
        <div><span>MAX</span><b>178 m</b></div>
        <div><span>MIN</span><b>92 m</b></div>
        <div><span>Δ</span><b>+86 m</b></div>
      </div>
    </div>
  );
}

// -------- Street View panel (small road photo on the right)
function MapStreetViewPanel({ t }) {
  const inP = Math.max(0, Math.min(1, (t - 4.0) / 0.5));
  if (inP <= 0) return null;
  return (
    <div className="map-streetview-panel" style={{
      opacity: inP,
      transform: `translateX(${(1 - inP) * 24}px)`,
    }}>
      <div className="msv-head">
        <span className="msv-pin">📷</span>
        <span className="msv-title">Street View</span>
        <span className="msv-coords">53.0091°N, -2.0173°W</span>
        <span className="msv-x">✕</span>
      </div>
      <div className="msv-photo">
        {/* Sky */}
        <div className="msv-sky"></div>
        {/* Trees on left */}
        <div className="msv-tree msv-tree-l"></div>
        <div className="msv-tree msv-tree-l2"></div>
        {/* Hedge on right */}
        <div className="msv-hedge"></div>
        {/* Road */}
        <div className="msv-road"></div>
        <div className="msv-road-line"></div>
        {/* Vignette */}
        <div className="msv-overlay"></div>
        {/* Compass + chainage tag */}
        <div className="msv-compass">↑ N</div>
        <div className="msv-tag">ch 412.6</div>
      </div>
    </div>
  );
}

// -------- Stage: Overview dashboard (defect summary + heatmap)
function StageOverview({ t }) {
  // local time inside overview stage
  const local = Math.max(0, t - TIMELINE.showOverview[0]);
  return (
    <div className="stage-overview">
      {/* Asset header */}
      <div className="ov-asset-header">
        <div className="ov-asset-row">
          <h3>Review Results</h3>
        </div>
        <div className="ov-sub">Inspection analysis and defect identification</div>

        <div className="ov-asset-card">
          <div className="ov-asset-title-row">
            <span className="ov-asset-name">Demo Tunnel</span>
            <span className="ov-pill ov-pill-tunnel">TUNNEL</span>
            <span className="ov-asset-id">Asset ID: a9c2f1ae-e5ef-4683-b585-fe17192c6b51</span>
          </div>
          <div className="ov-asset-meta">
            <span><b>Data collected:</b> Jan 1, 2025</span>
            <span><b>Defect types:</b> 3</span>
            <span><b>Length analysed:</b> 750 m</span>
          </div>
          <div className="ov-asset-tags">
            <span className="ov-tag ov-tag-green">Data quality score: <b>9.6 / 10</b></span>
            <span className="ov-tag ov-tag-blue">AI analysis coverage %: <b>100.0%</b></span>
          </div>
        </div>
      </div>

      {/* Defect summary */}
      <div className="ov-section">
        <div className="ov-section-head">
          <div>
            <h4>Defect Summary</h4>
            <div className="ov-section-sub">Computed from the defects currently loaded for this asset</div>
          </div>
          <div className="ov-section-totals">
            <span className="ov-mega-num">{fmtN(Math.floor(11263 * Math.min(1, local / 0.7)))}</span>
            <span className="ov-mega-label">Total Defects</span>
            <span className="ov-mega-pill">5.3% Critical Priority</span>
          </div>
        </div>

        <div className="ov-defect-grid">
          <DefectCategory name="Spalling" sub="Surface damage" total={5616} critical={188} high={1250} medium={2181} low={1997} delay={0.15} local={local}/>
          <DefectCategory name="Mortar loss" sub="Joint deterioration" total={5188} critical={386} high={839} medium={1477} low={2486} delay={0.30} local={local}/>
          <DefectCategory name="Fracture" sub="Structural cracking" total={459} critical={18} high={96} medium={198} low={147} delay={0.45} local={local}/>
        </div>
      </div>

      {/* Spatial distribution */}
      <div className="ov-section">
        <div className="ov-section-head">
          <div>
            <h4>Spatial Distribution</h4>
            <div className="ov-section-sub">Live spatial distribution of the loaded defects across tunnel sections and chainage positions</div>
          </div>
        </div>
        <HeatmapStrip local={local}/>
      </div>

      {/* Statistical analysis (depth distribution + by-chainage stacks) */}
      <StatisticalAnalysis local={local} delay={1.4}/>
    </div>
  );
}

function DefectCategory({ name, sub, total, critical, high, medium, low, delay, local }) {
  const p = Math.max(0, Math.min(1, (local - delay) / 0.7));
  const totalPct = critical + high + medium + low;
  const widths = totalPct ? {
    crit: (critical / totalPct) * 100,
    high: (high / totalPct) * 100,
    med:  (medium / totalPct) * 100,
    low:  (low / totalPct) * 100,
  } : {crit: 100, high: 0, med: 0, low: 0};

  return (
    <div className="ov-cat" style={{opacity: p, transform: `translateY(${(1 - p) * 10}px)`}}>
      <div className="ov-cat-head">
        <div>
          <div className="ov-cat-name">{name}</div>
          <div className="ov-cat-sub">{sub}</div>
        </div>
        <div className="ov-cat-total">
          <div className="ov-cat-total-num">{fmtN(Math.floor(total * p))}</div>
          <div className="ov-cat-total-lbl">Total Defects</div>
        </div>
      </div>
      <div className="ov-cat-rows">
        <SevRow color="var(--sev-critical)" name="Critical" range=">=75mm" count={Math.floor(critical * p)} pct={widths.crit}/>
        <SevRow color="var(--sev-high)"     name="High"     range="35-75mm" count={Math.floor(high * p)}     pct={widths.high}/>
        <SevRow color="var(--sev-medium)"   name="Medium"   range="10-35mm" count={Math.floor(medium * p)}   pct={widths.med}/>
        <SevRow color="var(--ink-400)"      name="Low"      range="<10mm"   count={Math.floor(low * p)}      pct={widths.low}/>
      </div>
    </div>
  );
}

function SevRow({ color, name, range, count, pct }) {
  return (
    <div className="sev-row">
      <div className="sev-row-label">
        <span className="sev-dot" style={{background: color}}></span>
        <span className="sev-name">{name}</span>
        <span className="sev-range">{range}</span>
      </div>
      <div className="sev-row-bar">
        <div className="sev-row-fill" style={{width: `${pct}%`, background: color}}></div>
      </div>
      <div className="sev-row-count">{fmtN(count)}</div>
    </div>
  );
}

function HeatmapStrip({ local }) {
  // 5 rows × 32 cols, deterministic red intensity per cell
  const rows = ["Left Wall", "Left Haunch", "Crown", "Right Haunch", "Right Wall"];
  const cols = 32;
  const cells = [];
  let s = 7;
  const r = () => { s = (s * 9301 + 49297) % 233280; return s / 233280; };
  // intensity pattern that has hot spots
  for (let row = 0; row < rows.length; row++) {
    for (let col = 0; col < cols; col++) {
      const phase = (col / cols) * Math.PI * 2;
      let v = 0.18 + Math.sin(phase + row * 0.7) * 0.18 + r() * 0.3;
      // hot zone toward the right (later chainage)
      if (col > 22) v += 0.25;
      if (col > 27) v += 0.15;
      v = Math.max(0, Math.min(1, v));
      cells.push(v);
    }
  }

  // Cells reveal sequentially
  const reveal = Math.min(1, Math.max(0, (local - 0.4) / 1.6));
  const revealedCount = Math.floor(reveal * cells.length);

  return (
    <div className="heatmap">
      <div className="heatmap-rows">
        {rows.map((label, i) => (
          <div className="heatmap-row" key={label}>
            <div className="heatmap-label">{label}</div>
            <div className="heatmap-cells">
              {Array.from({length: cols}, (_, c) => {
                const idx = i * cols + c;
                const v = cells[idx];
                const visible = idx < revealedCount;
                const opacity = visible ? Math.max(0.06, v) : 0;
                return (
                  <div key={c} className="heatmap-cell" style={{
                    background: `rgba(220, 38, 38, ${opacity})`,
                    transition: "background 200ms",
                  }}></div>
                );
              })}
            </div>
          </div>
        ))}
      </div>
      <div className="heatmap-axis">
        <span>0m</span><span>180m</span><span>350m</span><span>520m</span><span>670m</span><span>760m</span>
      </div>
    </div>
  );
}

// -------- Stage: Bill of Quantities modal
function StageBom({ t }) {
  const local = Math.max(0, t - TIMELINE.showBom[0]);
  const inP = Math.min(1, local / 0.5);

  return (
    <div className="stage-bom" style={{opacity: inP}}>
      <div className="bom-backdrop"></div>
      <div className="bom-panel" style={{transform: `translateY(${(1 - inP) * 20}px)`}}>
        <div className="bom-head">
          <div>
            <h4>Bill of Quantities</h4>
            <div className="bom-sub">Source: Test — Selected Defects · 575 contributing defects · 5 line items</div>
          </div>
          <div className="bom-totals">
            <div className="bom-total-num">53.9091 m²</div>
            <div className="bom-total-lbl">Total Quantity</div>
          </div>
          <button className="bom-close">×</button>
        </div>

        <div className="bom-controls">
          <BomCtl label="GROUP BY" value="Location" active/>
          <BomCtl label="MEASURE"  value="Area" active/>
          <span className="bom-pill">Volume</span>
          <span className="bom-pill">Length</span>
          <BomCtl label="UNIT" value="m²" active/>
          <BomCtl label="AGG"  value="Sum" active/>
          <span className="bom-pill">Average</span>
          <span className="bom-pill" style={{marginLeft: "auto"}}>↻ Refresh</span>
          <button className="bom-export">↓ Export ▾</button>
        </div>

        <div className="bom-table">
          <div className="bom-row bom-row-head">
            <span>CODE ↑</span><span>LOCATION</span><span>DESCRIPTION</span><span>MEASUREMENT</span><span>UNIT</span><span>QUANTITY</span><span>COUNT</span><span>ACTIONS</span>
          </div>
          {[
            { code: "CROWN",        loc: "Crown",        desc: "Crown",        qty: "7.3764",  count: 193, items: 1 },
            { code: "RIGHT HAUNCH", loc: "Right Haunch", desc: "Right Haunch", qty: "16.6365", count: 157, items: 1 },
            { code: "LEFT HAUNCH",  loc: "Left Haunch",  desc: "Left Haunch",  qty: "8.1208",  count: 93,  items: 1 },
            { code: "RIGHT WALL",   loc: "Right Wall",   desc: "Right Wall",   qty: "4.1913",  count: 78,  items: 1 },
            { code: "LEFT WALL",    loc: "Left Wall",    desc: "Left Wall",    qty: "17.5842", count: 54,  items: 1 },
          ].map((r, i) => {
            const visible = Math.min(1, Math.max(0, (local - 0.6 - i * 0.12) / 0.3));
            return (
              <React.Fragment key={i}>
                <div className="bom-row bom-row-group" style={{opacity: visible, transform: `translateX(${(1 - visible) * 12}px)`}}>
                  <span className="bom-chev">▾</span>
                  <span className="bom-code">{r.code}</span>
                  <span className="bom-items">{r.items} item</span>
                </div>
                <div className="bom-row bom-row-item" style={{opacity: visible, transform: `translateX(${(1 - visible) * 12}px)`}}>
                  <span></span>
                  <span>{r.loc}</span>
                  <span>{r.desc}</span>
                  <span>Area</span>
                  <span>m²</span>
                  <span className="bom-qty">{r.qty}</span>
                  <span className="bom-count">{r.count}</span>
                  <span className="bom-act">✎ 👁</span>
                </div>
              </React.Fragment>
            );
          })}
        </div>

        <div className="bom-foot">
          <span>575 total defects across 5 items</span>
          <div>
            <span className="bom-grand-label">Grand Total</span>
            <span className="bom-grand-num">53.9091 m²</span>
          </div>
        </div>
      </div>
    </div>
  );
}

function BomCtl({ label, value, active }) {
  return (
    <div className="bom-ctl">
      <span className="bom-ctl-lbl">{label}</span>
      <span className={`bom-pill ${active ? "active" : ""}`}>{value} ▾</span>
    </div>
  );
}

// -------- Click cursor overlay
function ClickCursor({ t }) {
  // Click choreography:
  //  - 1.5–3.5s  glide to asset marker (map)        click ≈ 2.6
  //  - 8.8–9.8s  glide to "List View" tab            click ≈ 9.6
  //  - 14.6–15.6s glide to "3D View" tab             click ≈ 15.6
  //  - 20.6–21.8s glide to Generate button (list)    click ≈ 21.6
  let pos = null;
  let clicking = false;

  if (t > 4.1 && t < 5.6) {
    const tt = clampCursor((t - 4.1) / 1.1);
    const startX = 70, startY = 70;
    const endX = 50, endY = 60;        // asset marker, in frame coords
    pos = { x: lerp(startX, endX, tt), y: lerp(startY, endY, tt), unit: "%" };
    clicking = t > 5.1 && t < 5.4;
  } else if (t > 10.7 && t < 11.9) {
    // Up to the "List View" tab in the top tab strip
    const tt = clampCursor((t - 10.7) / 1.0);
    const startX = 55, startY = 55;
    const endX = 78, endY = 4;          // "List View" tab in the title bar
    pos = { x: lerp(startX, endX, tt), y: lerp(startY, endY, tt), unit: "%" };
    clicking = t > 11.55 && t < 11.8;
  } else if (t > 17.6 && t < 18.8) {
    // Up to the "3D View" tab
    const tt = clampCursor((t - 17.6) / 1.0);
    const startX = 55, startY = 55;
    const endX = 85, endY = 4;          // "3D View" tab in the title bar
    pos = { x: lerp(startX, endX, tt), y: lerp(startY, endY, tt), unit: "%" };
    clicking = t > 18.55 && t < 18.8;
  } else if (t > 24.6 && t < 26.0) {
    // Down to the Generate button on the list view (visible during 3D too via shared header logic? actually Generate lives in list — we click on 3D, but BoQ opens regardless)
    const tt = clampCursor((t - 24.6) / 1.0);
    const startX = 50, startY = 50;
    const endX = 93, endY = 23;         // Generate button — top-right of list/3D canvas, in frame coords
    pos = { x: lerp(startX, endX, tt), y: lerp(startY, endY, tt), unit: "%" };
    clicking = t > 25.55 && t < 25.8;
  }

  if (!pos) return null;

  return (
    <div className="click-cursor" style={{left: pos.x + pos.unit, top: pos.y + pos.unit}}>
      <svg width="22" height="22" viewBox="0 0 22 22">
        <path d="M3 2 L3 17 L7 13 L11 21 L14 19 L10 11 L17 11 Z" fill="#0A0A0A" stroke="#FFFFFF" strokeWidth="1.2" strokeLinejoin="round"/>
      </svg>
      {clicking && <div className="click-ripple"></div>}
    </div>
  );
}

const clampCursor = (v) => Math.max(0, Math.min(1, v));
const lerp = (a, b, t) => a + (b - a) * t;

const fmtN = (n) => n.toLocaleString("en-GB");

Object.assign(window, { ProductMockup });
