// section1.jsx- Section 1 slides (0 through 1.15)

// === Slide 0 (display): Title- now first ===
function Slide11() {
  return (
    <section className="slide" data-screen-label="00 Title">
      <Chrome slide={0} total={33} sectionLabel="TITLE" />
      <div className="slide-inner" style={{justifyContent:'center', alignItems:'flex-start', position:'relative', paddingLeft:120}}>
        <div style={{maxWidth:1560}}>
          <p className="eyebrow" style={{marginBottom:32}}>A talk · 2026</p>
          <h1 className="title" style={{fontSize:120, lineHeight:0.94, marginBottom:32, letterSpacing:'-0.03em'}}>
            <span style={{color:'var(--red-3)'}}>Mastra</span>:<br/>
            Mapping the AI Engineering<br/>
            Ecosystem through a library.
          </h1>
          <hr className="rule" style={{margin:'32px 0', maxWidth:200, borderColor:'var(--red-2)'}}/>
          <p style={{fontSize:26, color:'var(--text-2)', maxWidth:1280, lineHeight:1.45}}>
            The LLM stack has been shifting constantly the last few months, but a handful of components have started to feel permanent. Tonight we'll use Mastra- a TypeScript framework for deploying AI- as our map, and walk every module from tools and memory through to observability to study how powerful (and effective) AI applications are built today.
          </p>
        </div>
        <div style={{
          position:'absolute', right:-100, bottom:-100, width:700, height:700,
          background:'radial-gradient(circle, rgba(196,48,48,0.10), transparent 60%)',
          pointerEvents:'none',
        }}/>
      </div>
    </section>
  );
}

// === Slide 1 (display): Preamble- "we're not memorizing syntax" ===
function Slide00() {
  return (
    <section className="slide" data-screen-label="01 Preamble">
      <Chrome slide={2} total={33} sectionLabel="PREAMBLE" />
      <div className="slide-inner" style={{justifyContent:'center'}}>
        <div style={{maxWidth:1380}}>
          <p className="eyebrow">∅ · Before we start</p>
          <h1 className="title" style={{fontSize:88}}>Why we're not memorising<br/>syntax tonight.</h1>
          <hr className="rule" style={{margin:'40px 0', maxWidth:200, borderColor:'var(--red-2)'}}/>
          <Bullets items={[
            { text: 'Agents are writing the application code now.', tip: "Claude Code, Cursor, Codex, ChatGPT- they're writing more and more of our actual code. Deep framework-syntax memorisation is becoming a less valuable use of time." },
            { text: 'Memorising framework syntax is a fading skill.', tip: "What compounds is a map- a working mental model of what each piece of an AI system is doing and why." },
            { text: 'What compounds is concepts and intuitions- and that is what we will build tonight.', tip: "We'll spend most of the evening at the conceptual level rather than walking the API surface." },
            { text: 'We use Mastra as the map, but the concepts themselves are universal.', tip: "Mastra is a TypeScript framework for AI apps- we use it as a map because it exposes every concept cleanly. The same concepts apply to every agent framework you'll meet." },
            { text: "We'll mix in lab-insider tidbits from OpenAI, Anthropic, xAI, and Google at every layer.", tip: "Observations about how each lab actually approaches each part of the stack- the kind of things you only notice once you've built or extensively used these systems." },
            { text: "If Mastra disappears from the talk for ten minutes after this, that is on purpose.", tip: "We'll go to the bare LLM and build outward from there. Mastra comes back the moment we need to talk about how the framework exposes each concept- not before." },
          ]}/>
        </div>
        <div style={{
          position:'absolute', right:-100, bottom:-100, width:700, height:700,
          background:'radial-gradient(circle, rgba(196,48,48,0.12), transparent 60%)',
          pointerEvents:'none',
        }}/>
      </div>
    </section>
  );
}

// === Slide 1.2: Full picture (TOC) ===
function Slide12() {
  const [hover, setHover] = useState(null);
  const sections = [
    { id: 1, name: 'The LLM Core', color: 'var(--sec-1)', desc: 'Model + special tokens + classifiers + the API wrapper.' },
    { id: 2, name: 'The Context Layer', color: 'var(--sec-2)', desc: 'Memory, working memory, semantic recall, observational, file-based.' },
    { id: 3, name: 'The Action Surfaces', color: 'var(--sec-3)', desc: 'Tools, MCP, workspaces, browser- what lets the model do things.' },
    { id: 4, name: 'Orchestration', color: 'var(--sec-4)', desc: 'Workflows, multi-agent, swarms.' },
    { id: 5, name: 'The Feedback Loop', color: 'var(--sec-5)', desc: 'Observability, tracing, evals.' },
  ];
  // Highlight maps section id → ConsoleVisual layer name
  const highlightMap = { 1: 'envelope', 2: 'cartridges', 3: 'wires', 4: 'agent', 5: 'orch' };
  const highlight = hover ? highlightMap[hover] : null;

  return (
    <section className="slide" data-screen-label="02 Full Picture">
      <Chrome slide={3} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{flexDirection:'row', gap:48, paddingTop:160}}>
        <div style={{flex: '0 0 480px'}}>
          <p className="eyebrow">Tonight's map</p>
          <h2 className="title" style={{fontSize:44, marginBottom:32}}>Five layers we'll walk through, plus a footnote on deployment.</h2>
          <ol style={{listStyle:'none', padding:0, margin:0, display:'flex', flexDirection:'column', gap:14}}>
            {sections.map(s => (
              <li key={s.id}
                  onMouseEnter={() => setHover(s.id)}
                  onMouseLeave={() => setHover(null)}
                  style={{
                    padding:'16px 20px', borderRadius:6,
                    background: hover === s.id ? 'var(--ink-3)' : 'var(--ink-2)',
                    border: '1px solid ' + (hover === s.id ? s.color : 'var(--ink-4)'),
                    borderLeft: '4px solid ' + s.color,
                    cursor:'pointer', transition:'all 0.2s',
                  }}>
                <div style={{display:'flex', alignItems:'center', gap:14}}>
                  <span style={{fontFamily:'JetBrains Mono', color:s.color, fontSize:14}}>0{s.id}</span>
                  <span style={{fontSize:26, fontWeight:600, color: hover === s.id ? 'var(--text-0)' : 'var(--text-1)'}}>{s.name}</span>
                </div>
                <div style={{fontSize:15, color:'var(--text-2)', marginTop:6, marginLeft:34}}>{s.desc}</div>
              </li>
            ))}
            <li style={{padding:'10px 20px', borderRadius:6, marginLeft:24, color:'var(--text-3)', fontSize:16, fontStyle:'italic'}}>
              ↓ Footnote: Deployment
            </li>
          </ol>
        </div>
        <div style={{flex:1, display:'flex', alignItems:'center', justifyContent:'center'}}>
          <div style={{width:'100%', maxWidth:1280, height:'100%', display:'flex', alignItems:'center'}}
               dangerouslySetInnerHTML={{__html: window.SystemDiagram({ size:'full', stage: 5, highlight })}}/>
        </div>
      </div>
      <div style={{position:'absolute', bottom:36, left:96, right:96, display:'flex', justifyContent:'space-between', alignItems:'center', fontFamily:'JetBrains Mono', fontSize:13, color:'var(--text-3)', letterSpacing:'0.1em'}}>
        <span>HOVER A SECTION TO LIGHT UP THE DIAGRAM ↗</span>
        <span>HANDS UP- WHO'S COMFORTABLE WITH EACH? WHO STILL FINDS IT MAGIC?</span>
        <span>↳ AT §3 I'LL ASK WHAT TO LEAN INTO</span>
      </div>
    </section>
  );
}

// === Slide 1.3: What Mastra is ===
function Slide13() {
  return (
    <section className="slide" data-screen-label="03 What Mastra Is">
      <Chrome slide={4} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{paddingTop:140}}>
        <p className="eyebrow">10 seconds- what Mastra is</p>
        <h2 className="title" style={{maxWidth:1500}}>Mastra in 10 seconds, so the rest of the talk makes sense.</h2>
        <div style={{display:'flex', gap:56, marginTop:56, flex:1, alignItems:'center'}}>
          <div style={{flex:'0 0 620px', display:'flex', flexDirection:'column', justifyContent:'center'}}>
            <Bullets items={[
              { text: 'A TypeScript framework for building AI applications.' },
              { text: 'Open source.' },
              { text: 'Agents, workflows, memory, tools, MCP, observability- all in one box.', tip: "Mastra ships every layer of the stack we'll discuss tonight in a single coherent surface." },
              { text: 'Runs anywhere TypeScript runs.', tip: "Node, Bun, Deno, edge runtimes- wherever your TypeScript already runs, Mastra runs." },
              { text: "We'll show short snippets at every stop on the tour.", tip: "Each section will surface a small Mastra snippet to show how the concept lands in code, then we move on." },
              { text: 'We use Mastra as the map- but the concepts are universal.', tip: "You'll see how Mastra exposes each concept, but the concepts apply to every agent framework- OpenAI Agents SDK, Vercel AI SDK, LangGraph, your own glue. Mastra just happens to be the cleanest exposure." },
              { text: "Before we even open Mastra, we have to talk about what's at the centre of all this.", tip: "Verbal transition into the strip animation: we kill every layer of the diagram until only the bare LLM remains, then dig in." },
            ]}/>
          </div>
          <div style={{
            flex:1, alignSelf:'stretch',
            display:'flex', alignItems:'center', justifyContent:'center',
            border:'1px solid var(--ink-5)', borderRadius:8,
            background:'var(--ink-2)', padding:18,
          }}>
            <img src="media/Mastra-homepage.png" alt="Mastra homepage"
                 loading="eager" decoding="async"
                 style={{maxWidth:'100%', maxHeight:'100%', width:'auto', height:'auto', objectFit:'contain', display:'block'}}/>
          </div>
        </div>
      </div>
    </section>
  );
}

