// Tempo — pages: Home (carte blanche), Daily Journal, Trades, Journal Modal, Login, placeholders

// ─── HOME — carte blanche ─────────────────────────────────────────
function Home({ nav, navStats, openJournal, openImport, openTrade, state }) {
  const t = useLiveTime();
  // Raccourcis vers la section Statistiques (vue trading / habitudes). Inertes si navStats absent.
  const goStatsTrading = navStats ? () => navStats('trading') : (nav ? () => nav('stats') : undefined);
  const goStatsHabits  = navStats ? () => navStats('habits')  : (nav ? () => nav('stats') : undefined);
  const { habits, pretradeItems, toggleHabit, agenda, toggleAgenda, trades, stats, tradesLoading } = state;
  const news = useNewsBriefing();

  // City clocks via Intl.DateTimeFormat (timezone-correct on the user's machine).
  const ny  = tzTime(t, 'America/New_York');
  const ldn = tzTime(t, 'Europe/London');
  const par = tzTime(t, 'Europe/Paris');
  // Paris hour/minute drives session open/close logic
  const parisHM = parisHourMinute(t);
  const sessions = sessionStatus(parisHM.h, parisHM.m, parisHM.d);
  const marketOpenCME = useMarketOpen();

  // Greeting name: real display name (profile) with email/Trader fallbacks (see state.displayName).
  const greeting = state?.displayName || '';
  const net = stats.netPnl || 0;
  const recent = trades.slice(0, 5);

  // Hero status pill — coherent with header CME pill:
  //   CME closed             → "Marchés fermés" (grey)
  //   CME open + NY session  → "Session NY ouverte" (green)
  //   CME open + London      → "Session Londres ouverte" (green)
  //   CME open + no session  → "CME ouvert · hors session liquide" (green)
  const heroPill = !marketOpenCME
    ? { text: 'Marchés fermés', open: false }
    : sessions.newyork
      ? { text: 'Session NY ouverte', open: true }
      : sessions.london
        ? { text: 'Session Londres ouverte', open: true }
        : { text: 'CME ouvert · hors session liquide', open: true };

  // Live, locale-aware date label: "Mardi 26 mai · S22 · J146"
  const dateLabel = buildDateLabel(new Date());

  // Pretrade items from state (cochables, persisted via toggleHabit).
  const pretrade = pretradeItems || [];
  const pretradeDone = pretrade.filter(p => p.d).length;

  return (
    <div className="scroll" style={{ width: '100%', height: '100%', overflow: 'auto' }}>
      <PageHeader title="Accueil"/>

      <div style={{ padding: '24px 24px 48px' }}>

        {/* ── Hero — big personal card ── */}
        <div className="stagger" style={{ display: 'grid', gridTemplateColumns: '1.65fr 1fr', gap: 16, marginBottom: 16 }}>
          {/* Hero left — gradient + personal greeting */}
          <div style={{
            position: 'relative', overflow: 'hidden',
            background: 'linear-gradient(135deg, #0f172a 0%, #1e293b 60%, #0c4a6e 100%)',
            borderRadius: 18, padding: '32px 36px', color: '#fff',
            minHeight: 260,
          }}>
            {/* shimmer */}
            <div style={{ position: 'absolute', top: 0, left: 0, right: 0, height: 1, background: 'linear-gradient(90deg, transparent, rgba(255,255,255,0.25), transparent)', animation: 'shimmer 4s var(--ease) infinite' }}></div>
            {/* halo */}
            <div style={{ position: 'absolute', top: -80, right: -80, width: 280, height: 280, borderRadius: '50%', background: 'radial-gradient(circle, rgba(59,130,246,0.30), transparent 70%)', pointerEvents: 'none' }}></div>

            <div style={{ position: 'relative' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10, marginBottom: 14 }}>
                {heroPill.open ? (
                  <span className="pill" style={{ background: 'rgba(34,197,94,0.18)', color: '#86efac', border: '1px solid rgba(34,197,94,0.35)' }}>
                    <span style={{ width: 5, height: 5, borderRadius: '50%', background: '#22c55e', animation: 'pulse-dot 2s var(--ease) infinite' }}></span>
                    {heroPill.text}
                  </span>
                ) : (
                  <span className="pill" style={{ background: 'rgba(255,255,255,0.10)', color: 'rgba(255,255,255,0.72)', border: '1px solid rgba(255,255,255,0.18)' }}>
                    <span style={{ width: 5, height: 5, borderRadius: '50%', background: 'rgba(255,255,255,0.4)' }}></span>
                    {heroPill.text}
                  </span>
                )}
                <span style={{ fontSize: 11.5, color: 'rgba(255,255,255,0.55)', letterSpacing: '-.005em' }}>{dateLabel}</span>
              </div>

              <div style={{ display: 'flex', alignItems: 'flex-end', justifyContent: 'space-between', gap: 24 }}>
                <div>
                  <h1 style={{ fontSize: 38, fontWeight: 700, letterSpacing: '-.025em', margin: 0, lineHeight: 1.05 }}>Bonjour{greeting ? ', ' + greeting : ''}.</h1>
                  <p style={{ marginTop: 12, marginBottom: 0, fontSize: 14, color: 'rgba(255,255,255,0.72)', lineHeight: 1.55, maxWidth: 460 }}>
                    {stats.count === 0
                      ? <>Tempo est prêt. Importe ton premier CSV ou ajoute un trade manuellement pour démarrer ton journal.</>
                      : <>Tu as enregistré <b style={{ color: '#fff' }}>{stats.count} trade{stats.count > 1 ? 's' : ''}</b> · {stats.winRate.toFixed(0)}% de win rate · R-moyen {stats.avgR.toFixed(2)}.</>}
                  </p>
                </div>
                <div
                  onClick={goStatsTrading}
                  className={goStatsTrading ? 'tap' : ''}
                  title={goStatsTrading ? 'Voir les statistiques détaillées' : undefined}
                  style={{ flexShrink: 0, textAlign: 'right', cursor: goStatsTrading ? 'pointer' : 'default' }}>
                  <span style={{ fontSize: 11, letterSpacing: '.08em', textTransform: 'uppercase', color: 'rgba(255,255,255,0.45)', fontWeight: 500 }}>Net</span>
                  <div style={{ fontSize: 34, fontWeight: 700, letterSpacing: '-.025em', color: net >= 0 ? '#86efac' : '#fda4af', marginTop: 8, lineHeight: 1, whiteSpace: 'nowrap' }}>
                    {tradesLoading ? '—' : fmtMoney(net, true)}
                  </div>
                </div>
              </div>

              {/* Live sessions */}
              <div style={{ display: 'flex', gap: 20, marginTop: 24, paddingTop: 20, borderTop: '1px solid rgba(255,255,255,0.10)' }}>
                {[
                  { c: 'PARIS',    t: par, on: marketOpenCME, label: marketOpenCME ? 'CME OUVERT' : 'CME FERMÉ' },
                  { c: 'LONDRES',  t: ldn, on: sessions.london, label: sessions.london ? 'OPEN' : 'CLOSED' },
                  { c: 'NEW YORK', t: ny,  on: sessions.newyork, label: sessions.newyork ? 'OPEN' : 'CLOSED' },
                ].map(s => (
                  <div key={s.c} style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                    <span style={{ fontSize: 10.5, fontWeight: 500, letterSpacing: '.08em', color: 'rgba(255,255,255,0.45)', textTransform: 'uppercase' }}>{s.c}</span>
                    <span className="mono" style={{ fontSize: 13, fontWeight: 500, color: '#fff' }}>{s.t}</span>
                    <span style={{ width: 6, height: 6, borderRadius: '50%', background: s.on ? '#22c55e' : 'rgba(248,113,113,0.55)' }}></span>
                    <span style={{ fontSize: 9.5, fontWeight: 600, letterSpacing: '.08em', color: s.on ? '#86efac' : 'rgba(255,255,255,0.4)' }}>{s.label}</span>
                  </div>
                ))}
              </div>
            </div>
          </div>

          {/* Pre-trade checklist — actionable, persisted via habits.pretrade */}
          <div className="card lift" style={{ padding: '22px 22px' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14 }}>
              <span style={{ fontSize: 14, fontWeight: 600, letterSpacing: '-.01em' }}>Pré-trade checklist</span>
              <span className="pill pill-gray">{pretradeDone} / {pretrade.length} OK</span>
            </div>
            <p style={{ fontSize: 12, color: 'var(--fg-3)', marginTop: 0, marginBottom: 14 }}>Valide avant ta première position du jour.</p>
            {pretrade.length === 0 ? (
              <div style={{ fontSize: 12, color: 'var(--fg-3)', padding: '12px 0' }}>
                Ajoute tes points pré-trade depuis <button onClick={() => nav('routines')} className="tap" style={{ background: 'transparent', border: 'none', color: 'var(--blue-600)', cursor: 'pointer', padding: 0, fontSize: 12, fontFamily: 'inherit', textDecoration: 'underline' }}>Routines</button>.
              </div>
            ) : pretrade.map((p, i) => (
              <PreTradeRow key={p.id} item={p} onToggle={() => toggleHabit(p.id)}/>
            ))}
            <button onClick={() => openImport && openImport()} className="btn btn-blue tap" style={{ marginTop: 12, width: '100%', justifyContent: 'center' }}>
              {Ico.plus} Logger un trade
            </button>
          </div>
        </div>

        {/* ── 4 KPI quick row ── */}
        <div className="stagger" style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 14, marginBottom: 16 }}>
          <QuickStat label="Net P&L"   value={stats.netPnl || 0} isMoney pos={stats.netPnl > 0} neg={stats.netPnl < 0} sub={`${stats.count} trade${stats.count > 1 ? 's' : ''}`}/>
          <QuickStat label="Win Rate"  value={stats.winRate || 0} decimals={1} suffix="%" sub={`${stats.wins}W · ${stats.losses}L`}/>
          <QuickStat label="R-moyen"   value={stats.avgR || 0} decimals={2} suffix="R" sub={stats.count === 0 ? 'Aucune donnée' : 'cible 1,5R'}/>
          <QuickStat label="Profit Factor" value={Number.isFinite(stats.profitFactor) ? stats.profitFactor : 0} display={stats.count === 0 ? '—' : !Number.isFinite(stats.profitFactor) ? '∞' : undefined} decimals={2} sub={stats.count === 0 ? '—' : 'sur tous les trades'}/>
        </div>

        {/* ── Today's agenda + Habits + Briefing ── */}
        <div className="stagger" style={{ display: 'grid', gridTemplateColumns: '1.2fr 1fr 1.1fr', gap: 16, marginBottom: 16 }}>

          {/* Agenda live */}
          <div className="card lift" style={{ padding: '22px 22px' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14 }}>
              <span style={{ fontSize: 14, fontWeight: 600, letterSpacing: '-.01em' }}>Agenda du jour</span>
              <button onClick={() => nav('routines')} className="tap" style={{ background: 'transparent', border: 'none', color: 'var(--blue-600)', fontSize: 11.5, fontWeight: 500, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 4 }}>Modifier{Ico.chev}</button>
            </div>
            {agenda.length === 0 ? (
              <div style={{ fontSize: 12, color: 'var(--fg-3)', padding: '10px 0' }}>Aucun événement aujourd'hui — ajoute-en depuis Routines.</div>
            ) : (
              <AgendaTimeline now={t} agenda={agenda} toggleAgenda={toggleAgenda}/>
            )}
          </div>

          {/* Habits */}
          <div className="card lift" style={{ padding: '22px 22px' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14 }}>
              <span style={{ fontSize: 14, fontWeight: 600, letterSpacing: '-.01em' }}>Habitudes</span>
              <div style={{ display: 'inline-flex', alignItems: 'center', gap: 12 }}>
                {goStatsHabits && <button onClick={goStatsHabits} className="tap" style={{ background: 'transparent', border: 'none', color: 'var(--blue-600)', fontSize: 11.5, fontWeight: 500, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 4 }}>Stats{Ico.chev}</button>}
                <button onClick={() => nav('routines')} className="tap" style={{ background: 'transparent', border: 'none', color: 'var(--blue-600)', fontSize: 11.5, fontWeight: 500, cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: 4 }}>Modifier{Ico.chev}</button>
              </div>
            </div>
            <HabitsList habits={habits} toggleHabit={toggleHabit}/>
          </div>

          {/* News briefing — live RSS */}
          <div className="card lift" style={{ padding: '22px 22px' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14 }}>
              <span style={{ fontSize: 14, fontWeight: 600, letterSpacing: '-.01em' }}>{typeof briefingTitle === 'function' ? briefingTitle(t.getHours()) : 'Briefing du marché'}</span>
              <span style={{ fontSize: 11.5, color: 'var(--fg-3)' }}>{news.length || 4} sources</span>
            </div>
            {news.length === 0 ? (
              [0, 1, 2, 3].map(i => (
                <div key={i} style={{
                  padding: '10px 0', borderTop: i ? '1px solid var(--line)' : 'none',
                }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 6 }}>
                    <span style={{ display: 'inline-block', width: 60, height: 8, background: 'var(--bg-elev)', borderRadius: 4 }}></span>
                    <span style={{ display: 'inline-block', width: 32, height: 8, background: 'var(--bg-elev)', borderRadius: 4 }}></span>
                  </div>
                  <span style={{ display: 'inline-block', width: '95%', height: 12, background: 'var(--bg-elev)', borderRadius: 4 }}></span>
                </div>
              ))
            ) : news.map((n, i) => (
              <a key={i} href={n.link || '#'} target="_blank" rel="noopener noreferrer" className="tap" style={{
                display: 'block', padding: '10px 0', borderTop: i ? '1px solid var(--line)' : 'none',
                cursor: 'pointer', textDecoration: 'none', color: 'inherit',
              }}>
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 4 }}>
                  <span style={{ fontSize: 10, fontWeight: 600, letterSpacing: '.08em', color: 'var(--blue-600)' }}>{(n.source || '').toUpperCase()}</span>
                  {n.time && <span className="mono" style={{ fontSize: 10, color: 'var(--fg-3)' }}>{n.time}</span>}
                </div>
                <div style={{ fontSize: 13, lineHeight: 1.4, color: 'var(--fg)', letterSpacing: '-.005em' }}>{n.headline}</div>
              </a>
            ))}
          </div>
        </div>

        {/* ── Recent journals + Quick navigate row ── */}
        <div className="stagger" style={{ display: 'grid', gridTemplateColumns: '1fr 320px', gap: 16 }}>
          <div className="card" style={{ padding: '20px 22px' }}>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14 }}>
              <div>
                <div style={{ fontSize: 14, fontWeight: 600, letterSpacing: '-.01em' }}>Trades récents</div>
                <div style={{ fontSize: 11.5, color: 'var(--fg-3)', marginTop: 4 }}>{recent.length === 0 ? 'Aucun trade pour l\'instant' : 'Cliquer une ligne pour ouvrir le détail'}</div>
              </div>
              <button onClick={() => nav('trades')} className="btn tap">
                Tous les trades <span style={{ color: 'var(--fg-3)' }}>{Ico.chev}</span>
              </button>
            </div>
            {tradesLoading ? (
              <div style={{ fontSize: 12, color: 'var(--fg-3)', padding: '20px 0', textAlign: 'center' }}>Chargement…</div>
            ) : recent.length === 0 ? (
              <div style={{ padding: '24px 0', textAlign: 'center' }}>
                <div style={{ fontSize: 13, color: 'var(--fg-2)', marginBottom: 6 }}>Aucun trade pour l'instant</div>
                <div style={{ fontSize: 12, color: 'var(--fg-3)', marginBottom: 14 }}>Importe ton premier CSV ou ajoute un trade manuellement.</div>
                <button onClick={() => openImport && openImport()} className="btn btn-blue tap">{Ico.plus} Ajouter un trade</button>
              </div>
            ) : (
              <TradesMiniTableReal trades={recent} openTrade={openTrade} openJournal={openJournal}/>
            )}
          </div>

          <div style={{ display: 'flex', flexDirection: 'column', gap: 14 }}>
            <NavTile nav={nav} to="stats" onClick={goStatsTrading} title="Statistiques" desc="Analyse poussée trading & habitudes" ico={Ico.stats}/>
            <NavTile nav={nav} to="dashboard" title="Dashboard" desc="KPIs, score, calendrier P&L" ico={Ico.dashboard}/>
            <NavTile nav={nav} to="daily"     title="Daily Journal" desc="Liste de tes journaux quotidiens" ico={Ico.daily}/>
            <NavTile nav={nav} to="strategy"  title="Stratégies" desc="Tes playbooks et leur perf" ico={Ico.strategy}/>
          </div>
        </div>

      </div>
    </div>
  );
}

