// Train your AI — interactive forecasting lab for non-AI viewers.
// Goal: a 56-year-old with no AI background can read every word at a glance.
// Rules: upright sans for everything except the big section headline.
// Big type. High contrast. Plain language.

const { useState: useTState, useEffect: useTEffect, useMemo: useTMemo, useRef: useTRef } = React;

function useMobile() {
  const [w, setW] = useTState(window.innerWidth);
  useTEffect(() => {
    const fn = () => setW(window.innerWidth);
    window.addEventListener('resize', fn);
    return () => window.removeEventListener('resize', fn);
  }, []);
  return w <= 640;
}

// ───────────────────────── Data
const PROFILES = [
  { id: 'coffee',  name: 'Coffee shop chain',  sku: 'House blend · 250g', base: 320, trendDir:  1, phase: 0.2, icon: '☕',
    blurb: 'Steady customers, more in winter, students come back from break.' },
  { id: 'apparel', name: 'Outdoor apparel',    sku: 'Wool sock · merino', base: 180, trendDir: -1, phase: 1.4, icon: '🧦',
    blurb: 'Winter spike, summer slump. Sales taper off year to year.' },
  { id: 'bike',    name: 'Bike retailer',      sku: 'Garmin Edge 540',    base: 80,  trendDir:  1, phase: 2.6, icon: '🚲',
    blurb: 'Spring and summer dominate. Cycling tech is on the rise.' },
];

const MONTHS_FULL = 14;
function buildHistory(profile, seed = 1) {
  const rnd = (n) => {
    const x = Math.sin(n * 9999 + seed * 137 + profile.phase * 13) * 43758.5;
    return x - Math.floor(x);
  };
  const out = [];
  for (let i = 0; i < MONTHS_FULL; i++) {
    const t = i / (MONTHS_FULL - 1);
    const trend = profile.trendDir * t * profile.base * 0.45;
    const phase = (i / 12) * Math.PI * 2 + profile.phase;
    const season = Math.sin(phase) * profile.base * 0.42;
    const noise = (rnd(i) - 0.5) * profile.base * 0.08;
    out.push(Math.max(0, Math.round(profile.base + trend + season + noise)));
  }
  return out;
}

function worldAIForecast(profile, history, horizon) {
  const start = history.length;
  return Array.from({ length: horizon }, (_, i) => {
    const t = (start + i) / (MONTHS_FULL - 1);
    const trend = profile.trendDir * t * profile.base * 0.45;
    const phase = ((start + i) / 12) * Math.PI * 2 + profile.phase;
    const season = Math.sin(phase) * profile.base * 0.42;
    return Math.max(0, Math.round(profile.base + trend + season));
  });
}

function coldAIForecast(history, horizon) {
  const tail = history.slice(-3);
  const avg = tail.reduce((a, b) => a + b, 0) / tail.length;
  return Array.from({ length: horizon }, () => Math.round(avg));
}

const STEPS = [
  { id: 'pick',  num: 1, label: 'Pick a business' },
  { id: 'spot',  num: 2, label: 'Spot the pattern' },
  { id: 'train', num: 3, label: 'Train the AI' },
  { id: 'race',  num: 4, label: 'You vs. the AIs' },
  { id: 'ask',   num: 5, label: 'Ask the AI' },
];

const MONTH_LABELS_14 = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec', 'Jan', 'Feb'];

// ───────────────────────── Reusable chart
function Chart({ series, height = 240, monthLabels, xCursor }) {
  const allValues = series.flatMap(s => s.data.filter(v => v != null));
  if (!allValues.length) return null;
  const max = Math.max(...allValues) * 1.12;
  const min = Math.min(0, ...allValues);
  const w = 700, h = height, padL = 40, padR = 20, padT = 18, padB = 34;
  const len = Math.max(...series.map(s => s.data.length));
  const xStep = (w - padL - padR) / (len - 1);
  const xy = (v, i) => [padL + i * xStep, h - padB - ((v - min) / (max - min)) * (h - padT - padB)];
  const pathFor = (data) => data.map((v, i) => {
    if (v == null) return null;
    const [x, y] = xy(v, i);
    return (i === 0 || data[i - 1] == null) ? `M${x},${y}` : `L${x},${y}`;
  }).filter(Boolean).join(' ');

  return (
    <svg viewBox={`0 0 ${w} ${h}`} style={{ width: '100%', height: 'auto', display: 'block' }}>
      {[0, 0.25, 0.5, 0.75, 1].map(t => (
        <line key={t} x1={padL} x2={w - padR}
          y1={h - padB - t * (h - padT - padB)} y2={h - padB - t * (h - padT - padB)}
          stroke="var(--line)" strokeDasharray="2 4" strokeWidth="1" />
      ))}
      {monthLabels && monthLabels.map((m, i) => (
        <text key={i} x={padL + i * xStep} y={h - 10} textAnchor="middle"
          style={{ fontFamily: 'var(--sans)', fontSize: 13, fill: 'var(--muted)', fontWeight: 500 }}>{m}</text>
      ))}
      {xCursor != null && (
        <line x1={padL + xCursor * xStep} x2={padL + xCursor * xStep}
          y1={padT} y2={h - padB}
          stroke="var(--accent)" strokeWidth="1.5" strokeDasharray="3 3" opacity="0.6" />
      )}
      {series.map((s, si) => (
        <g key={si} style={{ opacity: s.opacity ?? 1, transition: 'opacity 400ms' }}>
          <path d={pathFor(s.data)} fill="none" stroke={s.color}
            strokeWidth={s.thick ? 3.5 : 2.5}
            strokeDasharray={s.dashed ? '6 5' : s.dotted ? '2 4' : null}
            strokeLinecap="round" strokeLinejoin="round" />
          {s.data.map((v, i) => v != null && (
            <circle key={i} cx={xy(v, i)[0]} cy={xy(v, i)[1]} r={s.thick ? 5 : 3.2}
              fill={s.color} />
          ))}
        </g>
      ))}
    </svg>
  );
}