// === Slide 1.4: Strip animation- peel away layers down to the bare model ===
function Slide14() {
  const resetKey = useSlideResetKey();
  const [phase, setPhase] = useState(5);
  const speed = useAnimSpeed();
  useEffect(() => {
    setPhase(5);
    const ticks = [
      [600,  4],  // orchestration goes
      [1300, 3],  // agent shell goes
      [2000, 2],  // wires go
      [2700, 1],  // cartridges go
      [3400, 0],  // envelope goes- just the core remains
    ];
    const ids = ticks.map(([ms, p]) => setTimeout(() => setPhase(p), ms / speed));
    return () => ids.forEach(clearTimeout);
  }, [resetKey, speed]);

  const labels = [
    'orchestration',
    'agent shell',
    'tool surface',
    'memory cartridges',
    'API wrapper',
    'just the model',
  ];
  const stripped = 5 - phase; // how many layers gone

  return (
    <section className="slide" data-screen-label="04 Strip Animation">
      <Chrome slide={5} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{flexDirection:'row', gap:48, paddingTop:120}}>
        <div style={{flex:'0 0 380px'}}>
          <p className="eyebrow">Reset · take it apart</p>
          <h2 className="title" style={{fontSize:54, lineHeight:1.0}}>
            Strip everything away.<br/>
            <span style={{color:'var(--red-3)'}}>Watch the model alone.</span>
          </h2>
          <hr className="rule" style={{margin:'32px 0', maxWidth:120, borderColor:'var(--red-2)'}}/>
          <div style={{fontFamily:'JetBrains Mono', fontSize:13, color:'var(--text-3)', letterSpacing:'0.18em', marginBottom:14}}>STRIPPING ↓</div>
          <ul className="bullets" style={{fontSize:20}}>
            {labels.slice(0, 5).map((ln, i) => (
              <li key={i} style={{
                opacity: i < stripped ? 0.35 : 1,
                textDecoration: i < stripped ? 'line-through' : 'none',
                color: i === stripped ? 'var(--red-3)' : (i < stripped ? 'var(--text-3)' : 'var(--text-1)'),
                transition:'all 0.4s',
              }}>
                <span>— {ln}</span>
              </li>
            ))}
            <li style={{
              marginTop:14, opacity: phase === 0 ? 1 : 0.25,
              color: phase === 0 ? 'var(--text-0)' : 'var(--text-3)',
              fontWeight: phase === 0 ? 600 : 400,
              transition:'all 0.4s',
            }}><span>= just the model.</span></li>
          </ul>
        </div>
        <div style={{flex:1, display:'flex', alignItems:'center', justifyContent:'center'}}>
          <div style={{width:'100%', maxWidth: 1300, height:'100%', display:'flex', alignItems:'center', transition:`opacity ${0.4/speed}s ease`}}
               dangerouslySetInnerHTML={{__html: window.ConsoleVisual({ size:'full', stage: phase })}}/>
        </div>
      </div>
    </section>
  );
}

// === Slide 1.5: The bare model- the printer never stops ===
function Slide15() {
  return (
    <section className="slide" data-screen-label="05 The Naked Model">
      <Chrome slide={6} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{flexDirection:'column', gap:18, paddingTop:78}}>
        <div style={{display:'flex', alignItems:'flex-start', gap:56}}>
          <div style={{flex:'0 0 540px'}}>
            <p className="eyebrow">The bare model</p>
            <h2 className="title" style={{fontSize:56, lineHeight:1.0}}>
              It can't stop.<br/>It can't tell us apart.
            </h2>
          </div>
          <div style={{flex:1, display:'grid', gridTemplateColumns:'1fr 1fr', gap:'10px 36px'}}>
            <ul className="bullets" style={{fontSize:18, gap:10}}>
              <li>
                <span>A magic black box: words go in, words come out- that's all it can do.</span>
                <div className="tip">Pre-training gives you sequence completion. Nothing else. No memory, no concept of turns, no sense of "you" or "me."</div>
              </li>
              <li>
                <span>It doesn't know it's in a conversation.</span>
                <div className="tip">There is no notion of "user" or "assistant" in the raw model. The pre-training data has no role markers- the model just sees one stream of tokens.</div>
              </li>
              <li>
                <span>It doesn't know who's speaking.</span>
                <div className="tip">It can't tell what came from you and what came from itself a few turns ago. Both are just tokens in the same sequence.</div>
              </li>
            </ul>
            <ul className="bullets" style={{fontSize:18, gap:10}}>
              <li>
                <span>It can't stop.</span>
                <div className="tip">Without a stop token the labs train it to emit, sampling is open-loop- it generates until you cut the connection.</div>
              </li>
              <li>
                <span>One token at a time, never multiple at once.</span>
              </li>
              <li>
                <span>The rest of tonight is about what the labs build on top of this printer to make it useful.</span>
              </li>
            </ul>
          </div>
        </div>
        <div style={{flex:1, position:'relative', minHeight:0}}>
          <PaperPrinter noDividers={true} maxOutputs={220}/>
        </div>
      </div>
    </section>
  );
}

// === Slide 1.6: Wrapper materializes- EOS halts the printer ===
function Slide16() {
  return (
    <section className="slide" data-screen-label="06 Wrapper Materializes">
      <Chrome slide={7} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{flexDirection:'column', gap:18, paddingTop:78}}>
        <div style={{display:'flex', alignItems:'flex-start', gap:56}}>
          <div style={{flex:'0 0 540px'}}>
            <p className="eyebrow">Special tokens · the wrapper</p>
            <h2 className="title" style={{fontSize:48, lineHeight:1.05}}>
              The wrapper materialises.<br/>
              <span style={{color:'var(--text-2)', fontSize:30, fontWeight:500}}>The thing the labs hide behind the API.</span>
            </h2>
          </div>
          <div style={{flex:1, display:'grid', gridTemplateColumns:'1fr 1fr', gap:'9px 32px'}}>
            <ul className="bullets" style={{fontSize:17, gap:9}}>
              <li>
                <span>The wrapper is built and maintained by the lab.</span>
                <div className="tip">It sits between the raw model and the API endpoint you hit. You never see it directly- but it's what makes "ChatGPT" feel like a chat instead of a runaway printer.</div>
              </li>
              <li>
                <span>The labs train the model to emit special tokens- words nobody speaks.</span>
                <div className="tip">Important framing: the wrapper does not "teach" the model anything at runtime. The labs train the model to understand that a wrapper exists around it and to cooperate with it.</div>
              </li>
              <li>
                <span>⟨eos⟩ is a special token that tells the wrapper to stop sampling- teaches the model a way to finally shut itself up.</span>
                <div className="tip">When the model emits the end-of-sequence special token, the wrapper halts generation. Without this, sampling is open-loop forever (slide 06).</div>
              </li>
              <li>
                <span>Role markers wrap each turn so user and assistant become distinct in the input.</span>
                <div className="tip">Special tokens around every message so the model can tell who said what across turns. Without them, the input is one undifferentiated blob.</div>
              </li>
            </ul>
            <ul className="bullets" style={{fontSize:17, gap:9}}>
              <li>
                <span>⟨bod⟩ ... ⟨eod⟩ bracket attached files and context blocks.</span>
                <div className="tip">Start/end tokens around documents so the model knows where attached context begins and ends.</div>
              </li>
              <li>
                <span>⟨tool_call⟩ comes next- the seed of every agent we'll discuss tonight.</span>
                <div className="tip">Same family of special tokens, but for "I want to call a function." We unpack this on the next slide.</div>
              </li>
              <li>
                <span>This whole package is also called the API wrapper- the lab seals it before exposing it.</span>
                <div className="tip">Wrapper + classifiers + special-token machinery, packaged together. We come back to this when we close section 1 and physically seal the wrapper.</div>
              </li>
              <li>
                <span>Watch: when ⟨eos⟩ glows, the printer halts. That's the wrapper doing its job.</span>
                <div className="tip">The wrapper border on the right stays quiet until the model emits ⟨eos⟩. The instant it does, the wrapper lights up bright orange and printing stops cold.</div>
              </li>
            </ul>
          </div>
        </div>
        <div style={{flex:1, position:'relative', minHeight:0}}>
          <PaperPrinter showWrapper={true} showStop={true} maxOutputs={30}/>
        </div>
      </div>
    </section>
  );
}