function PreTradeRow({ item, onToggle }) {
  // When an onToggle callback is provided, persistence is handled by the parent (Supabase via toggleHabit).
  // Otherwise we keep a local state — used for the legacy sample-data preview path.
  const [localDone, setLocalDone] = React.useState(!!item.d);
  const done = onToggle ? !!item.d : localDone;
  const click = () => { if (onToggle) onToggle(); else setLocalDone(d => !d); };
  return (
    <div onClick={click} className="tap" style={{
      display: 'flex', alignItems: 'center', gap: 12, padding: '9px 0',
      borderBottom: '1px solid var(--line)', cursor: 'pointer',
    }}>
      <div style={{
        width: 18, height: 18, borderRadius: 6,
        border: '1.5px solid ' + (done ? 'var(--blue)' : 'var(--line-2)'),
        background: done ? 'var(--blue)' : 'var(--bg-card)',
        display: 'flex', alignItems: 'center', justifyContent: 'center',
        color: '#fff', transition: 'all .2s var(--ease)',
      }}>{done && Ico.check}</div>
      <span style={{ fontSize: 13, color: done ? 'var(--fg-3)' : 'var(--fg)', textDecoration: done ? 'line-through' : 'none', flex: 1, letterSpacing: '-.005em' }}>{item.t}</span>
    </div>
  );
}

function QuickStat({ label, value, isMoney, pos, neg, decimals, suffix, sub, display }) {
  return (
    <div className="card lift" style={{ padding: '18px 20px' }}>
      <div style={{ fontSize: 12, color: 'var(--fg-2)', marginBottom: 12, fontWeight: 500 }}>{label}</div>
      <div style={{ fontSize: 26, fontWeight: 700, letterSpacing: '-.022em', color: pos ? 'var(--green)' : (neg ? 'var(--red)' : 'var(--fg)'), lineHeight: 1 }}>
        {display != null
          ? <span>{display}</span>
          : isMoney ? <AnimatedMoney value={value} size={26} weight={700} color={pos ? 'var(--green)' : 'var(--fg)'}/> : <span><AnimatedNumber value={value} decimals={decimals || 0} size={26} weight={700} color={pos ? 'var(--green)' : 'var(--fg)'}/>{suffix && <span>{suffix}</span>}</span>}
      </div>
      {sub && <div style={{ fontSize: 11.5, color: 'var(--fg-3)', marginTop: 10 }}>{sub}</div>}
    </div>
  );
}

function AgendaTimeline({ now, agenda, toggleAgenda }) {
  const events = agenda || [];
  const nowMin = now.getHours() * 60 + now.getMinutes();
  return (
    <div style={{ display: 'flex', flexDirection: 'column' }}>
      {events.map((e, i) => {
        const [h, m] = e.h.split(':').map(Number);
        const eventMin = h * 60 + m;
        const isActive = Math.abs(eventMin - nowMin) <= 30 && !e.done;
        return (
          <div key={e.id} style={{ display: 'flex', alignItems: 'flex-start', gap: 14, padding: '8px 0' }}>
            <span className="mono" style={{ fontSize: 11.5, color: e.done ? 'var(--fg-3)' : 'var(--fg-2)', fontWeight: 500, minWidth: 38, paddingTop: 2 }}>{e.h}</span>
            <div style={{ width: 10, display: 'flex', flexDirection: 'column', alignItems: 'center', paddingTop: 2 }}>
              <div onClick={() => toggleAgenda && toggleAgenda(e.id)} className="tap" style={{
                width: 8, height: 8, borderRadius: '50%', cursor: 'pointer',
                background: isActive ? 'var(--blue)' : (e.done ? 'var(--fg-4)' : 'var(--bg-card)'),
                border: isActive ? '2px solid var(--blue-soft)' : '1px solid var(--line-2)',
                boxShadow: isActive ? '0 0 0 3px rgba(37,99,235,0.20)' : 'none',
              }}></div>
              {i < events.length - 1 && <div style={{ width: 1, flex: 1, background: 'var(--line)', marginTop: 4, minHeight: 12 }}></div>}
            </div>
            <div style={{ flex: 1, paddingBottom: 4 }}>
              <span style={{ fontSize: 13, color: e.done ? 'var(--fg-3)' : 'var(--fg)', textDecoration: e.done ? 'line-through' : 'none', letterSpacing: '-.005em' }}>{e.e}</span>
              {e.tag && <span style={{ marginLeft: 8, padding: '1px 7px', borderRadius: 4, background: 'var(--bg-elev)', color: 'var(--fg-2)', fontSize: 10, fontWeight: 500 }}>{e.tag}</span>}
            </div>
          </div>
        );
      })}
    </div>
  );
}