// ───────────────────────── Common UI bits — high contrast, no italics in body
function StepHeading({ children }) {
  return (
    <div style={{
      fontFamily: 'var(--sans)', fontWeight: 600,
      fontSize: 26, color: 'var(--text)', lineHeight: 1.2,
      letterSpacing: '-0.01em',
    }}>{children}</div>
  );
}

function StepSub({ children }) {
  return (
    <p style={{
      margin: '8px 0 0', fontSize: 17, color: 'var(--text)',
      lineHeight: 1.55, maxWidth: 820, fontWeight: 400,
    }}>{children}</p>
  );
}

function Hint({ children, tone = 'info' }) {
  const colors = {
    info: { bar: 'var(--accent)', bg: 'oklch(0.45 0.18 255 / 0.06)' },
    good: { bar: 'oklch(0.55 0.13 150)', bg: 'oklch(0.55 0.13 150 / 0.08)' },
    bad:  { bar: 'oklch(0.55 0.16 35)',  bg: 'oklch(0.55 0.16 35 / 0.08)' },
  };
  const c = colors[tone] || colors.info;
  return (
    <div style={{
      borderLeft: '4px solid ' + c.bar,
      background: c.bg,
      padding: '16px 20px', borderRadius: '0 10px 10px 0',
      fontSize: 16, color: 'var(--text)', lineHeight: 1.6,
      fontWeight: 400,
    }}>
      {children}
    </div>
  );
}

function Tag({ children, color }) {
  return (
    <div style={{
      fontFamily: 'var(--mono)', fontSize: 11, fontWeight: 600,
      color: color || 'var(--muted)',
      letterSpacing: '0.16em', textTransform: 'uppercase',
    }}>{children}</div>
  );
}

window.__trainLab = {
  PROFILES, STEPS, buildHistory, worldAIForecast, coldAIForecast,
  MONTHS_FULL, MONTH_LABELS_14,
  Chart, StepHeading, StepSub, Hint, Tag,
};