// === Slide 1.7: Every input watched, every output watched ===
function Slide17() {
  return (
    <section className="slide" data-screen-label="07 Wrapper Does More">
      <Chrome slide={8} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{flexDirection:'column', gap:18, paddingTop:78}}>
        <div style={{display:'flex', alignItems:'flex-start', gap:56}}>
          <div style={{flex:'0 0 540px'}}>
            <p className="eyebrow">The wrapper does more than format</p>
            <h2 className="title" style={{fontSize:50, lineHeight:1.05}}>
              Every input watched.<br/>Every output watched.
            </h2>
          </div>
          <div style={{flex:1, display:'grid', gridTemplateColumns:'1fr 1fr', gap:'9px 32px'}}>
            <ul className="bullets" style={{fontSize:17, gap:9}}>
              <li>
                <span>Every input you send is being watched.</span>
                <div className="tip">Before the model sees your message, a classifier looks at it for policy violations. If it trips, the request never reaches the model.</div>
              </li>
              <li>
                <span>Every output the model emits is being watched too.</span>
                <div className="tip">After the model generates a response, another classifier scans it. If it trips, you get a refusal back- never the original output.</div>
              </li>
              <li>
                <span>OpenAI uses small auxiliary classifier models.</span>
                <div className="tip">Dedicated classifier networks running outside the main model on every request and response.</div>
              </li>
              <li>
                <span>Anthropic uses constitutional classifiers, trained on a written constitution of policies.</span>
                <div className="tip">Same job as OpenAI's auxiliary classifiers, different recipe. Anthropic trains the classifier against a "constitution" of explicit policies rather than ad-hoc labelled data.</div>
              </li>
            </ul>
            <ul className="bullets" style={{fontSize:17, gap:9}}>
              <li>
                <span>Trip a classifier, and the API just returns a refusal.</span>
                <div className="tip">You never see what the model would have actually said. The classifier short-circuits the response.</div>
              </li>
              <li>
                <span>Same prompt can succeed via API and fail in ChatGPT- or vice versa.</span>
                <div className="tip">Different products mount different classifier configurations on top of the same underlying model. The model didn't change; the surrounding classifiers did.</div>
              </li>
              <li>
                <span>Hint: this is where most jailbreak blocking actually lives.</span>
                <div className="tip">The main model was trained to follow user instructions, so labs leaned heavily on the surrounding classifiers to do the refusing. If you're poking at jailbreaks, the input/output classifiers are the real target- not the model itself.</div>
              </li>
            </ul>
          </div>
        </div>
        <div style={{flex:1, position:'relative', minHeight:0}}>
          <PaperPrinter showWrapper={true} showStop={true} bigEyes={true} staticMode={true} maxOutputs={30}/>
        </div>
      </div>
    </section>
  );
}

// === Slide 1.8: Forgot to teach it to shut up ===
function Slide18() {
  return (
    <section className="slide" data-screen-label="08 Forgot To Shut Up">
      <Chrome slide={9} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{justifyContent:'center', alignItems:'center', textAlign:'center'}}>
        <p className="eyebrow" style={{textAlign:'center'}}>When the wrapper breaks</p>
        <h2 className="title" style={{fontSize:64, maxWidth:1400, margin:'0 auto 28px'}}>
          When the lab forgets to teach it to shut up.
        </h2>
        <ul className="bullets" style={{
          fontSize:18, gap:8, maxWidth:1100, margin:'0 auto 28px',
          textAlign:'left', display:'inline-flex', alignItems:'flex-start',
          flexDirection:'column',
        }}>
          <li><span>The wrapper exists. The lab just didn't train the model well enough to use it.</span></li>
          <li><span>Without ⟨eos⟩ at the right moment, the printer just keeps printing.</span></li>
          <li><span>Famous example: Gemini's existential crises loops.</span></li>
          <li><span>15 seconds of comedy- then we move on.</span></li>
        </ul>
        <div style={{
          width:1400, height:520, margin:'0 auto',
          display:'flex', gap:24, alignItems:'stretch', justifyContent:'center',
        }}>
          <div style={{
            flex:'0 0 480px',
            border:'1px solid var(--ink-5)', borderRadius:6,
            background:'var(--ink-2)', padding:14,
            display:'flex', alignItems:'center', justifyContent:'center',
          }}>
            <img src="media/gemini-psychosis.jpeg" alt="Gemini infinite-generation crisis"
                 loading="eager" decoding="async"
                 style={{maxWidth:'100%', maxHeight:'100%', width:'auto', height:'auto', objectFit:'contain', display:'block'}}/>
          </div>
          <div style={{
            flex:1,
            border:'1px solid var(--ink-5)', borderRadius:6,
            background:'var(--ink-2)', padding:14,
            display:'flex', alignItems:'center', justifyContent:'center',
          }}>
            <img src="media/gemini-psychosis-2.png" alt="Gemini infinite-generation crisis 2"
                 loading="eager" decoding="async"
                 style={{maxWidth:'100%', maxHeight:'100%', width:'auto', height:'auto', objectFit:'contain', display:'block'}}/>
          </div>
        </div>
        <p style={{fontSize:22, color:'var(--text-2)', marginTop:32, fontStyle:'italic'}}>
          The wrapper is present, but the lab just didn't train the model well enough to cooperate with it. The model fails to emit ⟨eos⟩ at the right time, so the printer just keeps printing.
        </p>
      </div>
    </section>
  );
}

// === Slide 1.9: Tool-call special token ===
function Slide19() {
  const xmlPayload =
    `<span class="kw">&lt;tool_call&gt;</span>
  <span class="kw">&lt;name&gt;</span><span class="str">search_web</span><span class="kw">&lt;/name&gt;</span>
  <span class="kw">&lt;arguments&gt;</span><span class="pn">{</span><span class="ty">"query"</span><span class="pn">:</span><span class="str">"weather"</span><span class="pn">}</span><span class="kw">&lt;/arguments&gt;</span>
<span class="kw">&lt;/tool_call&gt;</span>`;
  const jsonPayload =
    `<span class="pn">{</span>
  <span class="ty">"type"</span><span class="pn">:</span> <span class="str">"tool_use"</span><span class="pn">,</span>
  <span class="ty">"name"</span><span class="pn">:</span> <span class="str">"search_web"</span><span class="pn">,</span>
  <span class="ty">"input"</span><span class="pn">:</span> <span class="pn">{</span><span class="ty">"query"</span><span class="pn">:</span> <span class="str">"weather"</span><span class="pn">}</span>
<span class="pn">}</span>`;

  return (
    <section className="slide" data-screen-label="09 Tool-Call Token">
      <Chrome slide={10} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{flexDirection:'row', gap:60, paddingTop:140}}>
        <div style={{flex:'0 0 620px'}}>
          <p className="eyebrow">One more special token</p>
          <h2 className="title" style={{fontSize:50}}>One more special token: the tool call.<br/><span style={{color:'var(--text-2)', fontSize:30, fontWeight:500}}>The seed of every agent we'll talk about tonight.</span></h2>
          <div style={{marginTop:28}}>
            <Bullets items={[
              { text: 'Same wrapper that handles ⟨eos⟩ and role markers also handles ⟨tool_call⟩.', tip: "Tool-call markers are one more member of the same family of special tokens- just for a different control signal." },
              { text: 'First the model emits ⟨tool_call⟩ to signal its intent, then follows up with a structured payload when it wants to call a function.', tip: "The special token itself isn't the payload- it's just a signal. The wrapper sees ⟨tool_call⟩ and knows a structured chunk is coming next. When ⟨/tool_call⟩ closes, the wrapper pauses streaming and ships the payload back to the handler to execute the function and return the result." },
              { text: 'OpenAI trained their models to emit JSON.', tip: "On the wire, OpenAI emits tool calls as JSON deltas streamed back through the API." },
              { text: 'Anthropic trained Claude to emit XML-flavoured tags (they have since moved on to JSON too).', tip: "Anthropic originally emitted tool calls as XML-flavoured tags on the wire- different format, same idea. They've since moved Claude to JSON like everyone else." },
              { text: 'Same concept, two flavours- your SDK normalises both before you see them.', tip: "Mastra (and every other agent SDK) abstracts the wire format away. You write one tool definition; the SDK formats it correctly per provider." },
              { text: "This loop is the seed of every agent- Claude Code, Cursor, Codex, ChatGPT all run it.", tip: "Every agent product in the room is the same four-stage loop with different tools plugged in. We zoom into the full lifecycle on the next slide." },
            ]}/>
          </div>
        </div>
        <div style={{flex:1, display:'flex', flexDirection:'column', justifyContent:'center', gap:18}}>
          <div style={{fontFamily:'JetBrains Mono', fontSize:12, letterSpacing:'0.18em', color:'var(--text-3)', textAlign:'center', marginBottom:4}}>
            ↓ THE SAME TOOL CALL, ON THE WIRE
          </div>
          <div style={{display:'flex', gap:24}}>
            <div style={{flex:1, display:'flex', flexDirection:'column', gap:10}}>
              <div style={{
                display:'inline-flex', alignSelf:'flex-start',
                padding:'6px 14px', borderRadius:3,
                background:'var(--red-deep)', color:'var(--red-4)',
                fontFamily:'JetBrains Mono', fontSize:13, letterSpacing:'0.15em',
                border:'1px solid var(--red-2)',
              }}>ANTHROPIC · XML</div>
              <div className="code" style={{fontSize:15}}>
                <div className="code-header">WIRE PAYLOAD · CLAUDE</div>
                <div className="code-body" dangerouslySetInnerHTML={{__html: xmlPayload}}/>
              </div>
            </div>
            <div style={{flex:1, display:'flex', flexDirection:'column', gap:10}}>
              <div style={{
                display:'inline-flex', alignSelf:'flex-start',
                padding:'6px 14px', borderRadius:3,
                background:'var(--red-deep)', color:'var(--red-4)',
                fontFamily:'JetBrains Mono', fontSize:13, letterSpacing:'0.15em',
                border:'1px solid var(--red-2)',
              }}>OPENAI · JSON</div>
              <div className="code" style={{fontSize:15}}>
                <div className="code-header">WIRE PAYLOAD · GPT</div>
                <div className="code-body" dangerouslySetInnerHTML={{__html: jsonPayload}}/>
              </div>
            </div>
          </div>
          <div style={{
            marginTop:8, padding:'14px 20px',
            background:'var(--ink-3)', borderLeft:'3px solid var(--red-3)', borderRadius:4,
            fontFamily:'Inter Tight', fontSize:16, color:'var(--text-1)', lineHeight:1.45,
            fontStyle:'italic',
          }}>
            Different shape, same payload. The SDK normalises both before your code sees them.
          </div>
        </div>
      </div>
    </section>
  );
}