function HabitsList({ habits, toggleHabit }) {
  const totalHabits = habits.reduce((s, g) => s + g.items.length, 0);
  if (totalHabits === 0) {
    return (
      <div style={{ fontSize: 12, color: 'var(--fg-3)', padding: '8px 0' }}>
        Aucune habitude — ajoute-en dans Routines.
      </div>
    );
  }
  return (
    <div>
      {habits.map((g, gi) => (
        g.items.length === 0 ? null : (
          <div key={g.g} style={{ marginBottom: gi < habits.length - 1 ? 12 : 0 }}>
            <div style={{ fontSize: 10, fontWeight: 600, letterSpacing: '.08em', color: 'var(--fg-3)', textTransform: 'uppercase', marginBottom: 8 }}>{g.g}</div>
            {g.items.map(it => (
              <div key={it.id} onClick={() => toggleHabit(it.id)} className="tap" style={{ display: 'flex', alignItems: 'center', gap: 10, padding: '6px 0', cursor: 'pointer' }}>
                <div style={{ width: 16, height: 16, borderRadius: 5, border: '1.5px solid ' + (it.d ? 'var(--blue)' : 'var(--line-2)'), background: it.d ? 'var(--blue)' : 'var(--bg-card)', display: 'flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>{it.d && Ico.check}</div>
                <span style={{ fontSize: 13, color: it.d ? 'var(--fg-3)' : 'var(--fg)', textDecoration: it.d ? 'line-through' : 'none', flex: 1, letterSpacing: '-.005em' }}>{it.t}</span>
              </div>
            ))}
          </div>
        )
      ))}
    </div>
  );
}

function TradesMiniTable({ trades, openJournal }) {
  return (
    <div>
      <div style={{ display: 'grid', gridTemplateColumns: '54px 56px 30px 90px 90px 1fr 70px 90px', padding: '8px 4px', borderBottom: '1px solid var(--line)', gap: 4 }}>
        {['DATE', 'SYM', 'D', 'ENTRY', 'EXIT', 'SETUP', 'R', 'P&L'].map((h, i) => (
          <span key={h} style={{ fontSize: 10, fontWeight: 600, color: 'var(--fg-3)', letterSpacing: '.06em', textAlign: i === 7 ? 'right' : 'left' }}>{h}</span>
        ))}
      </div>
      {trades.map(t => (
        <div key={t.id} className="tap" onClick={() => openJournal && openJournal(t)} style={{
          display: 'grid', gridTemplateColumns: '54px 56px 30px 90px 90px 1fr 70px 90px',
          padding: '12px 4px', borderBottom: '1px solid var(--line)', alignItems: 'center', cursor: 'pointer',
          transition: 'background .15s var(--ease)', gap: 4,
        }} onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-soft)'} onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
          <span style={{ fontSize: 12, color: 'var(--fg-2)' }}>{t.date}</span>
          <span style={{ fontSize: 13, fontWeight: 600 }}>{t.sym}</span>
          <span className="pill" style={{
            background: t.dir === 'L' ? 'var(--green-soft)' : 'var(--red-soft)',
            color: t.dir === 'L' ? 'var(--green-text)' : 'var(--red-text)',
            border: 'none', padding: '2px 6px', fontSize: 10, fontWeight: 600, borderRadius: 4, width: 22, justifyContent: 'center',
          }}>{t.dir}</span>
          <span className="mono" style={{ fontSize: 11.5, color: 'var(--fg-2)' }}>{t.entry}</span>
          <span className="mono" style={{ fontSize: 11.5, color: 'var(--fg-2)' }}>{t.exit}</span>
          <span style={{ fontSize: 12.5, color: 'var(--fg-2)' }}>{t.setup}</span>
          <span className={'mono ' + (t.r >= 0 ? 'pos' : 'neg')} style={{ fontSize: 12, fontWeight: 500 }}>{t.r >= 0 ? '+' : ''}{t.r.toFixed(1)}R</span>
          <span className={'num ' + (t.pnl >= 0 ? 'pos' : 'neg')} style={{ fontSize: 14, fontWeight: 600, textAlign: 'right', letterSpacing: '-.018em' }}>{t.pnl >= 0 ? '+$' : '−$'}{Math.abs(t.pnl)}</span>
        </div>
      ))}
    </div>
  );
}

function TradesMiniTableReal({ trades, openJournal, openTrade }) {
  const handleClick = (t) => {
    if (openTrade) return openTrade(t);
    if (openJournal) return openJournal(t.executed_at);
  };
  return (
    <div>
      <div style={{ display: 'grid', gridTemplateColumns: '90px 60px 30px 90px 90px 1fr 60px 90px', padding: '8px 4px', borderBottom: '1px solid var(--line)', gap: 4 }}>
        {['DATE', 'SYM', 'D', 'ENTRY', 'EXIT', 'SETUP', 'R', 'P&L'].map((h, i) => (
          <span key={h} style={{ fontSize: 10, fontWeight: 600, color: 'var(--fg-3)', letterSpacing: '.06em', textAlign: i === 7 ? 'right' : 'left' }}>{h}</span>
        ))}
      </div>
      {trades.map(t => {
        const pnl = Number(t.pnl) || 0;
        const r   = Number(t.r_multiple);
        const dirLetter = t.direction === 'short' ? 'S' : 'L';
        return (
          <div key={t.id} className="tap" onClick={() => handleClick(t)} style={{
            display: 'grid', gridTemplateColumns: '90px 60px 30px 90px 90px 1fr 60px 90px',
            padding: '12px 4px', borderBottom: '1px solid var(--line)', alignItems: 'center', cursor: 'pointer',
            transition: 'background .15s var(--ease)', gap: 4,
          }} onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-soft)'} onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
            <span style={{ fontSize: 12, color: 'var(--fg-2)' }}>{fmtShortDate(t.executed_at)}</span>
            <span style={{ fontSize: 13, fontWeight: 600 }}>{t.symbol || '—'}</span>
            <span className="pill" style={{
              background: dirLetter === 'L' ? 'var(--green-soft)' : 'var(--red-soft)',
              color: dirLetter === 'L' ? 'var(--green-text)' : 'var(--red-text)',
              border: 'none', padding: '2px 6px', fontSize: 10, fontWeight: 600, borderRadius: 4, width: 22, justifyContent: 'center',
            }}>{dirLetter}</span>
            <span className="mono" style={{ fontSize: 11.5, color: 'var(--fg-2)' }}>{t.entry ?? '—'}</span>
            <span className="mono" style={{ fontSize: 11.5, color: 'var(--fg-2)' }}>{t.exit_price ?? '—'}</span>
            <span style={{ fontSize: 12.5, color: 'var(--fg-2)' }}>{t.setup || '—'}</span>
            <span className={'mono ' + (r >= 0 ? 'pos' : 'neg')} style={{ fontSize: 12, fontWeight: 500 }}>{Number.isFinite(r) ? (r >= 0 ? '+' : '') + r.toFixed(1) + 'R' : '—'}</span>
            <span className={'num ' + (pnl >= 0 ? 'pos' : 'neg')} style={{ fontSize: 14, fontWeight: 600, textAlign: 'right', letterSpacing: '-.018em' }}>{fmtMoney(pnl, true)}</span>
          </div>
        );
      })}
    </div>
  );
}