// ───────────────────────── Main slide
function TrainSlide() {
  const slideStyles = window.__slideStyles;
  const L = window.__trainLab;
  const lang = window.__useLang(); const T = window.TDATA[lang];

  const [stepIdx, setStepIdx] = useTState(0);
  const [profileIdx, setProfileIdx] = useTState(0);
  const profile = L.PROFILES[profileIdx];

  const [seed] = useTState(1);
  const fullHistory = useTMemo(() => L.buildHistory(profile, seed), [profile, seed]);
  const SHOWN = 8;
  const HORIZON = 6;
  const visibleHistory = fullHistory.slice(0, SHOWN);
  const truth = fullHistory.slice(SHOWN);

  const [spotPick, setSpotPick] = useTState(null);
  const [trainStarted, setTrainStarted] = useTState(false);
  const [trainProgress, setTrainProgress] = useTState(0);
  const [userGuess, setUserGuess] = useTState(null);
  const [locked, setLocked] = useTState(false);

  useTEffect(() => {
    setSpotPick(null);
    setTrainStarted(false);
    setTrainProgress(0);
    setUserGuess(null);
    setLocked(false);
  }, [profileIdx]);

  useTEffect(() => {
    if (!trainStarted) return;
    const id = setInterval(() => {
      setTrainProgress(p => {
        if (p >= 1) { return 1; }
        return Math.min(1, p + 0.04);
      });
    }, 80);
    return () => clearInterval(id);
  }, [trainStarted]);

  const step = L.STEPS[stepIdx];

  const canAdvance =
    (step.id === 'pick'  && true) ||
    (step.id === 'spot'  && spotPick != null) ||
    (step.id === 'train' && trainProgress >= 1) ||
    (step.id === 'race'  && locked) ||
    (step.id === 'ask'   && false);

  return (
    <div className="slide-wrap" style={{ ...slideStyles.wrap, overflowX: 'hidden', overflowY: 'auto' }}>
      <h1 style={{
        ...slideStyles.h1,
        fontSize: 'clamp(28px, 3.4vw, 44px)',
        margin: '0 0 6px', maxWidth: 'unset', lineHeight: 1.1,
      }}>
        {T.train.h1a} <span style={slideStyles.italic}>{T.train.h1b}</span>{T.train.h1c}
      </h1>
      <p style={{ ...slideStyles.lead, fontSize: 15, maxWidth: 880, lineHeight: 1.5, margin: '0 0 4px' }}>
        {T.train.lead}
      </p>

      <div style={{ overflowX: 'auto', overflowY: 'hidden', WebkitOverflowScrolling: 'touch' }}>
        <Stepper steps={L.STEPS} current={stepIdx} onGo={setStepIdx} />
      </div>

      {/* Content card — fits viewport, no scroll */}
      <div className="resp-train-card" style={{
        marginTop: 12,
        flex: 1, minHeight: 0,
        border: '1px solid var(--line)', borderRadius: 14,
        background: 'var(--bg-3)',
        boxShadow: '0 8px 24px -20px oklch(0 0 0 / 0.14)',
        overflow: 'hidden',
        display: 'flex', flexDirection: 'column',
      }}>
        <div style={{
          flex: 1, minHeight: 0,
          padding: '16px 20px',
          display: 'flex', flexDirection: 'column',
          overflow: 'hidden',
        }}>
          {step.id === 'pick'  && <StepPick   {...{ profileIdx, setProfileIdx }} />}
          {step.id === 'spot'  && <StepSpot   {...{ profile, visibleHistory, spotPick, setSpotPick }} />}
          {step.id === 'train' && <StepTrain  {...{ trainStarted, setTrainStarted, trainProgress }} />}
          {step.id === 'race'  && <StepRace   {...{ profile, visibleHistory, truth, userGuess, setUserGuess, locked, setLocked, trainProgress }} />}
          {step.id === 'ask'   && <StepAsk    {...{ profile, visibleHistory, truth }} />}
        </div>
      </div>

      <div style={{ marginTop: 12, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <button onClick={() => setStepIdx(Math.max(0, stepIdx - 1))} disabled={stepIdx === 0} style={{
          padding: '10px 16px', borderRadius: 10,
          border: '1px solid var(--line)', background: 'transparent',
          color: stepIdx === 0 ? 'var(--dim)' : 'var(--text)',
          fontSize: 14, fontFamily: 'var(--sans)', fontWeight: 500,
          cursor: stepIdx === 0 ? 'default' : 'pointer',
        }}>
          {T.train.back}
        </button>
        <div style={{ fontFamily: 'var(--mono)', fontSize: 12, fontWeight: 600, color: 'var(--text)', letterSpacing: '0.12em' }}>
          {T.train.stepOf.replace('{num}', step.num).replace('{total}', L.STEPS.length)}
        </div>
        <button onClick={() => canAdvance && setStepIdx(Math.min(L.STEPS.length - 1, stepIdx + 1))}
          disabled={!canAdvance || stepIdx === L.STEPS.length - 1}
          style={{
            padding: '10px 18px', borderRadius: 10,
            background: canAdvance && stepIdx < L.STEPS.length - 1 ? 'var(--pill-active)' : 'var(--line)',
            color: canAdvance && stepIdx < L.STEPS.length - 1 ? 'var(--pill-active-text)' : 'var(--dim)',
            fontSize: 14, fontWeight: 500,
            cursor: canAdvance && stepIdx < L.STEPS.length - 1 ? 'pointer' : 'default',
          }}>
          {stepIdx < L.STEPS.length - 1 ? `${T.train.next}: ${T.train.steps[stepIdx + 1]} →` : T.train.done}
        </button>
      </div>
    </div>
  );
}

function Stepper({ steps, current, onGo }) {
  const lang = window.__useLang(); const T = window.TDATA[lang];
  return (
    <div style={{
      marginTop: 22,
      display: 'grid', gridTemplateColumns: `repeat(${steps.length}, 1fr)`,
      minWidth: 480, // ensures steps don't squish below readable size
      borderTop: '1px solid var(--line)', borderBottom: '1px solid var(--line)',
    }}>
      {steps.map((s, i) => {
        const active = i === current;
        const done = i < current;
        return (
          <button key={s.id} onClick={() => onGo(i)} style={{
            padding: '14px 16px', textAlign: 'left',
            borderRight: i < steps.length - 1 ? '1px solid var(--line)' : '0',
            background: active ? 'oklch(0.45 0.18 255 / 0.08)' : 'transparent',
            cursor: 'pointer',
            display: 'flex', alignItems: 'center', gap: 12,
            transition: 'background 200ms',
          }}>
            <span style={{
              width: 28, height: 28, borderRadius: 99,
              display: 'grid', placeItems: 'center',
              fontFamily: 'var(--sans)', fontSize: 13, fontWeight: 600,
              background: active || done ? 'var(--accent)' : 'transparent',
              color: active || done ? 'var(--bg-3)' : 'var(--dim)',
              border: '2px solid ' + (active || done ? 'var(--accent)' : 'var(--line)'),
              flexShrink: 0,
            }}>
              {done ? '✓' : s.num}
            </span>
            <span style={{
              fontFamily: 'var(--sans)', fontSize: 16, fontWeight: 600,
              lineHeight: 1.2,
              color: active || done ? 'var(--text)' : 'var(--muted)',
            }}>
              {T.train.steps[i]}
            </span>
          </button>
        );
      })}
    </div>
  );
}


// ───────────────────────── Step 1: Pick
function StepPick({ profileIdx, setProfileIdx }) {
  const { PROFILES, StepHeading, StepSub, Hint } = window.__trainLab;
  const lang = window.__useLang(); const T = window.TDATA[lang];
  return (
    <div>
      <StepHeading>{T.train.s1.heading}</StepHeading>
      <StepSub>{T.train.s1.sub}</StepSub>
      <div className="resp-grid-3" style={{ marginTop: 20, display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 16 }}>
        {PROFILES.map((p, i) => {
          const active = i === profileIdx;
          return (
            <button key={p.id} onClick={() => setProfileIdx(i)} style={{
              padding: '22px 24px',
              borderRadius: 12, textAlign: 'left',
              border: '2px solid ' + (active ? 'var(--accent)' : 'var(--line)'),
              background: active ? 'oklch(0.45 0.18 255 / 0.06)' : 'transparent',
              display: 'flex', flexDirection: 'column', gap: 10,
              transition: 'border-color 200ms, background 200ms',
              cursor: 'pointer',
            }}>
              <div style={{ fontSize: 40 }}>{p.icon}</div>
              <div style={{
                fontFamily: 'var(--sans)', fontWeight: 600,
                fontSize: 20, lineHeight: 1.2, color: 'var(--text)',
              }}>
                {T.train.s1.businesses[i].name}
              </div>
              <div style={{ fontSize: 14, color: 'var(--muted)', lineHeight: 1.5 }}>
                {T.train.s1.businesses[i].desc}
              </div>
              {active && (
                <div style={{
                  marginTop: 'auto',
                  fontFamily: 'var(--mono)', fontSize: 11, fontWeight: 600,
                  color: 'var(--accent)', letterSpacing: '0.14em', textTransform: 'uppercase',
                }}>
                  {T.train.s1.selected}
                </div>
              )}
            </button>
          );
        })}
      </div>
      <div style={{ marginTop: 18 }}>
        <Hint>{T.train.s1.hint}</Hint>
      </div>
    </div>
  );
}


// ───────────────────────── Step 2: Spot the pattern
function StepSpot({ profile, visibleHistory, spotPick, setSpotPick }) {
  const { Chart, MONTH_LABELS_14, StepHeading, StepSub, Hint, Tag } = window.__trainLab;
  const lang = window.__useLang(); const T = window.TDATA[lang];
  const isMobile = useMobile();

  const correct = {
    coffee:  ['rhythm', 'up'],
    apparel: ['rhythm', 'down'],
    bike:    ['rhythm', 'up'],
  }[profile.id];

  const options = T.train.s2.options;

  const isRight = spotPick && correct.includes(spotPick);

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: 'auto' }}>
      <StepHeading>{T.train.s2.heading}</StepHeading>
      <p style={{ margin: '4px 0 0', fontSize: 14, color: 'var(--muted)' }}>
        {T.train.s2.sub}
      </p>

      <div className="resp-grid-2" style={{ marginTop: 12, display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1.15fr 0.85fr', gap: 16 }}>
        <div style={{ border: '1px solid var(--line)', borderRadius: 12, background: 'var(--bg)', display: 'flex', flexDirection: 'column' }}>
          <Tag>{T.train.s2.chartLabel.replace('{sku}', profile.sku)}</Tag>
          <div style={{ marginTop: 8, display: 'flex', alignItems: 'center' }}>
            <Chart
              series={[{ data: visibleHistory, color: 'var(--text)' }]}
              monthLabels={MONTH_LABELS_14.slice(0, visibleHistory.length)}
              height={180}
            />
          </div>
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 6 }}>
          {options.map(o => {
            const picked = spotPick === o.id;
            const wasCorrect = picked && correct.includes(o.id);
            const wasWrong = picked && !correct.includes(o.id);
            return (
              <button key={o.id} onClick={() => setSpotPick(o.id)} style={{
                padding: '10px 12px', borderRadius: 8, textAlign: 'left',
                border: '2px solid ' + (wasCorrect ? 'oklch(0.55 0.13 150)' : wasWrong ? 'oklch(0.55 0.16 35)' : 'var(--line)'),
                background: wasCorrect ? 'oklch(0.55 0.13 150 / 0.08)' : wasWrong ? 'oklch(0.55 0.16 35 / 0.06)' : 'var(--bg)',
                display: 'flex', flexDirection: 'column', gap: 2,
                cursor: 'pointer',
              }}>
                <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                  <span style={{
                    width: 14, height: 14, borderRadius: 99,
                    background: picked ? (wasCorrect ? 'oklch(0.55 0.13 150)' : 'oklch(0.55 0.16 35)') : 'transparent',
                    border: '2px solid ' + (picked ? (wasCorrect ? 'oklch(0.55 0.13 150)' : 'oklch(0.55 0.16 35)') : 'var(--line)'),
                    flexShrink: 0,
                  }}></span>
                  <span style={{ fontFamily: 'var(--sans)', fontWeight: 600, fontSize: 15, color: 'var(--text)' }}>
                    {o.label}
                  </span>
                </div>
                <div style={{ fontSize: 12, color: 'var(--muted)', marginLeft: 24, lineHeight: 1.35 }}>{o.sub}</div>
              </button>
            );
          })}
          {spotPick && (
            <div style={{ marginTop: 4 }}>
              {isRight ? (
                <Hint tone="good">{T.train.s2.correctFeedback}</Hint>
              ) : (
                <Hint tone="bad">{T.train.s2.wrongFeedback}</Hint>
              )}
            </div>
          )}
        </div>
      </div>
    </div>
  );
}