// === Slide 1.10: Format wars ===
function Slide110() {
  return (
    <section className="slide" data-screen-label="10 Format Wars">
      <Chrome slide={11} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{paddingTop:140}}>
        <p className="eyebrow">The format wars</p>
        <h2 className="title" style={{fontSize:54, marginBottom:36, maxWidth:1700}}>
          Both labs converged on XML- <span style={{color:'var(--red-3)'}}>and Cursor noticed before OpenAI did.</span>
        </h2>

        <div style={{display:'flex', gap:64, flex:1, alignItems:'center'}}>
          {/* LEFT: bullet talking points */}
          <div style={{flex:'0 0 880px'}}>
            <div style={{fontFamily:'JetBrains Mono', fontSize:12, color:'var(--red-3)', letterSpacing:'0.2em', marginBottom:14}}>※ THE CONVERGENCE STORY</div>
            <ul className="bullets" style={{fontSize:21, gap:14}}>
              <li>
                <span>Anthropic trained Claude on XML-structured data from day one- and it ended up surprisingly good at following XML-tagged instructions.</span>
                <div className="tip">Whatever was in their pre-training cocktail was heavy on XML, and Claude came out the other side natively responsive to XML-formatted prompts. Nobody has a clean public explanation for why it stuck so well.</div>
              </li>
              <li>
                <span>That's why every Anthropic prompt guide has pushed XML-tagged prompting from the start.</span>
                <div className="tip">Their cookbook is wall-to-wall &lt;instructions&gt;...&lt;/instructions&gt;, &lt;example&gt;...&lt;/example&gt;, &lt;context&gt;...&lt;/context&gt;. House style for years.</div>
              </li>
              <li>
                <span>OpenAI's guides have always recommended Markdown- headers, bullets, code fences.</span>
                <div className="tip">For years, OpenAI's cookbook treated structure as a Markdown thing, not XML. Two completely different houses of style sitting next to each other.</div>
              </li>
              <li>
                <span>2025: <span style={{color:'var(--red-4)', fontWeight:600}}>Cursor</span> tunes for the freshly-released GPT-5 and discovers it actually prefers XML too.</span>
                <div className="tip">When GPT-5 dropped, Cursor was squeezing performance out of it and found the model was unusually responsive to XML-tagged prompts. They flagged it publicly- well before OpenAI updated their own guides.</div>
              </li>
              <li>
                <span>Later that year: Anthropic accused OpenAI of training on distilled Claude data. OpenAI denied.</span>
                <div className="tip">Anthropic's claim was specific- OpenAI was using Claude outputs (distilled) as training data. OpenAI denied publicly. But the GPT-5 "XML moment" had already happened, and the timing raised a lot of eyebrows.</div>
              </li>
              <li><span style={{color:'var(--text-2)', fontStyle:'italic'}}>Make of that what you will.</span></li>
            </ul>
          </div>

          {/* RIGHT: chimera meme */}
          <div style={{
            flex:1, alignSelf:'stretch',
            display:'flex', alignItems:'center', justifyContent:'center',
            border:'1px solid var(--ink-5)', borderRadius:8,
            background:'var(--ink-2)', padding:18,
          }}>
            <img src="media/anthropic-scraping.PNG" alt="Anthropic vs OpenAI scraping accusation"
                 loading="eager" decoding="async"
                 style={{maxWidth:'100%', maxHeight:'100%', width:'auto', height:'auto', objectFit:'contain', display:'block'}}/>
          </div>
        </div>
      </div>
    </section>
  );
}

