/* ============================================================
   LEARNING CENTER — fully browsable article system
   ============================================================ */
const { useState: useS2 } = React;

const LEARN_CATS = [
  {
    id: 'articles',
    name: 'Articles',
    count: 22,
    color: '#F59E0B',
    bg: 'rgba(245,158,11,.15)',
    icon: (
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
        <path d="M4 4h6l2 2h8v12H4z"/><path d="M8 12h8M8 16h5"/>
      </svg>
    ),
  },
  {
    id: 'tutorials',
    name: 'Guided Tutorials',
    count: 8,
    color: '#8BA4EE',
    bg: 'rgba(107,138,228,.15)',
    icon: (
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <path d="M12 3l10 5-10 5L2 8l10-5z"/><path d="M6 10v5c0 2 3 3 6 3s6-1 6-3v-5"/>
      </svg>
    ),
  },
  {
    id: 'drawing',
    name: 'Chart Drawing',
    count: 33,
    color: '#10B981',
    bg: 'rgba(16,185,129,.12)',
    icon: (
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
        <path d="M3 21l6-6"/><path d="M9 15l10-10 4 4L13 19z"/>
      </svg>
    ),
  },
  {
    id: 'quizzes',
    name: 'Pattern Quizzes',
    count: 12,
    color: '#A78BFA',
    bg: 'rgba(167,139,250,.15)',
    icon: (
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
        <circle cx="12" cy="12" r="9"/><path d="M9.5 9a2.5 2.5 0 015 0c0 2-2.5 2-2.5 4"/><circle cx="12" cy="17" r=".5" fill="currentColor"/>
      </svg>
    ),
  },
  {
    id: 'glossary',
    name: 'Glossary',
    count: '80+',
    color: '#8BA4EE',
    bg: 'rgba(107,138,228,.15)',
    icon: (
      <svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
        <rect x="4" y="10" width="4" height="10" rx="1"/><rect x="10" y="5" width="4" height="15" rx="1"/><rect x="16" y="13" width="4" height="7" rx="1"/>
      </svg>
    ),
  },
];

/* ============================================================
   Stub body used for not-yet-written articles — the full content
   ships in the mobile app. The web surface lists the entire library
   so readers can see what's covered, but only the flagship articles
   are authored on the web.
   ============================================================ */
const stubBody = (sub) => (
  <>
    <p>{sub}</p>
    <div className="callout">
      <strong>Full article in the app.</strong> Every entry in the Learning Center ships in the mobile app with chart diagrams, interactive examples, and a short knowledge check. The web preview lists the library so you can see what's inside before you download.
    </div>
    <p>Open this article in the app to read the full piece, see live chart examples, and save your progress.</p>
  </>
);

