/* wow-effects.jsx — AI visualization + interactive components for kiosk
 * Components: ParticleField, NeuralNet, BodyMap, VisionFeed, RPPGGraph,
 *             ReasoningChain, PatientsLikeYou, VoiceWaveform
 */

// ─────────────────────────────────────────────────────────────
// PARTICLE FIELD — gentle floating dots behind hero (welcome aura)
// ─────────────────────────────────────────────────────────────
function ParticleField({ count = 40, color = '#6FC3C4', opacity = 0.5 }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const c = ref.current; if (!c) return;
    const ctx = c.getContext('2d');
    const W = c.width = c.offsetWidth * 2;
    const H = c.height = c.offsetHeight * 2;
    ctx.scale(2, 2);
    const w = c.offsetWidth, h = c.offsetHeight;
    const pts = Array.from({ length: count }, () => ({
      x: Math.random() * w, y: Math.random() * h,
      vx: (Math.random() - 0.5) * 0.3,
      vy: (Math.random() - 0.5) * 0.3,
      r: 1 + Math.random() * 3,
      a: 0.3 + Math.random() * 0.6,
    }));
    let raf;
    const tick = () => {
      ctx.clearRect(0, 0, w, h);
      pts.forEach(p => {
        p.x += p.vx; p.y += p.vy;
        if (p.x < 0 || p.x > w) p.vx *= -1;
        if (p.y < 0 || p.y > h) p.vy *= -1;
        ctx.beginPath();
        ctx.arc(p.x, p.y, p.r, 0, Math.PI * 2);
        ctx.fillStyle = color;
        ctx.globalAlpha = p.a * opacity;
        ctx.fill();
      });
      // connections
      ctx.globalAlpha = 0.15 * opacity;
      ctx.strokeStyle = color;
      ctx.lineWidth = 1;
      for (let i = 0; i < pts.length; i++) {
        for (let j = i + 1; j < pts.length; j++) {
          const dx = pts[i].x - pts[j].x, dy = pts[i].y - pts[j].y;
          const d2 = dx * dx + dy * dy;
          if (d2 < 110 * 110) {
            ctx.beginPath();
            ctx.moveTo(pts[i].x, pts[i].y);
            ctx.lineTo(pts[j].x, pts[j].y);
            ctx.stroke();
          }
        }
      }
      raf = requestAnimationFrame(tick);
    };
    tick();
    return () => cancelAnimationFrame(raf);
  }, [count, color, opacity]);
  return <canvas ref={ref} style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}/>;
}