// === Slide 1.11: Tool-call lifecycle (4-step loop) ===
// Reusable visual- we come back to it in §3 (action surfaces).
function ToolCallLoop({ active }) {
  // 2×2 grid forms a natural cycle. Step 1 → 2 → 3 → 4 → back to 1.
  // ViewBox is roughly square so it fits a side-by-side slide layout.
  const W = 900, H = 820;
  const boxW = 380, boxH = 260;
  const padX = 30, padY = 30;
  const positions = [
    { x: padX,                y: padY },                 // [1] top-left
    { x: W - padX - boxW,     y: padY },                 // [2] top-right
    { x: W - padX - boxW,     y: H - padY - boxH },      // [3] bottom-right
    { x: padX,                y: H - padY - boxH },      // [4] bottom-left
  ];
  const steps = [
    {
      who: 'MODEL',
      title: 'Emits a tool-call payload',
      detail: `⟨tool_call⟩
{
  "name": "search_web",
  "args": { "query": "weather" }
}
⟨/tool_call⟩`,
      kind: 'mono',
    },
    {
      who: 'WRAPPER',
      title: 'Halts sampling, fires the event',
      detail: 'API stops generating tokens and sends the parsed tool-call event back to the handler.',
      kind: 'prose',
    },
    {
      who: 'YOU / SDK / HANDLER',
      title: 'Runs the function, returns the result',
      detail: 'The SDK / handler matches the tool name to your registered function, runs it, and formats the return value back for the wrapper.',
      kind: 'prose',
    },
    {
      who: 'MODEL',
      title: 'Receives the result, continues generating',
      detail: 'The tool result is inserted as the latest message in the input. The model resumes generating from there.',
      kind: 'prose',
    },
  ];

  // Centers + arrow paths between adjacent boxes
  const cx_box = i => positions[i].x + boxW / 2;
  const cy_box = i => positions[i].y + boxH / 2;
  const arrows = [
    // 1 → 2 across the top
    { d: `M ${positions[0].x + boxW + 8} ${cy_box(0)} L ${positions[1].x - 8} ${cy_box(1)}`, label: '①' },
    // 2 → 3 down the right
    { d: `M ${cx_box(1)} ${positions[1].y + boxH + 8} L ${cx_box(2)} ${positions[2].y - 8}`, label: '②' },
    // 3 → 4 across the bottom (right-to-left)
    { d: `M ${positions[2].x - 8} ${cy_box(2)} L ${positions[3].x + boxW + 8} ${cy_box(3)}`, label: '③' },
    // 4 → 1 up the left (loop back)
    { d: `M ${cx_box(3)} ${positions[3].y - 8} L ${cx_box(0)} ${positions[0].y + boxH + 8}`, label: '④ loop' },
  ];

  return (
    <svg viewBox={`0 0 ${W} ${H}`} style={{width:'100%', height:'100%', display:'block'}}>
      <defs>
        <marker id="arr-tcl" markerWidth="12" markerHeight="12" refX="9" refY="3" orient="auto">
          <path d="M0,0 L0,6 L9,3 z" fill="var(--red-3)"/>
        </marker>
        <marker id="arr-tcl-dim" markerWidth="12" markerHeight="12" refX="9" refY="3" orient="auto">
          <path d="M0,0 L0,6 L9,3 z" fill="var(--ink-5)"/>
        </marker>
      </defs>

      {/* Arrows */}
      {arrows.map((a, i) => {
        const lit = active === i || active === (i + 1) % 4;
        return (
          <g key={i}>
            <path d={a.d} fill="none"
                  stroke={lit ? 'var(--red-3)' : 'var(--ink-5)'}
                  strokeWidth={lit ? 3 : 2}
                  strokeDasharray={lit ? '0' : '6 6'}
                  opacity={lit ? 1 : 0.55}
                  markerEnd={lit ? 'url(#arr-tcl)' : 'url(#arr-tcl-dim)'}/>
          </g>
        );
      })}

      {/* Step boxes */}
      {steps.map((s, i) => {
        const p = positions[i];
        const isActive = active === i;
        return (
          <g key={i} style={{transition:'all 0.3s'}}>
            <rect x={p.x} y={p.y} width={boxW} height={boxH}
                  rx="8" ry="8"
                  fill={isActive ? '#1f0f0e' : 'var(--ink-2)'}
                  stroke={isActive ? 'var(--red-3)' : 'var(--ink-5)'}
                  strokeWidth={isActive ? 3 : 1.6}
                  style={{filter: isActive ? 'drop-shadow(0 0 22px rgba(232,80,80,0.5))' : 'none'}}/>
            {/* Step number badge */}
            <circle cx={p.x + 32} cy={p.y + 32} r="22"
                    fill={isActive ? 'var(--red-3)' : 'var(--ink-3)'}
                    stroke={isActive ? 'var(--red-3)' : 'var(--ink-5)'} strokeWidth="1.6"/>
            <text x={p.x + 32} y={p.y + 40} textAnchor="middle"
                  fontFamily="JetBrains Mono" fontSize="22" fontWeight="700"
                  fill={isActive ? '#fff' : 'var(--text-2)'}>{i + 1}</text>
            {/* Actor label */}
            <text x={p.x + 72} y={p.y + 32} textAnchor="start"
                  fontFamily="JetBrains Mono" fontSize="14"
                  letterSpacing="3"
                  fill={isActive ? 'var(--red-4)' : 'var(--text-3)'}
                  fontWeight="600">{s.who}</text>
            {/* Title + detail (HTML in SVG so long titles wrap inside the box) */}
            <foreignObject x={p.x + 24} y={p.y + 64} width={boxW - 48} height={boxH - 76}>
              <div xmlns="http://www.w3.org/1999/xhtml"
                   style={{
                     display:'flex', flexDirection:'column', gap:10,
                     height:'100%',
                   }}>
                <div style={{
                  fontFamily:'Inter Tight, sans-serif',
                  fontSize: 22,
                  fontWeight: 600,
                  lineHeight: 1.2,
                  color: isActive ? 'var(--text-0)' : 'var(--text-1)',
                }}>
                  {s.title}
                </div>
                <div style={{
                  fontFamily: s.kind === 'mono' ? 'JetBrains Mono, monospace' : 'Inter Tight, sans-serif',
                  fontSize: s.kind === 'mono' ? 13 : 15,
                  lineHeight: s.kind === 'mono' ? 1.55 : 1.45,
                  color: isActive ? 'var(--text-1)' : 'var(--text-2)',
                  letterSpacing: s.kind === 'mono' ? '0.02em' : 0,
                  whiteSpace: s.kind === 'mono' ? 'pre' : 'normal',
                  padding: s.kind === 'mono' ? '10px 12px' : 0,
                  borderLeft: s.kind === 'mono' ? `2px solid ${isActive ? 'var(--red-3)' : 'var(--ink-5)'}` : 'none',
                  background: s.kind === 'mono' ? (isActive ? 'rgba(196,48,48,0.06)' : 'rgba(15,10,9,0.55)') : 'transparent',
                  borderRadius: s.kind === 'mono' ? 3 : 0,
                  flex: s.kind === 'mono' ? '0 0 auto' : 1,
                }}>
                  {s.detail}
                </div>
              </div>
            </foreignObject>
          </g>
        );
      })}

      {/* center loop label */}
      <text x={W / 2} y={H / 2 - 8} textAnchor="middle"
            fontFamily="JetBrains Mono" fontSize="13"
            letterSpacing="0.25em" fill="var(--text-3)">THE TOOL-CALL LOOP</text>
      <text x={W / 2} y={H / 2 + 18} textAnchor="middle"
            fontFamily="Inter Tight" fontSize="22" fontWeight="600"
            fill="var(--text-1)">every agent runs this</text>
    </svg>
  );
}

function Slide111() {
  const resetKey = useSlideResetKey();
  const [active, setActive] = useState(0);
  const speed = useAnimSpeed();
  useEffect(() => {
    setActive(0);
    const id = setInterval(() => setActive(a => (a + 1) % 4), 1500 / Math.max(0.05, speed));
    return () => clearInterval(id);
  }, [resetKey, speed]);

  return (
    <section className="slide" data-screen-label="11 Tool-Call Loop">
      <Chrome slide={12} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{flexDirection:'row', gap:56, paddingTop:140, alignItems:'stretch'}}>
        <div style={{flex:'0 0 760px', display:'flex', flexDirection:'column'}}>
          <p className="eyebrow">The tool-call loop · the seed of every agent</p>
          <h2 className="title" style={{fontSize:54, lineHeight:1.05, marginBottom:24}}>
            Four steps.<br/>Every agent runs this loop.
          </h2>
          <ul className="bullets" style={{fontSize:19, gap:12, maxWidth:760}}>
            <li><span>The model emits a structured tool-call payload- a special token.</span></li>
            <li><span>The wrapper halts sampling and fires the parsed event back to the caller.</span></li>
            <li><span>The SDK (or you) runs the function and returns the result in the expected format.</span></li>
            <li><span>The result is inserted as the latest message; the model resumes generating tokens.</span></li>
            <li><span>This is the entire mechanism- Claude Code, Cursor, Codex, ChatGPT all run this loop.</span></li>
            <li><span>We come back to this exact diagram in §3 (action surfaces).</span></li>
          </ul>
        </div>
        <div style={{flex:1, position:'relative', display:'flex', alignItems:'center', justifyContent:'center'}}>
          <ToolCallLoop active={active}/>
        </div>
      </div>
    </section>
  );
}

// Expose for reuse later in §3
window.ToolCallLoop = ToolCallLoop;

// === Slide 1.12: Context-length floodgates ===
function Slide112() {
  const milestones = [
    { year: '2023 Q1',    name: ['GPT-4'],                  tokens: 8,    k: '8K'   },
    { year: '2023 Q3',    name: ['GPT-4-32K'],              tokens: 32,   k: '32K'  },
    { year: '2023 Q4',    name: ['GPT-4 Turbo'],            tokens: 128,  k: '128K' },
    { year: 'early 2024', name: ['GPT-4o', 'Sonnet 3.5'],   tokens: 200,  k: '200K' },
    { year: 'late 2024',  name: ['Gemini 2.5'],             tokens: 1000, k: '1M'   },
    { year: '2025',       name: ['Opus 4.5', 'Gemini 3'],   tokens: 1000, k: '1M'   },
    { year: 'early 2026', name: ['Opus 4.6', 'GPT-5.4'],    tokens: 1000, k: '1M+'  },
    { year: 'mid 2026',   name: ['Grok 4.X'],               tokens: 2000, k: '2M'   },
  ];
  const maxT = 2000;
  return (
    <section className="slide" data-screen-label="12 Floodgates">
      <Chrome slide={13} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{paddingTop:140}}>
        <p className="eyebrow">The context-length floodgates · §1 closing tidbit</p>
        <h2 className="title" style={{fontSize:50, marginBottom:24}}>We taught it to call tools. <span style={{color:'var(--red-3)'}}>Then we had to feed the floodwater.</span></h2>

        {/* Timeline visual */}
        <div style={{display:'flex', flexDirection:'column', justifyContent:'center', marginBottom:28}}>
          <div style={{display:'flex', alignItems:'flex-end', gap:18, height:240, padding:'0 24px', borderBottom:'1px solid var(--ink-5)', position:'relative'}}>
            {milestones.map((m, i) => {
              // sqrt scale so the early bars (8K, 32K, 128K) are still visible while 2M still tops out
              const h = Math.max(22, Math.sqrt(m.tokens / maxT) * 220);
              return (
                <div key={i} style={{flex:1, display:'flex', flexDirection:'column', alignItems:'center', gap:8}}>
                  <div style={{fontFamily:'JetBrains Mono', fontSize:16, color:'var(--red-4)', fontWeight:600}}>{m.k}</div>
                  <div style={{
                    width:'100%', height: h,
                    background:`linear-gradient(180deg, var(--red-3), var(--red-deep))`,
                    border:'1px solid var(--red-2)',
                    borderRadius:'2px 2px 0 0',
                    position:'relative',
                    boxShadow:'inset 0 0 12px rgba(232,80,80,0.2)',
                  }}>
                    <div style={{position:'absolute', inset:0,
                      backgroundImage:'repeating-linear-gradient(0deg, transparent 0 8px, rgba(0,0,0,0.2) 8px 9px)',
                    }}/>
                  </div>
                </div>
              );
            })}
          </div>
          <div style={{display:'flex', gap:18, padding:'10px 24px 0'}}>
            {milestones.map((m, i) => (
              <div key={i} style={{flex:1, textAlign:'center'}}>
                <div style={{fontSize:14, color:'var(--text-1)', fontWeight:600, lineHeight:1.25}}>
                  {m.name.map((line, k) => <div key={k}>{line}</div>)}
                </div>
                <div style={{fontFamily:'JetBrains Mono', fontSize:11, color:'var(--text-3)', letterSpacing:'0.1em', marginTop:4}}>{m.year}</div>
              </div>
            ))}
          </div>
        </div>

        {/* Story bullets- the floodgates causal chain only.
            The "sharp upper limit" / "three bottlenecks" content is the next slide. */}
        <div style={{display:'flex', gap:48, alignItems:'flex-start'}}>
          <div style={{flex:1}}>
            <Bullets items={[
              { text: 'Tool calls finally let the model reach past its training data.', tip: "Before tool calls, the model was stuck with whatever it learned during pre-training. Tool calls broke the box- the model could ask the world for fresh information." },
              { text: 'Web search came first- it solved the immediate "trapped in training data" problem.', tip: "The most obvious use of a tool: let the model search the web for current information. Solved an entire class of complaints overnight." },
              { text: 'Then we opened the floodgates- code exec, filesystem, browser, database queries, anything the API could call.', tip: "Once one tool worked, the labs realised every kind of tool could plug in. Code execution let it run scripts. Filesystem let it read files. Browser let it navigate pages. Each made the model exponentially more useful." },
              { text: 'But tool outputs are fat- file dumps, multi-page search results, raw HTML, query rows.', tip: "A web search result is hundreds of tokens. A file read is thousands. A code execution log is huge. All of it has to be fed back into the model as the next input." },
            ]}/>
          </div>
          <div style={{flex:1}}>
            <Bullets items={[
              { text: 'Context windows had to grow to digest them.', tip: 'OpenAI went from 8K to 32K to 128K inside 2023 alone. Anthropic pushed Claude to 100K, then 200K, then 1M. Gemini and the latest frontier ships 1M+ today.' },
              { text: 'That same context now fits whole codebases, hour-long agent traces, and dozens of prior tool results in a single shot.' },
              { text: 'The scale-up of tool calling alongside long context enabled much of the modern useful AI we use day to day.' },
            ]}/>
          </div>
        </div>
      </div>
    </section>
  );
}