function NavTile({ nav, to, title, desc, ico, onClick }) {
  return (
    <button onClick={onClick ? onClick : () => nav(to)} className="card lift tap" style={{
      padding: '18px 18px',
      border: '1px solid var(--line)', borderRadius: 12,
      cursor: 'pointer', textAlign: 'left',
      display: 'flex', flexDirection: 'column', gap: 8,
      background: 'var(--bg-card)', fontFamily: 'inherit',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
        <div style={{ width: 32, height: 32, borderRadius: 8, background: 'var(--blue-soft)', color: 'var(--blue-600)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>
          {React.cloneElement(ico, { width: 16, height: 16 })}
        </div>
        <span style={{ fontSize: 14, fontWeight: 600, flex: 1, letterSpacing: '-.01em' }}>{title}</span>
        <span style={{ color: 'var(--fg-3)' }}>{Ico.chev}</span>
      </div>
      <p style={{ fontSize: 12, color: 'var(--fg-3)', margin: 0, marginLeft: 42, lineHeight: 1.4, letterSpacing: '-.005em' }}>{desc}</p>
    </button>
  );
}

// ─── DAILY JOURNAL list page ──────────────────────────────────────
function Daily({ nav, openJournal, openImport, state }) {
  const [tab, setTab] = React.useState('all');
  const { tradesByDay, tradesLoading, today } = state || { tradesByDay: {}, tradesLoading: false, today: todayISO() };

  // Build day list: every day with trades, sorted desc. Always include today first.
  const dayList = React.useMemo(() => {
    const days = Object.keys(tradesByDay).sort().reverse();
    if (!days.includes(today)) days.unshift(today);
    return days.slice(0, 30).map(day => {
      const data = tradesByDay[day] || { trades: [], pnl: 0, wins: 0, losses: 0 };
      const trades = data.trades || [];
      const wr = trades.length > 0 ? Math.round((data.wins / trades.length) * 100) : 0;
      let totalWin = 0, totalLoss = 0;
      for (const t of trades) {
        const p = Number(t.pnl) || 0;
        if (p > 0) totalWin += p;
        else if (p < 0) totalLoss += Math.abs(p);
      }
      const pf = totalLoss > 0 ? totalWin / totalLoss : (totalWin > 0 ? Infinity : 0);
      return {
        day, // ISO date
        date: fmtLongDate(day),
        p: data.pnl,
        t: trades.length,
        w: data.wins,
        l: data.losses,
        wr,
        pf: Number.isFinite(pf) ? pf : 0,
      };
    });
  }, [tradesByDay, today]);

  return (
    <div className="scroll" style={{ width: '100%', height: '100%', overflow: 'auto' }}>
      <PageHeader title="Daily Journal"/>
      <div style={{ padding: '20px 24px 40px' }}>
        <div style={{ marginBottom: 18 }}>
          <FilterBar
            activeTab={tab} setActiveTab={setTab}
            tabs={[
              { id: 'all',      label: 'Tous',     ico: null },
              { id: 'verified', label: 'Avec trades', ico: <span style={{ width: 14, height: 14, borderRadius: 999, background: 'var(--green)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', color: '#fff' }}>{Ico.check}</span> },
            ]}
            right={[
              <button key="new" onClick={openImport} className="btn btn-blue tap">{Ico.plus} Nouveau trade</button>,
            ]}
          />
        </div>

        {tradesLoading ? (
          <div style={{ fontSize: 12, color: 'var(--fg-3)', padding: '20px 0', textAlign: 'center' }}>Chargement…</div>
        ) : dayList.length === 0 || (dayList.length === 1 && dayList[0].t === 0) ? (
          <div className="card" style={{ padding: '40px 24px', textAlign: 'center' }}>
            <div style={{ fontSize: 14, color: 'var(--fg-2)', marginBottom: 6 }}>Aucun journal pour l'instant</div>
            <div style={{ fontSize: 12, color: 'var(--fg-3)', marginBottom: 16 }}>Tes journaux apparaîtront ici dès que tu auras ajouté des trades.</div>
            <button onClick={openImport} className="btn btn-blue tap">{Ico.plus} Ajouter un trade</button>
          </div>
        ) : (
          <div className="stagger" style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
            {dayList.filter(d => tab === 'all' || d.t > 0).map((d, i) => (
              <DayJournalCard key={d.day} day={d} highlight={d.day === today} openJournal={openJournal}/>
            ))}
          </div>
        )}
      </div>
    </div>
  );
}

function DayJournalCard({ day, highlight, openJournal }) {
  const hasTrades = day.t > 0;
  const tone = day.p > 0 ? 'pos' : (day.p < 0 ? 'neg' : 'flat');
  return (
    <div className="card lift" style={{
      padding: '24px 28px',
      border: highlight ? '1.5px solid var(--blue)' : '1px solid var(--line)',
      boxShadow: highlight ? '0 0 0 3px rgba(59,130,246,0.08)' : 'none',
      display: 'grid', gridTemplateColumns: '200px 1fr 130px',
      gap: 24, alignItems: 'center',
    }}>
      <div>
        <div style={{ fontSize: 18, fontWeight: 600, letterSpacing: '-.015em' }}>{day.date}</div>
        <div style={{ marginTop: 8, height: 2, width: 60, background: 'var(--line-2)', borderRadius: 2 }}></div>
        {highlight && <div style={{ marginTop: 12 }}><span className="pill pill-blue" style={{ padding: '3px 9px', fontSize: 10.5 }}>Aujourd'hui</span></div>}
      </div>

      <div style={{ display: 'grid', gridTemplateColumns: 'repeat(3, 1fr) repeat(3, 1fr)', gap: 20 }}>
        <DayMetric label="P&L" value={hasTrades ? (day.p >= 0 ? `+$${day.p.toLocaleString('fr-FR')}` : `−$${Math.abs(day.p).toLocaleString('fr-FR')}`) : '$0,00'} tone={tone} big/>
        <DayMetric label="Trades" value={day.t} sub="Total"/>
        <DayMetric label="Wins" value={day.w} tone={day.w > 0 ? 'pos' : null}/>
        <DayMetric label="Losses" value={day.l} tone={day.l > 0 ? 'neg' : null}/>
        <DayMetric label="Win Rate" value={hasTrades ? `${day.wr}%` : '0%'}/>
        <DayMetric label="Profit Factor" value={hasTrades ? day.pf.toFixed(2).replace('.', ',') : '0,0'}/>
      </div>

      <div style={{ display: 'flex', flexDirection: 'column', gap: 8, alignItems: 'flex-end' }}>
        <button onClick={() => openJournal && openJournal(day.day)} className="btn btn-outline-blue tap">
          {Ico.book} Journal
        </button>
      </div>
    </div>
  );
}

function DayMetric({ label, value, sub, tone, big }) {
  const color = tone === 'pos' ? 'var(--green)' : (tone === 'neg' ? 'var(--red)' : 'var(--fg)');
  return (
    <div>
      <div style={{ fontSize: 10.5, fontWeight: 600, color: 'var(--fg-3)', letterSpacing: '.04em', textTransform: 'uppercase', marginBottom: 6 }}>{label}</div>
      <div className="num" style={{ fontSize: big ? 22 : 18, fontWeight: 600, color, letterSpacing: '-.018em', lineHeight: 1 }}>{value}</div>
      {sub && <div style={{ fontSize: 10, color: 'var(--fg-4)', marginTop: 4 }}>{sub}</div>}
    </div>
  );
}

// ─── Journal modal — Statistics / Notes / Trades / Attachments ───
function JournalModal({ open, dayISO, onClose, state, openImport, openTrade }) {
  const [tab, setTab] = React.useState('stats');
  const [notes, setNotesLocal] = React.useState('');
  const [mood, setMoodLocal] = React.useState(null);
  const [attachments, setAttachments] = React.useState([]);
  const [loadingJournal, setLoadingJournal] = React.useState(false);
  const [uploading, setUploading] = React.useState(false);
  const [drag, setDrag] = React.useState(false);
  const [previews, setPreviews] = React.useState({}); // file_path → signedUrl
  // Internal navigation state seeded from the dayISO prop. Updating this with the prev/next
  // arrows shifts the viewed day without closing the modal.
  const [currentDay, setCurrentDay] = React.useState(dayISO || null);
  const inputRef = React.useRef(null);
  const saveTimer = React.useRef(null);

  // When the modal is (re)opened from a calendar cell, snap currentDay back to that prop.
  React.useEffect(() => {
    if (open && dayISO) setCurrentDay(dayISO);
  }, [open, dayISO]);

  React.useEffect(() => {
    if (!open || !currentDay || !state) return;
    let live = true;
    setLoadingJournal(true);
    // Reset previews so old images don't linger across day switches
    setPreviews({});
    (async () => {
      const [journal, atts] = await Promise.all([
        state.getDayJournal(currentDay),
        state.getDayAttachments(currentDay),
      ]);
      if (!live) return;
      setNotesLocal(journal?.notes || '');
      setMoodLocal(journal?.mood ?? null);
      setAttachments(atts || []);
      setLoadingJournal(false);
      // Pre-fetch signed URLs for image previews
      (atts || []).forEach(async (a) => {
        if (!a.mime_type || !a.mime_type.startsWith('image/')) return;
        const url = await state.getAttachmentUrl(a.file_path);
        if (url && live) setPreviews(prev => ({ ...prev, [a.file_path]: url }));
      });
    })();
    return () => { live = false; };
  }, [open, currentDay]);

  if (!open) return null;

  // Shift currentDay by N days (negative for previous, positive for next).
  const shiftDay = (delta) => {
    if (!currentDay) return;
    // Parse YYYY-MM-DD as a UTC date to avoid DST surprises on add/subtract, then format back.
    const m = /^(\d{4})-(\d{2})-(\d{2})/.exec(currentDay);
    if (!m) return;
    const d = new Date(Date.UTC(+m[1], +m[2] - 1, +m[3]));
    d.setUTCDate(d.getUTCDate() + delta);
    const y = d.getUTCFullYear();
    const mo = String(d.getUTCMonth() + 1).padStart(2, '0');
    const da = String(d.getUTCDate()).padStart(2, '0');
    setCurrentDay(`${y}-${mo}-${da}`);
    // Flush any pending notes save so they belong to the day we are leaving, not the new one.
    if (saveTimer.current) { clearTimeout(saveTimer.current); saveTimer.current = null; }
  };

  const debouncedSaveNotes = (v) => {
    setNotesLocal(v);
    if (saveTimer.current) clearTimeout(saveTimer.current);
    const day = currentDay;
    saveTimer.current = setTimeout(() => { state?.setDayJournalNotes(day, v); }, 500);
  };
  const setMood = (v) => {
    setMoodLocal(v);
    state?.setDayJournalMood(currentDay, v);
  };
  const addAttach = async (f) => {
    setUploading(true);
    const { data, error } = await state.uploadDayAttachment(currentDay, f);
    setUploading(false);
    if (error) { alert('Upload échoué: ' + (error.message || 'inconnu')); return; }
    setAttachments(prev => [data, ...prev]);
    if (data.mime_type?.startsWith('image/')) {
      const url = await state.getAttachmentUrl(data.file_path);
      if (url) setPreviews(prev => ({ ...prev, [data.file_path]: url }));
    }
  };
  const removeAttach = async (id) => {
    const att = attachments.find(a => a.id === id);
    setAttachments(prev => prev.filter(a => a.id !== id));
    await state.deleteDayAttachment(currentDay, id);
    if (att) setPreviews(prev => { const n = { ...prev }; delete n[att.file_path]; return n; });
  };

  // Day stats from DB trades — use currentDay so prev/next arrows update the table too.
  const dayTrades = (state?.tradesByDay?.[currentDay]?.trades) || [];
  const hasTrades = dayTrades.length > 0;
  let netPnl = 0, wins = 0, losses = 0, best = -Infinity, worst = Infinity, totalWin = 0, totalLoss = 0;
  for (const t of dayTrades) {
    const p = Number(t.pnl) || 0;
    netPnl += p;
    if (p > 0) { wins++; totalWin += p; }
    else if (p < 0) { losses++; totalLoss += Math.abs(p); }
    if (p > best)  best = p;
    if (p < worst) worst = p;
  }
  const winRate = hasTrades ? Math.round((wins / dayTrades.length) * 100) : 0;
  const pf = totalLoss > 0 ? (totalWin / totalLoss).toFixed(2).replace('.', ',') : (totalWin > 0 ? '∞' : '0,00');
  const date = fmtLongDate(currentDay);

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 200,
      background: 'rgba(15,23,42,0.34)',
      backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 40, animation: 'fade-in .25s var(--ease)',
      overflowY: 'auto',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: 880, maxHeight: '90%',
        background: 'var(--bg-card)', borderRadius: 16,
        overflow: 'hidden', display: 'flex', flexDirection: 'column',
        boxShadow: '0 24px 48px rgba(0,0,0,.20)',
        animation: 'fade-up .35s var(--ease)',
      }}>
        {/* Modal header */}
        <div style={{ padding: '20px 24px 16px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 14 }}>
            <button onClick={() => shiftDay(-1)} title="Jour précédent" className="tap" style={{ width: 28, height: 28, borderRadius: 8, border: '1px solid var(--line)', background: 'var(--bg-card)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', color: 'var(--fg-2)' }}>{Ico.arrL}</button>
            <span style={{ fontSize: 17, fontWeight: 600, letterSpacing: '-.015em' }}>{date}</span>
            <button onClick={() => shiftDay(1)} title="Jour suivant" className="tap" style={{ width: 28, height: 28, borderRadius: 8, border: '1px solid var(--line)', background: 'var(--bg-card)', display: 'flex', alignItems: 'center', justifyContent: 'center', cursor: 'pointer', color: 'var(--fg-2)' }}>{Ico.arrR}</button>
          </div>
          <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
            {/* Bouton clair pour ajouter un trade DIRECTEMENT sur ce jour (pré-rempli). */}
            <button onClick={() => { openImport && openImport(currentDay); onClose(); }} className="btn btn-blue tap" title="Ajouter un trade à cette date">{Ico.plus} Ajouter un trade</button>
            <button onClick={onClose} className="tap" style={{ width: 28, height: 28, borderRadius: 8, border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--fg-2)', display: 'flex', alignItems: 'center', justifyContent: 'center' }}>{Ico.x}</button>
          </div>
        </div>

        {/* Tabs */}
        <div style={{ padding: '14px 24px 0' }}>
          <div style={{ display: 'inline-flex', gap: 4, padding: 4, background: 'var(--bg-elev)', borderRadius: 10 }}>
            {[
              { id: 'stats', l: 'Statistiques' },
              { id: 'notes', l: 'Notes' },
              { id: 'trades', l: 'Trades', count: dayTrades.length },
              { id: 'attach', l: 'Pièces jointes', count: attachments.length },
            ].map(t => (
              <button key={t.id} onClick={() => setTab(t.id)} className="tap" style={{
                background: tab === t.id ? 'var(--bg-card)' : 'transparent',
                color: tab === t.id ? 'var(--blue-600)' : 'var(--fg-2)',
                border: tab === t.id ? '1.5px solid var(--blue)' : '1.5px solid transparent',
                borderRadius: 7, padding: '5px 14px', fontSize: 12.5, fontWeight: tab === t.id ? 600 : 500,
                letterSpacing: '-.005em', cursor: 'pointer', fontFamily: 'inherit',
                display: 'inline-flex', alignItems: 'center', gap: 6,
              }}>
                {t.l}
                {t.count != null && t.count > 0 && (
                  <span style={{ background: tab === t.id ? 'var(--blue-soft)' : 'var(--bg-elev)', color: tab === t.id ? 'var(--blue-600)' : 'var(--fg-3)', borderRadius: 999, padding: '1px 7px', fontSize: 10, fontWeight: 600 }}>{t.count}</span>
                )}
              </button>
            ))}
          </div>
        </div>

        {/* Tab content */}
        <div className="scroll" style={{ flex: 1, overflow: 'auto', padding: '20px 24px' }}>
          {tab === 'stats' && (
            <div>
              <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 14, letterSpacing: '-.01em' }}>Statistiques de la journée</div>
              {hasTrades ? (
                <div style={{ display: 'grid', gridTemplateColumns: 'repeat(4, 1fr)', gap: 14 }}>
                  <ModalStat label="P&L net" value={fmtMoney(netPnl, true)} pos={netPnl > 0} neg={netPnl < 0}/>
                  <ModalStat label="Trades" value={dayTrades.length}/>
                  <ModalStat label="Win Rate" value={`${winRate}%`}/>
                  <ModalStat label="Profit Factor" value={pf}/>
                  <ModalStat label="Wins / Losses" value={`${wins} / ${losses}`}/>
                  <ModalStat label="Best Trade" value={fmtMoney(best === -Infinity ? 0 : best, true)} pos={best > 0}/>
                  <ModalStat label="Worst Trade" value={fmtMoney(worst === Infinity ? 0 : worst, true)} neg={worst < 0}/>
                  <ModalStat label="Volume" value={`${dayTrades.reduce((s, t) => s + (Number(t.lots) || 0), 0)} lots`}/>
                </div>
              ) : (
                <div style={{ padding: '40px 0', textAlign: 'center', color: 'var(--fg-3)' }}>
                  <svg width="48" height="48" viewBox="0 0 48 48" style={{ margin: '0 auto 12px' }}>
                    <rect x="8" y="12" width="32" height="28" rx="3" fill="none" stroke="currentColor" strokeWidth="1.5"/>
                    <path d="M8 20h32M16 8v4M32 8v4" stroke="currentColor" strokeWidth="1.5" strokeLinecap="round"/>
                  </svg>
                  <div style={{ fontSize: 14, color: 'var(--fg-2)', marginBottom: 6 }}>Aucune activité de trading ce jour</div>
                  <div style={{ fontSize: 12, color: 'var(--fg-3)' }}>Tu peux quand même rédiger un journal personnel.</div>
                </div>
              )}
              <div style={{ marginTop: 28, paddingTop: 20, borderTop: '1px solid var(--line)' }}>
                <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 12, letterSpacing: '-.01em' }}>Mood &amp; énergie</div>
                <MoodBlock mood={mood} setMood={setMood}/>
              </div>
            </div>
          )}
          {tab === 'notes' && (
            <div>
              <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 14, letterSpacing: '-.01em' }}>Notes de la journée</div>
              {loadingJournal ? (
                <div style={{ fontSize: 12, color: 'var(--fg-3)', padding: '12px 0' }}>Chargement…</div>
              ) : (
                <textarea
                  value={notes} onChange={e => debouncedSaveNotes(e.target.value)}
                  placeholder="Écris tes notes du jour ici… Qu'est-ce qui s'est bien passé ? Qu'est-ce que tu peux améliorer ?"
                  style={{
                    width: '100%', minHeight: 220, padding: '14px 16px',
                    border: '1px solid var(--line)', borderRadius: 10,
                    fontFamily: 'inherit', fontSize: 13.5, lineHeight: 1.6,
                    color: 'var(--fg)', resize: 'vertical', outline: 'none', background: 'var(--bg-card)',
                  }}/>
              )}
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: 10 }}>
                <span style={{ fontSize: 11.5, color: 'var(--fg-3)' }}>{notes.length} caractères · auto-save activé</span>
              </div>
            </div>
          )}
          {tab === 'trades' && (
            <div>
              <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 14, letterSpacing: '-.01em' }}>Trades du jour</div>
              {hasTrades ? <TradesMiniTableReal trades={dayTrades} openTrade={openTrade} openJournal={() => {}}/> : (
                <div style={{ padding: '40px 0', textAlign: 'center', color: 'var(--fg-3)' }}>
                  <div style={{ fontSize: 14, color: 'var(--fg-2)', marginBottom: 6 }}>Pas de trades enregistrés ce jour</div>
                  <div style={{ fontSize: 12, color: 'var(--fg-3)', marginBottom: 18 }}>Ajoute un trade manuellement ou importe un CSV.</div>
                  <button onClick={() => { openImport && openImport(currentDay); onClose(); }} className="btn btn-blue tap">{Ico.plus} Ajouter un trade</button>
                </div>
              )}
            </div>
          )}
          {tab === 'attach' && (
            <div>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'baseline', marginBottom: 14 }}>
                <div style={{ fontSize: 14, fontWeight: 600, letterSpacing: '-.01em' }}>Pièces jointes <span style={{ fontSize: 11, color: 'var(--fg-3)', fontWeight: 500, marginLeft: 6 }}>{attachments.length}</span></div>
                <button onClick={() => inputRef.current && inputRef.current.click()} className="btn btn-outline-blue tap" disabled={uploading}>{Ico.upload} {uploading ? 'Upload…' : 'Uploader'}</button>
                <input ref={inputRef} type="file" accept="image/*" multiple style={{ display: 'none' }}
                  onChange={e => { Array.from(e.target.files || []).forEach(f => addAttach(f)); e.target.value = ''; }}/>
              </div>

              <div
                onDragOver={e => { e.preventDefault(); setDrag(true); }}
                onDragLeave={() => setDrag(false)}
                onDrop={e => { e.preventDefault(); setDrag(false); Array.from(e.dataTransfer.files || []).forEach(f => addAttach(f)); }}
                onClick={() => inputRef.current && inputRef.current.click()}
                style={{
                  border: '1.5px dashed ' + (drag ? 'var(--blue)' : 'var(--line-2)'),
                  background: drag ? 'var(--blue-soft)' : 'var(--bg-soft)',
                  borderRadius: 12, padding: '32px 20px', textAlign: 'center',
                  color: 'var(--fg-2)', cursor: 'pointer', transition: 'all .15s var(--ease)',
                }}>
                <svg width="36" height="36" viewBox="0 0 42 42" style={{ margin: '0 auto 10px', color: drag ? 'var(--blue)' : 'var(--fg-3)' }}>
                  <rect x="6" y="8" width="30" height="22" rx="3" fill="none" stroke="currentColor" strokeWidth="1.5"/>
                  <circle cx="14" cy="16" r="2.5" fill="none" stroke="currentColor" strokeWidth="1.5"/>
                  <path d="M6 26l8-8 6 6 4-4 12 10" fill="none" stroke="currentColor" strokeWidth="1.5"/>
                </svg>
                <div style={{ fontSize: 13.5, fontWeight: 600, color: drag ? 'var(--blue-600)' : 'var(--fg)', marginBottom: 4 }}>
                  {drag ? 'Relâche pour ajouter' : (uploading ? 'Upload en cours…' : 'Glisse tes screenshots ici')}
                </div>
                <div style={{ fontSize: 11.5, color: 'var(--fg-2)' }}>ou clique · PNG, JPG, GIF · multiple OK</div>
              </div>

              {attachments.length > 0 && (
                <div style={{ marginTop: 14, display: 'grid', gridTemplateColumns: 'repeat(3, 1fr)', gap: 10 }}>
                  {attachments.map(a => {
                    const previewUrl = previews[a.file_path];
                    const isImage = (a.mime_type || '').startsWith('image/');
                    return (
                      <div key={a.id} style={{ position: 'relative', borderRadius: 10, border: '1px solid var(--line)', overflow: 'hidden', background: 'var(--bg-soft)' }}>
                        <div style={{ height: 110, display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'linear-gradient(135deg, var(--bg-elev), var(--bg-soft))', color: 'var(--fg-3)' }}>
                          {isImage && previewUrl ? (
                            <img src={previewUrl} alt={a.file_name} style={{ width: '100%', height: '100%', objectFit: 'cover' }}/>
                          ) : (
                            React.cloneElement(Ico.data, { width: 28, height: 28 })
                          )}
                        </div>
                        <div style={{ padding: '8px 10px', borderTop: '1px solid var(--line)' }}>
                          <div style={{ fontSize: 11.5, fontWeight: 500, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>{a.file_name}</div>
                          <div style={{ fontSize: 10, color: 'var(--fg-3)', marginTop: 2 }}>{(Number(a.size_bytes) / 1024).toFixed(0)} ko</div>
                        </div>
                        <button onClick={(e) => { e.stopPropagation(); removeAttach(a.id); }} className="tap" style={{
                          position: 'absolute', top: 6, right: 6,
                          width: 22, height: 22, borderRadius: 6, border: 'none',
                          background: 'rgba(15,23,42,0.65)', color: '#fff', cursor: 'pointer',
                          display: 'flex', alignItems: 'center', justifyContent: 'center',
                        }}>{Ico.x}</button>
                      </div>
                    );
                  })}
                </div>
              )}
            </div>
          )}
        </div>

        {/* Modal footer */}
        <div style={{ padding: '14px 24px', borderTop: '1px solid var(--line)', display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: 10, background: 'var(--bg-soft)' }}>
          <span style={{ fontSize: 11, color: 'var(--fg-3)' }}>Tes modifications sont sauvegardées automatiquement.</span>
          <button onClick={onClose} className="btn btn-blue tap">{Ico.check} Fermer</button>
        </div>
      </div>
    </div>
  );
}