const ARTICLES = {
  articles: [
    {
      id: 'a1',
      title: 'Candlestick Anatomy',
      time: '5 min',
      level: 'Beginner',
      sub: 'Every chart tells a story. Learn to read it one candle at a time.',
      done: true,
      body: (
        <>
          <p>A single candlestick compresses four numbers into one visual: the <strong>open</strong>, <strong>close</strong>, <strong>high</strong>, and <strong>low</strong> of a given time period. The colored body shows where price opened and closed — green (or hollow) if the close was higher than the open, red (or filled) if the close was lower. The thin lines above and below are <strong>wicks</strong> or <strong>shadows</strong>, showing how far price reached before pulling back.</p>
          <div className="ex-grid">
            <div className="ex-item bull">
              <div className="lbl">Bullish</div>
              <div className="desc">Close above open. Buyers pushed price up during the period. Long lower wick means sellers were rejected.</div>
            </div>
            <div className="ex-item bear">
              <div className="lbl">Bearish</div>
              <div className="desc">Close below open. Sellers dominated. Long upper wick means buyers failed to hold highs.</div>
            </div>
          </div>
          <h3>Why the body matters more than the wick</h3>
          <p>The body represents where price actually <em>settled</em> at the open and close — the consensus moments. Wicks represent failed attempts: price tried to go there, but couldn't stay. A long body with short wicks signals conviction; a small body with long wicks signals indecision.</p>
          <div className="callout">
            <strong>Try it:</strong> In Vero's Free Play mode, turn off all indicators and focus on just candle bodies and wicks. You'll develop an instinct for momentum without any technical crutches.
          </div>
          <h3>Common single-candle signals</h3>
          <p><strong>Doji</strong> — open and close are nearly identical. A pause, indecision, a possible reversal if it appears at an extreme. <strong>Hammer</strong> — small body at the top with a long lower wick. Buyers took control after early selling. Bullish at support. <strong>Shooting star</strong> — small body at the bottom with a long upper wick. Sellers reclaimed after a rally. Bearish at resistance.</p>
        </>
      ),
    },
    {
      id: 'a2',
      title: 'Support & Resistance — The Two Lines That Matter',
      time: '7 min',
      level: 'Beginner',
      sub: 'Before any pattern, any indicator, any strategy — there are levels.',
      done: true,
      body: (
        <>
          <p><strong>Support</strong> is a price level where buyers have stepped in repeatedly. <strong>Resistance</strong> is where sellers have. These aren't magic lines — they're simply the receipts of past decisions, left on the chart as visible proof that <em>something happened here before</em>.</p>
          <p>The more times a level is tested without breaking, the more weight it carries. The cleaner the rejections (long wicks, sharp reversals), the more respected the level. When a strong level breaks, traders expect price to accelerate — the old guardrail is gone.</p>
          <h3>Drawing them well</h3>
          <p>Connect <em>wicks</em> for the most conservative levels, <em>bodies</em> for the most respected. Don't chase exact prices — draw zones, not hairlines. A 0.3% band around a round number often matters more than a single tick.</p>
          <div className="callout">
            <strong>Practice:</strong> Vero's Chart Drawing exercises include 33 scenarios where you place support/resistance lines and get graded against historical outcomes.
          </div>
          <h3>The role-reversal rule</h3>
          <p>When resistance breaks, it often becomes the new support. When support breaks, it becomes the new resistance. This is one of the most reliable phenomena in technical analysis, because the psychology is simple: traders who sold at $100 are relieved when price returns to $100 after a breakout, and buy again to "get back in."</p>
        </>
      ),
    },
    {
      id: 'a3',
      title: 'Reading Volume',
      time: '6 min',
      level: 'Beginner',
      sub: "Price is what happened. Volume is how much people cared.",
      body: (
        <>
          <p>Volume confirms or contradicts price. A breakout on rising volume is real participation — traders are putting money behind the move. A breakout on falling volume often fails, because the price movement isn't supported by conviction.</p>
          <h3>The four volume patterns</h3>
          <p><strong>Rising price + rising volume</strong> — healthy uptrend. <strong>Rising price + falling volume</strong> — weakening, watch for reversal. <strong>Falling price + rising volume</strong> — genuine selling pressure. <strong>Falling price + falling volume</strong> — exhaustion, possible bottom.</p>
          <div className="callout">
            In Vero's chart interface, the Volume pane sits directly below price. Toggle it on from Game Setup → Indicators to train on volume-aware reads.
          </div>
        </>
      ),
    },
    { id: 'a4',  title: 'Doji: The Candle of Indecision',               time: '4 min', level: 'Beginner',     sub: 'When buyers and sellers finish in a tie, the market is telling you something.', get body() { return stubBody(this.sub); } },
    { id: 'a5',  title: 'Hammer & Shooting Star',                       time: '5 min', level: 'Beginner',     sub: 'Two single-candle reversals with opposite meanings — and why location matters more than shape.', get body() { return stubBody(this.sub); } },
    { id: 'a6',  title: 'Engulfing Patterns: The Takeover Candle',      time: '6 min', level: 'Beginner',     sub: 'One candle that swallows the last is one of the most reliable two-candle reversal signals.', get body() { return stubBody(this.sub); } },
    { id: 'a7',  title: 'Morning Star & Evening Star',                  time: '6 min', level: 'Intermediate', sub: 'The three-candle reversal that shows up at the end of every major trend change.', get body() { return stubBody(this.sub); } },
    { id: 'a8',  title: 'Trend Lines: How to Draw Them Right',          time: '8 min', level: 'Beginner',     sub: 'Two touches make a line; three touches make a trend. The rest is discipline.', get body() { return stubBody(this.sub); } },
    { id: 'a9',  title: 'Moving Averages: SMA vs EMA',                  time: '7 min', level: 'Beginner',     sub: 'Both smooth price. One reacts faster. Knowing which to use, and when, changes everything.', get body() { return stubBody(this.sub); } },
    { id: 'a10', title: 'RSI: Reading Momentum',                        time: '8 min', level: 'Intermediate', sub: 'Overbought and oversold are starting points, not signals. Here is how RSI actually earns its keep.', get body() { return stubBody(this.sub); } },
    { id: 'a11', title: 'MACD: When Averages Disagree',                 time: '9 min', level: 'Intermediate', sub: 'The crossover is the headline. The histogram is where the real information lives.', get body() { return stubBody(this.sub); } },
    { id: 'a12', title: 'Bollinger Bands: Volatility as Context',       time: '7 min', level: 'Intermediate', sub: 'Bands are not signals. They are a frame that makes every other signal easier to read.', get body() { return stubBody(this.sub); } },
    { id: 'a13', title: 'VWAP: The Institution Price',                  time: '6 min', level: 'Intermediate', sub: 'Why the volume-weighted average is the single level most professional desks care about intraday.', get body() { return stubBody(this.sub); } },
    { id: 'a14', title: 'Head & Shoulders: The Classic Reversal',       time: '8 min', level: 'Intermediate', sub: 'The most recognized chart pattern in technical analysis — and the most frequently misidentified.', get body() { return stubBody(this.sub); } },
    { id: 'a15', title: 'Double Top & Double Bottom',                   time: '6 min', level: 'Beginner',     sub: 'Two equal peaks (or troughs) tell you a trend has run out of steam. Here is what to do about it.', get body() { return stubBody(this.sub); } },
    { id: 'a16', title: 'Flags & Pennants: Continuation Patterns',      time: '5 min', level: 'Intermediate', sub: 'The market rarely moves in a straight line. Flags are the pauses that give you the next entry.', get body() { return stubBody(this.sub); } },
    { id: 'a17', title: 'Ascending & Descending Triangles',             time: '7 min', level: 'Intermediate', sub: 'Flat ceiling, rising floor. Or vice versa. Why the asymmetric pressure always resolves.', get body() { return stubBody(this.sub); } },
    { id: 'a18', title: 'The Cup & Handle',                             time: '6 min', level: 'Intermediate', sub: 'William O’Neil’s signature bullish setup — how to spot it, and why most traders get the handle wrong.', get body() { return stubBody(this.sub); } },
    { id: 'a19', title: 'Fibonacci Retracement: Why Markets Respect Math', time: '9 min', level: 'Advanced',  sub: 'The 38.2%, 50%, and 61.8% retracements show up over and over. Superstition, or self-fulfilling?', get body() { return stubBody(this.sub); } },
    { id: 'a20', title: 'Market Structure: Highs, Lows & Context',      time: '8 min', level: 'Intermediate', sub: 'Before any pattern or indicator, identify where price is within the structural trend.', get body() { return stubBody(this.sub); } },
    { id: 'a21', title: 'Risk-to-Reward: The Math of Trading',          time: '7 min', level: 'Advanced',     sub: 'Why a 40% win-rate strategy can still be extremely profitable — and a 70% one can lose.', get body() { return stubBody(this.sub); } },
    { id: 'a22', title: 'Why Technical Analysis Works (and When It Doesn’t)', time: '10 min', level: 'Advanced', sub: 'A candid look at what TA is really modeling, and the situations where it stops working.', get body() { return stubBody(this.sub); } },
  ],
  tutorials: [
    {
      id: 't1',
      title: 'Your First Chart Read — Step by Step',
      time: '15 min',
      level: 'Interactive',
      sub: 'A guided walkthrough of a single chart, from zoomed-out context to the trade decision.',
      body: (
        <>
          <p>This tutorial walks you through reading a single equity chart the way a disciplined trader would — in a specific order, without skipping steps. You'll answer questions along the way and Vero will grade your reads.</p>
          <h3>Step 1 — Zoom out</h3>
          <p>Before looking at anything small, pull back to a multi-year view. What's the major trend? Is this stock in a sustained uptrend, a downtrend, or ranging? This decides your default bias for everything that follows.</p>
          <h3>Step 2 — Find the key levels</h3>
          <p>Mark support and resistance on the weekly chart. Only the obvious ones — the two or three that jump out. You don't need ten lines; you need the ones price has respected repeatedly.</p>
          <h3>Step 3 — Drop to daily</h3>
          <p>Now zoom in. Where is price relative to the weekly levels you drew? At support? At resistance? In the middle? This is your setup quality.</p>
          <div className="callout">
            <strong>You'll practice this on 5 real charts.</strong> Each one ends with a multiple-choice read: what's the highest-probability next move, and why?
          </div>
          <h3>Step 4 — Check the indicators</h3>
          <p>Only <em>after</em> you've formed a view from price action, do you look at indicators — and only to confirm or contradict. If RSI is overbought at resistance, that's confirmation. If it's oversold at resistance, that's a contradiction worth understanding.</p>
        </>
      ),
    },
    {
      id: 't2',
      title: 'Building a Watchlist That Works',
      time: '12 min',
      level: 'Interactive',
      sub: 'Most traders watch too many names badly. Here\'s how to watch a few exceptionally.',
      body: (
        <>
          <p>The best traders often follow 20 tickers or fewer — and they follow them <em>deeply</em>. You'll learn to set up a watchlist by liquidity, volatility, and sector coverage, and to rotate names in and out based on setup quality rather than news.</p>
          <h3>The three-tier system</h3>
          <p><strong>Tier 1 — Core watch (5 names):</strong> The tickers you know intimately. You know their typical range, their personality, their reaction to earnings. <strong>Tier 2 — Active scan (15 names):</strong> Broader coverage for setup hunting. <strong>Tier 3 — Bench:</strong> Anything else, reviewed weekly.</p>
          <div className="callout">
            Vero's chart library is built around a curated set of liquid names — SPY, QQQ, IWM, AAPL, NVDA, TSLA, EEM, and EFA — so every round you play is on a ticker that trades like the ones serious traders watch.
          </div>
        </>
      ),
    },
    { id: 't3', title: 'Reading Indicators Without Overloading',        time: '14 min', level: 'Interactive', sub: 'A disciplined order for adding indicators — and knowing when to turn them off.', get body() { return stubBody(this.sub); } },
    { id: 't4', title: 'The Three-Step Pattern Recognition Process',    time: '16 min', level: 'Interactive', sub: 'Frame, identify, confirm. The workflow that prevents every false-positive pattern call.', get body() { return stubBody(this.sub); } },
    { id: 't5', title: 'Drawing Support & Resistance Zones',            time: '13 min', level: 'Interactive', sub: 'Stop drawing lines. Start drawing zones — and grading each one by weight of evidence.', get body() { return stubBody(this.sub); } },
    { id: 't6', title: 'Understanding Trend Structure',                 time: '18 min', level: 'Interactive', sub: 'Higher highs, higher lows, and the moment the sequence breaks. Structure before signal.', get body() { return stubBody(this.sub); } },
    { id: 't7', title: 'Entry Timing: The Setup + Trigger Framework',   time: '17 min', level: 'Interactive', sub: 'A setup is a reason to care. A trigger is a reason to act. Never confuse the two.', get body() { return stubBody(this.sub); } },
    { id: 't8', title: 'Learning From Every Round: Post-Trade Review',  time: '11 min', level: 'Interactive', sub: 'The habit that separates deliberate practice from mindless reps. A scoring rubric for every round you play.', get body() { return stubBody(this.sub); } },
  ],
  drawing: [
    {
      id: 'd1',
      title: 'Trend Lines Done Right',
      time: 'Exercise',
      level: 'Intermediate',
      sub: 'The line itself is trivial. Choosing where to draw it is everything.',
      body: (
        <>
          <p>A trend line needs at least <strong>two touches</strong> to exist and a <strong>third touch</strong> to become meaningful. Anything less is wishful thinking. In this exercise you'll be given a series of charts and asked to draw the dominant trend line — then see how price actually behaved next.</p>
          <h3>Rules for a clean trend line</h3>
          <p>Connect the most obvious extremes. If you find yourself stretching to make two points line up, the line isn't there. Use wicks for strict lines, bodies for looser ones — and commit to one approach per chart. Don't mix.</p>
          <div className="callout">
            The app grades your line by computing the R² of actual touches against the line you drew, then shows you where a well-trained eye would have placed it.
          </div>
        </>
      ),
    },
    { id: 'd2', title: 'Uptrend Channels',                 time: 'Exercise', level: 'Intermediate', sub: 'Draw both the trend line and its parallel. Price spends most of its life between the two.', get body() { return stubBody(this.sub); } },
    { id: 'd3', title: 'Downtrend Channels',               time: 'Exercise', level: 'Intermediate', sub: 'The same skill on the short side — and why most traders are worse at it.', get body() { return stubBody(this.sub); } },
    { id: 'd4', title: 'Horizontal Support Zones',         time: 'Exercise', level: 'Beginner',     sub: 'Place the zone, not the line. Ten exercises on tickers where support was decisive.', get body() { return stubBody(this.sub); } },
    { id: 'd5', title: 'Horizontal Resistance Zones',      time: 'Exercise', level: 'Beginner',     sub: 'Ceilings the market respected — some once, some a dozen times. Can you tell the difference?', get body() { return stubBody(this.sub); } },
    { id: 'd6', title: 'Breakout Entry Lines',             time: 'Exercise', level: 'Intermediate', sub: 'Where exactly do you commit to a breakout? Five charts, five commitment lines, graded.', get body() { return stubBody(this.sub); } },
    { id: 'd7', title: 'Fibonacci Retracement',            time: 'Exercise', level: 'Advanced',     sub: 'Anchor the swing right and the 38.2% / 50% / 61.8% levels fall where they should.', get body() { return stubBody(this.sub); } },
    { id: 'd8', title: 'Head & Shoulders Neckline',        time: 'Exercise', level: 'Advanced',     sub: 'The pattern lives or dies by where you draw the neckline. Ten classic setups.', get body() { return stubBody(this.sub); } },
  ],
  quizzes: [
    {
      id: 'q1',
      title: 'Name That Pattern — 20 Classic Formations',
      time: '10 min',
      level: 'Test',
      sub: 'Head & shoulders. Double top. Cup & handle. Can you spot them cold?',
      body: (
        <>
          <p>A timed quiz with 20 real historical charts. You see the setup, you name the pattern, you commit to a direction. Afterwards Vero shows you what happened and where your eye matched or missed.</p>
          <div className="callout">
            <strong>Scoring:</strong> Correct pattern name = 1 pt. Correct direction = 1 pt. Correct on both without the hint = 3 pts. High score unlocks the advanced pattern set.
          </div>
          <h3>What you'll be tested on</h3>
          <p>Head & shoulders (regular and inverse). Double top / double bottom. Triple top / triple bottom. Cup & handle. Bullish and bearish flags. Ascending and descending triangles. Symmetrical triangles. Falling and rising wedges. Rounding bottoms.</p>
        </>
      ),
    },
    { id: 'q2',  title: 'Candlestick Reversals',              time: '8 min',  level: 'Test', sub: 'Hammer, shooting star, engulfing, morning star, evening star — in context.', get body() { return stubBody(this.sub); } },
    { id: 'q3',  title: 'Continuation Patterns',              time: '9 min',  level: 'Test', sub: 'Flags, pennants, rectangles. When the pause is the signal.', get body() { return stubBody(this.sub); } },
    { id: 'q4',  title: 'Support vs Resistance Break',        time: '10 min', level: 'Test', sub: 'Is this a clean break, a fakeout, or a retest? Fifteen charts to decide on.', get body() { return stubBody(this.sub); } },
    { id: 'q5',  title: 'Trend vs Range',                     time: '7 min',  level: 'Test', sub: 'Half the battle is knowing which regime you are in. Train the classification.', get body() { return stubBody(this.sub); } },
    { id: 'q6',  title: 'Volume Confirmation',                time: '9 min',  level: 'Test', sub: 'Spot the breakouts that had conviction behind them — and the ones that did not.', get body() { return stubBody(this.sub); } },
    { id: 'q7',  title: 'Indicator Divergence',               time: '11 min', level: 'Test', sub: 'Price makes a new high, RSI does not. A gift, or a fake-out? You call it.', get body() { return stubBody(this.sub); } },
    { id: 'q8',  title: 'Moving Average Crossovers',          time: '9 min',  level: 'Test', sub: 'Golden cross, death cross — and the majority of crossovers that are neither.', get body() { return stubBody(this.sub); } },
    { id: 'q9',  title: 'Multi-Timeframe Reads',              time: '13 min', level: 'Test', sub: 'Weekly says one thing. Daily says another. Which wins?', get body() { return stubBody(this.sub); } },
    { id: 'q10', title: 'Reversal vs Continuation',           time: '10 min', level: 'Test', sub: 'The skill that matters most — and the one most traders never practice.', get body() { return stubBody(this.sub); } },
    { id: 'q11', title: 'Pattern Failure Recognition',        time: '12 min', level: 'Test', sub: 'Every pattern fails sometimes. The tell is usually obvious in hindsight. Train for foresight.', get body() { return stubBody(this.sub); } },
    { id: 'q12', title: 'Advanced Pattern Mix — Timed',       time: '15 min', level: 'Test', sub: 'Twenty charts, twenty seconds each, every pattern from the library. The final boss.', get body() { return stubBody(this.sub); } },
  ],
  glossary: [
    {
      id: 'g1',
      title: 'Trading Glossary — Every Term That Matters',
      time: 'Reference',
      level: 'Searchable',
      sub: 'Every term that shows up in the app, defined plainly and paired with a chart example.',
      body: (
        <>
          <p>A searchable reference for the vocabulary of technical analysis — from <strong>accumulation</strong> to <strong>volume</strong>, explained plainly, without the academic hedging.</p>
          <h3>A selection</h3>
          <p><strong>Accumulation</strong> — The quiet phase after a downtrend where smart money is buying while retail is still selling. Price moves sideways, volume is dull, but the trajectory is quietly stabilizing.</p>
          <p><strong>Breakout</strong> — Price moves decisively through a defined level of support or resistance, ideally on above-average volume. Not every cross of a line is a breakout; most are fakeouts.</p>
          <p><strong>Consolidation</strong> — A period of sideways price action after a directional move, as the market "digests" the move. Often precedes continuation.</p>
          <p><strong>Divergence</strong> — When price makes a new high (or low) but the indicator doesn't. A warning that momentum is fading.</p>
          <p><strong>Fakeout</strong> — A breakout that fails within a few bars. Frequently engineered by larger players hunting stop losses.</p>
          <div className="callout">
            The full glossary is searchable in-app, with tappable terms cross-linked to their articles and chart examples.
          </div>
        </>
      ),
    },
  ],
};