// ─────────────────────────────────────────────────────────────
// NEURAL NET — animated multi-layer net during AI thinking
// ─────────────────────────────────────────────────────────────
function NeuralNet({ width = 720, height = 320, layers = [4, 6, 6, 4, 3], speed = 1 }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const c = ref.current; if (!c) return;
    const ctx = c.getContext('2d');
    const dpr = 2;
    c.width = width * dpr; c.height = height * dpr;
    ctx.scale(dpr, dpr);

    // build node positions
    const nodes = [];
    layers.forEach((n, li) => {
      const lx = ((li + 1) / (layers.length + 1)) * width;
      for (let i = 0; i < n; i++) {
        const ly = ((i + 1) / (n + 1)) * height;
        nodes.push({ x: lx, y: ly, layer: li, idx: i, activation: 0 });
      }
    });
    // edges
    const edges = [];
    for (let li = 0; li < layers.length - 1; li++) {
      const from = nodes.filter(n => n.layer === li);
      const to = nodes.filter(n => n.layer === li + 1);
      from.forEach(a => to.forEach(b => {
        edges.push({ a, b, w: Math.random() * 2 - 1, pulse: Math.random() });
      }));
    }

    let t0 = performance.now();
    let raf;
    const tick = () => {
      const t = (performance.now() - t0) / 1000 * speed;
      ctx.clearRect(0, 0, width, height);

      // edges
      edges.forEach(e => {
        const phase = (t * 0.7 + e.pulse) % 1;
        const px = e.a.x + (e.b.x - e.a.x) * phase;
        const py = e.a.y + (e.b.y - e.a.y) * phase;
        // base line
        ctx.strokeStyle = `rgba(111,195,196,${0.18 + Math.abs(e.w) * 0.12})`;
        ctx.lineWidth = 1;
        ctx.beginPath(); ctx.moveTo(e.a.x, e.a.y); ctx.lineTo(e.b.x, e.b.y); ctx.stroke();
        // glow pulse traveling
        const grd = ctx.createRadialGradient(px, py, 0, px, py, 14);
        grd.addColorStop(0, `rgba(47,82,82,0.85)`);
        grd.addColorStop(1, `rgba(47,82,82,0)`);
        ctx.fillStyle = grd;
        ctx.beginPath(); ctx.arc(px, py, 14, 0, Math.PI * 2); ctx.fill();
        // brighten target node
        e.b.activation = Math.max(e.b.activation, 1 - Math.abs(phase - 0.95) * 6);
      });

      // nodes
      nodes.forEach(n => {
        const a = Math.max(0, Math.min(1, n.activation));
        const r = 8 + a * 4;
        // halo
        if (a > 0.1) {
          ctx.fillStyle = `rgba(251,115,92,${a * 0.45})`;
          ctx.beginPath(); ctx.arc(n.x, n.y, r + 8, 0, Math.PI * 2); ctx.fill();
        }
        ctx.fillStyle = a > 0.4 ? '#FB735C' : '#2F5252';
        ctx.beginPath(); ctx.arc(n.x, n.y, r, 0, Math.PI * 2); ctx.fill();
        ctx.fillStyle = '#fff';
        ctx.beginPath(); ctx.arc(n.x - r * 0.3, n.y - r * 0.3, r * 0.3, 0, Math.PI * 2); ctx.fill();

        n.activation *= 0.93;
      });

      // layer labels
      ctx.fillStyle = 'rgba(123,154,156,.7)';
      ctx.font = "500 11px Anuphan, system-ui";
      ctx.textAlign = 'center';
      const labels = ['INPUT', 'EMBED', 'ATTENTION', 'CLASSIFY', 'OUTPUT'];
      layers.forEach((n, li) => {
        const lx = ((li + 1) / (layers.length + 1)) * width;
        ctx.fillText(labels[li] || `L${li}`, lx, height - 6);
      });

      raf = requestAnimationFrame(tick);
    };
    tick();
    return () => cancelAnimationFrame(raf);
  }, [width, height, JSON.stringify(layers), speed]);
  return <canvas ref={ref} style={{ width, height, display: 'block' }}/>;
}

// ─────────────────────────────────────────────────────────────
// BODY MAP — interactive human silhouette, tap to mark pain
// ─────────────────────────────────────────────────────────────
const BODY_REGIONS = [
  { id: 'head',     label: { th: 'ศีรษะ',         en: 'Head' },        cx: 250, cy: 80,  r: 36 },
  { id: 'throat',   label: { th: 'คอ/ลำคอ',       en: 'Throat/Neck' }, cx: 250, cy: 138, r: 22 },
  { id: 'chest',    label: { th: 'หน้าอก',         en: 'Chest' },       cx: 250, cy: 195, r: 38 },
  { id: 'shoulderL',label: { th: 'ไหล่ซ้าย',      en: 'Left shoulder' },cx: 192, cy: 178, r: 26 },
  { id: 'shoulderR',label: { th: 'ไหล่ขวา',       en: 'Right shoulder' },cx: 308, cy: 178, r: 26 },
  { id: 'abdomen',  label: { th: 'ท้อง',          en: 'Abdomen' },     cx: 250, cy: 268, r: 38 },
  { id: 'backL',    label: { th: 'หลังส่วนล่าง',   en: 'Lower back' },  cx: 250, cy: 320, r: 30 },
  { id: 'armL',     label: { th: 'แขนซ้าย',       en: 'Left arm' },    cx: 168, cy: 256, r: 22 },
  { id: 'armR',     label: { th: 'แขนขวา',        en: 'Right arm' },   cx: 332, cy: 256, r: 22 },
  { id: 'hipL',     label: { th: 'สะโพก/ขาซ้าย',  en: 'Left hip/leg' },cx: 222, cy: 360, r: 24 },
  { id: 'hipR',     label: { th: 'สะโพก/ขาขวา',   en: 'Right hip/leg' },cx: 278, cy: 360, r: 24 },
  { id: 'kneeL',    label: { th: 'เข่าซ้าย',       en: 'Left knee' },   cx: 220, cy: 460, r: 22 },
  { id: 'kneeR',    label: { th: 'เข่าขวา',        en: 'Right knee' },  cx: 280, cy: 460, r: 22 },
];

