// mobile-journal.jsx — Mobile trading journal for ultratrack
// Shares the same Firebase backend as the desktop version (trading-journal.jsx)
// SYNCED CONSTANTS/UTILITIES FROM: trading-journal.jsx (2026-04-09)

const { useState, useEffect, useRef } = React;

// ─── Constants (synced from desktop) ───
const STRATEGIES = ["Trend Follow", "Breakout", "Pullback", "Mean Reversion", "Scalp", "VWAP Fade", "Opening Range", "News Play", "Overnight Gap", "ICT/SMC", "Order Flow", "Momentum", "Other"];
const EMOTIONS = ["Calm", "Disciplined", "Confident", "In the Zone", "FOMO", "Anxious", "Greedy", "Fearful", "Revenge", "Bored", "Overconfident", "Distracted"];
const MISTAKES = ["None", "Premature Entry", "Late Entry", "Premature Exit", "Late Exit", "Wrong Size", "Ignored Stop", "Over-Traded", "Against Plan", "Chased Price", "Averaging Down", "Emotional Trade", "Poor Risk/Reward"];
const INSTRUMENTS = ["ES", "NQ", "MES", "MNQ", "YM", "RTY", "CL", "GC", "SI", "ZB", "ZN", "6E", "Other"];
const SESSIONS = ["Pre-Market", "RTH Open", "RTH Mid", "RTH Close", "Overnight"];
const MOOD_OPTIONS = ["Calm", "Focused", "Anxious", "Angry", "Tired", "FOMO", "Confident"];
const DISCIPLINE_TAG_OPTIONS = ["Followed plan", "Revenge traded", "Chased", "Oversized", "Hesitated", "Cut winners early"];

const RULE_CATEGORY_COLORS = {
  risk: "#ff5566",
  process: "#00ddff",
  mindset: "#7fffb2"
};

const RULE_CATEGORY_LABELS = {
  risk: "Risk Management",
  process: "Process / Discipline",
  mindset: "Mindset / Emotional"
};
const POINT_VALUES = { ES: 50, NQ: 20, MES: 5, MNQ: 2, YM: 5, RTY: 50, CL: 1000, GC: 100, SI: 5000, ZB: 1000, ZN: 1000, "6E": 125000, Other: 50 };

const emotionColors = {
  "Calm": "#7fffb2", "Disciplined": "#00ddff", "Confident": "#aaff44", "In the Zone": "#ffdd00",
  "FOMO": "#ff9900", "Anxious": "#ff7744", "Greedy": "#ff5566", "Fearful": "#ff3355",
  "Revenge": "#ff0033", "Bored": "#666666", "Overconfident": "#ffbb00", "Distracted": "#bb66ff"
};

const mistakeColors = {
  "None": "#7fffb2",
  "Premature Entry": "#ff9900", "Late Entry": "#ff9900",
  "Premature Exit": "#ff7744", "Late Exit": "#ff7744",
  "Wrong Size": "#ff5566", "Ignored Stop": "#ff0033",
  "Over-Traded": "#ff3355", "Against Plan": "#ff0033",
  "Chased Price": "#ffbb00", "Averaging Down": "#ff5566",
  "Emotional Trade": "#ff7744", "Poor Risk/Reward": "#ff9900"
};

// ─── Utilities (synced from desktop) ───
function getMistakes(trade) {
  if (!trade.mistake) return ["None"];
  if (Array.isArray(trade.mistake)) return trade.mistake.length > 0 ? trade.mistake : ["None"];
  return [trade.mistake];
}

function calcPnl(trade) {
  const diff = trade.direction === "Long" ? trade.exit - trade.entry : trade.entry - trade.exit;
  const gross = diff * trade.size * (POINT_VALUES[trade.market] || 50);
  const fees = Number(trade.commission) || 0;
  return parseFloat((gross - fees).toFixed(2));
}

function formatDateToYMD(dateString) {
  if (!dateString) return "";
  if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) return dateString;
  if (/^\d{1,2}\/\d{1,2}\/\d{4}$/.test(dateString)) {
    const [month, day, year] = dateString.split('/');
    return `${year}-${String(month).padStart(2, '0')}-${String(day).padStart(2, '0')}`;
  }
  try {
    const date = new Date(dateString);
    if (isNaN(date.getTime())) return dateString;
    return `${date.getFullYear()}-${String(date.getMonth() + 1).padStart(2, '0')}-${String(date.getDate()).padStart(2, '0')}`;
  } catch { return dateString; }
}

function formatDateDisplay(dateString) {
  if (!dateString) return "";
  if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) {
    const [year, month, day] = dateString.split('-');
    return `${month}/${day}/${year}`;
  }
  return dateString;
}

function getTodayLocalDate() {
  const today = new Date();
  return `${today.getFullYear()}-${String(today.getMonth() + 1).padStart(2, '0')}-${String(today.getDate()).padStart(2, '0')}`;
}

function getLastTradingDate(trades, todayKey) {
  if (!Array.isArray(trades) || trades.length === 0) return null;
  const dates = new Set();
  for (const t of trades) {
    const d = formatDateToYMD(t.date);
    if (d && d < todayKey) dates.add(d);
  }
  if (dates.size === 0) return null;
  return Array.from(dates).sort().pop();
}

function modeOf(arr) {
  if (!arr || !arr.length) return null;
  const counts = {};
  for (const v of arr) counts[v] = (counts[v] || 0) + 1;
  let best = null, bestN = 0;
  for (const [k, n] of Object.entries(counts)) {
    if (n > bestN) { best = k; bestN = n; }
  }
  return best;
}

function summarizeDay(allTrades, dateKey, journalEntry, breakevenThreshold = 10) {
  const beT = Math.max(0, Number(breakevenThreshold) || 0);
  const dayTrades = allTrades.filter(t => formatDateToYMD(t.date) === dateKey);
  const withPnl = dayTrades.map(t => ({ ...t, _pnl: typeof t.pnl === 'number' ? t.pnl : calcPnl(t) }));
  const wins = withPnl.filter(t => t._pnl > beT);
  const losses = withPnl.filter(t => t._pnl < -beT);
  const breakevens = withPnl.filter(t => Math.abs(t._pnl) <= beT);
  const netPnl = withPnl.reduce((s, t) => s + t._pnl, 0);
  const winRate = withPnl.length ? (wins.length / withPnl.length) * 100 : 0;
  const best = withPnl.reduce((a, b) => (a && a._pnl >= b._pnl ? a : b), null);
  const worst = withPnl.reduce((a, b) => (a && a._pnl <= b._pnl ? a : b), null);
  const mistakeCounts = {};
  for (const t of withPnl) {
    for (const m of getMistakes(t)) {
      if (m && m !== 'None') mistakeCounts[m] = (mistakeCounts[m] || 0) + 1;
    }
  }
  const topMistakes = Object.entries(mistakeCounts).sort((a, b) => b[1] - a[1]).slice(0, 3).map(([name, count]) => ({ name, count }));
  const dominantEmotion = modeOf(withPnl.map(t => t.emotion).filter(Boolean));
  const stratMap = {};
  for (const t of withPnl) {
    const k = t.strategy || 'Unknown';
    if (!stratMap[k]) stratMap[k] = { name: k, pnl: 0, count: 0 };
    stratMap[k].pnl += t._pnl;
    stratMap[k].count += 1;
  }
  const strategies = Object.values(stratMap).sort((a, b) => b.pnl - a.pnl);
  let ruleAdherencePct = null;
  const checkoffs = journalEntry && journalEntry.mindset && journalEntry.mindset.ruleCheckoffs;
  if (checkoffs && typeof checkoffs === 'object') {
    const vals = Object.values(checkoffs);
    if (vals.length) {
      const followed = vals.filter(v => v === true || v === 'yes').length;
      ruleAdherencePct = Math.round((followed / vals.length) * 100);
    }
  }
  return {
    date: dateKey, tradeCount: withPnl.length, winCount: wins.length, lossCount: losses.length, beCount: breakevens.length,
    netPnl: parseFloat(netPnl.toFixed(2)), winRate: parseFloat(winRate.toFixed(1)),
    best: best ? { ticker: best.ticker || best.market, pnl: best._pnl, strategy: best.strategy } : null,
    worst: worst && worst !== best ? { ticker: worst.ticker || worst.market, pnl: worst._pnl, strategy: worst.strategy } : null,
    topMistakes, dominantEmotion, strategies, ruleAdherencePct,
  };
}

function buildMechanicalRecs(stats) {
  const recs = [];
  const NEG = new Set(['Revenge', 'FOMO', 'Anxious', 'Fearful', 'Greedy', 'Overconfident', 'Distracted', 'Bored']);
  if (stats.topMistakes[0] && stats.topMistakes[0].count >= 2) recs.push(`Watch for: ${stats.topMistakes[0].name} (${stats.topMistakes[0].count}x yesterday).`);
  if (stats.dominantEmotion && NEG.has(stats.dominantEmotion)) recs.push(`Reset before first trade — yesterday flagged ${stats.dominantEmotion}.`);
  const losingStrat = stats.strategies.find(s => s.pnl < 0 && s.count >= 2);
  if (losingStrat) recs.push(`Sit out ${losingStrat.name} until A+ confirmation.`);
  if (stats.netPnl > 0 && stats.ruleAdherencePct !== null && stats.ruleAdherencePct >= 80 && stats.strategies[0]) recs.push(`Repeat the process: ${stats.strategies[0].name} worked.`);
  recs.push("Define today's key levels and primary A+ setup before the bell.");
  return recs;
}