/* ============================================================
   LearningCenter component
   ============================================================ */
const LearningCenter = () => {
  const [cat, setCat] = useS2('articles');
  const [artId, setArtId] = useS2('a1');

  const articles = ARTICLES[cat] || [];
  const article = articles.find(a => a.id === artId) || articles[0];

  const onCatChange = (id) => {
    setCat(id);
    setArtId(ARTICLES[id]?.[0]?.id || '');
  };

  return (
    <>
      {/* category picker — grouped like the in-app Learning Center */}
      <div className="learn-groups">
        {[
          { name: 'Learn', ids: ['articles', 'tutorials'] },
          { name: 'Practice', ids: ['drawing', 'quizzes'] },
          { name: 'Reference', ids: ['glossary'] },
        ].map(grp => (
          <div key={grp.name} className="learn-group">
            <h5 className="learn-group-title">{grp.name}</h5>
            <div className="learn-group-row" data-cols={grp.ids.length}>
              {grp.ids.map(id => {
                const c = LEARN_CATS.find(x => x.id === id);
                return (
                  <div key={c.id} className={'learn-cat' + (cat === c.id ? ' active' : '')} onClick={() => onCatChange(c.id)}>
                    <div className="ic" style={{ background: c.bg, color: c.color }}>{c.icon}</div>
                    <div className="name">{c.name}</div>
                    <div className="ct">{c.count} {c.id === 'articles' ? 'topics' : c.id === 'tutorials' ? 'lessons' : c.id === 'drawing' ? 'exercises' : c.id === 'quizzes' ? 'quizzes' : 'terms'}</div>
                  </div>
                );
              })}
            </div>
          </div>
        ))}
      </div>

      {/* body */}
      <div className="learn-body">
        {/* toc */}
        <div className="learn-toc">
          <h4>{LEARN_CATS.find(c => c.id === cat)?.name}</h4>
          {articles.map(a => (
            <div key={a.id} className={'learn-toc-item' + (artId === a.id ? ' active' : '') + (a.done ? ' done' : '')} onClick={() => setArtId(a.id)}>
              <div className="lt">{a.title}</div>
              <div className="rt">{a.done ? '✓' : a.time}</div>
            </div>
          ))}
          {articles.length === 0 && <div style={{ fontSize: 13, color: 'var(--vero-fg-3)', padding: '20px 4px', lineHeight: 1.5 }}>Full library available in-app.</div>}
          {articles.length > 0 && (cat === 'drawing' || cat === 'glossary') && (
            <div style={{ fontSize: 12, color: 'var(--vero-fg-3)', padding: '16px 4px 4px', lineHeight: 1.5, borderTop: '1px solid rgba(255,255,255,0.06)', marginTop: 8 }}>
              Preview only — the full library lives in the mobile app.
            </div>
          )}
        </div>

        {/* article */}
        <article className="learn-article">
          {article && (
            <>
              <div className="meta">
                <span className="chip">{article.level}</span>
                <span>·</span>
                <span>{article.time} read</span>
                {article.done && <><span>·</span><span style={{ color: 'var(--vero-bull)' }}>✓ Completed</span></>}
              </div>
              <h1>{article.title}</h1>
              <p className="sub">{article.sub}</p>
              {article.body}
              <NavRow articles={articles} artId={artId} setArtId={setArtId}/>
            </>
          )}
        </article>
      </div>
    </>
  );
};

const NavRow = ({ articles, artId, setArtId }) => {
  const idx = articles.findIndex(a => a.id === artId);
  const prev = idx > 0 ? articles[idx - 1] : null;
  const next = idx < articles.length - 1 ? articles[idx + 1] : null;
  return (
    <div className="nav-row">
      {prev ? (
        <div className="nb" onClick={() => setArtId(prev.id)}>
          <div className="dir">← Previous</div>
          <div className="ttl">{prev.title}</div>
        </div>
      ) : <div style={{ flex: 1 }}/>}
      {next ? (
        <div className="nb r" onClick={() => setArtId(next.id)}>
          <div className="dir">Next →</div>
          <div className="ttl">{next.title}</div>
        </div>
      ) : <div style={{ flex: 1 }}/>}
    </div>
  );
};

window.LearningCenter = LearningCenter;