function getBodyLabel(r, lang) {
  if (!r || !r.label) return '';
  if (typeof r.label === 'string') return r.label;
  return r.label[lang] || r.label.th || r.label.en || '';
}

function BodyMap({ selected = [], onToggle, intensity = {}, view = 'front', lang = 'th' }) {
  return (
    <svg viewBox="0 0 500 580" style={{ width: '100%', maxWidth: 460, height: 'auto', display: 'block' }}>
      <defs>
        <radialGradient id="bm-skin" cx="50%" cy="35%">
          <stop offset="0%" stopColor="#FBE3CB"/>
          <stop offset="100%" stopColor="#E0BFA4"/>
        </radialGradient>
        <radialGradient id="bm-pain" cx="50%" cy="50%">
          <stop offset="0%" stopColor="#FB735C" stopOpacity="0.85"/>
          <stop offset="60%" stopColor="#FB735C" stopOpacity="0.35"/>
          <stop offset="100%" stopColor="#FB735C" stopOpacity="0"/>
        </radialGradient>
      </defs>

      {/* Body silhouette (front) */}
      <g fill="url(#bm-skin)" stroke="#4F8A8B" strokeWidth="1.5" strokeLinejoin="round">
        {/* head */}
        <ellipse cx="250" cy="80" rx="38" ry="44"/>
        {/* neck */}
        <rect x="232" y="118" width="36" height="22" rx="6"/>
        {/* torso */}
        <path d="M195,150 Q170,154 168,180 L162,260 Q160,300 178,330 L172,400 Q186,408 218,408 L218,470 Q220,560 230,572 L270,572 Q280,560 282,470 L282,408 Q314,408 328,400 L322,330 Q340,300 338,260 L332,180 Q330,154 305,150 Z"/>
        {/* arms */}
        <path d="M168,180 Q146,200 144,240 L150,310 Q156,338 168,348 L184,344 Q174,318 172,290 L178,238 Q186,206 195,196 Z"/>
        <path d="M332,180 Q354,200 356,240 L350,310 Q344,338 332,348 L316,344 Q326,318 328,290 L322,238 Q314,206 305,196 Z"/>
        {/* legs already in torso path bottom */}
      </g>

      {/* Region hit zones + heatmap */}
      {BODY_REGIONS.map(r => {
        const isSel = selected.includes(r.id);
        const lvl = intensity[r.id] || (isSel ? 0.7 : 0);
        return (
          <g key={r.id}
             onClick={() => onToggle && onToggle(r.id)}
             style={{ cursor: 'pointer' }}>
            {/* Heat halo */}
            {lvl > 0 && (
              <circle cx={r.cx} cy={r.cy} r={r.r + 14} fill="url(#bm-pain)" opacity={lvl}>
                <animate attributeName="r" values={`${r.r + 10};${r.r + 22};${r.r + 10}`} dur="2s" repeatCount="indefinite"/>
              </circle>
            )}
            {/* Hit zone */}
            <circle cx={r.cx} cy={r.cy} r={r.r}
                    fill={isSel ? '#FB735C' : 'rgba(255,255,255,0)'}
                    fillOpacity={isSel ? 0.25 : 0}
                    stroke={isSel ? '#FB735C' : 'rgba(47,82,82,0.18)'}
                    strokeWidth={isSel ? 2.5 : 1.5}
                    strokeDasharray={isSel ? '0' : '4 4'}/>
            {isSel && (
              <text x={r.cx} y={r.cy + 4} textAnchor="middle"
                    fontFamily="Anuphan" fontWeight="600" fontSize="13" fill="#fff"
                    stroke="#0F2A2C" strokeWidth="0.5" paintOrder="stroke">
                {getBodyLabel(r, lang)}
              </text>
            )}
          </g>
        );
      })}
    </svg>
  );
}