// === Slide 1.12.5: Why long context is hard (3 bottlenecks + tidbit) ===
// Sits between the floodgates timeline (1.12) and the wrapper closer (1.13).
// Pulls the "sharp upper limit" + "long context only matters because of tools" beats
// off the timeline slide so 1.12 can stay visual.
function Slide1125() {
  const cardStyle = (accent) => ({
    flex: 1,
    background: 'var(--ink-2)',
    border: '1px solid var(--ink-5)',
    borderTop: `5px solid ${accent}`,
    padding: '34px 32px 30px',
    borderRadius: '6px 6px 8px 8px',
    display: 'flex',
    flexDirection: 'column',
    gap: 18,
  });
  const liStyle = { fontSize: 19, lineHeight: 1.42, color: 'var(--text-1)' };
  const cardLabelStyle = (color) => ({
    fontFamily: 'JetBrains Mono', fontSize: 15, color, letterSpacing: '0.22em', fontWeight: 600,
  });

  return (
    <section className="slide" data-screen-label="13 Long Context Hard">
      <Chrome slide={14} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{paddingTop:120}}>
        <p className="eyebrow">§1 closing tidbit · why long context is hard</p>
        <h2 className="title" style={{fontSize:64, marginBottom:32, lineHeight:1.05}}>
          Long context struggles for <span style={{color:'var(--red-3)'}}>three main reasons.</span>
        </h2>

        <div style={{display:'flex', gap:32, flex:1}}>
          {/* === 01- Compute scarcity === */}
          <div style={cardStyle('var(--red-3)')}>
            <div style={cardLabelStyle('var(--red-3)')}>01 · COMPUTE SCARCITY</div>
            <h3 style={{fontSize:30, color:'var(--text-0)', margin:0, lineHeight:1.18, fontWeight:600}}>There isn't enough compute to train on million-token sequences.</h3>
            <div style={{
              padding:'18px 20px', background:'var(--ink-3)', border:'1px solid var(--ink-5)', borderRadius:6,
              fontFamily:'JetBrains Mono', fontSize:16, color:'var(--text-2)', display:'flex', flexDirection:'column', gap:8,
            }}>
              <div>pretrain      ▮▮▮▮ 32k – 64k</div>
              <div>post-train    ▮▮▮▮▮▮▮▮ 100k – 200k</div>
              <div>deployment    ▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮▮ 1M+</div>
            </div>
            <ul className="bullets" style={{gap:11}}>
              <li style={liStyle}><span>Pre-training fits around 32k–64k tokens on today's GPU deployments.</span></li>
              <li style={liStyle}><span>Post-training pushes that up to roughly 100k–200k.</span></li>
              <li style={liStyle}><span>Memory cost scales <strong>quadratically</strong> with sequence length, so longer pretraining gets expensive fast.</span></li>
              <li style={liStyle}><span>Most deployed models end up cutting you off around a few hundred thousand tokens.</span></li>
            </ul>
          </div>

          {/* === 02- Data scarcity (xAI / Substack tidbit lives here) === */}
          <div style={cardStyle('var(--sec-3)')}>
            <div style={cardLabelStyle('var(--sec-3)')}>02 · DATA SCARCITY</div>
            <h3 style={{fontSize:30, color:'var(--text-0)', margin:0, lineHeight:1.18, fontWeight:600}}>Long-form coherent training data is hard to come by.</h3>
            <div style={{
              padding:'18px 20px', background:'var(--ink-3)', border:'1px solid var(--ink-5)', borderRadius:6,
              fontSize:14, color:'var(--text-2)',
            }}>
              <div style={{display:'flex', flexDirection:'column', gap:6}}>
                <div style={{height:30, width:'34%', background:'var(--sec-3)', borderRadius:2}} title="books"/>
                <div style={{height:10, width:'88%', background:'var(--text-3)', borderRadius:2}}/>
                <div style={{height:10, width:'72%', background:'var(--text-3)', borderRadius:2}}/>
                <div style={{height:10, width:'90%', background:'var(--text-3)', borderRadius:2}}/>
                <div style={{height:10, width:'60%', background:'var(--text-3)', borderRadius:2}}/>
                <div style={{height:10, width:'78%', background:'var(--text-3)', borderRadius:2}}/>
              </div>
              <div style={{marginTop:12, fontFamily:'JetBrains Mono', fontSize:13, letterSpacing:'0.16em', color:'var(--text-3)'}}>
                ▮ books (≈75k+ words) ░ short docs · web pages · tweets · email
              </div>
            </div>
            <ul className="bullets" style={{gap:11}}>
              <li style={liStyle}><span>Coherent text much longer than ~75k words doesn't really exist naturally.</span></li>
              <li style={liStyle}><span>Books are around- but that's one type of data, and it runs out.</span></li>
              <li style={liStyle}><span>Long technical conversations and multi-day reasoning aren't really sitting on the open web either.</span></li>
              <li style={{...liStyle, color:'var(--sec-3)'}}><span><strong>xAI rolled out Articles recently- rumoured to be one part of a long-context training-data grab for Grok.</strong></span></li>
              <li style={liStyle}><span>It also competes with Substack; the training-data angle is rumoured to be one factor in the play.</span></li>
              <li style={liStyle}><span>Engagement on the platform doubles as a quality filter for what gets used.</span></li>
            </ul>
          </div>

          {/* === 03- Algorithmic decay === */}
          <div style={cardStyle('var(--sec-5)')}>
            <div style={cardLabelStyle('var(--sec-5)')}>03 · ALGORITHMIC DECAY</div>
            <h3 style={{fontSize:30, color:'var(--text-0)', margin:0, lineHeight:1.18, fontWeight:600}}>Even when the context fits, accuracy tends to drop with depth.</h3>
            <div style={{
              height:280, width:'100%',
              background:'var(--ink-3)', border:'1px solid var(--ink-5)', borderRadius:6,
              padding:10,
              display:'flex', alignItems:'center', justifyContent:'center',
            }}>
              <img src="media/long-context-claude.png" alt="Claude long-context accuracy decay"
                   loading="eager" decoding="async"
                   style={{maxWidth:'100%', maxHeight:'100%', width:'auto', height:'auto', objectFit:'contain', display:'block'}}/>
            </div>
            <ul className="bullets" style={{gap:11}}>
              <li style={liStyle}><span>Labs use mathematical tricks at inference to stretch context past the trained range.</span></li>
              <li style={liStyle}><span>It works well enough to ship- but accuracy still drops as you push deeper.</span></li>
              <li style={liStyle}><span>This decay may or may not be a fundamental algorithmic limit.</span></li>
              <li style={liStyle}><span>We can't really tell yet- bottlenecks 01 and 02 aren't solved enough to isolate it.</span></li>
            </ul>
          </div>
        </div>

        <div style={{marginTop:32, padding:'22px 32px', background:'var(--ink-2)', border:'1px solid var(--ink-5)', borderLeft:'4px solid var(--red-3)', borderRadius:6}}>
          <div style={{fontFamily:'JetBrains Mono', fontSize:14, color:'var(--red-3)', letterSpacing:'0.22em', marginBottom:10, fontWeight:600}}>※ THE PUNCHLINE</div>
          <p style={{margin:0, fontSize:22, color:'var(--text-1)', fontStyle:'italic', lineHeight:1.5}}>
            Tools opening the floodgates is what made long context matter in the first place- and the labs all reach for similar math tricks to push past the wall. We come back to this at the end of §2 with the memory subsystems.
          </p>
        </div>
      </div>
    </section>
  );
}