function ModalStat({ label, value, pos, neg }) {
  return (
    <div className="card" style={{ padding: '14px 16px', background: 'var(--bg-soft)', border: '1px solid var(--line)' }}>
      <div style={{ fontSize: 10.5, fontWeight: 600, color: 'var(--fg-3)', letterSpacing: '.04em', textTransform: 'uppercase', marginBottom: 6 }}>{label}</div>
      <div className="num" style={{ fontSize: 18, fontWeight: 600, letterSpacing: '-.018em', color: pos ? 'var(--green)' : (neg ? 'var(--red)' : 'var(--fg)') }}>{value}</div>
    </div>
  );
}

function MoodBlock({ mood, setMood }) {
  const m = mood;
  return (
    <div>
      <div style={{ display: 'flex', gap: 8 }}>
        {[1, 2, 3, 4, 5].map(n => (
          <button key={n} onClick={() => setMood(n)} className="tap" style={{
            flex: 1, padding: '12px 0', border: '1.5px solid ' + (m === n ? 'var(--blue)' : 'var(--line)'),
            background: m === n ? 'var(--blue-soft)' : 'var(--bg-card)',
            color: m === n ? 'var(--blue-600)' : 'var(--fg-2)',
            borderRadius: 9, fontSize: 18, fontWeight: 600, cursor: 'pointer', fontFamily: 'inherit',
            letterSpacing: '-.01em',
          }}>{n}</button>
        ))}
      </div>
      <div style={{ display: 'flex', justifyContent: 'space-between', marginTop: 8, fontSize: 11, color: 'var(--fg-3)' }}>
        <span>Frustré</span>
        <span>Neutre</span>
        <span>Excellent</span>
      </div>
    </div>
  );
}