// ───────────────────────── Step 3: Train (study the world)
function StepTrain({ trainStarted, setTrainStarted, trainProgress }) {
  const { StepHeading, StepSub, Hint, Tag } = window.__trainLab;
  const lang = window.__useLang(); const T = window.TDATA[lang];
  const isMobile = useMobile();

  const worldData = [
    { name: 'Coffee · Norway',     shape: 'wave',  trendDir: 1,  phase: 0.2 },
    { name: 'Sock factory · DE',   shape: 'wave',  trendDir: -1, phase: 1.4 },
    { name: 'E-bikes · NL',        shape: 'wave',  trendDir: 1,  phase: 2.6 },
    { name: 'Ice cream · IT',      shape: 'wave',  trendDir: 0,  phase: 1.8 },
    { name: 'School supplies',     shape: 'spike', trendDir: 0,  phase: 2.0 },
    { name: 'Heating oil · NO',    shape: 'wave',  trendDir: -1, phase: 3.0 },
    { name: 'Beach gear',          shape: 'wave',  trendDir: 0,  phase: 1.2 },
    { name: 'Ski lift tickets',    shape: 'wave',  trendDir: 1,  phase: 3.4 },
    { name: 'Garden supplies',     shape: 'wave',  trendDir: 0,  phase: 0.6 },
    { name: 'Office chairs',       shape: 'trend',trendDir: 1,  phase: 0   },
    { name: 'Cold remedies · US',  shape: 'wave',  trendDir: 0,  phase: 3.6 },
    { name: 'Lawn mowers',         shape: 'wave',  trendDir: 0,  phase: 0.8 },
  ];

  const patternAts = [0.15, 0.35, 0.55, 0.75, 0.92];
  const patterns = T.train.s3.patterns.map((p, i) => ({ ...p, at: patternAts[i] }));

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: 'auto' }}>
      <StepHeading>{T.train.s3.heading}</StepHeading>
      <p style={{ margin: '4px 0 0', fontSize: 14, color: 'var(--muted)' }}>
        {T.train.s3.sub}
      </p>

      <div className="resp-grid-2" style={{ marginTop: 12, display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1.1fr 0.9fr', gap: 16 }}>
        <div style={{
          border: '1px solid var(--line)', borderRadius: 12,
          background: 'var(--bg)',
          display: 'flex', flexDirection: 'column',
        }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 8 }}>
            <Tag>{T.train.s3.worldLabel}</Tag>
            <Tag color={trainStarted ? 'var(--accent)' : 'var(--muted)'}>
              {trainProgress >= 1 ? 'COMPLETE ✓' : trainStarted ? `${Math.round(trainProgress * 100)}%` : 'WAITING'}
            </Tag>
          </div>
          <div style={{
            display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 6,
            marginTop: 6,
          }}>
            {worldData.map((d, i) => {
              const light = trainProgress > i / worldData.length;
              return (
                <div key={i} style={{
                  border: '1px solid ' + (light ? 'var(--accent)' : 'var(--line)'),
                  borderRadius: 6,
                  background: light ? 'oklch(0.45 0.18 255 / 0.06)' : 'var(--bg-3)',
                  transition: 'border-color 280ms, background 280ms',
                  display: 'flex', flexDirection: 'column',
                }}>
                  <div>
                    <MiniWaveSVG d={d} active={light} />
                  </div>
                  <div style={{
                    marginTop: 3, fontFamily: 'var(--sans)', fontSize: 9.5, fontWeight: 500,
                    color: light ? 'var(--text)' : 'var(--muted)', lineHeight: 1.15,
                  }}>
                    {d.name}
                  </div>
                </div>
              );
            })}
          </div>
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 10, minHeight: 0 }}>
          <div style={{
            border: '1px solid ' + (trainProgress > 0 ? 'var(--accent)' : 'var(--line)'),
            borderRadius: 12,
            background: trainProgress > 0 ? 'oklch(0.45 0.18 255 / 0.04)' : 'var(--bg)',
            flex: 1, minHeight: 0, overflow: 'hidden',
          }}>
            <Tag color={trainProgress > 0 ? 'var(--accent)' : 'var(--muted)'}>{T.train.s3.learningLabel}</Tag>
            <div style={{ marginTop: 8, display: 'flex', flexDirection: 'column', gap: 8 }}>
              {patterns.map((p) => {
                const on = trainProgress >= p.at;
                return (
                  <div key={p.id} style={{
                    display: 'grid', gridTemplateColumns: '16px 1fr', gap: 10,
                    opacity: on ? 1 : 0.32,
                    transition: 'opacity 360ms',
                  }}>
                    <span style={{
                      width: 12, height: 12, borderRadius: 99, marginTop: 3,
                      background: on ? 'var(--accent)' : 'transparent',
                      border: '2px solid ' + (on ? 'var(--accent)' : 'var(--line)'),
                    }}></span>
                    <div>
                      <div style={{ fontFamily: 'var(--sans)', fontWeight: 600, fontSize: 14, lineHeight: 1.2, color: 'var(--text)' }}>
                        {p.label}
                      </div>
                      <div style={{ fontSize: 12, color: 'var(--muted)', marginTop: 1, lineHeight: 1.35 }}>
                        {p.desc}
                      </div>
                    </div>
                  </div>
                );
              })}
            </div>
          </div>

          {!trainStarted && trainProgress < 1 && (
            <button onClick={() => setTrainStarted(true)} style={{
              padding: '12px 16px', borderRadius: 10,
              background: 'var(--pill-active)', color: 'var(--pill-active-text)',
              fontWeight: 600, fontSize: 15,
              cursor: 'pointer',
            }}>
              {T.train.s3.waitBtn}
            </button>
          )}
          {trainProgress >= 1 && (
            <Hint tone="good">{T.train.s3.doneMsg}</Hint>
          )}
        </div>
      </div>
    </div>
  );
}