// === Slide 1.13: Section 1 closer- animated build-up, wrapper in focus ===
//
// Animation:
//   phase 0 (0–0.9s)  - just the LLM core, highlighted (where we've been all section)
//   phase 1 (0.9–2.0s)- wrapper materialises around it; wrapper takes focus, core greys
//   phase 2 (2.0s+)   - rest of the architecture fades in around them, all greyed
//
// Cartridges and wires are passed with lit:0 so they render at low opacity (the
// ConsoleVisual already routes lit:0 through reduced alpha + ink colours).
function Slide113() {
  const resetKey = useSlideResetKey();
  const speed = useAnimSpeed();
  const [stage, setStage] = useState(0);
  const [highlight, setHighlight] = useState('core');

  useEffect(() => {
    setStage(0);
    setHighlight('core');
    const s = Math.max(0.05, speed);
    const ids = [
      setTimeout(() => { setStage(1); setHighlight('envelope'); }, 900 / s),
      setTimeout(() => { setStage(5); setHighlight('envelope'); }, 2000 / s),
    ];
    return () => ids.forEach(clearTimeout);
  }, [resetKey, speed]);

  const dimCartridges = [
    { label: 'MSG · HISTORY',     color: '#c9a227', lit: 0 },
    { label: 'WORKING · MEM',     color: '#e85050', lit: 0 },
    { label: 'SEMANTIC · RECALL', color: '#4a90a4', lit: 0 },
    { label: 'OBSERVATIONAL',     color: '#8b6cae', lit: 0 },
  ];
  const dimWires = [
    { label: 'tools',     lit: 0 },
    { label: 'MCP',       lit: 0 },
    { label: 'skills',    lit: 0 },
    { label: 'workspace', lit: 0 },
  ];

  const html = useMemo(
    () => window.ConsoleVisual({
      size: 'full',
      stage,
      highlight,
      cartridges: dimCartridges,
      wires: dimWires,
    }),
    [stage, highlight]
  );

  return (
    <section className="slide" data-screen-label="14 Section 1 Closer">
      <Chrome slide={15} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{flexDirection:'row', gap:40, paddingTop:140, alignItems:'stretch'}}>
        <div style={{flex:'0 0 520px', display:'flex', flexDirection:'column'}}>
          <p className="eyebrow">Section 1- done</p>
          <h2 className="title" style={{fontSize:48, lineHeight:1.05, marginBottom:24}}>
            The <span style={{color:'var(--red-3)'}}>model + wrapper</span> is sealed.<br/>
            The rest of the picture is what we cover next.
          </h2>
          <Bullets items={[
            { text: 'The LLM core is the model + special tokens + classifiers + the API wrapper.', tip: "Everything we covered in §1- raw model, ⟨eos⟩, role markers, document markers, tool-call markers, safety classifiers- is now packaged behind a single API endpoint." },
            { text: 'From here on, "the model" means this whole packaged unit, not just the raw weights.', tip: "Whenever we say 'the model' for the rest of the talk, we mean the lab's API behind the wrapper- not the bare next-token predictor." },
            { text: 'Greyed around it: memory, action surfaces, orchestration, observability.', tip: "Each greyed-out shape is a section we'll come back and light up: §2 memory cartridges, §3 action surfaces, §4 orchestration shell, §5 the dotted feedback loop." },
            { text: "Each layer is its own section. We unpack them one at a time.", tip: "The talk's spine is build → strip → rebuild. We just finished the innermost ring; everything outside it is what's coming." },
          ]}/>
        </div>

        <div style={{flex:1, position:'relative', display:'flex', alignItems:'center', justifyContent:'center', minWidth:0}}>
          {/* Full architecture builds up over the slide; envelope is the only bright element. */}
          <div style={{
            width:'100%', height:'100%',
            display:'flex', alignItems:'center', justifyContent:'center',
            transition: `opacity ${0.45 / Math.max(0.05, speed)}s ease`,
          }}
               dangerouslySetInnerHTML={{__html: html}}/>
          {/* Subtle red wash behind the wrapper to push the "in focus" feel */}
          <div style={{
            position:'absolute', inset:0,
            background: 'radial-gradient(ellipse at center, rgba(232,80,80,0.10), transparent 58%)',
            pointerEvents: 'none',
            opacity: stage >= 1 ? 1 : 0,
            transition: `opacity ${0.6 / Math.max(0.05, speed)}s ease`,
          }}/>
        </div>
      </div>
    </section>
  );
}

// === Slide 1.14: Mastra absorbs next layer ===
function Slide114() {
  return (
    <section className="slide" data-screen-label="15 Mastra Absorbs">
      <Chrome slide={16} total={33} sectionLabel="01 · LLM CORE" />
      <div className="slide-inner" style={{paddingTop:90}}>
        <p className="eyebrow">Mastra · the model router</p>
        <h2 className="title" style={{fontSize:56, lineHeight:1.05, marginBottom:36}}>
          The lab abstracts the model.<br/>Mastra abstracts the labs.
        </h2>

        <div style={{display:'flex', gap:56, flex:1, alignItems:'stretch', minHeight:0}}>
          {/* CODE- left, wide */}
          <div style={{flex:'1 1 1080px', display:'flex', flexDirection:'column'}}>
            <div className="code" style={{fontSize:19, lineHeight:1.55, padding:'28px 32px', flex:1}}>
              <div className="code-header">AGENTS / MATH.TS</div>
              <div className="code-body" dangerouslySetInnerHTML={{__html:
                `<span class="kw">import</span> { <span class="ty">Agent</span>, <span class="ty">createTool</span> } <span class="kw">from</span> <span class="str">'@mastra/core'</span>
<span class="kw">import</span> { <span class="ty">z</span> } <span class="kw">from</span> <span class="str">'zod'</span>

<span class="cm">// 1 · Define a simple tool the agent can call.</span>
<span class="kw">const</span> <span class="fn">addNumbers</span> = <span class="fn">createTool</span>({
  <span class="ty">id</span>: <span class="str">'add_numbers'</span>,
  <span class="ty">description</span>: <span class="str">'Add two numbers together.'</span>,
  <span class="ty">inputSchema</span>: <span class="ty">z</span>.<span class="fn">object</span>({ <span class="ty">a</span>: <span class="ty">z</span>.<span class="fn">number</span>(), <span class="ty">b</span>: <span class="ty">z</span>.<span class="fn">number</span>() }),
  <span class="ty">execute</span>: <span class="kw">async</span> ({ <span class="ty">context</span> }) =&gt; <span class="ty">context</span>.<span class="ty">a</span> + <span class="ty">context</span>.<span class="ty">b</span>,
})

<span class="cm">// 2 · Build the agent. Pick any provider with a single string, attach the tool.</span>
<span class="kw">export const</span> <span class="fn">mathAgent</span> = <span class="kw">new</span> <span class="ty">Agent</span>({
  <span class="ty">name</span>: <span class="str">'math'</span>,
  <span class="ty">instructions</span>: <span class="str">'Answer math questions. Use add_numbers to sum two numbers.'</span>,
  <span class="ty">model</span>: <span class="str">'openai/gpt-5.4'</span>,            <span class="cm">// swap → 'anthropic/claude-opus-4-7'</span>
                                       <span class="cm">//     → 'google/gemini-3.1-pro'</span>
                                       <span class="cm">//     → 'deepseek/v4', 'groq/...', etc.</span>
  <span class="ty">tools</span>: { <span class="fn">addNumbers</span> },
})`
              }}/>
            </div>
          </div>

          {/* BULLETS- right, compact */}
          <div style={{flex:'0 0 540px', display:'flex', alignItems:'center'}}>
            <ul className="bullets" style={{fontSize:18, gap:14, width:'100%'}}>
              <li>
                <span>One <code style={{fontFamily:'JetBrains Mono', color:'var(--red-3)', fontSize:'0.92em', background:'var(--ink-3)', border:'1px solid var(--ink-5)', padding:'2px 8px', borderRadius:4, verticalAlign:'middle', lineHeight:1, display:'inline-block'}}>provider/model</code> string covers every lab Mastra supports.</span>
                <div className="tip">OpenAI, Anthropic, Google (Vertex + AI Studio), DeepSeek, OpenRouter, Mistral, Groq- all reachable through the same string convention.</div>
              </li>
              <li>
                <span>Mastra normalises wire format, headers, and stop conditions per provider.</span>
                <div className="tip">Each lab's API wrapper is shaped slightly differently- different headers, different stop conditions, different tool-call payload shapes. Mastra hides all of it behind one interface.</div>
              </li>
              <li>
                <span>Tools attach with a tiny <code style={{fontFamily:'JetBrains Mono', color:'var(--red-3)', fontSize:'0.92em', background:'var(--ink-3)', border:'1px solid var(--ink-5)', padding:'2px 8px', borderRadius:4, verticalAlign:'middle', lineHeight:1, display:'inline-block'}}>tools: {'{...}'}</code> object on the agent.</span>
                <div className="tip">No registration boilerplate, no event-loop wiring. The SDK takes care of routing the tool-call payload back to the right function.</div>
              </li>
              <li>
                <span>Each tool is a description, a Zod input schema, and an execute function.</span>
                <div className="tip">The schema becomes the tool's JSON-schema on the wire automatically. The execute function is the only step you actually write.</div>
              </li>
              <li>
                <span>Write the agent once. Swap the model string. Done.</span>
                <div className="tip">This is the second layer of abstraction tonight: the lab abstracts the raw model, your SDK abstracts the labs.</div>
              </li>
            </ul>
          </div>
        </div>
      </div>
    </section>
  );
}