function detectSession(timestamp) {
  const date = new Date(timestamp);
  const etString = date.toLocaleString("en-US", { timeZone: "America/New_York" });
  const etDate = new Date(etString);
  const time = etDate.getHours() * 60 + etDate.getMinutes();
  if (time >= 570 && time < 630) return "RTH Open";
  if (time >= 630 && time < 900) return "RTH Mid";
  if (time >= 900 && time < 960) return "RTH Close";
  if (time >= 960 && time < 1080) return "Overnight";
  return "Pre-Market";
}

// ─── Firestore helpers (synced from desktop) ───
async function saveTradesToFirestore(userId, trades) {
  try {
    const tradesCollection = db.collection('users').doc(userId).collection('trades');
    const batch = db.batch();
    let batchCount = 0;
    const existingDocs = await tradesCollection.get();
    const tradeIds = new Set(trades.map(t => String(t.id)));
    existingDocs.forEach(doc => {
      if (doc.id !== 'metadata' && !tradeIds.has(doc.id)) {
        batch.delete(tradesCollection.doc(doc.id));
        batchCount++;
      }
    });
    if (batchCount > 0) await batch.commit();

    const batches = [];
    let currentBatch = db.batch();
    batchCount = 0;
    for (const trade of trades) {
      currentBatch.set(tradesCollection.doc(String(trade.id)), trade);
      batchCount++;
      if (batchCount >= 500) {
        batches.push(currentBatch.commit());
        currentBatch = db.batch();
        batchCount = 0;
      }
    }
    if (batchCount > 0) batches.push(currentBatch.commit());
    const metadataBatch = db.batch();
    metadataBatch.set(tradesCollection.doc('metadata'), { count: trades.length, updatedAt: firebase.firestore.FieldValue.serverTimestamp() });
    batches.push(metadataBatch.commit());
    await Promise.all(batches);
  } catch (error) {
    console.error('Failed to save trades:', error);
    throw error;
  }
}

async function loadTradesFromFirestore(userId) {
  try {
    const snapshot = await db.collection('users').doc(userId).collection('trades').get();
    if (snapshot.empty) return [];
    let trades = [];
    snapshot.forEach(doc => {
      const data = doc.data();
      if (data.trades && Array.isArray(data.trades)) {
        trades = [...trades, ...data.trades];
      } else if (doc.id !== 'metadata' && doc.id !== 'data' && doc.id !== 'undefined') {
        trades.push(data);
      }
    });
    return trades;
  } catch (error) {
    console.error('Failed to load trades:', error);
    return [];
  }
}

async function saveJournalToFirestore(userId, journalEntries) {
  try {
    const batch = db.batch();
    let batchCount = 0;
    for (const [dateKey, entryData] of Object.entries(journalEntries)) {
      batch.set(db.collection('users').doc(userId).collection('journal').doc(dateKey), {
        ...entryData,
        updatedAt: firebase.firestore.FieldValue.serverTimestamp()
      });
      batchCount++;
      if (batchCount >= 500) { await batch.commit(); batchCount = 0; }
    }
    if (batchCount > 0) await batch.commit();
  } catch (error) {
    console.error('Failed to save journal:', error);
    throw error;
  }
}

async function loadJournalFromFirestore(userId) {
  try {
    const snapshot = await db.collection('users').doc(userId).collection('journal').get();
    if (snapshot.empty) return {};
    const entries = {};
    snapshot.docs.forEach(doc => {
      if (doc.id !== 'entries') entries[doc.id] = doc.data();
    });
    return entries;
  } catch (error) {
    console.error('Failed to load journal:', error);
    return {};
  }
}

async function loadTradingRulesFromFirestore(userId) {
  try {
    const doc = await db.collection('users').doc(userId).collection('settings').doc('tradingRules').get();
    if (doc.exists) return doc.data().rules || [];
    return [];
  } catch (error) {
    console.error('Failed to load trading rules:', error);
    return [];
  }
}

async function loadGoalsFromFirestore(userId) {
  try {
    const doc = await db.collection('users').doc(userId).collection('settings').doc('goals').get();
    return doc.exists ? (doc.data() || {}) : {};
  } catch (error) {
    console.error('Failed to load goals:', error);
    return {};
  }
}


// ─── Shared styles ───
const FONT = "-apple-system, BlinkMacSystemFont, 'SF Mono', 'Monaco', 'Menlo', 'Consolas', 'Roboto Mono', monospace";
const COLORS = {
  bg: "#000000",
  card: "#0c0c0c",
  cardBorder: "#1a1a1a",
  accent: "#7fffb2",
  red: "#ff4466",
  text: "#ffffff",
  textMuted: "#888888",
  textDim: "#666666",
  inputBg: "#0a0a0a",
  inputBorder: "#1e1e1e",
};

// ─── Logo Component ───
function UltratrackLogo({ size = 28 }) {
  const letters = "ultratrack";
  const colors = ["#e45e54", "#f28b57", "#fabf53", "#8bc268", "#7ca5d4", "#a08ecc", "#c581b6", "#e45e54", "#f28b57", "#fabf53"];
  return (
    <span style={{ fontFamily: "'Courier New', Courier, monospace", fontSize: size, fontWeight: 700, letterSpacing: "1px" }}>
      {letters.split("").map((ch, i) => <span key={i} style={{ color: colors[i] }}>{ch}</span>)}
    </span>
  );
}

// ─── Auth Page ───
function MobileAuthPage({ authMode, setAuthMode }) {
  const [email, setEmail] = useState('');
  const [password, setPassword] = useState('');
  const [error, setError] = useState('');
  const [loading, setLoading] = useState(false);
  const [verificationSent, setVerificationSent] = useState(false);

  const handleSubmit = async (e) => {
    e.preventDefault();
    setError('');
    setLoading(true);
    try {
      if (authMode === 'signup') {
        const cred = await auth.createUserWithEmailAndPassword(email, password);
        await cred.user.sendEmailVerification();
        setVerificationSent(true);
        setLoading(false);
      } else {
        await auth.signInWithEmailAndPassword(email, password);
      }
    } catch (err) {
      setError(err.message);
      setLoading(false);
    }
  };

  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: COLORS.bg, padding: 20 }}>
      <div style={{ width: '100%', maxWidth: 400, background: '#0f0f0f', border: '1px solid #1e1e1e', borderRadius: 16, padding: '32px 24px' }}>
        <div style={{ textAlign: 'center', marginBottom: 28 }}>
          <UltratrackLogo size={28} />
          <p style={{ color: '#888', fontSize: 13, marginTop: 6 }}>Trading Journal</p>
        </div>

        <form onSubmit={handleSubmit}>
          <div style={{ marginBottom: 16 }}>
            <label style={{ display: 'block', color: '#ccc', fontSize: 13, marginBottom: 6 }}>Email</label>
            <input type="email" value={email} onChange={(e) => setEmail(e.target.value)} required
              style={{ width: '100%', padding: 14, background: '#1a1a1a', border: '1px solid #2a2a2a', borderRadius: 10, color: '#fff', fontSize: 16, outline: 'none' }} />
          </div>
          <div style={{ marginBottom: 20 }}>
            <label style={{ display: 'block', color: '#ccc', fontSize: 13, marginBottom: 6 }}>Password</label>
            <input type="password" value={password} onChange={(e) => setPassword(e.target.value)} required minLength="6"
              style={{ width: '100%', padding: 14, background: '#1a1a1a', border: '1px solid #2a2a2a', borderRadius: 10, color: '#fff', fontSize: 16, outline: 'none' }} />
          </div>

          {error && (
            <div style={{ padding: 12, background: 'rgba(255,68,102,0.1)', border: '1px solid rgba(255,68,102,0.3)', borderRadius: 8, marginBottom: 16 }}>
              <p style={{ color: '#ff4466', fontSize: 13, margin: 0 }}>{error}</p>
            </div>
          )}

          {verificationSent && (
            <div style={{ padding: 12, background: 'rgba(139,194,104,0.1)', border: '1px solid rgba(139,194,104,0.3)', borderRadius: 8, marginBottom: 16 }}>
              <p style={{ color: '#8bc268', fontSize: 13, margin: 0, fontWeight: 600 }}>Verification email sent!</p>
              <p style={{ color: '#8bc268', fontSize: 12, margin: '6px 0 0' }}>Check your inbox and click the link to activate your account.</p>
            </div>
          )}

          <button type="submit" disabled={loading || verificationSent}
            style={{ width: '100%', padding: 16, background: loading ? '#444' : COLORS.accent, color: loading ? '#999' : '#000', border: 'none', borderRadius: 10, fontSize: 16, fontWeight: 600, cursor: loading ? 'not-allowed' : 'pointer' }}>
            {loading ? 'Please wait...' : (authMode === 'login' ? 'Sign In' : 'Create Account')}
          </button>
        </form>

        <div style={{ marginTop: 20, textAlign: 'center' }}>
          <p style={{ color: '#888', fontSize: 14 }}>
            {authMode === 'login' ? "Don't have an account? " : "Already have an account? "}
            <button onClick={() => { setAuthMode(authMode === 'login' ? 'signup' : 'login'); setError(''); }}
              style={{ background: 'none', border: 'none', color: COLORS.accent, cursor: 'pointer', textDecoration: 'underline', fontSize: 14 }}>
              {authMode === 'login' ? 'Sign up' : 'Sign in'}
            </button>
          </p>
        </div>
      </div>
    </div>
  );
}