function MiniWaveSVG({ d, active }) {
  const pts = Array.from({ length: 14 }, (_, i) => {
    const t = i / 13;
    let y = 0.5;
    if (d.shape === 'wave') {
      y = 0.5 - Math.sin(t * Math.PI * 2 + d.phase) * 0.32 - (d.trendDir * t * 0.18);
    } else if (d.shape === 'spike') {
      y = 0.7 - (Math.exp(-Math.pow((t - 0.55) * 4, 2)) * 0.5);
    } else if (d.shape === 'trend') {
      y = 0.7 - t * 0.4 * d.trendDir;
    }
    y = Math.max(0.05, Math.min(0.95, y));
    return [i / 13 * 100, y * 30 + 2];
  });
  const path = pts.map((p, i) => (i === 0 ? `M${p[0]},${p[1]}` : `L${p[0]},${p[1]}`)).join(' ');
  return (
    <svg viewBox="0 0 100 34" preserveAspectRatio="none" style={{ width: '100%', height: 36 }}>
      <path d={path} fill="none"
        stroke={active ? 'oklch(0.45 0.18 255)' : 'var(--dim)'}
        strokeWidth={active ? 2 : 1.4}
        strokeLinecap="round" strokeLinejoin="round" />
    </svg>
  );
}


// ───────────────────────── Step 4: Race
function StepRace({ profile, visibleHistory, truth, userGuess, setUserGuess, locked, setLocked, trainProgress }) {
  const L = window.__trainLab;
  const { Chart, MONTH_LABELS_14, StepHeading, StepSub, Hint, Tag } = L;
  const lang = window.__useLang(); const T = window.TDATA[lang];
  const isMobile = useMobile();

  const defaultGuess = Math.round(visibleHistory.slice(-3).reduce((a, b) => a + b, 0) / 3);
  const minG = Math.round(profile.base * 0.2);
  const maxG = Math.round(profile.base * 2.0);
  const g = userGuess ?? defaultGuess;

  const trained = trainProgress >= 1;
  const coldF = useTMemo(() => L.coldAIForecast(visibleHistory, 6), [visibleHistory]);
  const worldF = useTMemo(() => L.worldAIForecast(profile, visibleHistory, 6), [profile, visibleHistory]);

  const HOR = 6;
  const padArr = (arr, before) => [...Array(before).fill(null), ...arr];
  const fullVis = [...visibleHistory, ...Array(HOR).fill(null)];

  const userSeries  = locked ? padArr([visibleHistory[visibleHistory.length - 1], g, g, g, g, g, g], visibleHistory.length - 1) : null;
  const coldSeries  = locked ? padArr([visibleHistory[visibleHistory.length - 1], ...coldF], visibleHistory.length - 1) : null;
  const worldSeries = locked ? padArr([visibleHistory[visibleHistory.length - 1], ...worldF], visibleHistory.length - 1) : null;
  const truthSeries = locked ? padArr([visibleHistory[visibleHistory.length - 1], ...truth], visibleHistory.length - 1) : null;
  const liveGuessSeries = !locked ? padArr([visibleHistory[visibleHistory.length - 1], g], visibleHistory.length - 1) : null;

  const absErr = (arr) => arr.reduce((a, v, i) => a + Math.abs(v - truth[i]), 0) / arr.length;
  const userErr = locked ? Math.abs(g - truth[0]) : 0;
  const coldErr = locked ? absErr(coldF) : 0;
  const worldErr = locked ? absErr(worldF) : 0;

  let winner = null;
  if (locked) {
    const me = userErr, c = coldErr, w = worldErr;
    if (w <= me && w <= c) winner = 'world';
    else if (me <= c) winner = 'you';
    else winner = 'cold';
  }

  const series = [
    { data: fullVis, color: 'var(--text)', thick: false },
  ];
  if (locked) {
    series.push({ data: truthSeries, color: 'oklch(0.20 0.005 60)', thick: true, opacity: 0.6 });
    series.push({ data: coldSeries,  color: 'oklch(0.55 0.05 60)', dashed: true });
    series.push({ data: worldSeries, color: 'var(--accent)', dashed: true, thick: true });
    series.push({ data: userSeries,  color: 'oklch(0.45 0.16 270)', dotted: true });
  } else {
    series.push({ data: liveGuessSeries, color: 'oklch(0.45 0.16 270)', dotted: true });
  }

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: 'auto' }}>
      <StepHeading>{T.train.s4.heading}</StepHeading>
      <p style={{ margin: '4px 0 0', fontSize: 14, color: 'var(--muted)' }}>
        {T.train.s4.sub}
      </p>

      <div className="resp-grid-2" style={{ marginTop: 12, display: 'grid', gridTemplateColumns: isMobile ? '1fr' : '1.3fr 0.7fr', gap: 16 }}>
        <div style={{ border: '1px solid var(--line)', borderRadius: 12, background: 'var(--bg)', display: 'flex', flexDirection: 'column' }}>
          <Tag>{T.train.s4.chartLabel.replace('{sku}', profile.sku)}</Tag>
          <div style={{ marginTop: 8, display: 'flex', alignItems: 'center' }}>
            <Chart
              series={series}
              monthLabels={MONTH_LABELS_14}
              height={200}
              xCursor={!locked ? visibleHistory.length : null}
            />
          </div>
          {locked && (
            <Legend items={[
              { label: T.train.s4.legend[0], color: 'oklch(0.45 0.16 270)', dotted: true },
              { label: T.train.s4.legend[1], color: 'oklch(0.55 0.05 60)',  dashed: true },
              { label: T.train.s4.legend[2], color: 'var(--accent)',         dashed: true, thick: true },
              { label: T.train.s4.legend[3], color: 'oklch(0.20 0.005 60)' },
            ]} />
          )}
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 8 }}>
          {!locked ? (
            <>
              <div style={{ border: '2px solid oklch(0.45 0.16 270 / 0.4)', borderRadius: 12, background: 'oklch(0.45 0.16 270 / 0.04)' }}>
                <Tag color="oklch(0.45 0.16 270)">{T.train.s4.guessLabel}</Tag>
                <div style={{
                  marginTop: 4, fontFamily: 'var(--sans)', fontWeight: 600,
                  fontSize: 38, letterSpacing: '-0.02em', lineHeight: 1,
                  color: 'oklch(0.40 0.16 270)',
                }}>
                  {g} <span style={{ fontSize: 14, color: 'var(--muted)', fontWeight: 400 }}>{T.train.s4.units}</span>
                </div>
                <input type="range" min={minG} max={maxG} step="1" value={g}
                  onChange={(e) => setUserGuess(Number(e.target.value))}
                  style={{ width: '100%', accentColor: 'oklch(0.45 0.16 270)', marginTop: 8 }} />
                <div style={{
                  display: 'flex', justifyContent: 'space-between',
                  fontSize: 11, color: 'var(--muted)', fontWeight: 500,
                }}>
                  <span>{minG}</span><span>{maxG}</span>
                </div>
              </div>
              <button onClick={() => { if (userGuess == null) setUserGuess(defaultGuess); setLocked(true); }} style={{
                padding: '12px 16px', borderRadius: 10,
                background: 'var(--pill-active)', color: 'var(--pill-active-text)',
                fontWeight: 600, fontSize: 15, cursor: 'pointer',
              }}>
                {T.train.s4.lockBtn}
              </button>
              {!trained && (
                <div style={{ fontSize: 12, color: 'oklch(0.55 0.16 35)', lineHeight: 1.4 }}>
                  {T.train.s4.skipWarning}
                </div>
              )}
            </>
          ) : (
            <>
              <ResultRow who={T.train.s4.winners[0]} err={userErr}  hero={winner === 'you'} />
              <ResultRow who={T.train.s4.winners[1]} err={coldErr}  hero={winner === 'cold'} />
              <ResultRow who={T.train.s4.winners[2]} err={worldErr} hero={winner === 'world'} />
              <div style={{
                padding: '10px 12px', borderRadius: 8,
                background: 'oklch(0.45 0.18 255 / 0.06)',
                border: '1px solid var(--accent)',
                fontSize: 13, color: 'var(--text)', lineHeight: 1.45,
              }}>
                {winner === 'world'
                  ? T.train.s4.winners_msg_world
                  : winner === 'you'
                    ? T.train.s4.winners_msg_you
                    : T.train.s4.winners_msg_cold}
              </div>
              <button onClick={() => { setLocked(false); setUserGuess(null); }} style={{
                padding: '8px 12px', borderRadius: 8,
                border: '1px solid var(--line)', background: 'transparent',
                color: 'var(--text)', fontSize: 13, fontWeight: 500, cursor: 'pointer',
              }}>
                {T.train.s4.resetBtn}
              </button>
            </>
          )}
        </div>
      </div>
    </div>
  );
}