// === Slide 1.15: Section transition (Hook #3) ===
function Slide115() {
  const resetKey = useSlideResetKey();
  const [pulse, setPulse] = useState(false);
  useEffect(() => {
    setPulse(false);
    const id = setTimeout(() => setPulse(true), 700);
    return () => clearTimeout(id);
  }, [resetKey]);

  return (
    <section className="slide" data-screen-label="16 Section Transition">
      <Chrome slide={17} total={33} sectionLabel="01 → 02 · TRANSITION" />
      <div className="slide-inner" style={{flexDirection:'column', alignItems:'center', justifyContent:'center', gap:36}}>
        {/* TEXT BLOCK- centered */}
        <div style={{textAlign:'center', maxWidth:1500}}>
          <p className="eyebrow" style={{textAlign:'center'}}>Section 1 of 5- done.</p>
          <h2 className="title" style={{fontSize:84, lineHeight:1.0, marginBottom:24}}>
            This is <span style={{color:'var(--red-3)'}}>the billion-dollar thing.</span>
          </h2>
          <p className="subtitle" style={{margin:'0 auto', maxWidth:1200, fontSize:26, color:'var(--text-2)'}}>
            The rest of tonight is everything we built around it<br/>to make those billion dollars actually do something useful.
          </p>
        </div>

        {/* DIAGRAM- sealed model + API envelope, big and centered as a callback to §1 */}
        <div style={{
          width:'100%', maxWidth:1000,
          aspectRatio: '1100 / 780',
          opacity: pulse ? 0.95 : 0.5,
          transition:'opacity 0.9s ease',
        }}
          dangerouslySetInnerHTML={{__html: window.SystemDiagram({
            size:'full',
            stage: 1,
            highlight: 'envelope',
          })}}/>

        {/* §2 hand-off cue */}
        <div style={{position:'absolute', bottom:56, left:0, right:0, textAlign:'center'}}>
          <div style={{fontFamily:'JetBrains Mono', fontSize:18, color:'var(--red-4)', letterSpacing:'0.3em'}}>
            ↓ SECTION 02 · THE CONTEXT LAYER ↓
          </div>
        </div>
      </div>
    </section>
  );
}

// === Intro slide- duplicate of the wrap-up · Parcel + Ahnaf contact ===
function SlideIntro() {
  return (
    <section className="slide" data-screen-label="01 Intro · Ahnaf">
      <Chrome slide={1} total={33} sectionLabel="INTRO" />
      <div className="slide-inner" style={{flexDirection:'column', justifyContent:'center', alignItems:'center', gap:36}}>
       <div style={{width:'100%', maxWidth:1200, display:'flex', flexDirection:'column', gap:36}}>

        {/* Header */}
        <div style={{display:'flex', flexDirection:'column', gap:12}}>
          <h2 className="title" style={{fontSize:60, lineHeight:1.05, margin:0}}>
            Hi, I'm <span style={{color:'var(--red-3)'}}>Ahnaf</span>
          </h2>
          <p style={{fontSize:22, color:'var(--text-1)', lineHeight:1.45, margin:0}}>
            Building <a href="https://withparcel.ai" style={{color:'var(--sec-2)', textDecoration:'none'}}><strong>@Parcel</strong></a> + leading AI at a small SaaS company. Builder across the stack from LLM magics to product stuff.
          </p>
          <p style={{fontSize:17, color:'var(--text-2)', lineHeight:1.5, margin:0, maxWidth:980}}>
            Tonight: a builder's-eye tour of the modern AI stack behind powerful harnesses. See what's behind the stuff changing the way you work.
          </p>
        </div>

        {/* Two cards- matching treatment */}
        <div style={{display:'flex', flexDirection:'row', gap:28, alignItems:'stretch'}}>

          {/* LinkedIn card */}
          <div style={{
            flex:1,
            display:'flex', flexDirection:'column', gap:22, alignItems:'center',
            padding:32,
            background:'var(--ink-2)',
            border:'1px solid var(--ink-5)',
            borderRadius:10,
          }}>
            <img src="media/ahnaf-linkedin-qr.jpg" alt="Ahnaf Tazwar · LinkedIn QR"
                 style={{width:360, height:320, objectFit:'contain', borderRadius:8, display:'block'}}/>
            <div style={{display:'flex', flexDirection:'column', gap:10, alignItems:'center', textAlign:'center', maxWidth:420}}>
              <h3 style={{
                fontSize:24, lineHeight:1.15, margin:0, fontWeight:700,
                color:'var(--text-0)', letterSpacing:'-0.005em',
              }}>
                Let's connect on <span style={{color:'#0A66C2'}}>LinkedIn</span> <span style={{color:'var(--text-2)'}}>→</span>
              </h3>
              <p style={{margin:0, fontSize:15, color:'var(--text-2)', lineHeight:1.55}}>
                Reach out if anything tonight clicks- super new on there but happy to chat AI, product, or anything in between.
              </p>
            </div>
          </div>

          {/* Parcel card */}
          <div style={{
            flex:1,
            display:'flex', flexDirection:'column', gap:22, alignItems:'center',
            padding:32,
            background:'var(--ink-2)',
            border:'1px solid var(--ink-5)',
            borderRadius:10,
          }}>
            {/* QR mini-card- locked to same 360x320 footprint as LinkedIn QR */}
            <div style={{
              width:360,
              height:320,
              background:'var(--ink-1)',
              border:'1px solid var(--ink-5)',
              borderRadius:8,
              overflow:'hidden',
              display:'flex', flexDirection:'column',
            }}>
              <div style={{
                padding:'18px 16px 12px',
                display:'flex', flexDirection:'column', gap:6, alignItems:'center',
                flexShrink:0,
              }}>
                <img src="media/parcel-logo-white.svg" alt="Parcel"
                     style={{height:26, width:'auto', objectFit:'contain'}}/>
                <span style={{fontSize:13, color:'var(--text-2)', fontWeight:500, letterSpacing:'0.01em'}}>
                  Join the waitlist
                </span>
              </div>
              <div style={{flex:1, display:'flex', justifyContent:'center', alignItems:'center', paddingBottom:16}}>
                <div style={{background:'#fff', padding:10, borderRadius:4, display:'flex'}}>
                  <img src="media/parcel-qr.png" alt="withparcel.ai QR"
                       style={{width:196, height:196, objectFit:'contain', display:'block'}}/>
                </div>
              </div>
            </div>
            <div style={{display:'flex', flexDirection:'column', gap:10, alignItems:'center', textAlign:'center', maxWidth:420}}>
              <h3 style={{
                fontSize:24, lineHeight:1.15, margin:0, fontWeight:700,
                color:'var(--text-0)', letterSpacing:'-0.005em',
              }}>
                Try <span style={{color:'var(--sec-2)'}}>Parcel</span> on your product <span style={{color:'var(--text-2)'}}>→</span>
              </h3>
              <p style={{fontSize:15, color:'var(--text-2)', lineHeight:1.55, margin:0}}>
                If you're building software and have users, <strong style={{color:'var(--sec-2)'}}>Parcel</strong> helps you ship better by understanding what they love and hate.
              </p>
            </div>
          </div>
        </div>
       </div>
      </div>
    </section>
  );
}

Object.assign(window, {
  SlideIntro,
  Slide00, Slide11, Slide12, Slide13, Slide14, Slide15, Slide16, Slide17, Slide18,
  Slide19, Slide110, Slide111, Slide112, Slide1125, Slide113, Slide114, Slide115,
});