// ─── Email Verification Page ───
function MobileVerificationPage({ user }) {
  const [resending, setResending] = useState(false);
  const [resendSuccess, setResendSuccess] = useState(false);
  const [checking, setChecking] = useState(false);

  return (
    <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', minHeight: '100vh', background: COLORS.bg, padding: 20 }}>
      <div style={{ width: '100%', maxWidth: 400, background: '#0f0f0f', border: '1px solid #1e1e1e', borderRadius: 16, padding: '32px 24px', textAlign: 'center' }}>
        <UltratrackLogo size={24} />
        <div style={{ fontSize: 40, margin: '20px 0' }}>📧</div>
        <h2 style={{ color: '#fff', fontSize: 20, marginBottom: 12, fontWeight: 600 }}>Verify Your Email</h2>
        <p style={{ color: '#aaa', fontSize: 14, lineHeight: 1.6, marginBottom: 20 }}>
          We sent a verification email to <strong style={{ color: COLORS.accent }}>{user.email}</strong>
        </p>

        {resendSuccess && (
          <div style={{ padding: 12, background: 'rgba(139,194,104,0.1)', border: '1px solid rgba(139,194,104,0.3)', borderRadius: 8, marginBottom: 16 }}>
            <p style={{ color: '#8bc268', fontSize: 13, margin: 0 }}>Verification email sent!</p>
          </div>
        )}

        <div style={{ display: 'flex', flexDirection: 'column', gap: 10 }}>
          <button onClick={async () => { setChecking(true); try { await user.reload(); if (user.emailVerified) window.location.reload(); } catch(e) {} setChecking(false); }}
            disabled={checking}
            style={{ width: '100%', padding: 14, background: checking ? '#444' : COLORS.accent, color: checking ? '#aaa' : '#000', border: 'none', borderRadius: 10, fontSize: 15, fontWeight: 600, cursor: 'pointer' }}>
            {checking ? 'Checking...' : "I've Verified My Email"}
          </button>
          <button onClick={async () => { setResending(true); try { await user.sendEmailVerification(); setResendSuccess(true); } catch(e) {} setResending(false); }}
            disabled={resending}
            style={{ width: '100%', padding: 14, background: 'transparent', color: '#7ca5d4', border: '1px solid #2a2a2a', borderRadius: 10, fontSize: 14, fontWeight: 600, cursor: 'pointer' }}>
            {resending ? 'Sending...' : 'Resend Email'}
          </button>
          <button onClick={() => auth.signOut()}
            style={{ width: '100%', padding: 14, background: 'transparent', color: COLORS.red, border: '1px solid rgba(255,68,102,0.3)', borderRadius: 10, fontSize: 14, fontWeight: 600, cursor: 'pointer' }}>
            Sign Out
          </button>
        </div>
      </div>
    </div>
  );
}

// ─── Bottom Tab Bar ───
function TabBar({ view, setView }) {
  const tabs = [
    { id: "dashboard", label: "Home", icon: "M3 12l2-2m0 0l7-7 7 7M5 10v10a1 1 0 001 1h3m10-11l2 2m-2-2v10a1 1 0 01-1 1h-3m-4 0h4" },
    { id: "trades", label: "Trades", icon: "M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z" },
    { id: "journal", label: "Journal", icon: "M11 5H6a2 2 0 00-2 2v11a2 2 0 002 2h11a2 2 0 002-2v-5m-1.414-9.414a2 2 0 112.828 2.828L11.828 15H9v-2.828l8.586-8.586z" },
  ];

  return (
    <div style={{
      position: 'fixed', bottom: 0, left: 0, right: 0,
      height: 56,
      paddingBottom: 'env(safe-area-inset-bottom, 0px)',
      background: '#000000',
      borderTop: '1px solid #1a1a1a',
      display: 'flex',
      zIndex: 1000,
    }}>
      {tabs.map(tab => {
        const active = view === tab.id;
        return (
          <button key={tab.id} onClick={() => setView(tab.id)}
            style={{
              flex: 1, display: 'flex', flexDirection: 'column', alignItems: 'center', justifyContent: 'center', gap: 2,
              background: 'none', border: 'none', cursor: 'pointer',
              color: active ? COLORS.accent : '#555555',
              padding: 0,
            }}>
            <svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="1.8" strokeLinecap="round" strokeLinejoin="round">
              <path d={tab.icon} />
            </svg>
            <span style={{ fontSize: 10, fontFamily: FONT, fontWeight: active ? 600 : 400 }}>{tab.label}</span>
          </button>
        );
      })}
    </div>
  );
}