// ─── Trade detail modal (view / edit / delete a single trade) ────
function TradeDetailModal({ open, trade, onClose, state }) {
  const [mode, setMode] = React.useState('view'); // 'view' | 'edit'
  const [busy, setBusy] = React.useState(false);
  const [error, setError] = React.useState('');
  const [confirmDelete, setConfirmDelete] = React.useState(false);

  const toDtLocal = (iso) => {
    if (!iso) return '';
    const d = new Date(iso);
    if (isNaN(d.getTime())) return '';
    const y = d.getFullYear(), m = String(d.getMonth() + 1).padStart(2, '0'), dd = String(d.getDate()).padStart(2, '0');
    const hh = String(d.getHours()).padStart(2, '0'), mm = String(d.getMinutes()).padStart(2, '0');
    return `${y}-${m}-${dd}T${hh}:${mm}`;
  };

  const [form, setForm] = React.useState(() => ({
    symbol: '', direction: 'long',
    entry: '', exit_price: '',
    lots: '', pnl: '', r_multiple: '',
    executed_at: '', setup: '', notes: '',
  }));

  // Reset state when modal opens/closes
  React.useEffect(() => {
    if (!open) {
      setMode('view'); setError(''); setConfirmDelete(false); setBusy(false);
      return;
    }
    if (trade) {
      setForm({
        symbol: trade.symbol || '',
        direction: trade.direction || 'long',
        entry: trade.entry ?? '',
        exit_price: trade.exit_price ?? '',
        lots: trade.lots ?? '',
        pnl: trade.pnl ?? '',
        r_multiple: trade.r_multiple ?? '',
        executed_at: toDtLocal(trade.executed_at),
        setup: trade.setup || '',
        notes: trade.notes || '',
      });
    }
  }, [open, trade?.id]);

  if (!open || !trade) return null;

  const upd = (k) => (e) => setForm(f => ({ ...f, [k]: e.target.value }));

  const toNumOrNull = (v) => {
    if (v === null || v === undefined || v === '') return null;
    const s = String(v).replace(/\s/g, '').replace(',', '.');
    const n = parseFloat(s);
    return Number.isFinite(n) ? n : null;
  };

  const submitEdit = async (e) => {
    e.preventDefault();
    if (!form.symbol.trim()) { setError('Le symbole est obligatoire.'); return; }
    setBusy(true); setError('');
    // Build a clean update payload using DB column names — updateTrade strips id/user_id/created_at.
    let executedISO = trade.executed_at;
    if (form.executed_at) {
      const d = new Date(form.executed_at);
      if (!isNaN(d.getTime())) executedISO = d.toISOString();
    }
    const payload = {
      symbol: String(form.symbol).toUpperCase().trim(),
      direction: form.direction === 'short' ? 'short' : 'long',
      entry: toNumOrNull(form.entry),
      exit_price: toNumOrNull(form.exit_price),
      lots: toNumOrNull(form.lots),
      pnl: toNumOrNull(form.pnl) ?? 0,
      r_multiple: toNumOrNull(form.r_multiple),
      setup: form.setup ? form.setup.trim() : null,
      notes: form.notes ? form.notes : null,
      executed_at: executedISO,
    };
    const { error: err } = await window.updateTrade(trade.id, payload);
    setBusy(false);
    if (err) { setError('Erreur: ' + (err.message || 'mise à jour échouée')); return; }
    if (state?.refreshTrades) await state.refreshTrades();
    setMode('view');
    onClose && onClose();
  };

  const doDelete = async () => {
    setBusy(true); setError('');
    const { error: err } = await window.deleteTrade(trade.id);
    setBusy(false);
    if (err) { setError('Erreur: ' + (err.message || 'suppression échouée')); return; }
    if (state?.refreshTrades) await state.refreshTrades();
    onClose && onClose();
  };

  const pnl = Number(trade.pnl) || 0;
  const r = Number(trade.r_multiple);
  const dirLabel = trade.direction === 'short' ? 'SHORT' : 'LONG';

  return (
    <div onClick={onClose} style={{
      position: 'fixed', inset: 0, zIndex: 220,
      background: 'rgba(15,23,42,0.40)',
      backdropFilter: 'blur(8px)', WebkitBackdropFilter: 'blur(8px)',
      display: 'flex', alignItems: 'center', justifyContent: 'center',
      padding: 24, animation: 'fade-in .25s var(--ease)',
    }}>
      <div onClick={e => e.stopPropagation()} style={{
        width: '100%', maxWidth: 640, maxHeight: '92%',
        background: 'var(--bg-card)', borderRadius: 16,
        overflow: 'hidden', display: 'flex', flexDirection: 'column',
        boxShadow: '0 28px 56px rgba(0,0,0,.24)',
        animation: 'fade-up .35s var(--ease)',
      }}>
        {/* Header */}
        <div style={{ padding: '18px 22px', borderBottom: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 12 }}>
            <div style={{ width: 36, height: 36, borderRadius: 8, background: 'var(--bg-elev)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 11, fontWeight: 700, color: 'var(--fg-2)' }}>{(trade.symbol || '').slice(0, 2)}</div>
            <div>
              <div style={{ fontSize: 15, fontWeight: 700, letterSpacing: '-.015em' }}>{trade.symbol || '—'} · <span style={{ color: trade.direction === 'short' ? 'var(--red)' : 'var(--green)', fontWeight: 600 }}>{dirLabel}</span></div>
              <div style={{ fontSize: 11.5, color: 'var(--fg-3)', marginTop: 2 }}>{fmtShortDate(trade.executed_at)}{trade.imported_from ? ' · ' + trade.imported_from : ''}</div>
            </div>
          </div>
          <button onClick={onClose} className="tap" style={{ width: 28, height: 28, borderRadius: 8, border: 'none', background: 'transparent', cursor: 'pointer', color: 'var(--fg-2)' }}>{Ico.x}</button>
        </div>

        {/* Body */}
        <div className="scroll" style={{ flex: 1, overflow: 'auto', padding: '18px 22px' }}>
          {error && (
            <div style={{ marginBottom: 12, padding: '8px 12px', borderRadius: 8, background: 'var(--red-soft)', color: 'var(--red-text)', fontSize: 12.5, border: '1px solid var(--line)' }}>{error}</div>
          )}

          {mode === 'view' && (
            <div>
              <div style={{ display: 'grid', gridTemplateColumns: 'repeat(2, 1fr)', gap: 12, marginBottom: 16 }}>
                <ModalStat label="P&L" value={fmtMoney(pnl, true)} pos={pnl > 0} neg={pnl < 0}/>
                <ModalStat label="R-multiple" value={Number.isFinite(r) ? (r >= 0 ? '+' : '') + r.toFixed(2) + 'R' : '—'} pos={r > 0} neg={r < 0}/>
                <ModalStat label="Entry" value={trade.entry ?? '—'}/>
                <ModalStat label="Exit" value={trade.exit_price ?? '—'}/>
                <ModalStat label="Lots" value={trade.lots ?? '—'}/>
                <ModalStat label="Setup" value={trade.setup || '—'}/>
              </div>
              {trade.notes && (
                <div style={{ marginBottom: 12 }}>
                  <div style={{ fontSize: 10.5, fontWeight: 600, color: 'var(--fg-3)', letterSpacing: '.06em', textTransform: 'uppercase', marginBottom: 6 }}>Notes</div>
                  <div style={{ fontSize: 13, lineHeight: 1.55, color: 'var(--fg-2)', whiteSpace: 'pre-wrap', padding: '10px 12px', borderRadius: 8, background: 'var(--bg-soft)', border: '1px solid var(--line)' }}>{trade.notes}</div>
                </div>
              )}
            </div>
          )}

          {mode === 'edit' && (
            <form onSubmit={submitEdit}>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
                <div>
                  <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Symbole *</label>
                  <input className="input" value={form.symbol} onChange={upd('symbol')} required/>
                </div>
                <div>
                  <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Direction</label>
                  <select className="input" value={form.direction} onChange={upd('direction')} style={{ fontFamily: 'inherit' }}>
                    <option value="long">LONG</option>
                    <option value="short">SHORT</option>
                  </select>
                </div>
                <div>
                  <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Entry</label>
                  <input className="input" value={form.entry} onChange={upd('entry')} inputMode="decimal"/>
                </div>
                <div>
                  <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Exit</label>
                  <input className="input" value={form.exit_price} onChange={upd('exit_price')} inputMode="decimal"/>
                </div>
                <div>
                  <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Lots</label>
                  <input className="input" value={form.lots} onChange={upd('lots')} inputMode="decimal"/>
                </div>
                <div>
                  <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Date &amp; heure</label>
                  <input className="input" type="datetime-local" value={form.executed_at} onChange={upd('executed_at')}/>
                </div>
                <div>
                  <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>P&amp;L ($)</label>
                  <input className="input" value={form.pnl} onChange={upd('pnl')} inputMode="decimal"/>
                </div>
                <div>
                  <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>R-multiple</label>
                  <input className="input" value={form.r_multiple} onChange={upd('r_multiple')} inputMode="decimal"/>
                </div>
                <div style={{ gridColumn: '1 / -1' }}>
                  <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Setup</label>
                  <input className="input" value={form.setup} onChange={upd('setup')}/>
                </div>
                <div style={{ gridColumn: '1 / -1' }}>
                  <label style={{ fontSize: 11.5, fontWeight: 600, color: 'var(--fg-2)', display: 'block', marginBottom: 5 }}>Notes</label>
                  <textarea className="input" value={form.notes} onChange={upd('notes')} style={{ minHeight: 80, resize: 'vertical', fontFamily: 'inherit' }}/>
                </div>
              </div>
              {/* Hidden submit so Enter key works in inputs */}
              <button type="submit" style={{ display: 'none' }}/>
            </form>
          )}
        </div>

        {/* Footer */}
        <div style={{ padding: '14px 22px', borderTop: '1px solid var(--line)', display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 10, background: 'var(--bg-soft)' }}>
          {mode === 'view' ? (
            <React.Fragment>
              {confirmDelete ? (
                <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                  <span style={{ fontSize: 12, color: 'var(--red-text)' }}>Supprimer ce trade définitivement ?</span>
                  <button onClick={doDelete} disabled={busy} className="btn tap" style={{ background: 'var(--red)', color: '#fff', borderColor: 'var(--red)' }}>{busy ? '…' : 'Confirmer'}</button>
                  <button onClick={() => setConfirmDelete(false)} disabled={busy} className="btn tap">Annuler</button>
                </div>
              ) : (
                <button onClick={() => setConfirmDelete(true)} className="tap" style={{ background: 'transparent', border: 'none', color: 'var(--red)', fontSize: 12.5, fontWeight: 500, cursor: 'pointer', padding: 0, fontFamily: 'inherit' }}>Supprimer</button>
              )}
              <div style={{ display: 'flex', gap: 8 }}>
                <button onClick={onClose} className="btn tap">Fermer</button>
                <button onClick={() => setMode('edit')} className="btn btn-blue tap">Modifier</button>
              </div>
            </React.Fragment>
          ) : (
            <React.Fragment>
              <span style={{ fontSize: 11, color: 'var(--fg-3)' }}>Modifications enregistrées dans Supabase.</span>
              <div style={{ display: 'flex', gap: 8 }}>
                <button onClick={() => {
                  // Reset edit form to current trade values before going back to view.
                  setForm({
                    symbol: trade.symbol || '',
                    direction: trade.direction || 'long',
                    entry: trade.entry ?? '',
                    exit_price: trade.exit_price ?? '',
                    lots: trade.lots ?? '',
                    pnl: trade.pnl ?? '',
                    r_multiple: trade.r_multiple ?? '',
                    executed_at: toDtLocal(trade.executed_at),
                    setup: trade.setup || '',
                    notes: trade.notes || '',
                  });
                  setMode('view'); setError('');
                }} disabled={busy} className="btn tap">Annuler</button>
                <button onClick={submitEdit} disabled={busy} className="btn btn-blue tap">{busy ? 'Enregistrement…' : 'Enregistrer'}</button>
              </div>
            </React.Fragment>
          )}
        </div>
      </div>
    </div>
  );
}

// ─── Trades page ──────────────────────────────────────────────────
function TradesPage({ nav, openJournal, openImport, openTrade, state }) {
  const [tab, setTab] = React.useState('all');
  const [symbolFilter, setSymbolFilter] = React.useState('');
  const { trades, tradesLoading, refreshTrades } = state || { trades: [], tradesLoading: false };

  const filteredTrades = React.useMemo(() => {
    let arr = trades;
    if (symbolFilter) arr = arr.filter(t => (t.symbol || '').toUpperCase().includes(symbolFilter.toUpperCase()));
    return arr;
  }, [trades, symbolFilter]);

  const allSymbols = React.useMemo(() => {
    const s = new Set();
    for (const t of trades) if (t.symbol) s.add(t.symbol);
    return Array.from(s).sort();
  }, [trades]);

  return (
    <div className="scroll" style={{ width: '100%', height: '100%', overflow: 'auto' }}>
      <PageHeader title="Trades"/>
      <div style={{ padding: '20px 24px 32px' }}>
        <div style={{ marginBottom: 16 }}>
          <FilterBar
            activeTab={tab} setActiveTab={setTab}
            tabs={[
              { id: 'all',  label: `Tous les trades · ${trades.length}`, ico: null },
            ]}
            right={[
              <select key="sym" value={symbolFilter} onChange={e => setSymbolFilter(e.target.value)} className="input" style={{ width: 160, padding: '7px 10px', fontSize: 12 }}>
                <option value="">Tous symboles</option>
                {allSymbols.map(s => <option key={s} value={s}>{s}</option>)}
              </select>,
              <button key="refresh" onClick={refreshTrades} className="btn tap">{Ico.refresh} Actualiser</button>,
              <button key="new" onClick={openImport} className="btn btn-blue tap">{Ico.plus} Nouveau trade</button>,
            ]}
          />
        </div>

        {tradesLoading ? (
          <div className="card" style={{ padding: '32px 20px', textAlign: 'center', color: 'var(--fg-3)', fontSize: 13 }}>Chargement des trades…</div>
        ) : filteredTrades.length === 0 ? (
          <div className="card" style={{ padding: '40px 24px', textAlign: 'center' }}>
            <div style={{ fontSize: 14, color: 'var(--fg-2)', marginBottom: 6 }}>
              {trades.length === 0 ? 'Aucun trade pour l\'instant' : 'Aucun trade ne correspond à ce filtre'}
            </div>
            <div style={{ fontSize: 12, color: 'var(--fg-3)', marginBottom: 16 }}>
              {trades.length === 0 ? 'Importe ton premier CSV ou ajoute un trade manuellement.' : 'Modifie tes filtres ci-dessus.'}
            </div>
            {trades.length === 0 && <button onClick={openImport} className="btn btn-blue tap">{Ico.plus} Ajouter un trade</button>}
          </div>
        ) : (
          <div className="card" style={{ padding: 0, overflow: 'hidden' }}>
            <div style={{ display: 'grid', gridTemplateColumns: '120px 80px 50px 110px 110px 70px 1fr 110px 40px', padding: '12px 18px', background: 'var(--bg-soft)', borderBottom: '1px solid var(--line)', gap: 8 }}>
              {['DATE', 'SYMBOLE', 'DIR', 'ENTRY', 'EXIT', 'LOTS', 'SETUP', 'P&L', ''].map((h, i) => (
                <span key={h} style={{ fontSize: 10.5, fontWeight: 600, color: 'var(--fg-3)', letterSpacing: '.06em', textAlign: i === 7 ? 'right' : 'left' }}>{h}</span>
              ))}
            </div>
            {filteredTrades.map((t, i) => {
              const pnl = Number(t.pnl) || 0;
              const r = Number(t.r_multiple);
              const dirLetter = t.direction === 'short' ? 'S' : 'L';
              return (
                <div key={t.id} onClick={() => openTrade ? openTrade(t) : (openJournal && openJournal(t.executed_at))} className="tap" style={{
                  display: 'grid', gridTemplateColumns: '120px 80px 50px 110px 110px 70px 1fr 110px 40px',
                  padding: '14px 18px', borderBottom: i < filteredTrades.length - 1 ? '1px solid var(--line)' : 'none',
                  alignItems: 'center', cursor: 'pointer', gap: 8,
                  transition: 'background .15s var(--ease)',
                }} onMouseEnter={e => e.currentTarget.style.background = 'var(--bg-soft)'} onMouseLeave={e => e.currentTarget.style.background = 'transparent'}>
                  <div>
                    <div style={{ fontSize: 12.5, fontWeight: 500 }}>{fmtShortDate(t.executed_at)}</div>
                    {t.imported_from && <div className="mono" style={{ fontSize: 9.5, color: 'var(--fg-3)', marginTop: 2 }}>{t.imported_from.toUpperCase()}</div>}
                  </div>
                  <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
                    <div style={{ width: 24, height: 24, borderRadius: 6, background: 'var(--bg-elev)', display: 'flex', alignItems: 'center', justifyContent: 'center', fontSize: 9.5, fontWeight: 700, color: 'var(--fg-2)' }}>{(t.symbol || '').slice(0, 2)}</div>
                    <span style={{ fontSize: 13, fontWeight: 600 }}>{t.symbol || '—'}</span>
                  </div>
                  <span className="pill" style={{
                    background: dirLetter === 'L' ? 'var(--green-soft)' : 'var(--red-soft)',
                    color: dirLetter === 'L' ? 'var(--green-text)' : 'var(--red-text)',
                    border: 'none', padding: '3px 8px', fontSize: 10, fontWeight: 600, borderRadius: 4, width: 24, justifyContent: 'center',
                  }}>{dirLetter}</span>
                  <span className="mono" style={{ fontSize: 12, color: 'var(--fg-2)' }}>{t.entry ?? '—'}</span>
                  <span className="mono" style={{ fontSize: 12, color: 'var(--fg-2)' }}>{t.exit_price ?? '—'}</span>
                  <span className="mono" style={{ fontSize: 12, color: 'var(--fg-3)' }}>{t.lots ?? '—'}</span>
                  <span style={{ fontSize: 12.5, color: 'var(--fg-2)' }}>{t.setup || '—'}</span>
                  <div style={{ textAlign: 'right' }}>
                    <div className={'num ' + (pnl >= 0 ? 'pos' : 'neg')} style={{ fontSize: 14, fontWeight: 600, letterSpacing: '-.018em' }}>{fmtMoney(pnl, true)}</div>
                    {Number.isFinite(r) && <div className={'mono ' + (r >= 0 ? 'pos' : 'neg')} style={{ fontSize: 10.5, fontWeight: 500, marginTop: 2 }}>{r >= 0 ? '+' : ''}{r.toFixed(1)}R</div>}
                  </div>
                  <button onClick={(e) => { e.stopPropagation(); openTrade ? openTrade(t) : (openJournal && openJournal(t.executed_at)); }} className="tap" title="Ouvrir le trade" style={{ width: 26, height: 26, borderRadius: 6, border: '1px solid var(--line)', background: 'var(--bg-card)', cursor: 'pointer', color: 'var(--fg-3)', display: 'flex', alignItems: 'center', justifyContent: 'center', justifySelf: 'end' }}>{Ico.chev}</button>
                </div>
              );
            })}
          </div>
        )}
      </div>
    </div>
  );
}

// ─── Login (real Supabase auth) ──────────────────────────────────
function Login({ onLogin }) {
  const [mode, setMode] = React.useState('login'); // 'login' | 'signup' | 'reset'
  const [email, setEmail] = React.useState('');
  const [password, setPassword] = React.useState('');
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState('');
  const [info, setInfo] = React.useState('');
  // Consentement CGU/confidentialité (obligatoire à l'inscription) + modal légale.
  const [consent, setConsent] = React.useState(false);
  const [legalKind, setLegalKind] = React.useState(null); // 'cgu' | 'privacy' | null

  const submit = async (e) => {
    e.preventDefault();
    setError(''); setInfo('');
    if (!window.sb) { setError('Connexion à Supabase indisponible — recharge la page.'); return; }
    const cleanEmail = (email || '').trim();
    if (!cleanEmail) { setError('Entre ton email.'); return; }
    setLoading(true);
    try {
      if (mode === 'login') {
        if (!password) { setError('Entre ton mot de passe.'); setLoading(false); return; }
        const { error } = await window.sb.auth.signInWithPassword({ email: cleanEmail, password });
        if (error) { setError(sbErrorMessage(error)); setLoading(false); return; }
        setLoading(false);
        if (onLogin) onLogin();
      } else if (mode === 'signup') {
        if (!password || password.length < 6) { setError('Le mot de passe doit faire au moins 6 caractères.'); setLoading(false); return; }
        if (!consent) { setError('Merci d’accepter les conditions d’utilisation et la politique de confidentialité pour créer ton compte.'); setLoading(false); return; }
        const { data, error } = await window.sb.auth.signUp({
          email: cleanEmail, password,
          options: {
            emailRedirectTo: window.location.origin,
            // Preuve de consentement (RGPD) : horodatage + version des documents acceptés.
            data: { accepted_terms_at: new Date().toISOString(), accepted_terms_version: window.LEGAL_VERSION || null },
          },
        });
        if (error) { setError(sbErrorMessage(error)); setLoading(false); return; }
        setLoading(false);
        if (data?.session) { if (onLogin) onLogin(); return; }
        setInfo('Compte créé. Confirme ton email pour activer ton compte, puis reviens te connecter ici.');
        setMode('login');
      } else if (mode === 'reset') {
        const { error } = await window.sb.auth.resetPasswordForEmail(cleanEmail, {
          redirectTo: window.location.origin,
        });
        if (error) { setError(sbErrorMessage(error)); setLoading(false); return; }
        setLoading(false);
        setInfo('Si un compte existe avec cet email, tu vas recevoir un lien de réinitialisation dans quelques minutes.');
        setMode('login');
      }
    } catch (err) {
      console.error('[Tempo] auth submit', err);
      setError(sbErrorMessage(err));
      setLoading(false);
    }
  };

  const switchMode = (m) => { setMode(m); setError(''); setInfo(''); };

  return (
    <div style={{ width: '100%', minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'var(--bg-soft)', padding: 24 }}>
      <form onSubmit={submit} style={{ width: 380, maxWidth: '100%', padding: '36px 32px', background: 'var(--bg-card)', borderRadius: 16, border: '1px solid var(--line)', boxShadow: '0 12px 32px rgba(15,23,42,.08)' }}>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8, marginBottom: 24 }}>
          <div style={{ width: 44, height: 44, borderRadius: 12, background: 'var(--blue)', display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative' }}>
            <div style={{ width: 2, height: 18, background: '#fff' }}></div>
            <div style={{ position: 'absolute', width: 14, height: 2, background: '#fff', top: 13 }}></div>
          </div>
          <span style={{ fontSize: 22, fontWeight: 700, letterSpacing: '-.025em', color: 'var(--blue-600)' }}>Tempo</span>
          <span style={{ fontSize: 12, color: 'var(--fg-3)' }}>Ton journal de trading personnel</span>
        </div>

        <div style={{ display: 'flex', justifyContent: 'center', marginBottom: 18 }}>
          <div style={{ display: 'inline-flex', gap: 4, padding: 4, background: 'var(--bg-elev)', borderRadius: 10 }}>
            {[
              { id: 'login', l: 'Connexion' },
              { id: 'signup', l: 'Créer un compte' },
            ].map(t => (
              <button key={t.id} type="button" onClick={() => switchMode(t.id)} className="tap" style={{
                background: mode === t.id ? 'var(--bg-card)' : 'transparent',
                color: mode === t.id ? 'var(--blue-600)' : 'var(--fg-2)',
                border: mode === t.id ? '1.5px solid var(--blue)' : '1.5px solid transparent',
                borderRadius: 7, padding: '5px 12px', fontSize: 12, fontWeight: mode === t.id ? 600 : 500,
                cursor: 'pointer', fontFamily: 'inherit',
              }}>{t.l}</button>
            ))}
          </div>
        </div>

        <div style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
          <div>
            <label style={{ fontSize: 12, fontWeight: 500, color: 'var(--fg-2)', display: 'block', marginBottom: 6 }}>Email</label>
            <input className="input" value={email} onChange={e => setEmail(e.target.value)} type="email" autoComplete="email" placeholder="toi@example.com" required/>
          </div>
          {mode !== 'reset' && (
            <div>
              <label style={{ fontSize: 12, fontWeight: 500, color: 'var(--fg-2)', display: 'block', marginBottom: 6 }}>Mot de passe</label>
              <input className="input" value={password} onChange={e => setPassword(e.target.value)} type="password" autoComplete={mode === 'signup' ? 'new-password' : 'current-password'} placeholder={mode === 'signup' ? '6 caractères min.' : ''} required/>
            </div>
          )}

          {mode === 'signup' && (
            <label style={{ display: 'flex', gap: 8, alignItems: 'flex-start', fontSize: 11.5, color: 'var(--fg-2)', lineHeight: 1.5, cursor: 'pointer' }}>
              <input type="checkbox" checked={consent} onChange={e => setConsent(e.target.checked)} style={{ marginTop: 2, flexShrink: 0, accentColor: 'var(--blue)' }}/>
              <span>
                J’accepte les{' '}
                <button type="button" className="tap" onClick={() => setLegalKind('cgu')} style={{ background: 'transparent', border: 'none', padding: 0, cursor: 'pointer', color: 'var(--blue-600)', fontSize: 11.5, fontWeight: 600, fontFamily: 'inherit' }}>conditions d’utilisation</button>
                {' '}et la{' '}
                <button type="button" className="tap" onClick={() => setLegalKind('privacy')} style={{ background: 'transparent', border: 'none', padding: 0, cursor: 'pointer', color: 'var(--blue-600)', fontSize: 11.5, fontWeight: 600, fontFamily: 'inherit' }}>politique de confidentialité</button>
                , et je comprends que le trading comporte un risque élevé de perte en capital.
              </span>
            </label>
          )}

          {error && (
            <div style={{ fontSize: 12, color: 'var(--red-text)', background: 'var(--red-soft)', border: '1px solid var(--line)', padding: '8px 10px', borderRadius: 8 }}>
              {error}
            </div>
          )}
          {info && (
            <div style={{ fontSize: 12, color: 'var(--green-text)', background: 'var(--green-soft)', border: '1px solid var(--line)', padding: '8px 10px', borderRadius: 8 }}>
              {info}
            </div>
          )}

          <button type="submit" disabled={loading} className="btn btn-blue tap" style={{ width: '100%', justifyContent: 'center', padding: '11px 0', marginTop: 4, opacity: loading ? .7 : 1 }}>
            {loading ? 'Patiente…' : (mode === 'login' ? 'Se connecter' : mode === 'signup' ? 'Créer mon compte' : 'Envoyer le lien')}
          </button>

          {mode === 'login' && (
            <button type="button" onClick={() => switchMode('reset')} className="tap" style={{ background: 'transparent', border: 'none', color: 'var(--blue-600)', fontSize: 12, fontWeight: 500, cursor: 'pointer', padding: 6 }}>
              Mot de passe oublié ?
            </button>
          )}
          {mode === 'reset' && (
            <button type="button" onClick={() => switchMode('login')} className="tap" style={{ background: 'transparent', border: 'none', color: 'var(--fg-3)', fontSize: 12, fontWeight: 500, cursor: 'pointer', padding: 6 }}>
              ← Retour à la connexion
            </button>
          )}
        </div>

        <div style={{ marginTop: 18, paddingTop: 16, borderTop: '1px solid var(--line)', textAlign: 'center' }}>
          <span style={{ fontSize: 11.5, color: 'var(--fg-3)' }}>
            {mode === 'signup' ? 'Tu as déjà un compte ?' : "Pas encore de compte ?"}
          </span>{' '}
          <a onClick={() => switchMode(mode === 'signup' ? 'login' : 'signup')} style={{ fontSize: 11.5, color: 'var(--blue-600)', fontWeight: 500, textDecoration: 'none', cursor: 'pointer' }}>
            {mode === 'signup' ? 'Se connecter' : 'Créer un compte'}
          </a>
        </div>

        {/* Avertissement risque + liens légaux, visibles avant toute connexion. */}
        <div style={{ marginTop: 14, display: 'flex', flexDirection: 'column', gap: 6, alignItems: 'center' }}>
          {typeof window.TradingDisclaimer === 'function' && <window.TradingDisclaimer compact/>}
          {mode !== 'signup' && typeof window.LegalLinks === 'function' && <window.LegalLinks compact/>}
        </div>
      </form>
      {legalKind && typeof window.LegalModal === 'function' && (
        <window.LegalModal kind={legalKind} onClose={() => setLegalKind(null)}/>
      )}
    </div>
  );
}

// ─── Mot de passe : formulaire partagé (récupération + Réglages) ─────
// Appelle sb.auth.updateUser({ password }) — requiert une session active
// (session normale en Réglages, session de récupération après le lien email).
function PasswordForm({ onSuccess, submitLabel }) {
  const [pw, setPw] = React.useState('');
  const [pw2, setPw2] = React.useState('');
  const [loading, setLoading] = React.useState(false);
  const [error, setError] = React.useState('');
  const [ok, setOk] = React.useState('');

  const submit = async (e) => {
    e.preventDefault();
    setError(''); setOk('');
    if (!window.sb) { setError('Connexion à Supabase indisponible — recharge la page.'); return; }
    if (!pw || pw.length < 6) { setError('Le mot de passe doit faire au moins 6 caractères.'); return; }
    if (pw !== pw2) { setError('Les deux mots de passe ne correspondent pas.'); return; }
    setLoading(true);
    try {
      const { error } = await window.sb.auth.updateUser({ password: pw });
      if (error) { setError(sbErrorMessage(error)); setLoading(false); return; }
      setLoading(false);
      setPw(''); setPw2('');
      setOk('Mot de passe mis à jour.');
      if (onSuccess) onSuccess();
    } catch (err) {
      console.error('[Tempo] updateUser password', err);
      setError(sbErrorMessage(err));
      setLoading(false);
    }
  };

  return (
    <form onSubmit={submit} style={{ display: 'flex', flexDirection: 'column', gap: 12 }}>
      <div>
        <label style={{ fontSize: 12, fontWeight: 500, color: 'var(--fg-2)', display: 'block', marginBottom: 6 }}>Nouveau mot de passe</label>
        <input className="input" value={pw} onChange={e => setPw(e.target.value)} type="password" autoComplete="new-password" placeholder="6 caractères min." required/>
      </div>
      <div>
        <label style={{ fontSize: 12, fontWeight: 500, color: 'var(--fg-2)', display: 'block', marginBottom: 6 }}>Confirme le mot de passe</label>
        <input className="input" value={pw2} onChange={e => setPw2(e.target.value)} type="password" autoComplete="new-password" required/>
      </div>
      {error && (
        <div style={{ fontSize: 12, color: 'var(--red-text)', background: 'var(--red-soft)', border: '1px solid var(--line)', padding: '8px 10px', borderRadius: 8 }}>{error}</div>
      )}
      {ok && (
        <div style={{ fontSize: 12, color: 'var(--green-text)', background: 'var(--green-soft)', border: '1px solid var(--line)', padding: '8px 10px', borderRadius: 8 }}>{ok}</div>
      )}
      <button type="submit" disabled={loading} className="btn btn-blue tap" style={{ justifyContent: 'center', padding: '10px 0', opacity: loading ? .7 : 1 }}>
        {loading ? 'Patiente…' : (submitLabel || 'Mettre à jour le mot de passe')}
      </button>
    </form>
  );
}

// ─── Écran « nouveau mot de passe » (lien de récupération email) ─────
// Affiché par App quand Supabase émet l'événement PASSWORD_RECOVERY : le clic
// sur le lien email connecte l'utilisateur avec une session de récupération ;
// cet écran lui fait définir son nouveau mot de passe avant d'entrer dans Tempo.
function UpdatePassword({ onDone }) {
  const [done, setDone] = React.useState(false);
  return (
    <div style={{ width: '100%', minHeight: '100vh', display: 'flex', alignItems: 'center', justifyContent: 'center', background: 'var(--bg-soft)', padding: 24 }}>
      <div style={{ width: 380, maxWidth: '100%', padding: '36px 32px', background: 'var(--bg-card)', borderRadius: 16, border: '1px solid var(--line)', boxShadow: '0 12px 32px rgba(15,23,42,.08)' }}>
        <div style={{ display: 'flex', flexDirection: 'column', alignItems: 'center', gap: 8, marginBottom: 22 }}>
          <div style={{ width: 44, height: 44, borderRadius: 12, background: 'var(--blue)', display: 'flex', alignItems: 'center', justifyContent: 'center', position: 'relative' }}>
            <div style={{ width: 2, height: 18, background: '#fff' }}></div>
            <div style={{ position: 'absolute', width: 14, height: 2, background: '#fff', top: 13 }}></div>
          </div>
          <span style={{ fontSize: 20, fontWeight: 700, letterSpacing: '-.02em' }}>Nouveau mot de passe</span>
          <span style={{ fontSize: 12, color: 'var(--fg-3)', textAlign: 'center', lineHeight: 1.5 }}>
            {done ? 'C’est fait ! Tu peux entrer dans Tempo.' : 'Choisis ton nouveau mot de passe pour finaliser la récupération.'}
          </span>
        </div>
        {done ? (
          <button onClick={onDone} className="btn btn-blue tap" style={{ width: '100%', justifyContent: 'center', padding: '11px 0' }}>
            Continuer vers Tempo
          </button>
        ) : (
          <React.Fragment>
            <PasswordForm onSuccess={() => setDone(true)}/>
            <button type="button" onClick={onDone} className="tap" style={{ width: '100%', background: 'transparent', border: 'none', color: 'var(--fg-3)', fontSize: 12, fontWeight: 500, cursor: 'pointer', padding: 8, marginTop: 8 }}>
              Plus tard
            </button>
          </React.Fragment>
        )}
      </div>
    </div>
  );
}

// ─── Placeholder pages ────────────────────────────────────────────
function Placeholder({ title, sub, icon }) {
  return (
    <div style={{ width: '100%', height: '100%', overflow: 'auto' }} className="scroll">
      <PageHeader title={title}/>
      <div style={{ padding: '60px 24px 32px', display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', minHeight: '60%' }}>
        <div style={{ width: 56, height: 56, borderRadius: 14, background: 'var(--blue-soft)', color: 'var(--blue-600)', display: 'flex', alignItems: 'center', justifyContent: 'center', marginBottom: 16 }}>
          {React.cloneElement(icon || Ico.cockpit, { width: 28, height: 28 })}
        </div>
        <div style={{ fontSize: 22, fontWeight: 700, letterSpacing: '-.02em', marginBottom: 8 }}>{title}</div>
        <p style={{ fontSize: 14, color: 'var(--fg-3)', maxWidth: 360, textAlign: 'center', lineHeight: 1.5 }}>{sub}</p>
        <span className="pill pill-blue" style={{ marginTop: 18 }}>Bientôt disponible</span>
      </div>
    </div>
  );
}

// ─── Time / date helpers (timezone-aware) ────────────────────────
function tzTime(date, tz) {
  try {
    return new Intl.DateTimeFormat('fr-FR', {
      timeZone: tz, hour12: false, hour: '2-digit', minute: '2-digit', second: '2-digit',
    }).format(date || new Date());
  } catch (e) { return '--:--:--'; }
}

function parisHourMinute(date) {
  // Returns { h, m, d } where d is the weekday number in Paris time (0=Sun, 6=Sat)
  try {
    const parts = new Intl.DateTimeFormat('en-GB', {
      timeZone: 'Europe/Paris', hour12: false,
      hour: '2-digit', minute: '2-digit', weekday: 'short',
    }).formatToParts(date || new Date());
    const h = parseInt((parts.find(p => p.type === 'hour') || {}).value || '0', 10);
    const m = parseInt((parts.find(p => p.type === 'minute') || {}).value || '0', 10);
    const wkd = (parts.find(p => p.type === 'weekday') || {}).value || '';
    const dayMap = { Sun: 0, Mon: 1, Tue: 2, Wed: 3, Thu: 4, Fri: 5, Sat: 6 };
    const d = dayMap[wkd] ?? (date || new Date()).getDay();
    return { h, m, d };
  } catch (e) {
    const dd = date || new Date();
    return { h: dd.getHours(), m: dd.getMinutes(), d: dd.getDay() };
  }
}

// Cash-session open windows in Paris-local hours, weekdays only.
//   Tokyo   01:00 → 10:00 (Tue-Sat 1am Paris, since Tokyo Mon-Fri 9am-6pm = Paris early morning)
//   Londres 09:00 → 18:00 (Mon-Fri Paris)
//   NY      15:30 → 22:00 (Mon-Fri Paris)
// Weekend (Sat + Sun): all sessions closed.
function sessionStatus(parisHour, parisMinute, parisDay) {
  const day = parisDay == null ? new Date().getDay() : parisDay;
  // Saturday (6) and Sunday (0): markets closed
  if (day === 0 || day === 6) {
    return { tokyo: false, london: false, newyork: false };
  }
  const dec = (parisHour || 0) + (parisMinute || 0) / 60;
  return {
    tokyo:   dec >= 1   && dec < 10,
    london:  dec >= 9   && dec < 18,
    newyork: dec >= 15.5 && dec < 22,
  };
}

// ISO week number (Monday-based)
function isoWeek(d) {
  const t = new Date(d); t.setHours(0,0,0,0);
  t.setDate(t.getDate() + 3 - ((t.getDay() + 6) % 7));
  const week1 = new Date(t.getFullYear(), 0, 4);
  return 1 + Math.round(((t - week1) / 86400000 - 3 + ((week1.getDay() + 6) % 7)) / 7);
}

function dayOfYear(d) {
  const start = new Date(d.getFullYear(), 0, 0);
  const diff = (d - start) + ((start.getTimezoneOffset() - d.getTimezoneOffset()) * 60000);
  return Math.floor(diff / 86400000);
}

function buildDateLabel(d) {
  const date = d || new Date();
  const dayName = date.toLocaleDateString('fr-FR', { weekday: 'long' });
  const monthName = date.toLocaleDateString('fr-FR', { month: 'long' });
  const cap = s => s.charAt(0).toUpperCase() + s.slice(1);
  return `${cap(dayName)} ${date.getDate()} ${monthName} · S${isoWeek(date)} · J${dayOfYear(date)}`;
}

Object.assign(window, {
  Home, Daily, DayJournalCard, JournalModal, TradesPage, Login, Placeholder, TradesMiniTable,
  TradeDetailModal, PasswordForm, UpdatePassword,
  tzTime, parisHourMinute, sessionStatus, isoWeek, dayOfYear, buildDateLabel,
});