function ResultRow({ who, err, hero }) {
  const lang = window.__useLang(); const T = window.TDATA[lang];
  return (
    <div style={{
      display: 'grid', gridTemplateColumns: '1fr auto', gap: 10, alignItems: 'center',
      padding: '10px 12px', borderRadius: 8,
      border: '2px solid ' + (hero ? 'var(--accent)' : 'var(--line)'),
      background: hero ? 'oklch(0.45 0.18 255 / 0.08)' : 'var(--bg)',
    }}>
      <div>
        {hero && (
          <div style={{
            fontFamily: 'var(--mono)', fontSize: 9, fontWeight: 600,
            color: 'var(--accent)', letterSpacing: '0.18em', textTransform: 'uppercase',
          }}>
            {T.train.s4.closest}
          </div>
        )}
        <div style={{
          fontFamily: 'var(--sans)', fontWeight: 600,
          fontSize: 15, lineHeight: 1.1, color: 'var(--text)',
        }}>
          {who}
        </div>
      </div>
      <div style={{ textAlign: 'right' }}>
        <div style={{
          fontFamily: 'var(--sans)', fontWeight: 600,
          fontSize: 20, letterSpacing: '-0.01em', lineHeight: 1, color: 'var(--text)',
        }}>
          {Math.round(err)}
        </div>
        <div style={{ fontSize: 10, color: 'var(--muted)' }}>{T.train.s4.unitOff}</div>
      </div>
    </div>
  );
}