// ─── Dashboard ───
function MobileDashboard({ trades, onViewTrades, onOpenRecap, breakevenThreshold = 10 }) {
  const beT = Math.max(0, Number(breakevenThreshold) || 0);
  const today = getTodayLocalDate();
  const totalPnl = trades.reduce((s, t) => s + t.pnl, 0);
  const todayTrades = trades.filter(t => t.date === today);
  const todayPnl = todayTrades.reduce((s, t) => s + t.pnl, 0);

  // This week
  const now = new Date();
  const dow = now.getDay();
  const weekStart = new Date(now);
  weekStart.setDate(now.getDate() - dow);
  weekStart.setHours(0, 0, 0, 0);
  const weekTrades = trades.filter(t => new Date(t.date) >= weekStart);
  const weekPnl = weekTrades.reduce((s, t) => s + t.pnl, 0);
  const weekWinners = weekTrades.filter(t => t.pnl > beT);
  const weekWinRate = weekTrades.length ? Math.round((weekWinners.length / weekTrades.length) * 100) : 0;

  // Profit factor uses all trades (same as desktop)
  const allWinners = trades.filter(t => t.pnl > beT);
  const allLosers = trades.filter(t => t.pnl < -beT);
  const avgWin = allWinners.length ? allWinners.reduce((s, t) => s + t.pnl, 0) / allWinners.length : 0;
  const avgLoss = allLosers.length ? Math.abs(allLosers.reduce((s, t) => s + t.pnl, 0) / allLosers.length) : 1;
  const profitFactor = allLosers.length ? ((avgWin * allWinners.length) / (avgLoss * allLosers.length)).toFixed(2) : "\u221e";

  const recentTrades = trades.slice(0, 5);

  const cardStyle = {
    background: COLORS.card, border: `1px solid ${COLORS.cardBorder}`, borderRadius: 14, padding: '16px 18px',
  };

  return (
    <div style={{ padding: '16px 16px 80px', animation: 'fadeIn 0.3s ease' }}>
      {/* Header */}
      <div style={{ marginBottom: 20, display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <UltratrackLogo size={22} />
        <div style={{ display: 'flex', gap: 8, alignItems: 'center' }}>
          {onOpenRecap && (
            <button onClick={onOpenRecap} style={{ background: 'rgba(127,255,178,0.1)', border: '1px solid rgba(127,255,178,0.25)', color: '#7fffb2', fontSize: 11, padding: '5px 10px', borderRadius: 999, cursor: 'pointer', fontFamily: FONT }}>☀️ Recap</button>
          )}
          <button onClick={() => auth.signOut()} style={{ background: 'none', border: 'none', color: COLORS.textDim, fontSize: 12, cursor: 'pointer', fontFamily: FONT }}>Sign Out</button>
        </div>
      </div>

      {/* Total P&L */}
      <div style={{ ...cardStyle, marginBottom: 14, textAlign: 'center' }}>
        <p style={{ color: COLORS.textMuted, fontSize: 11, fontFamily: FONT, margin: '0 0 4px', letterSpacing: '.05em' }}>TOTAL P&L</p>
        <p style={{ fontSize: 36, fontWeight: 700, fontFamily: FONT, margin: '4px 0', color: totalPnl >= 0 ? COLORS.accent : COLORS.red }}>
          ${totalPnl.toFixed(2)}
        </p>
        <p style={{ color: COLORS.textMuted, fontSize: 12, fontFamily: FONT, margin: 0 }}>
          {trades.length} trade{trades.length !== 1 ? 's' : ''} total
        </p>
      </div>

      {/* Week Stats Grid */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 14 }}>
        <div style={cardStyle}>
          <p style={{ color: COLORS.textMuted, fontSize: 10, fontFamily: FONT, margin: '0 0 4px', letterSpacing: '.05em' }}>TODAY P&L</p>
          <p style={{ fontSize: 22, fontWeight: 700, fontFamily: FONT, margin: 0, color: todayPnl >= 0 ? COLORS.accent : COLORS.red }}>${todayPnl.toFixed(2)}</p>
        </div>
        <div style={cardStyle}>
          <p style={{ color: COLORS.textMuted, fontSize: 10, fontFamily: FONT, margin: '0 0 4px', letterSpacing: '.05em' }}>WIN RATE</p>
          <p style={{ fontSize: 22, fontWeight: 700, fontFamily: FONT, margin: 0, color: '#fff' }}>{weekWinRate}%</p>
        </div>
        <div style={cardStyle}>
          <p style={{ color: COLORS.textMuted, fontSize: 10, fontFamily: FONT, margin: '0 0 4px', letterSpacing: '.05em' }}>TRADES</p>
          <p style={{ fontSize: 22, fontWeight: 700, fontFamily: FONT, margin: 0, color: '#fff' }}>{weekTrades.length}</p>
        </div>
        <div style={cardStyle}>
          <p style={{ color: COLORS.textMuted, fontSize: 10, fontFamily: FONT, margin: '0 0 4px', letterSpacing: '.05em' }}>PROFIT FACTOR</p>
          <p style={{ fontSize: 22, fontWeight: 700, fontFamily: FONT, margin: 0, color: '#fff' }}>{profitFactor}</p>
        </div>
      </div>

      {/* Recent Trades */}
      <div style={cardStyle}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
          <p style={{ color: '#fff', fontSize: 14, fontFamily: FONT, fontWeight: 600, margin: 0 }}>Recent Trades</p>
          <button onClick={onViewTrades} style={{ background: 'none', border: 'none', color: COLORS.accent, fontSize: 12, cursor: 'pointer', fontFamily: FONT }}>View All</button>
        </div>
        {recentTrades.length === 0 ? (
          <p style={{ color: COLORS.textMuted, fontSize: 13, fontFamily: FONT, textAlign: 'center', padding: '20px 0' }}>No trades yet</p>
        ) : (
          recentTrades.map(trade => (
            <div key={trade.id} style={{ display: 'flex', alignItems: 'center', justifyContent: 'space-between', padding: '10px 0', borderBottom: `1px solid ${COLORS.cardBorder}` }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
                <span style={{ fontSize: 12, fontWeight: 700, fontFamily: FONT, color: '#fff', background: '#1a1a1a', padding: '3px 8px', borderRadius: 6 }}>{trade.market || trade.ticker}</span>
                <span style={{ fontSize: 12, fontFamily: FONT, color: trade.direction === 'Long' ? COLORS.accent : COLORS.red }}>{trade.direction === 'Long' ? '\u2191' : '\u2193'}</span>
                <span style={{ fontSize: 11, fontFamily: FONT, color: COLORS.textMuted }}>{formatDateDisplay(trade.date)}</span>
              </div>
              <span style={{ fontSize: 14, fontWeight: 700, fontFamily: FONT, color: trade.pnl >= 0 ? COLORS.accent : COLORS.red }}>${trade.pnl.toFixed(2)}</span>
            </div>
          ))
        )}
      </div>
    </div>
  );
}

// ─── Trade Card ───
function TradeCard({ trade, expanded, onToggle }) {
  const mistakes = getMistakes(trade);
  return (
    <div onClick={onToggle} style={{
      background: COLORS.card, border: `1px solid ${COLORS.cardBorder}`, borderRadius: 14, padding: '14px 16px', marginBottom: 10, cursor: 'pointer',
      transition: 'all 0.2s',
    }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10 }}>
          <span style={{ fontSize: 13, fontWeight: 700, fontFamily: FONT, color: '#fff', background: '#1a1a1a', padding: '4px 10px', borderRadius: 8 }}>{trade.market || trade.ticker}</span>
          <span style={{ fontSize: 13, fontFamily: FONT, color: trade.direction === 'Long' ? COLORS.accent : COLORS.red, fontWeight: 600 }}>
            {trade.direction === 'Long' ? '\u2191 Long' : '\u2193 Short'}
          </span>
        </div>
        <span style={{ fontSize: 16, fontWeight: 700, fontFamily: FONT, color: trade.pnl >= 0 ? COLORS.accent : COLORS.red }}>${trade.pnl.toFixed(2)}</span>
      </div>

      <div style={{ display: 'flex', gap: 10, marginTop: 8, alignItems: 'center' }}>
        <span style={{ fontSize: 11, fontFamily: FONT, color: COLORS.textMuted }}>{formatDateDisplay(trade.date)}</span>
        {trade.strategy && <span style={{ fontSize: 10, fontFamily: FONT, color: '#7ca5d4', background: 'rgba(124,165,212,0.1)', padding: '2px 8px', borderRadius: 6 }}>{trade.strategy}</span>}
        {trade.session && <span style={{ fontSize: 10, fontFamily: FONT, color: COLORS.textDim }}>{trade.session}</span>}
      </div>

      {expanded && (
        <div style={{ marginTop: 14, paddingTop: 14, borderTop: `1px solid ${COLORS.cardBorder}`, animation: 'fadeIn 0.2s ease' }}>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            <div>
              <p style={{ color: COLORS.textMuted, fontSize: 10, fontFamily: FONT, margin: '0 0 2px' }}>ENTRY</p>
              <p style={{ color: '#fff', fontSize: 14, fontFamily: FONT, margin: 0, fontWeight: 600 }}>{trade.entry}{trade.entryTime ? ` @ ${trade.entryTime}` : ''}</p>
            </div>
            <div>
              <p style={{ color: COLORS.textMuted, fontSize: 10, fontFamily: FONT, margin: '0 0 2px' }}>EXIT</p>
              <p style={{ color: '#fff', fontSize: 14, fontFamily: FONT, margin: 0, fontWeight: 600 }}>{trade.exit}{trade.exitTime ? ` @ ${trade.exitTime}` : ''}</p>
            </div>
            <div>
              <p style={{ color: COLORS.textMuted, fontSize: 10, fontFamily: FONT, margin: '0 0 2px' }}>SIZE</p>
              <p style={{ color: '#fff', fontSize: 14, fontFamily: FONT, margin: 0 }}>{trade.size} ct</p>
            </div>
            <div>
              <p style={{ color: COLORS.textMuted, fontSize: 10, fontFamily: FONT, margin: '0 0 2px' }}>EMOTION</p>
              <p style={{ color: emotionColors[trade.emotion] || '#fff', fontSize: 14, fontFamily: FONT, margin: 0 }}>{trade.emotion}</p>
            </div>
          </div>
          {mistakes[0] !== "None" && (
            <div style={{ marginTop: 10 }}>
              <p style={{ color: COLORS.textMuted, fontSize: 10, fontFamily: FONT, margin: '0 0 4px' }}>MISTAKES</p>
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: 4 }}>
                {mistakes.map(m => (
                  <span key={m} style={{ fontSize: 10, fontFamily: FONT, color: mistakeColors[m] || COLORS.red, background: `${mistakeColors[m] || COLORS.red}15`, padding: '2px 8px', borderRadius: 6 }}>{m}</span>
                ))}
              </div>
            </div>
          )}
          {trade.notes && (
            <div style={{ marginTop: 10 }}>
              <p style={{ color: COLORS.textMuted, fontSize: 10, fontFamily: FONT, margin: '0 0 4px' }}>NOTES</p>
              <p style={{ color: '#ccc', fontSize: 12, fontFamily: FONT, margin: 0, lineHeight: 1.5 }}>{trade.notes}</p>
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// ─── Trade Form ───
function MobileTradeForm({ onSave, onClose }) {
  const [form, setForm] = useState({
    date: getTodayLocalDate(),
    market: "ES",
    direction: "Long",
    entry: "",
    exit: "",
    entryTime: "",
    exitTime: "",
    size: "1",
    commission: "",
    strategy: "Opening Range",
    emotion: "Calm",
    mistake: ["None"],
    session: detectSession(Date.now()),
    notes: "",
  });

  const update = (field, value) => setForm(prev => ({ ...prev, [field]: value }));

  const toggleMistake = (m) => {
    setForm(prev => {
      if (m === "None") return { ...prev, mistake: ["None"] };
      const without = prev.mistake.filter(x => x !== "None");
      if (without.includes(m)) {
        const result = without.filter(x => x !== m);
        return { ...prev, mistake: result.length === 0 ? ["None"] : result };
      }
      return { ...prev, mistake: [...without, m] };
    });
  };

  const handleSave = () => {
    if (!form.entry || !form.exit || !form.size) {
      alert('Entry, exit, and size are required');
      return;
    }
    const entryNum = +form.entry, exitNum = +form.exit, sizeNum = +form.size;
    const commissionNum = form.commission === "" ? 0 : +form.commission;
    if (!(sizeNum > 0)) { alert('Size must be greater than 0'); return; }
    if (!(entryNum > 0) || !(exitNum > 0)) { alert('Entry and exit prices must be greater than 0'); return; }
    if (commissionNum < 0) { alert('Commission cannot be negative'); return; }
    if (form.entryTime && form.exitTime && form.exitTime < form.entryTime) {
      alert('Exit time cannot be before entry time');
      return;
    }
    const t = { ...form, id: Date.now(), entry: entryNum, exit: exitNum, size: sizeNum, commission: commissionNum, ticker: form.market, source: "manual" };
    t.pnl = calcPnl(t);
    onSave(t);
  };

  const inputStyle = { width: '100%', padding: 14, background: COLORS.inputBg, border: `1px solid ${COLORS.inputBorder}`, borderRadius: 10, color: '#fff', fontSize: 16, fontFamily: FONT, outline: 'none' };
  const labelStyle = { display: 'block', color: COLORS.textMuted, fontSize: 11, fontFamily: FONT, marginBottom: 6, letterSpacing: '.03em' };

  return (
    <div style={{
      position: 'fixed', top: 0, left: 0, right: 0, bottom: 0,
      background: COLORS.bg, zIndex: 2000,
      overflowY: 'auto', WebkitOverflowScrolling: 'touch',
      animation: 'slideUp 0.3s ease',
    }}>
      <div style={{ padding: '16px 16px 100px' }}>
        {/* Header */}
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 20 }}>
          <button onClick={onClose} style={{ background: 'none', border: 'none', color: COLORS.textMuted, fontSize: 14, cursor: 'pointer', fontFamily: FONT }}>Cancel</button>
          <p style={{ color: '#fff', fontSize: 16, fontFamily: FONT, fontWeight: 600, margin: 0 }}>New Trade</p>
          <button onClick={handleSave} style={{ background: 'none', border: 'none', color: COLORS.accent, fontSize: 14, cursor: 'pointer', fontFamily: FONT, fontWeight: 600 }}>Save</button>
        </div>

        {/* Date */}
        <div style={{ marginBottom: 16 }}>
          <label style={labelStyle}>DATE</label>
          <input type="date" value={form.date} onChange={e => update('date', e.target.value)} style={inputStyle} />
        </div>

        {/* Market pills */}
        <div style={{ marginBottom: 16 }}>
          <label style={labelStyle}>MARKET</label>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 8 }}>
            {INSTRUMENTS.map(m => (
              <button key={m} onClick={() => update('market', m)}
                style={{
                  padding: '10px 16px', borderRadius: 10, fontSize: 13, fontFamily: FONT, fontWeight: 600, cursor: 'pointer',
                  background: form.market === m ? COLORS.accent + '20' : '#111111',
                  border: form.market === m ? `1px solid ${COLORS.accent}` : '1px solid #1e1e1e',
                  color: form.market === m ? COLORS.accent : '#aaa',
                }}>
                {m}
              </button>
            ))}
          </div>
        </div>

        {/* Direction */}
        <div style={{ marginBottom: 16 }}>
          <label style={labelStyle}>DIRECTION</label>
          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10 }}>
            {['Long', 'Short'].map(d => (
              <button key={d} onClick={() => update('direction', d)}
                style={{
                  padding: 14, borderRadius: 10, fontSize: 15, fontFamily: FONT, fontWeight: 600, cursor: 'pointer',
                  background: form.direction === d ? (d === 'Long' ? 'rgba(127,255,178,0.12)' : 'rgba(255,68,102,0.12)') : '#111111',
                  border: form.direction === d ? `1px solid ${d === 'Long' ? COLORS.accent : COLORS.red}` : '1px solid #1e1e1e',
                  color: form.direction === d ? (d === 'Long' ? COLORS.accent : COLORS.red) : '#aaa',
                }}>
                {d === 'Long' ? '\u2191' : '\u2193'} {d}
              </button>
            ))}
          </div>
        </div>

        {/* Entry / Exit */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 16 }}>
          <div>
            <label style={labelStyle}>ENTRY PRICE</label>
            <input type="number" inputMode="decimal" step="any" value={form.entry} onChange={e => update('entry', e.target.value)} placeholder="0.00" style={inputStyle} />
          </div>
          <div>
            <label style={labelStyle}>EXIT PRICE</label>
            <input type="number" inputMode="decimal" step="any" value={form.exit} onChange={e => update('exit', e.target.value)} placeholder="0.00" style={inputStyle} />
          </div>
        </div>

        {/* Entry / Exit Time */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 16 }}>
          <div>
            <label style={labelStyle}>ENTRY TIME</label>
            <input type="time" step="1" value={form.entryTime} onChange={e => update('entryTime', e.target.value)} style={inputStyle} />
          </div>
          <div>
            <label style={labelStyle}>EXIT TIME</label>
            <input type="time" step="1" value={form.exitTime} onChange={e => update('exitTime', e.target.value)} style={inputStyle} />
          </div>
        </div>

        {/* Size + Commission */}
        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 10, marginBottom: 16 }}>
          <div>
            <label style={labelStyle}>SIZE (CONTRACTS)</label>
            <input type="number" inputMode="numeric" value={form.size} onChange={e => update('size', e.target.value)} style={inputStyle} />
          </div>
          <div>
            <label style={labelStyle}>COMMISSION ($)</label>
            <input type="number" inputMode="decimal" step="0.01" min="0" placeholder="0.00" value={form.commission} onChange={e => update('commission', e.target.value)} style={inputStyle} />
          </div>
        </div>

        {/* Strategy */}
        <div style={{ marginBottom: 16 }}>
          <label style={labelStyle}>STRATEGY</label>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {STRATEGIES.map(s => (
              <button key={s} onClick={() => update('strategy', s)}
                style={{
                  padding: '8px 14px', borderRadius: 20, fontSize: 12, fontFamily: FONT, cursor: 'pointer',
                  background: form.strategy === s ? 'rgba(124,165,212,0.15)' : 'transparent',
                  border: form.strategy === s ? '1px solid #7ca5d4' : '1px solid #1e1e1e',
                  color: form.strategy === s ? '#7ca5d4' : '#888',
                }}>
                {s}
              </button>
            ))}
          </div>
        </div>

        {/* Emotion */}
        <div style={{ marginBottom: 16 }}>
          <label style={labelStyle}>EMOTION</label>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {EMOTIONS.map(e => (
              <button key={e} onClick={() => update('emotion', e)}
                style={{
                  padding: '8px 14px', borderRadius: 20, fontSize: 12, fontFamily: FONT, cursor: 'pointer',
                  background: form.emotion === e ? `${emotionColors[e]}20` : 'transparent',
                  border: form.emotion === e ? `1px solid ${emotionColors[e]}` : '1px solid #1e1e1e',
                  color: form.emotion === e ? emotionColors[e] : '#888',
                }}>
                {e}
              </button>
            ))}
          </div>
        </div>

        {/* Mistakes */}
        <div style={{ marginBottom: 16 }}>
          <label style={labelStyle}>MISTAKES</label>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {MISTAKES.map(m => {
              const active = form.mistake.includes(m);
              return (
                <button key={m} onClick={() => toggleMistake(m)}
                  style={{
                    padding: '8px 14px', borderRadius: 20, fontSize: 12, fontFamily: FONT, cursor: 'pointer',
                    background: active ? `${mistakeColors[m]}20` : 'transparent',
                    border: active ? `1px solid ${mistakeColors[m]}` : '1px solid #1e1e1e',
                    color: active ? mistakeColors[m] : '#888',
                  }}>
                  {m}
                </button>
              );
            })}
          </div>
        </div>

        {/* Session */}
        <div style={{ marginBottom: 16 }}>
          <label style={labelStyle}>SESSION</label>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {SESSIONS.map(s => (
              <button key={s} onClick={() => update('session', s)}
                style={{
                  padding: '8px 14px', borderRadius: 20, fontSize: 12, fontFamily: FONT, cursor: 'pointer',
                  background: form.session === s ? 'rgba(160,142,204,0.15)' : 'transparent',
                  border: form.session === s ? '1px solid #a08ecc' : '1px solid #1e1e1e',
                  color: form.session === s ? '#a08ecc' : '#888',
                }}>
                {s}
              </button>
            ))}
          </div>
        </div>

        {/* Notes */}
        <div style={{ marginBottom: 20 }}>
          <label style={labelStyle}>NOTES</label>
          <textarea value={form.notes} onChange={e => update('notes', e.target.value)} placeholder="Trade notes..."
            rows={4}
            style={{ ...inputStyle, resize: 'vertical', minHeight: 80, lineHeight: 1.5 }} />
        </div>

        {/* P&L Preview */}
        {form.entry && form.exit && form.size && (
          <div style={{ textAlign: 'center', marginBottom: 20 }}>
            <p style={{ color: COLORS.textMuted, fontSize: 11, fontFamily: FONT, margin: '0 0 4px' }}>ESTIMATED P&L</p>
            <p style={{
              fontSize: 28, fontWeight: 700, fontFamily: FONT, margin: 0,
              color: calcPnl({ ...form, entry: +form.entry, exit: +form.exit, size: +form.size, commission: form.commission === "" ? 0 : +form.commission }) >= 0 ? COLORS.accent : COLORS.red
            }}>
              ${calcPnl({ ...form, entry: +form.entry, exit: +form.exit, size: +form.size, commission: form.commission === "" ? 0 : +form.commission }).toFixed(2)}
            </p>
          </div>
        )}

        {/* Save Button */}
        <button onClick={handleSave}
          disabled={!form.entry || !form.exit || !form.size}
          style={{
            width: '100%', padding: 16, borderRadius: 12, fontSize: 16, fontWeight: 700, fontFamily: FONT, cursor: 'pointer',
            background: (!form.entry || !form.exit || !form.size) ? '#333' : COLORS.accent,
            color: (!form.entry || !form.exit || !form.size) ? '#666' : '#000',
            border: 'none',
          }}>
          Save Trade
        </button>
      </div>
    </div>
  );
}