// ─────────────────────────────────────────────────────────────
// VISION FEED — fake camera feed with face tracking overlay
// ─────────────────────────────────────────────────────────────
function VisionFeed({ active = true, hr = 78 }) {
  const [t, setT] = React.useState(0);
  React.useEffect(() => {
    if (!active) return;
    const id = setInterval(() => setT(x => x + 1), 80);
    return () => clearInterval(id);
  }, [active]);
  const blink = (t * 80) / 1000 % 4 < 0.18;
  return (
    <div style={{
      position: 'relative', width: '100%', aspectRatio: '4/5',
      borderRadius: 24, overflow: 'hidden',
      background: `radial-gradient(ellipse at 50% 35%, #4a5d6e 0%, #1f2c36 70%, #0c1419 100%)`,
      border: '2px solid #2F5252',
      boxShadow: 'inset 0 0 60px rgba(0,0,0,.5)',
    }}>
      {/* Fake person silhouette */}
      <svg viewBox="0 0 400 500" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%', opacity: 0.55 }}>
        <defs>
          <radialGradient id="vf-face" cx="50%" cy="40%">
            <stop offset="0%" stopColor="#d8b8a0" stopOpacity="0.7"/>
            <stop offset="100%" stopColor="#1f2c36" stopOpacity="0"/>
          </radialGradient>
        </defs>
        <ellipse cx="200" cy="200" rx="105" ry="125" fill="url(#vf-face)"/>
        {/* shoulders */}
        <path d="M50,500 Q90,360 200,340 Q310,360 350,500 Z" fill="rgba(80,100,120,.4)"/>
        {/* eyes */}
        {!blink && (<>
          <ellipse cx="170" cy="190" rx="6" ry="3" fill="rgba(0,0,0,.5)"/>
          <ellipse cx="230" cy="190" rx="6" ry="3" fill="rgba(0,0,0,.5)"/>
        </>)}
        {blink && (<>
          <line x1="162" y1="190" x2="178" y2="190" stroke="rgba(0,0,0,.5)" strokeWidth="2"/>
          <line x1="222" y1="190" x2="238" y2="190" stroke="rgba(0,0,0,.5)" strokeWidth="2"/>
        </>)}
        {/* mouth */}
        <path d="M180,260 Q200,266 220,260" stroke="rgba(0,0,0,.4)" strokeWidth="2" fill="none"/>
      </svg>

      {/* Face detection bracket */}
      {active && (
        <svg viewBox="0 0 400 500" style={{ position: 'absolute', inset: 0, width: '100%', height: '100%' }}>
          {/* Corners around face */}
          {[
            [80, 80, 1, 1],   [320, 80, -1, 1],
            [80, 320, 1, -1], [320, 320, -1, -1],
          ].map(([x, y, dx, dy], i) => (
            <g key={i} stroke="#6FC3C4" strokeWidth="3" fill="none">
              <line x1={x} y1={y} x2={x + 26 * dx} y2={y}/>
              <line x1={x} y1={y} x2={x} y2={y + 26 * dy}/>
            </g>
          ))}
          {/* Forehead ROI (rPPG sample box) */}
          <rect x="160" y="125" width="80" height="32" fill="none" stroke="#FB735C" strokeWidth="2" strokeDasharray="4 4">
            <animate attributeName="stroke-opacity" values="0.4;1;0.4" dur="1.2s" repeatCount="indefinite"/>
          </rect>
          <text x="200" y="118" textAnchor="middle" fill="#FB735C" fontFamily="Anuphan" fontSize="12" fontWeight="600">rPPG ROI</text>
          {/* Tracked landmarks */}
          {[
            [170, 190], [230, 190], [200, 220], [200, 245], [180, 260], [220, 260],
            [150, 200], [250, 200], [200, 165], [200, 280],
          ].map(([x, y], i) => (
            <circle key={i} cx={x} cy={y} r="2.5" fill="#6FC3C4" opacity="0.9"/>
          ))}
        </svg>
      )}

      {/* HUD */}
      <div className="font-semibold leading-none text-base" style={{
        position: 'absolute', top: 14, left: 14, right: 14,
        display: 'flex', justifyContent: 'space-between',
        color: '#6FC3C4',
        textShadow: '0 1px 2px rgba(0,0,0,.6)',
      }}>
        <span style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
          <span style={{ width: 8, height: 8, borderRadius: '50%', background: '#FB735C', animation: 'kiosk-pulse 1s infinite' }}/>
          REC · 1080p · 60fps
        </span>
        <span>FACE LOCKED · 98%</span>
      </div>
      <div className="font-semibold leading-none text-base" style={{
        position: 'absolute', bottom: 14, left: 14, right: 14,
        display: 'flex', justifyContent: 'space-between',
        color: '#6FC3C4',
        textShadow: '0 1px 2px rgba(0,0,0,.6)',
      }}>
        <span>rPPG MODEL · DeepHR-v3</span>
        <span style={{ color: '#FB735C' }}>♥ {hr} bpm</span>
      </div>

      {/* Scan sweep */}
      <div style={{
        position: 'absolute', left: 0, right: 0, height: 3,
        background: 'linear-gradient(90deg, transparent, #6FC3C4, transparent)',
        boxShadow: '0 0 12px #6FC3C4',
        animation: 'kiosk-vscan 2.4s linear infinite',
      }}/>
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// RPPG GRAPH — live pulse waveform extracted from skin tone
// ─────────────────────────────────────────────────────────────
function RPPGGraph({ width = 720, height = 140, hr = 78 }) {
  const ref = React.useRef(null);
  React.useEffect(() => {
    const c = ref.current; if (!c) return;
    const ctx = c.getContext('2d');
    const dpr = 2;
    c.width = width * dpr; c.height = height * dpr;
    ctx.scale(dpr, dpr);

    let t0 = performance.now();
    let raf;
    const tick = () => {
      const t = (performance.now() - t0) / 1000;
      ctx.clearRect(0, 0, width, height);
      // grid
      ctx.strokeStyle = 'rgba(111,195,196,.18)';
      ctx.lineWidth = 1;
      for (let x = 0; x < width; x += 30) {
        ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x, height); ctx.stroke();
      }
      for (let y = 0; y < height; y += 28) {
        ctx.beginPath(); ctx.moveTo(0, y); ctx.lineTo(width, y); ctx.stroke();
      }
      // Pulse waveform — sum of sines, sharper peak per beat
      const f = hr / 60; // beats/sec
      ctx.beginPath();
      ctx.strokeStyle = '#FB735C';
      ctx.lineWidth = 2.5;
      ctx.shadowColor = '#FB735C';
      ctx.shadowBlur = 8;
      for (let x = 0; x < width; x++) {
        const phase = (x / width) * 6 * Math.PI - t * f * 2 * Math.PI;
        // sharp peak: gaussian on each beat
        const p = ((phase / Math.PI / 2) % 1 + 1) % 1;
        let y = 0;
        const peak = Math.exp(-Math.pow((p - 0.15) * 14, 2)) * 1.0;
        const dicrotic = Math.exp(-Math.pow((p - 0.45) * 22, 2)) * 0.35;
        y = peak + dicrotic + Math.sin(t * 6 + x * 0.05) * 0.04;
        const py = height / 2 - y * height * 0.32;
        if (x === 0) ctx.moveTo(x, py); else ctx.lineTo(x, py);
      }
      ctx.stroke();
      ctx.shadowBlur = 0;
      raf = requestAnimationFrame(tick);
    };
    tick();
    return () => cancelAnimationFrame(raf);
  }, [width, height, hr]);
  return <canvas ref={ref} style={{ width, height, display: 'block', borderRadius: 12 }}/>;
}

// ─────────────────────────────────────────────────────────────
// VOICE WAVEFORM — animated bars (fake mic visualization)
// ─────────────────────────────────────────────────────────────
function VoiceWaveform({ active = false, bars = 24, color = '#2F5252' }) {
  const [t, setT] = React.useState(0);
  React.useEffect(() => {
    if (!active) return;
    const id = setInterval(() => setT(x => x + 1), 80);
    return () => clearInterval(id);
  }, [active]);
  return (
    <div style={{ display: 'flex', alignItems: 'center', gap: 4, height: 40 }}>
      {Array.from({ length: bars }).map((_, i) => {
        const phase = t * 0.4 + i * 0.5;
        const h = active ? 6 + Math.abs(Math.sin(phase) * Math.cos(phase * 0.7)) * 32 : 6;
        return (
          <div key={i} style={{
            width: 4, height: h, borderRadius: 4,
            background: color, opacity: active ? 0.8 : 0.3,
            transition: 'height .12s',
          }}/>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// REASONING CHAIN — typed-out reasoning steps with arrows
// ─────────────────────────────────────────────────────────────
function ReasoningChain({ chain, autoStart = true }) {
  const [i, setI] = React.useState(autoStart ? 0 : -1);
  React.useEffect(() => {
    if (!autoStart) return;
    if (i >= chain.length) return;
    const t = setTimeout(() => setI(i + 1), 600 + (chain[i]?.text?.length || 30) * 18);
    return () => clearTimeout(t);
  }, [i, chain.length]);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      {chain.map((step, idx) => {
        const visible = idx < i;
        const typing = idx === i - 1;
        return (
          <div key={idx} style={{
            display: 'flex', alignItems: 'flex-start', gap: 14,
            opacity: visible ? 1 : 0,
            transform: visible ? 'translateY(0)' : 'translateY(8px)',
            transition: 'all .35s',
          }}>
            <div className="font-bold leading-none text-base" style={{
              width: 32, height: 32, borderRadius: 10, flexShrink: 0,
              background: step.tone === 'finding' ? '#FFE6E0'
                        : step.tone === 'inference' ? '#D2ECED'
                        : step.tone === 'conclusion' ? '#2F5252' : '#F1F9F9',
              color: step.tone === 'conclusion' ? '#fff' : '#2F5252',
              display: 'flex', alignItems: 'center', justifyContent: 'center',
            }}>
              <i className={`ph-fill text-base ${
                step.tone === 'finding'    ? 'ph-magnifying-glass'
              : step.tone === 'inference'  ? 'ph-arrow-right'
              : step.tone === 'conclusion' ? 'ph-target'
              : 'ph-circle'}`}></i>
            </div>
            <div style={{ flex: 1 }}>
              <div className="font-medium leading-none text-base" style={{ color: '#7B9A9C', marginBottom: 4, letterSpacing: 1 }}>
                {step.tone === 'finding' ? 'OBSERVATION' :
                 step.tone === 'inference' ? 'INFERENCE' :
                 step.tone === 'conclusion' ? 'CONCLUSION' : 'STEP'}
              </div>
              <div className="font-medium leading-snug text-base sm:text-lg lg:text-xl" style={{
                color: step.tone === 'conclusion' ? '#0F2A2C' : '#2F5252',
                fontWeight: step.tone === 'conclusion' ? 700 : 500,
              }}>
                {step.text}{typing && <span style={{ display: 'inline-block', width: 8, height: 18, marginLeft: 4, background: '#2F5252', verticalAlign: 'text-top', animation: 'kiosk-blink 1s infinite' }}/>}
              </div>
              {step.evidence && (
                <div style={{ display: 'flex', gap: 6, flexWrap: 'wrap', marginTop: 8 }}>
                  {step.evidence.map((e, ei) => (
                    <span key={ei} className="font-medium leading-none text-base" style={{
                      color: '#4F8A8B',
                      background: '#F1F9F9', padding: '4px 10px', borderRadius: 999,
                      border: '1px solid #D4E6E7',
                    }}>{e}</span>
                  ))}
                </div>
              )}
            </div>
          </div>
        );
      })}
    </div>
  );
}

// ─────────────────────────────────────────────────────────────
// PATIENTS LIKE YOU — cohort similarity insight card
// ─────────────────────────────────────────────────────────────
function PatientsLikeYou({ n = 2847, outcomes = [], cohort, lang = 'th' }) {
  return (
    <div className="p-4 sm:p-5 md:p-6" style={{
      background: 'linear-gradient(135deg, #F1F9F9 0%, #fff 100%)',
      border: '1px solid #D4E6E7', borderRadius: 20,
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 12, marginBottom: 16 }}>
        <i className="ph-fill ph-users-three text-2xl" style={{ color: '#2F5252' }}></i>
        <div>
          <div className="font-semibold leading-none text-base sm:text-lg lg:text-xl" style={{ color: '#0F2A2C' }}>Patients Like You</div>
          <div className="font-normal leading-none text-base" style={{ color: '#7B9A9C', marginTop: 4 }}>
            {lang === 'en'
              ? <>From <b>{n.toLocaleString()}</b> similar cases in the MorDee database</>
              : <>จากเคสคล้ายกัน <b>{n.toLocaleString()}</b> เคส ในฐานข้อมูล MorDee</>}
          </div>
        </div>
      </div>
      {cohort && (
        <div className="grid grid-cols-1 sm:grid-cols-3 gap-2 sm:gap-3 mb-4">
          {cohort.map((c, i) => (
            <div key={i} style={{
              background: '#fff', border: '1px solid #D4E6E7',
              borderRadius: 12, padding: 12, textAlign: 'center',
            }}>
              <div className="font-bold leading-none text-lg sm:text-xl lg:text-2xl" style={{ color: '#2F5252' }}>{c.value}</div>
              <div className="font-normal leading-tight text-base" style={{ color: '#7B9A9C', marginTop: 4 }}>{c.label}</div>
            </div>
          ))}
        </div>
      )}
      {outcomes.map((o, i) => (
        <div key={i} style={{
          display: 'flex', alignItems: 'center', gap: 12,
          padding: '10px 0',
          borderTop: i > 0 ? '1px solid #E8F4F5' : 'none',
        }}>
          <div style={{ flex: 1 }}>
            <div className="font-medium leading-snug text-base sm:text-lg" style={{ color: '#0F2A2C' }}>{o.label}</div>
          </div>
          <div style={{ width: 120, height: 8, background: '#E8F4F5', borderRadius: 999, overflow: 'hidden' }}>
            <div style={{
              width: `${o.pct}%`, height: '100%',
              background: o.tone === 'good' ? '#28A338' : o.tone === 'warn' ? '#FB735C' : '#2F5252',
              borderRadius: 999,
            }}/>
          </div>
          <div className="font-bold leading-none text-base sm:text-lg" style={{ color: '#0F2A2C', minWidth: 48, textAlign: 'right' }}>{o.pct}%</div>
        </div>
      ))}
    </div>
  );
}

Object.assign(window, {
  ParticleField, NeuralNet, BodyMap, BODY_REGIONS, getBodyLabel,
  VisionFeed, RPPGGraph, VoiceWaveform,
  ReasoningChain, PatientsLikeYou,
});