function Legend({ items }) {
  return (
    <div style={{
      marginTop: 12, display: 'flex', gap: 18, flexWrap: 'wrap',
      fontFamily: 'var(--sans)', fontSize: 13, fontWeight: 500, color: 'var(--text)',
    }}>
      {items.map((it, i) => (
        <span key={i} style={{ display: 'inline-flex', alignItems: 'center', gap: 8 }}>
          <span style={{
            display: 'inline-block', width: 22, height: 0,
            borderTop: `${it.thick ? 3 : 2}px ${it.dashed ? 'dashed' : it.dotted ? 'dotted' : 'solid'} ${it.color}`,
          }}></span>
          {it.label}
        </span>
      ))}
    </div>
  );
}


// ───────────────────────── Step 5: Ask
function StepAsk({ profile, visibleHistory, truth }) {
  const { StepHeading, StepSub } = window.__trainLab;
  const lang = window.__useLang(); const T = window.TDATA[lang];
  const isMobile = useMobile();
  const profileIndex = ['coffee', 'apparel', 'bike'].indexOf(profile.id);
  const bizName = T.train.s1.businesses[profileIndex >= 0 ? profileIndex : 0].name;
  const [input, setInput] = useTState('');
  const [msgs, setMsgs] = useTState([
    { who: 'ai', text: T.train.s5.initMsg.replace('{biz}', bizName.toLowerCase()) },
  ]);
  const [busy, setBusy] = useTState(false);
  const scrollRef = useTRef(null);

  useTEffect(() => {
    if (scrollRef.current) scrollRef.current.scrollTop = scrollRef.current.scrollHeight;
  }, [msgs, busy]);

  const suggestions = T.train.s5.chips;

  const ask = async (q) => {
    if (!q || busy) return;
    const nextMsgs = [...msgs, { who: 'user', text: q }];
    setMsgs(nextMsgs);
    setInput('');
    setBusy(true);
    try {
      const sys = `You are AdMel's "World-Brain" forecasting AI, a foundation time-series model (think TimesFM / MOMENT). You are talking to a non-technical viewer who has just walked through a 5-step lab. Be warm, short (1-3 short sentences), and plain-spoken. Use vivid analogies (cooking, weather, kids learning to ride bikes). Never lecture.

Scenario:
- Business: ${profile.name}
- Product tracked: ${profile.sku}
- 8 months of sales the AI just saw: ${visibleHistory.join(', ')}
- The next 6 actual months (the "truth"): ${truth.join(', ')}
- The user just predicted month 9 by hand and compared with a cold AI and you.

When asked how you differ from a chat AI like ChatGPT, explain that ChatGPT learned from text, you learned from numbers-over-time, and that's why you spot rhythms a chat AI can't. Never break character.`;
      const resp = await fetch('/api/chat', {
        method: 'POST',
        headers: { 'Content-Type': 'application/json' },
        body: JSON.stringify({
          system: sys,
          messages: [{ role: 'user', content: q }],
        }),
      }).then(r => r.json()).then(d => d.text || '');
      setMsgs([...nextMsgs, { who: 'ai', text: resp.trim() }]);
    } catch (err) {
      setMsgs([...nextMsgs, { who: 'ai', text: T.train.s5.error }]);
    } finally {
      setBusy(false);
    }
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: 'auto' }}>
      <StepHeading>{T.train.s5.heading}</StepHeading>
      <p style={{ margin: '4px 0 0', fontSize: 14, color: 'var(--muted)' }}>
        {T.train.s5.sub}
      </p>

      <div style={{ marginTop: 10, display: 'flex', flexDirection: 'column', gap: 8 }}>
        <div ref={scrollRef} style={{
          border: '1px solid var(--line)', borderRadius: 12,
          background: 'var(--bg)',
          padding: '12px 14px',
          height: isMobile ? 220 : 260,
          overflowY: 'auto',
          display: 'flex', flexDirection: 'column', gap: 10,
        }}>
          {msgs.map((m, i) => <Bubble key={i} who={m.who}>{m.text}</Bubble>)}
          {busy && <Bubble who="ai" busy />}
        </div>

        <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {suggestions.map(s => (
            <button key={s} onClick={() => ask(s)} disabled={busy} style={{
              padding: '6px 12px', borderRadius: 999,
              border: '1px solid var(--line)', background: 'var(--bg-3)',
              fontSize: 12, color: 'var(--text)', fontWeight: 500,
              cursor: 'pointer',
            }}>
              {s}
            </button>
          ))}
        </div>

        <div style={{
          display: 'flex', gap: 8, alignItems: 'center',
          border: '1px solid var(--line)', borderRadius: 10,
          padding: '8px 12px', background: 'var(--bg-3)',
        }}>
          <input
            value={input}
            onChange={(e) => setInput(e.target.value)}
            onKeyDown={(e) => { if (e.key === 'Enter') ask(input); }}
            placeholder={T.train.s5.placeholder}
            disabled={busy}
            style={{ flex: 1, background: 'transparent', border: 0, outline: 'none', fontSize: 14, fontFamily: 'var(--sans)' }}
          />
          <button onClick={() => ask(input)} disabled={busy || !input.trim()} style={{
            padding: '8px 14px', borderRadius: 8,
            background: input.trim() && !busy ? 'var(--pill-active)' : 'var(--line)',
            color: input.trim() && !busy ? 'var(--pill-active-text)' : 'var(--dim)',
            fontSize: 13, fontWeight: 600,
            cursor: input.trim() && !busy ? 'pointer' : 'default',
          }}>
            {T.train.s5.sendBtn}
          </button>
        </div>
      </div>
    </div>
  );
}

function Bubble({ who, children, busy }) {
  const isAI = who === 'ai';
  return (
    <div style={{ display: 'flex', justifyContent: isAI ? 'flex-start' : 'flex-end' }}>
      <div style={{
        maxWidth: '82%',
        padding: '12px 16px', borderRadius: 12,
        background: isAI ? 'var(--bg-3)' : 'oklch(0.45 0.18 255 / 0.12)',
        border: '1px solid ' + (isAI ? 'var(--line)' : 'oklch(0.45 0.18 255 / 0.35)'),
        fontSize: 15.5, color: 'var(--text)', lineHeight: 1.55,
        fontFamily: 'var(--sans)', fontWeight: 400,
      }}>
        {busy ? <span style={{ opacity: 0.6 }}>{window.TDATA[window.__useLang()].train.s5.thinking}</span> : children}
      </div>
    </div>
  );
}

// ───────────────────────── Export
Object.assign(window, { TrainSlide });