// ─── Trades List ───
function MobileTradesList({ trades, onAddTrade }) {
  const [expandedId, setExpandedId] = useState(null);
  const [showForm, setShowForm] = useState(false);
  const [filter, setFilter] = useState("all"); // all, today, week, month

  const now = new Date();
  const today = getTodayLocalDate();
  const dow = now.getDay();
  const weekStart = new Date(now);
  weekStart.setDate(now.getDate() - dow);
  weekStart.setHours(0, 0, 0, 0);
  const monthStart = new Date(now.getFullYear(), now.getMonth(), 1);

  const filtered = trades.filter(t => {
    if (filter === "today") return t.date === today;
    if (filter === "week") return new Date(t.date) >= weekStart;
    if (filter === "month") return new Date(t.date) >= monthStart;
    return true;
  });

  const filteredPnl = filtered.reduce((s, t) => s + t.pnl, 0);

  if (showForm) {
    return <MobileTradeForm onSave={(t) => { onAddTrade(t); setShowForm(false); }} onClose={() => setShowForm(false)} />;
  }

  return (
    <div style={{ padding: '16px 16px 80px', animation: 'fadeIn 0.3s ease' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
        <p style={{ color: '#fff', fontSize: 18, fontFamily: FONT, fontWeight: 700, margin: 0 }}>Trades</p>
        <span style={{ fontSize: 16, fontWeight: 700, fontFamily: FONT, color: filteredPnl >= 0 ? COLORS.accent : COLORS.red }}>${filteredPnl.toFixed(2)}</span>
      </div>

      {/* Filter pills */}
      <div style={{ display: 'flex', gap: 8, marginBottom: 16, overflowX: 'auto', WebkitOverflowScrolling: 'touch' }}>
        {[['all', 'All'], ['today', 'Today'], ['week', 'This Week'], ['month', 'This Month']].map(([key, label]) => (
          <button key={key} onClick={() => setFilter(key)}
            style={{
              padding: '8px 16px', borderRadius: 20, fontSize: 12, fontFamily: FONT, cursor: 'pointer', whiteSpace: 'nowrap',
              background: filter === key ? COLORS.accent + '18' : 'transparent',
              border: filter === key ? `1px solid ${COLORS.accent}` : '1px solid #1e1e1e',
              color: filter === key ? COLORS.accent : '#888',
            }}>
            {label}
          </button>
        ))}
      </div>

      {/* Trade list */}
      {filtered.length === 0 ? (
        <div style={{ textAlign: 'center', padding: '40px 0' }}>
          <p style={{ color: COLORS.textMuted, fontSize: 14, fontFamily: FONT }}>No trades found</p>
        </div>
      ) : (
        filtered.map(t => (
          <TradeCard key={t.id} trade={t} expanded={expandedId === t.id} onToggle={() => setExpandedId(expandedId === t.id ? null : t.id)} />
        ))
      )}

      {/* FAB */}
      <button onClick={() => setShowForm(true)}
        style={{
          position: 'fixed', bottom: 72, right: 20,
          width: 56, height: 56, borderRadius: 28,
          background: COLORS.accent, border: 'none',
          color: '#000', fontSize: 28, fontWeight: 300,
          cursor: 'pointer', boxShadow: '0 4px 20px rgba(127,255,178,0.3)',
          display: 'flex', alignItems: 'center', justifyContent: 'center',
          zIndex: 900,
        }}>
        +
      </button>
    </div>
  );
}

// ─── Journal ───
function MobileJournal({ journalEntries, setJournalEntries, saveStatus, tradingRules = [] }) {
  const [selectedDate, setSelectedDate] = useState(getTodayLocalDate());

  const entry = journalEntries[selectedDate] || {};
  const mindset = entry.mindset || {};

  const updateMindset = (field, value) => {
    setJournalEntries(prev => ({
      ...prev,
      [selectedDate]: {
        ...prev[selectedDate],
        mindset: { ...(prev[selectedDate]?.mindset || {}), [field]: value }
      }
    }));
  };

  const toggleChip = (field, value) => {
    setJournalEntries(prev => {
      const current = prev[selectedDate]?.mindset?.[field] || [];
      const next = current.includes(value) ? current.filter(v => v !== value) : [...current, value];
      return {
        ...prev,
        [selectedDate]: {
          ...prev[selectedDate],
          mindset: { ...(prev[selectedDate]?.mindset || {}), [field]: next }
        }
      };
    });
  };

  const updateText = (field, value) => {
    setJournalEntries(prev => ({
      ...prev,
      [selectedDate]: { ...prev[selectedDate], [field]: value }
    }));
  };

  const activeRules = tradingRules.filter(r => r.active !== false);

  const updateRuleCheckoff = (ruleId, value) => {
    setJournalEntries(prev => {
      const entry = prev[selectedDate] || {};
      const ms = entry.mindset || {};
      const checkoffs = { ...(ms.ruleCheckoffs || {}), [ruleId]: value };
      const followed = activeRules.filter(r => checkoffs[r.id] === true).length;
      const total = activeRules.length;
      const ruleScore = total > 0 ? Math.round((followed / total) * 100) : null;
      const ruleAdherence = total > 0 ? Math.round((followed / total) * 10) : ms.ruleAdherence;
      return {
        ...prev,
        [selectedDate]: { ...entry, mindset: { ...ms, ruleCheckoffs: checkoffs, ruleScore, ruleAdherence } }
      };
    });
  };

  const cardStyle = { background: COLORS.card, border: `1px solid ${COLORS.cardBorder}`, borderRadius: 14, padding: '16px 18px', marginBottom: 12 };
  const labelStyle = { color: COLORS.textMuted, fontSize: 10, fontFamily: FONT, marginBottom: 4, letterSpacing: '.05em', display: 'block' };
  const numInput = { width: 60, padding: 10, background: COLORS.inputBg, border: `1px solid ${COLORS.inputBorder}`, borderRadius: 8, color: '#fff', fontSize: 16, fontFamily: FONT, outline: 'none', textAlign: 'center' };

  return (
    <div style={{ padding: '16px 16px 80px', animation: 'fadeIn 0.3s ease' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 16 }}>
        <p style={{ color: '#fff', fontSize: 18, fontFamily: FONT, fontWeight: 700, margin: 0 }}>Journal</p>
        <span style={{ fontSize: 11, fontFamily: FONT, color: saveStatus === 'saved' ? COLORS.accent : saveStatus === 'saving' ? '#ffdd00' : COLORS.textDim }}>
          {saveStatus === 'saved' ? 'Saved' : saveStatus === 'saving' ? 'Saving...' : ''}
        </span>
      </div>

      {/* Date picker */}
      <div style={{ marginBottom: 16 }}>
        <input type="date" value={selectedDate} onChange={e => setSelectedDate(e.target.value)}
          style={{ width: '100%', padding: 14, background: COLORS.inputBg, border: `1px solid ${COLORS.inputBorder}`, borderRadius: 10, color: '#fff', fontSize: 16, fontFamily: FONT, outline: 'none' }} />
      </div>

      {/* Morning Check-In */}
      <div style={{ ...cardStyle, borderLeft: `3px solid ${COLORS.accent}` }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
          <p style={{ color: '#fff', fontSize: 13, fontFamily: FONT, fontWeight: 600, margin: 0 }}>Morning Check-In</p>
          <span style={{ fontSize: 9, color: COLORS.accent, fontFamily: FONT, letterSpacing: '.1em' }}>PRE-MARKET</span>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr 1fr', gap: 8, marginBottom: 12 }}>
          <div>
            <label style={labelStyle}>SLEEP</label>
            <input type="number" step="0.5" min="0" max="24" inputMode="decimal"
              value={mindset.sleepHours ?? ""} onChange={e => updateMindset('sleepHours', e.target.value === "" ? null : Number(e.target.value))}
              style={numInput} />
          </div>
          <div>
            <label style={labelStyle}>STRESS</label>
            <input type="number" min="1" max="10" inputMode="numeric"
              value={mindset.stress ?? ""} onChange={e => updateMindset('stress', e.target.value === "" ? null : Number(e.target.value))}
              style={numInput} />
          </div>
          <div>
            <label style={labelStyle}>PREP</label>
            <input type="number" min="1" max="10" inputMode="numeric"
              value={mindset.prepQuality ?? ""} onChange={e => updateMindset('prepQuality', e.target.value === "" ? null : Number(e.target.value))}
              style={numInput} />
          </div>
          <div>
            <label style={labelStyle}>ENERGY</label>
            <input type="number" min="1" max="10" inputMode="numeric"
              value={mindset.energy ?? ""} onChange={e => updateMindset('energy', e.target.value === "" ? null : Number(e.target.value))}
              style={numInput} />
          </div>
        </div>

        <div>
          <label style={labelStyle}>MOOD</label>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {MOOD_OPTIONS.map(mood => {
              const active = (mindset.mood || []).includes(mood);
              return (
                <button key={mood} onClick={() => toggleChip('mood', mood)}
                  style={{
                    padding: '7px 14px', fontSize: 11, borderRadius: 20, fontFamily: FONT, cursor: 'pointer',
                    border: active ? `1px solid ${COLORS.accent}` : '1px solid rgba(255,255,255,0.12)',
                    background: active ? `${COLORS.accent}18` : 'transparent',
                    color: active ? COLORS.accent : '#aaa',
                  }}>
                  {mood}
                </button>
              );
            })}
          </div>
        </div>
      </div>

      {/* Pre-Market Plan */}
      <div style={cardStyle}>
        <label style={{ ...labelStyle, marginBottom: 8 }}>PRE-MARKET PLAN</label>
        <textarea value={entry.text || ""} onChange={e => updateText('text', e.target.value)}
          placeholder="Key levels, setups, rules for today..."
          rows={5}
          style={{ width: '100%', padding: 12, background: COLORS.inputBg, border: `1px solid ${COLORS.inputBorder}`, borderRadius: 10, color: '#fff', fontSize: 14, fontFamily: FONT, outline: 'none', resize: 'vertical', lineHeight: 1.6 }} />
      </div>

      {/* Evening Check-In */}
      <div style={{ ...cardStyle, borderLeft: `3px solid #a08ecc` }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: 12 }}>
          <p style={{ color: '#fff', fontSize: 13, fontFamily: FONT, fontWeight: 600, margin: 0 }}>Evening Check-In</p>
          <span style={{ fontSize: 9, color: '#a08ecc', fontFamily: FONT, letterSpacing: '.1em' }}>END OF DAY</span>
        </div>

        {/* Rules Checklist */}
        {activeRules.length > 0 ? (
          <div style={{ marginBottom: 14 }}>
            <label style={labelStyle}>TRADING RULES</label>
            {["risk", "process", "mindset"].map(cat => {
              const catRules = activeRules.filter(r => r.category === cat);
              if (catRules.length === 0) return null;
              return (
                <div key={cat} style={{ marginBottom: 8 }}>
                  <span style={{ fontSize: 9, color: RULE_CATEGORY_COLORS[cat], fontFamily: FONT, letterSpacing: '.08em', display: 'block', marginBottom: 4 }}>
                    {RULE_CATEGORY_LABELS[cat].toUpperCase()}
                  </span>
                  {catRules.map(rule => {
                    const checked = mindset.ruleCheckoffs?.[rule.id] === true;
                    return (
                      <label key={rule.id} style={{
                        display: 'flex', alignItems: 'center', gap: 10, padding: '8px 6px', cursor: 'pointer',
                        borderRadius: 6, background: checked ? `${RULE_CATEGORY_COLORS[cat]}08` : 'transparent'
                      }}>
                        <input type="checkbox" checked={checked}
                          onChange={e => updateRuleCheckoff(rule.id, e.target.checked)}
                          style={{ accentColor: RULE_CATEGORY_COLORS[cat], width: 18, height: 18 }} />
                        <span style={{
                          fontSize: 12, color: checked ? '#ccc' : '#888', fontFamily: FONT,
                          textDecoration: checked ? 'line-through' : 'none'
                        }}>{rule.text}</span>
                      </label>
                    );
                  })}
                </div>
              );
            })}

            {/* Score bar */}
            {(() => {
              const checkoffs = mindset.ruleCheckoffs;
              if (!checkoffs || Object.keys(checkoffs).length === 0) return null;
              const followed = activeRules.filter(r => checkoffs[r.id] === true).length;
              const total = activeRules.length;
              const pct = Math.round((followed / total) * 100);
              const barColor = pct >= 80 ? "#7fffb2" : pct >= 50 ? "#ffdd00" : "#ff5566";
              return (
                <div style={{ marginTop: 8, padding: '8px 10px', background: COLORS.inputBg, borderRadius: 8, border: `1px solid ${COLORS.inputBorder}` }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', marginBottom: 4 }}>
                    <span style={{ fontSize: 11, color: '#888', fontFamily: FONT }}>{followed}/{total} rules followed</span>
                    <span style={{ fontSize: 13, fontWeight: 700, color: barColor, fontFamily: FONT }}>{pct}%</span>
                  </div>
                  <div style={{ height: 4, background: '#1a1a1a', borderRadius: 2, overflow: 'hidden' }}>
                    <div style={{ height: '100%', width: `${pct}%`, background: barColor, borderRadius: 2, transition: 'width .3s' }} />
                  </div>
                </div>
              );
            })()}
          </div>
        ) : (
          <div style={{ marginBottom: 14, padding: '12px 0', textAlign: 'center' }}>
            <p style={{ fontSize: 11, color: '#666', fontFamily: FONT }}>Set up trading rules on desktop to track here</p>
          </div>
        )}

        {/* Day Rating */}
        <div style={{ marginBottom: 12 }}>
          <label style={labelStyle}>DAY RATING</label>
          <input type="number" min="1" max="10" inputMode="numeric"
            value={mindset.dayRating ?? ""} onChange={e => updateMindset('dayRating', e.target.value === "" ? null : Number(e.target.value))}
            style={numInput} />
        </div>

        {/* Discipline Tags */}
        <div>
          <label style={labelStyle}>DISCIPLINE TAGS</label>
          <div style={{ display: 'flex', flexWrap: 'wrap', gap: 6 }}>
            {DISCIPLINE_TAG_OPTIONS.map(tag => {
              const active = (mindset.disciplineTags || []).includes(tag);
              const isPositive = tag === "Followed plan";
              const accent = isPositive ? COLORS.accent : "#ff7744";
              return (
                <button key={tag} onClick={() => toggleChip('disciplineTags', tag)}
                  style={{
                    padding: '7px 14px', fontSize: 11, borderRadius: 20, fontFamily: FONT, cursor: 'pointer',
                    border: active ? `1px solid ${accent}` : '1px solid rgba(255,255,255,0.12)',
                    background: active ? `${accent}22` : 'transparent',
                    color: active ? accent : '#aaa',
                  }}>
                  {tag}
                </button>
              );
            })}
          </div>
        </div>
      </div>

      {/* Post-Session Review */}
      <div style={cardStyle}>
        <label style={{ ...labelStyle, marginBottom: 8 }}>POST-SESSION REVIEW</label>
        <textarea value={entry.postSession || ""} onChange={e => updateText('postSession', e.target.value)}
          placeholder="What went well? What to improve? Key lessons..."
          rows={5}
          style={{ width: '100%', padding: 12, background: COLORS.inputBg, border: `1px solid ${COLORS.inputBorder}`, borderRadius: 10, color: '#fff', fontSize: 14, fontFamily: FONT, outline: 'none', resize: 'vertical', lineHeight: 1.6 }} />
      </div>

      {/* Lessons */}
      <div style={cardStyle}>
        <label style={{ ...labelStyle, marginBottom: 8 }}>LESSONS & TAKEAWAYS</label>
        <textarea value={entry.lessons || ""} onChange={e => updateText('lessons', e.target.value)}
          placeholder="What did I learn today?"
          rows={3}
          style={{ width: '100%', padding: 12, background: COLORS.inputBg, border: `1px solid ${COLORS.inputBorder}`, borderRadius: 10, color: '#fff', fontSize: 14, fontFamily: FONT, outline: 'none', resize: 'vertical', lineHeight: 1.6 }} />
      </div>
    </div>
  );
}


// ─── Main Trading Journal Shell ───
function MobileTradingJournal({ user }) {
  const [view, setView] = useState("dashboard");
  const [trades, setTrades] = useState([]);
  const [tradesLoaded, setTradesLoaded] = useState(false);
  const [journalEntries, setJournalEntries] = useState({});
  const [journalLoaded, setJournalLoaded] = useState(false);
  const [journalSaveStatus, setJournalSaveStatus] = useState('');
  const lastSavedJournalRef = useRef({});
  const [tradingRules, setTradingRules] = useState([]);
  const [breakevenThreshold, setBreakevenThreshold] = useState(10);


  // Load trades
  useEffect(() => {
    async function load() {
      try {
        let loaded = await loadTradesFromFirestore(user.uid);
        loaded = loaded.map(t => ({
          ...t,
          date: formatDateToYMD(t.date),
          pnl: t.pnl != null ? t.pnl : calcPnl(t),
        }));
        // Sort by date descending
        loaded.sort((a, b) => {
          if (b.date !== a.date) return b.date.localeCompare(a.date);
          return (b.id || 0) - (a.id || 0);
        });
        setTrades(loaded);
        setTradesLoaded(true);
      } catch (error) {
        console.error('Failed to load trades:', error);
        setTradesLoaded(true);
      }
    }
    load();
  }, [user.uid]);

  // Auto-save trades
  useEffect(() => {
    if (tradesLoaded && trades.length > 0) {
      const timeout = setTimeout(() => {
        saveTradesToFirestore(user.uid, trades).catch(e => console.error('Auto-save failed:', e));
      }, 2000);
      return () => clearTimeout(timeout);
    }
  }, [trades, tradesLoaded, user.uid]);

  // Load journal
  useEffect(() => {
    async function load() {
      try {
        const entries = await loadJournalFromFirestore(user.uid);
        setJournalEntries(entries);
        lastSavedJournalRef.current = { ...entries };
        setJournalLoaded(true);
      } catch (error) {
        console.error('Failed to load journal:', error);
        setJournalLoaded(true);
      }
    }
    load();
  }, [user.uid]);

  // Load trading rules
  useEffect(() => {
    loadTradingRulesFromFirestore(user.uid).then(rules => setTradingRules(rules));
  }, [user.uid]);

  // Load goals (breakeven threshold is configured on desktop, shared here)
  useEffect(() => {
    loadGoalsFromFirestore(user.uid).then(goals => {
      if (goals.breakevenThreshold !== undefined && goals.breakevenThreshold !== null) {
        setBreakevenThreshold(Number(goals.breakevenThreshold) || 0);
      }
    });
  }, [user.uid]);

  // Auto-save journal (diff-only)
  useEffect(() => {
    if (!journalLoaded || Object.keys(journalEntries).length === 0) return;
    const timeout = setTimeout(() => {
      const last = lastSavedJournalRef.current || {};
      const changed = {};
      for (const [dateKey, entry] of Object.entries(journalEntries)) {
        if (last[dateKey] !== entry) changed[dateKey] = entry;
      }
      if (Object.keys(changed).length === 0) return;

      setJournalSaveStatus('saving');
      saveJournalToFirestore(user.uid, changed)
        .then(() => {
          lastSavedJournalRef.current = { ...journalEntries };
          setJournalSaveStatus('saved');
          setTimeout(() => setJournalSaveStatus(''), 2000);
        })
        .catch(() => setJournalSaveStatus(''));
    }, 2000);
    return () => clearTimeout(timeout);
  }, [journalEntries, journalLoaded, user.uid]);


  const addTrade = (trade) => {
    setTrades(prev => [trade, ...prev]);
  };

  // Daily Recap state — MUST be declared before any conditional return,
  // otherwise React error #310 (hooks count mismatch between renders).
  const [recapOpen, setRecapOpen] = useState(false);
  const [recapData, setRecapData] = useState(null);
  const recapBootRef = useRef(false);

  useEffect(() => {
    if (!tradesLoaded || !user || !user.uid) return;
    if (recapBootRef.current) return;
    if (view !== 'dashboard') return;
    const todayKey = getTodayLocalDate();
    const lastTradingDate = getLastTradingDate(trades, todayKey);
    if (!lastTradingDate) { recapBootRef.current = true; return; }
    recapBootRef.current = true;
    const journalEntry = journalEntries[lastTradingDate] || null;
    const stats = summarizeDay(trades, lastTradingDate, journalEntry, breakevenThreshold);
    const recs = buildMechanicalRecs(stats);

    // Read desktop-generated AI insight from Firestore (mobile is read-only here)
    (async () => {
      let aiInsight = null;
      try {
        const snap = await db.collection('users').doc(user.uid)
          .collection('dailyRecaps').doc(lastTradingDate).get();
        if (snap.exists) aiInsight = (snap.data() || {}).aiInsight || null;
      } catch (e) {
        console.warn('Failed to load daily recap from Firestore:', e);
      }
      setRecapData({ date: lastTradingDate, stats, recs, aiInsight });
      setRecapOpen(true);
    })();
  }, [tradesLoaded, trades, journalEntries, view, user.uid]);

  // Show loading while data loads (placed AFTER all hooks above)
  if (!tradesLoaded) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100vh', background: COLORS.bg }}>
        <div style={{ textAlign: 'center' }}>
          <UltratrackLogo size={24} />
          <p style={{ color: COLORS.textMuted, fontSize: 13, fontFamily: FONT, marginTop: 12, animation: 'pulse 1.5s ease-in-out infinite' }}>Loading...</p>
        </div>
      </div>
    );
  }

  // Render the recap as a full document-flow page instead of a fixed-position
  // modal — iOS Safari handles document scrolling natively without the
  // overflow/touch-action/nested-scroll quirks that plagued the modal version.
  if (recapOpen && recapData) {
    const s = recapData.stats;
    let prettyDate = recapData.date;
    try {
      const [y, m, d] = recapData.date.split('-').map(Number);
      prettyDate = new Date(y, m - 1, d).toLocaleDateString(undefined, { weekday: 'long', month: 'long', day: 'numeric' });
    } catch (_) {}
    const pnlColor = s.netPnl > 0 ? "#7fffb2" : s.netPnl < 0 ? "#ff4466" : "#aaa";
    const tile = { background: "#0d0d0d", border: "1px solid #1a1a1a", borderRadius: 10, padding: "12px 14px" };
    const lbl = { fontSize: 10, color: "#888", letterSpacing: ".08em", textTransform: "uppercase", margin: "0 0 6px", fontFamily: FONT };
    return (
      <div style={{ background: "#000", minHeight: "100vh", fontFamily: FONT }}>
        <div style={{ padding: "20px 16px calc(40px + env(safe-area-inset-bottom))", maxWidth: 480, margin: "0 auto", width: "100%" }}>
          <div style={{ display: "flex", justifyContent: "space-between", alignItems: "flex-start", marginBottom: 4 }}>
            <div>
              <div style={{ fontSize: 11, color: "#7fffb2", letterSpacing: ".15em", textTransform: "uppercase", marginBottom: 6 }}>Good morning</div>
              <h3 style={{ color: "#fff", margin: 0, fontSize: 16, fontWeight: 700 }}>{prettyDate}</h3>
            </div>
            <button onClick={() => setRecapOpen(false)} style={{ background: "none", border: "none", color: "#aaa", fontSize: 26, lineHeight: 1, padding: 0, cursor: "pointer" }}>×</button>
          </div>

          <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginTop: 16 }}>
            <div style={{ ...tile, gridColumn: "span 2" }}>
              <p style={lbl}>Net P&L</p>
              <p style={{ fontSize: 28, fontWeight: 700, color: pnlColor, margin: 0 }}>{s.netPnl >= 0 ? "+" : ""}${s.netPnl.toLocaleString()}</p>
            </div>
            <div style={tile}>
              <p style={lbl}>Win Rate</p>
              <p style={{ fontSize: 20, fontWeight: 700, color: "#fff", margin: 0 }}>{s.winRate}%</p>
              <p style={{ fontSize: 10, color: "#888", margin: "4px 0 0" }}>{s.winCount}W / {s.lossCount}L</p>
            </div>
            <div style={tile}>
              <p style={lbl}>Trades</p>
              <p style={{ fontSize: 20, fontWeight: 700, color: "#fff", margin: 0 }}>{s.tradeCount}</p>
              {s.ruleAdherencePct !== null && (
                <p style={{ fontSize: 10, color: s.ruleAdherencePct >= 80 ? "#7fffb2" : "#ff9900", margin: "4px 0 0" }}>{s.ruleAdherencePct}% rules</p>
              )}
            </div>
          </div>

          {(s.best || s.worst) && (
            <div style={{ display: "grid", gridTemplateColumns: "1fr 1fr", gap: 8, marginTop: 8 }}>
              {s.best && (
                <div style={tile}>
                  <p style={lbl}>Best</p>
                  <p style={{ fontSize: 14, fontWeight: 700, color: "#7fffb2", margin: 0 }}>{s.best.ticker} +${s.best.pnl.toFixed(0)}</p>
                </div>
              )}
              {s.worst && (
                <div style={tile}>
                  <p style={lbl}>Worst</p>
                  <p style={{ fontSize: 14, fontWeight: 700, color: "#ff4466", margin: 0 }}>{s.worst.ticker} ${s.worst.pnl.toFixed(0)}</p>
                </div>
              )}
            </div>
          )}

          {(s.topMistakes.length > 0 || s.dominantEmotion) && (
            <div style={{ marginTop: 16 }}>
              <p style={lbl}>What stood out</p>
              <div style={{ display: "flex", flexWrap: "wrap", gap: 6 }}>
                {s.dominantEmotion && (
                  <span style={{ background: (emotionColors[s.dominantEmotion] || "#444") + "22", color: emotionColors[s.dominantEmotion] || "#fff", fontSize: 11, padding: "4px 10px", borderRadius: 999 }}>{s.dominantEmotion}</span>
                )}
                {s.topMistakes.map(m => (
                  <span key={m.name} style={{ background: (mistakeColors[m.name] || "#444") + "22", color: mistakeColors[m.name] || "#fff", fontSize: 11, padding: "4px 10px", borderRadius: 999 }}>{m.name} ×{m.count}</span>
                ))}
              </div>
            </div>
          )}

          <div style={{ marginTop: 16 }}>
            <p style={lbl}>For today</p>
            <ul style={{ margin: 0, paddingLeft: 18, color: "#ddd", fontSize: 13, lineHeight: 1.6 }}>
              {recapData.recs.map((r, i) => <li key={i}>{r}</li>)}
            </ul>
          </div>

          <div style={{ marginTop: 16, padding: 14, background: "rgba(127,255,178,0.04)", border: "1px solid rgba(127,255,178,0.15)", borderRadius: 10 }}>
            <p style={{ ...lbl, color: "#7fffb2" }}>Lyra's read</p>
            {recapData.aiInsight ? (
              <ul style={{ margin: 0, paddingLeft: 18, color: "#ddd", fontSize: 13, lineHeight: 1.6 }}>
                {recapData.aiInsight.split('\n').map(l => l.replace(/^[-•*]\s*/, '').trim()).filter(Boolean).map((b, i) => <li key={i}>{b}</li>)}
              </ul>
            ) : (
              <p style={{ color: "#888", fontSize: 12, margin: 0, fontStyle: "italic" }}>
                Lyra has not reviewed this day yet. Open the desktop dashboard to generate the insight.
              </p>
            )}
          </div>

          <div style={{ display: "flex", gap: 8, marginTop: 24 }}>
            <button onClick={() => setRecapOpen(false)} style={{ flex: 1, background: "#1a1a1a", color: "#aaa", border: "1px solid #222", borderRadius: 10, padding: "14px", fontSize: 13, cursor: "pointer" }}>Dismiss</button>
            <button onClick={() => { setRecapOpen(false); setView('journal'); }} style={{ flex: 1, background: "#7fffb2", color: "#000", border: "none", borderRadius: 10, padding: "14px", fontSize: 13, fontWeight: 700, cursor: "pointer" }}>Open journal</button>
          </div>
          <p style={{ textAlign: "center", color: "#444", fontSize: 9, marginTop: 14, letterSpacing: ".1em" }}>build 2026-05-25l</p>
        </div>
      </div>
    );
  }

  return (
    <div style={{ fontFamily: FONT, color: '#fff', background: COLORS.bg, minHeight: '100vh' }}>
      {view === "dashboard" && (
        <MobileDashboard
          trades={trades}
          onViewTrades={() => setView("trades")}
          onOpenRecap={recapData ? () => setRecapOpen(true) : null}
          breakevenThreshold={breakevenThreshold}
        />
      )}
      {view === "trades" && <MobileTradesList trades={trades} onAddTrade={addTrade} />}
      {view === "journal" && <MobileJournal journalEntries={journalEntries} setJournalEntries={setJournalEntries} saveStatus={journalSaveStatus} tradingRules={tradingRules} />}
      <TabBar view={view} setView={setView} />
    </div>
  );
}

// ─── Error Boundary so a render error shows on screen instead of going black ───
class MobileErrorBoundary extends React.Component {
  constructor(props) { super(props); this.state = { error: null, info: null }; }
  static getDerivedStateFromError(error) { return { error }; }
  componentDidCatch(error, info) { this.setState({ info }); console.error('MobileErrorBoundary caught:', error, info); }
  render() {
    if (this.state.error) {
      const msg = (this.state.error && (this.state.error.message || String(this.state.error))) || 'Unknown error';
      const stk = this.state.info && this.state.info.componentStack ? this.state.info.componentStack : '';
      return (
        <div style={{ padding: 20, color: '#ff4466', fontFamily: 'monospace', fontSize: 12, whiteSpace: 'pre-wrap', wordBreak: 'break-word', background: '#000', minHeight: '100vh' }}>
          <p style={{ color: '#fff', fontSize: 14, marginBottom: 12 }}>Mobile crashed:</p>
          <p style={{ color: '#ffbb00', marginBottom: 12 }}>{msg}</p>
          <p style={{ color: '#888', fontSize: 10 }}>{stk}</p>
          <button onClick={() => this.setState({ error: null, info: null })} style={{ marginTop: 16, background: '#7fffb2', color: '#000', border: 'none', borderRadius: 8, padding: '10px 16px', fontSize: 12, fontWeight: 600 }}>Retry</button>
        </div>
      );
    }
    return this.props.children;
  }
}

// ─── Root App ───
function MobileApp() {
  const [user, setUser] = useState(null);
  const [loading, setLoading] = useState(true);
  const [authMode, setAuthMode] = useState('login');

  useEffect(() => {
    const unsubscribe = auth.onAuthStateChanged((u) => {
      setUser(u);
      setLoading(false);
    });
    return () => unsubscribe();
  }, []);

  if (loading) {
    return (
      <div style={{ display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100vh', background: '#000000' }}>
        <div style={{ textAlign: 'center' }}>
          <UltratrackLogo size={24} />
          <p style={{ color: '#888', fontSize: 13, fontFamily: FONT, marginTop: 12, animation: 'pulse 1.5s ease-in-out infinite' }}>Loading...</p>
        </div>
      </div>
    );
  }

  if (!user) return <MobileAuthPage authMode={authMode} setAuthMode={setAuthMode} />;
  if (!user.emailVerified) return <MobileVerificationPage user={user} />;
  return <MobileTradingJournal user={user} />;
}
