/* global React, window, document, navigator */
const { useState: useStateMd, useEffect: useEffectMd } = React;

/* ============================================================
   Moore /md · curso prático de IA para líderes (trilíngue)
   Fluxo espelhado do formato hands-on (sentir o poder -> construir
   o loop), conteúdo original da Moore, assets Moore/neutros.
   Sem backend: "Pedir ajuda" abre o contato. Estética Moore.
   ============================================================ */

const MD_T = {
  pt: {
    nav_ex: 'Exercícios', nav_help: 'Ajuda', nav_files: 'Arquivos',
    home_eyebrow: 'Curso prático de IA', home_title: 'Reimagine a sua operação',
    home_lead: 'Um curso de IA para líderes e times. Cerca de 6 horas de ponta a ponta, 2 a 3 se você for rápido. A ideia não é ouvir sobre o que a IA faz, é sentir, construindo coisas reais com um agente, com Claude Code e Codex. Comece aqui.',
    home_cta1: 'Estou pronto', home_cta2: 'Ver os exercícios',
    a1k: 'Ato I', a1h: 'Sentir o poder', a1p: 'Um prompt e algo que funciona. Você sai do primeiro exercício com uma coisa no ar e a ficha caindo.',
    a2k: 'Ato II', a2h: 'Construir o loop', a2p: 'Fluxos agênticos com revisão humana. O agente assume a tarefa de ponta a ponta e você aprova o que é crítico.',
    howk: 'Como funciona', howh: 'No seu ritmo', howp: 'Cada exercício é autocontido. Comece no 1.1, pule para o que importa, ou continue de onde parou. Travou?',
    howlink: 'Peça ajuda',
    idx_eyebrow: 'Currículo', idx_a: 'Onze exercícios.', idx_b: 'Dois atos.',
    idx_lead: 'Cerca de seis horas de ponta a ponta, menos se você pular os aprofundamentos. Todo exercício é autocontido: comece no 1.1, pule para o que importa, ou continue de onde parou.',
    all_ex: 'Todos os exercícios', of: 'DE 11', min: 'MIN', before: 'Antes de começar',
    prompt_label: 'Prompt', followup: 'Continuação, mesma conversa', copy: 'Copiar', copied: 'Copiado ✓',
    step_help: 'Preciso de ajuda neste passo →',
    debrief_tag: 'TRAVOU?', debrief_label: 'Debrief, o que deveria ter acontecido',
    faq_tag: 'TRAVOU?', faq_label: 'FAQ deste exercício',
    deeper_tag: 'OPCIONAL', deeper_label: 'Aprofundar',
    interlude_tag: 'REFLITA', why_label: 'A leitura da Moore',
    stuck: 'Travou? Falar com a Moore →', ask: 'Pedir ajuda',
    mark_done: 'Marcar como feito', next_to: 'próximo:', conclude: 'concluir',
    prev: 'Anterior', next: 'Próximo',
    files_title: 'Arquivos do curso', files_lead: 'Os arquivos usados nos exercícios. Clique para baixar e coloque na pasta onde o agente está trabalhando.', download: 'Baixar ↓',
    help_title: 'Pedir ajuda', help_lead: 'Escolha no que você travou e fale direto com a gente.',
    help_go: 'Abrir o chat →',
    help_cards: [
      { h: 'Configuração', p: 'Travou para instalar ou abrir o Claude Code / Codex? Eu te guio passo a passo.', mode: 'setup' },
      { h: 'Exercícios', p: 'Um prompt não fez o que você esperava? Conte o que aconteceu e a gente destrava.', mode: 'exercises' },
      { h: 'Geral', p: 'Qualquer dúvida sobre o curso. É só abrir um chat em branco.', mode: 'general' },
    ],
    chat: {
      setup_h: 'Ajuda de configuração', setup_intro: 'Vamos deixar a sua máquina pronta. Eu te guio na instalação para o seu sistema.',
      os_q: 'Primeiro, escolha o seu sistema', os_mac: 'Estou no Mac', os_mac_sub: 'macOS, Apple Silicon ou Intel', os_win: 'Estou no Windows', os_win_sub: 'Windows 10 ou 11',
      ex_h: 'Ajuda do exercício', ex_intro: 'Travou? Pergunte. Eu mergulho no currículo e te levo passo a passo.', back_ex: 'Voltar ao exercício',
      gen_h: 'Ajuda geral', gen_intro: 'Pergunte qualquer coisa sobre o curso. Sem prompts prontos, é só escrever.',
      try_label: 'Tente uma destas', placeholder: 'Pergunte qualquer coisa…', send: 'Enviar', sending: 'Pensando…',
      disclaimer: 'As saídas podem conter imprecisões. Não cole dados confidenciais ou de clientes.', contact: 'Falar com a Moore',
      ex_chips: ['O que o exercício {n} quer ensinar?', 'Travei no primeiro passo do {n}', 'Me mostra um exemplo de saída do {n}'],
      seed_user: 'Preciso de ajuda com o passo {n}/9: {title}.',
      back_checks: 'Resolvido, voltar aos itens',
    },
    home_link: 'Início',
    foot_disc: 'Use ambientes de teste ou não produtivos. Não suba dados confidenciais, de clientes ou não aprovados. Siga a política de TI e segurança da sua empresa. As saídas podem conter imprecisões.',
    foot_site: 'getmoore.ai', foot_priv: 'Privacidade', foot_terms: 'Termos',
  },
  en: {
    nav_ex: 'Exercises', nav_help: 'Help', nav_files: 'Files',
    home_eyebrow: 'Hands-on AI course', home_title: 'Reimagine your operation',
    home_lead: 'An AI course for leaders and teams. About 6 hours end to end, 2 to 3 if you move fast. The point is not to hear about what AI does, it is to feel it, building real things with an agent, with Claude Code and Codex. Start here.',
    home_cta1: 'I am ready', home_cta2: 'See the exercises',
    a1k: 'Act I', a1h: 'Feel the power', a1p: 'One prompt and something that works. You leave the first exercise with something live and the penny dropping.',
    a2k: 'Act II', a2h: 'Build the loop', a2p: 'Agentic workflows with human review. The agent takes the task end to end and you approve what is critical.',
    howk: 'How it works', howh: 'At your pace', howp: 'Every exercise is self-contained. Start at 1.1, jump to what matters, or pick up where you left off. Stuck?',
    howlink: 'Ask for help',
    idx_eyebrow: 'Curriculum', idx_a: 'Eleven exercises.', idx_b: 'Two acts.',
    idx_lead: 'About six hours end to end, less if you skip the deep dives. Every exercise is self-contained: start at 1.1, jump to what matters, or pick up where you left off.',
    all_ex: 'All exercises', of: 'OF 11', min: 'MIN', before: 'Before we start',
    prompt_label: 'Prompt', followup: 'Follow-up, same conversation', copy: 'Copy', copied: 'Copied ✓',
    step_help: 'I need help with this step →',
    debrief_tag: 'STUCK?', debrief_label: 'Debrief, what should have happened',
    faq_tag: 'STUCK?', faq_label: 'FAQ for this exercise',
    deeper_tag: 'OPTIONAL', deeper_label: 'Go deeper',
    interlude_tag: 'REFLECT', why_label: 'The Moore reading',
    stuck: 'Stuck? Talk to Moore →', ask: 'Ask for help',
    mark_done: 'Mark as done', next_to: 'next:', conclude: 'finish',
    prev: 'Previous', next: 'Next',
    files_title: 'Course files', files_lead: 'The files used in the exercises. Click to download and drop into the folder where the agent is working.', download: 'Download ↓',
    help_title: 'Ask for help', help_lead: 'Pick what you are stuck on and we open the right chat.',
    help_go: 'Open the chat →',
    help_cards: [
      { h: 'Setup', p: 'Stuck installing or opening Claude Code / Codex? I walk you through it step by step.', mode: 'setup' },
      { h: 'Exercises', p: 'A prompt did not do what you expected? Tell me what happened and we unblock it.', mode: 'exercises' },
      { h: 'General', p: 'Any question about the course. Just open a blank chat.', mode: 'general' },
    ],
    chat: {
      setup_h: 'Setup help', setup_intro: 'Let us get your machine ready. I will walk you through the install for your system.',
      os_q: 'First, pick your system', os_mac: 'I am on Mac', os_mac_sub: 'macOS, Apple Silicon or Intel', os_win: 'I am on Windows', os_win_sub: 'Windows 10 or 11',
      ex_h: 'Exercise help', ex_intro: 'Stuck? Ask away. I dig into the curriculum and walk you through it.', back_ex: 'Back to exercise',
      gen_h: 'General help', gen_intro: 'Ask anything about the course. No prefilled prompts, just type.',
      try_label: 'Try one of these', placeholder: 'Ask anything…', send: 'Send', sending: 'Thinking…',
      disclaimer: 'Outputs may contain inaccuracies. Do not paste confidential or customer data.', contact: 'Talk to Moore',
      ex_chips: ['What is exercise {n} trying to teach me?', 'I am stuck on the first step of {n}', 'Show me an example output for {n}'],
      seed_user: 'I need help with step {n}/9: {title}.',
      back_checks: 'I am sorted, back to the checks',
    },
    home_link: 'Home',
    foot_disc: 'Use sandbox or non-production environments. Do not upload confidential, customer, or unapproved data. Follow your organization’s IT and security policy. Outputs may contain inaccuracies.',
    foot_site: 'getmoore.ai', foot_priv: 'Privacy', foot_terms: 'Terms',
  },
  es: {
    nav_ex: 'Ejercicios', nav_help: 'Ayuda', nav_files: 'Archivos',
    home_eyebrow: 'Curso práctico de IA', home_title: 'Reimaginá tu operación',
    home_lead: 'Un curso de IA para líderes y equipos. Cerca de 6 horas de punta a punta, 2 a 3 si vas rápido. La idea no es escuchar sobre lo que hace la IA, es sentirlo, construyendo cosas reales con un agente, con Claude Code y Codex. Empezá acá.',
    home_cta1: 'Estoy listo', home_cta2: 'Ver los ejercicios',
    a1k: 'Acto I', a1h: 'Sentir el poder', a1p: 'Un prompt y algo que funciona. Salís del primer ejercicio con algo en vivo y la ficha cayendo.',
    a2k: 'Acto II', a2h: 'Construir el loop', a2p: 'Flujos agénticos con revisión humana. El agente asume la tarea de punta a punta y vos aprobás lo crítico.',
    howk: 'Cómo funciona', howh: 'A tu ritmo', howp: 'Cada ejercicio es autocontenido. Empezá en el 1.1, saltá a lo que importa, o seguí donde dejaste. ¿Trabado?',
    howlink: 'Pedí ayuda',
    idx_eyebrow: 'Currículum', idx_a: 'Once ejercicios.', idx_b: 'Dos actos.',
    idx_lead: 'Cerca de seis horas de punta a punta, menos si salteás los aprofundamientos. Cada ejercicio es autocontenido: empezá en el 1.1, saltá a lo que importa, o seguí donde dejaste.',
    all_ex: 'Todos los ejercicios', of: 'DE 11', min: 'MIN', before: 'Antes de empezar',
    prompt_label: 'Prompt', followup: 'Continuación, misma conversación', copy: 'Copiar', copied: 'Copiado ✓',
    step_help: 'Necesito ayuda en este paso →',
    debrief_tag: '¿TRABADO?', debrief_label: 'Debrief, qué debería haber pasado',
    faq_tag: '¿TRABADO?', faq_label: 'FAQ de este ejercicio',
    deeper_tag: 'OPCIONAL', deeper_label: 'Profundizar',
    interlude_tag: 'REFLEXIÓN', why_label: 'La lectura de Moore',
    stuck: '¿Trabado? Hablá con Moore →', ask: 'Pedir ayuda',
    mark_done: 'Marcar como hecho', next_to: 'próximo:', conclude: 'concluir',
    prev: 'Anterior', next: 'Próximo',
    files_title: 'Archivos del curso', files_lead: 'Los archivos usados en los ejercicios. Hacé clic para descargar y poné en la carpeta donde el agente está trabajando.', download: 'Descargar ↓',
    help_title: 'Pedir ayuda', help_lead: 'Elegí en qué te trabaste y abrimos el chat correcto.',
    help_go: 'Abrir el chat →',
    help_cards: [
      { h: 'Configuración', p: '¿Trabado para instalar o abrir Claude Code / Codex? Te guío paso a paso.', mode: 'setup' },
      { h: 'Ejercicios', p: '¿Un prompt no hizo lo que esperabas? Contame qué pasó y lo destrabamos.', mode: 'exercises' },
      { h: 'General', p: 'Cualquier duda sobre el curso. Solo abrí un chat en blanco.', mode: 'general' },
    ],
    chat: {
      setup_h: 'Ayuda de configuración', setup_intro: 'Vamos a dejar tu máquina lista. Te guío en la instalación para tu sistema.',
      os_q: 'Primero, elegí tu sistema', os_mac: 'Estoy en Mac', os_mac_sub: 'macOS, Apple Silicon o Intel', os_win: 'Estoy en Windows', os_win_sub: 'Windows 10 u 11',
      ex_h: 'Ayuda del ejercicio', ex_intro: '¿Trabado? Preguntá. Me meto en el currículum y te llevo paso a paso.', back_ex: 'Volver al ejercicio',
      gen_h: 'Ayuda general', gen_intro: 'Preguntá cualquier cosa sobre el curso. Sin prompts armados, solo escribí.',
      try_label: 'Probá una de estas', placeholder: 'Preguntá cualquier cosa…', send: 'Enviar', sending: 'Pensando…',
      disclaimer: 'Las salidas pueden contener imprecisiones. No pegues datos confidenciales o de clientes.', contact: 'Hablá con Moore',
      ex_chips: ['¿Qué quiere enseñar el ejercicio {n}?', 'Estoy trabado en el primer paso del {n}', 'Mostrame un ejemplo de salida del {n}'],
      seed_user: 'Necesito ayuda con el paso {n}/9: {title}.',
      back_checks: 'Listo, volver a los ítems',
    },
    home_link: 'Inicio',
    foot_disc: 'Usá ambientes de prueba o no productivos. No subas datos confidenciales, de clientes o no aprobados. Seguí la política de TI y seguridad de tu empresa. Las salidas pueden contener imprecisiones.',
    foot_site: 'getmoore.ai', foot_priv: 'Privacidad', foot_terms: 'Términos',
  },
};

const MD_ACTS = [
  { n: 1, title: { pt: 'Ato I · Sentir o poder', en: 'Act I · Feel the power', es: 'Acto I · Sentir el poder' }, note: { pt: 'um prompt, um app que funciona', en: 'one prompt, a working app', es: 'un prompt, una app que funciona' } },
  { n: 2, title: { pt: 'Ato II · Construir o loop', en: 'Act II · Build the loop', es: 'Acto II · Construir el loop' }, note: { pt: 'fluxos agênticos com revisão humana', en: 'agentic workflows with human review', es: 'flujos agénticos con revisión humana' } },
];

/* Helper para montar exercício trilíngue de forma compacta */
const MD_COURSE = [
  {
    id: '1.1', act: 1, min: 10,
    i18n: {
      pt: {
        title: 'Snake, cru', sub: 'Crie um jogo, sinta o WOW.',
        intro: 'Esta é a sua primeira rodada com um agente. Mantenha o prompt absurdamente simples e veja o que um bom agente faz com quase nada.',
        before: [
          { h: 'Abra uma sessão nova do Claude Code', p: 'Sempre que dissermos "abra uma sessão nova", é este o botão. Use uma máquina de trabalho, em ambiente de teste.' },
          { h: 'Crie uma pasta vazia e aponte o agente para ela', p: 'Crie uma pasta nova (ex.: snake) no Desktop e selecione ela no seletor de pasta do agente. A pasta escolhida é tudo o que o agente enxerga. Confirme com o prompt abaixo: a resposta deve dizer que a pasta está vazia.' },
        ],
        steps: [
          { h: 'Confira que você está no lugar certo', help: false, prompts: ['Que arquivos existem nesta pasta?'] },
          { h: 'Passo 1 · O prompt simples', help: true, p: 'Digite isto. Nada além disso. Observe o agente criar os arquivos sozinho e te dizer como abrir.', prompts: ['Crie um jogo da cobrinha em um único arquivo HTML. Quando terminar, me diga como abrir no navegador.'] },
        ],
        debrief: ['O agente decidiu a estrutura, escreveu o código e te explicou como usar.', 'Você descreveu o resultado, não os passos. A parte difícil nunca foi essa.'],
        faq: ['Não apareceu o seletor de pasta? Ele fica logo acima de onde você digita. Se o agente caiu na sua pasta pessoal, feche e reabra apontando para a pasta vazia.'],
        deeper: ['Peça uma variação: "adicione um placar e aumente a velocidade a cada 5 pontos". Veja como ele itera.'],
        why: 'Esse é o degrau "usar": IA como ferramenta direta. O resto do curso é transformar esse impulso em algo repetível e confiável.',
      },
      en: {
        title: 'Snake, raw', sub: 'Build a game, feel the WOW.',
        intro: 'This is your first run with an agent. Keep the prompt absurdly simple and watch what a good agent does with almost nothing.',
        before: [
          { h: 'Open a new Claude Code session', p: 'Whenever we say "open a new session", this is the button. Use a work machine, in a sandbox.' },
          { h: 'Create an empty folder and point the agent at it', p: 'Create a new folder (e.g. snake) on your Desktop and select it in the agent’s folder picker. The folder you pick is everything the agent can see. Confirm with the prompt below: the answer should say the folder is empty.' },
        ],
        steps: [
          { h: 'Check you are in the right place', help: false, prompts: ['What files are in this folder?'] },
          { h: 'Step 1 · The simple prompt', help: true, p: 'Type this. Nothing else. Watch the agent create the files itself and tell you how to open it.', prompts: ['Create a snake game in a single HTML file. When done, tell me how to open it in the browser.'] },
        ],
        debrief: ['The agent chose the structure, wrote the code and told you how to use it.', 'You described the outcome, not the steps. That was never the hard part.'],
        faq: ['No folder picker? It is just above where you type. If the agent landed in your home folder, quit and reopen pointing at the empty folder.'],
        deeper: ['Ask for a variation: "add a score and speed up every 5 points". See how it iterates.'],
        why: 'This is the "use" rung: AI as a direct tool. The rest of the course turns that spark into something repeatable and reliable.',
      },
      es: {
        title: 'Snake, crudo', sub: 'Creá un juego, sentí el WOW.',
        intro: 'Esta es tu primera corrida con un agente. Mantené el prompt absurdamente simple y mirá lo que un buen agente hace con casi nada.',
        before: [
          { h: 'Abrí una sesión nueva de Claude Code', p: 'Cada vez que digamos "abrí una sesión nueva", es este botón. Usá una máquina de trabajo, en ambiente de prueba.' },
          { h: 'Creá una carpeta vacía y apuntá el agente a ella', p: 'Creá una carpeta nueva (ej.: snake) en el Escritorio y seleccionala en el selector de carpeta del agente. La carpeta que elegís es todo lo que el agente ve. Confirmá con el prompt de abajo: la respuesta debería decir que la carpeta está vacía.' },
        ],
        steps: [
          { h: 'Verificá que estás en el lugar correcto', help: false, prompts: ['¿Qué archivos hay en esta carpeta?'] },
          { h: 'Paso 1 · El prompt simple', help: true, p: 'Escribí esto. Nada más. Mirá al agente crear los archivos solo y decirte cómo abrirlo.', prompts: ['Creá un juego de la viborita en un único archivo HTML. Cuando termines, decime cómo abrirlo en el navegador.'] },
        ],
        debrief: ['El agente decidió la estructura, escribió el código y te explicó cómo usarlo.', 'Vos describiste el resultado, no los pasos. Esa nunca fue la parte difícil.'],
        faq: ['¿No aparece el selector de carpeta? Está justo arriba de donde escribís. Si el agente cayó en tu carpeta personal, cerralo y reabrilo apuntando a la carpeta vacía.'],
        deeper: ['Pedí una variación: "agregá un marcador y aumentá la velocidad cada 5 puntos". Mirá cómo itera.'],
        why: 'Este es el escalón "usar": IA como herramienta directa. El resto del curso convierte ese impulso en algo repetible y confiable.',
      },
    },
  },
  {
    id: '1.2', act: 1, min: 15,
    i18n: {
      pt: {
        title: 'Snake, com contexto', sub: 'O mesmo prompt, agora com contexto.',
        intro: 'O 1.1 deu WOW a partir de uma folha em branco. Isso é ótimo de gancho, mas não é como se faz trabalho de verdade. Agora você adiciona o que é um briefing: tema, público, restrições. Ainda uma pergunta, resultado bem diferente.',
        steps: [
          { h: 'Passo 1 · Sessão nova, mesmo pedido, agora com spec', help: true, p: 'Abra uma sessão nova e rode o prompt abaixo. Mesmo modelo, mesma forma de pedido. A única coisa que mudou é a spec ao lado.', prompts: ['Crie um jogo da cobrinha em HTML com:\n- Pelo menos três fases\n- Uma tela de onboarding\n- Uma música no menu principal\nPublique no Vercel e me dê a URL ao vivo.\n(Use o Vercel CLI, já instalado, eu tenho conta no Vercel.)'] },
        ],
        debrief: ['Compare com o que o 1.1 produziu. Repare quanto mais de você está no resultado, e quão pouco veio do prompt em si.'],
        faq: ['Sem conta ou CLI do Vercel? Peça ao agente para só rodar localmente e te dizer como abrir.'],
        deeper: ['Troque o tema por algo do seu setor e veja o agente reaproveitar a mesma estrutura.'],
        interlude: { title: 'Interlúdio A · O que acabou de acontecer', body: ['Contexto vence o prompt. O segredo não é a frase perfeita, é o material certo ao lado dela.'] },
        why: 'Quase todo projeto de IA que falha, falha por aqui: o agente não tinha o contexto que só a sua operação tem.',
      },
      en: {
        title: 'Snake, with context', sub: 'Same prompt, now with context.',
        intro: '1.1 gave you WOW from a blank sheet. Great as a hook, not how real work happens. Now you add what a brief looks like: theme, audience, constraints. Still one question, very different output.',
        steps: [
          { h: 'Step 1 · New session, same ask, now with a spec', help: true, p: 'Open a new session and run the prompt below. Same model, same shape of ask. The only thing that changed is the spec next to it.', prompts: ['Create an HTML snake game with:\n- At least three levels\n- An onboarding screen\n- A theme song on the main menu\nDeploy it to Vercel and give me the live URL.\n(Use the Vercel CLI, already installed, I have a Vercel account.)'] },
        ],
        debrief: ['Compare it to what 1.1 produced. Notice how much more of you is in the result, and how little came from the prompt itself.'],
        faq: ['No Vercel account or CLI? Ask the agent to just run it locally and tell you how to open it.'],
        deeper: ['Swap the theme for something from your industry and watch the agent reuse the same structure.'],
        interlude: { title: 'Interlude A · What just happened', body: ['Context beats the prompt. The secret is not the perfect sentence, it is the right material next to it.'] },
        why: 'Almost every AI project that fails, fails here: the agent did not have the context only your operation has.',
      },
      es: {
        title: 'Snake, con contexto', sub: 'El mismo prompt, ahora con contexto.',
        intro: 'El 1.1 dio WOW desde una hoja en blanco. Buenísimo como gancho, no es cómo se hace trabajo de verdad. Ahora agregás lo que es un brief: tema, público, restricciones. Sigue siendo una pregunta, resultado muy distinto.',
        steps: [
          { h: 'Paso 1 · Sesión nueva, mismo pedido, ahora con spec', help: true, p: 'Abrí una sesión nueva y corré el prompt de abajo. Mismo modelo, misma forma de pedido. Lo único que cambió es la spec al lado.', prompts: ['Creá un juego de la viborita en HTML con:\n- Al menos tres niveles\n- Una pantalla de onboarding\n- Una música en el menú principal\nPublicá en Vercel y dame la URL en vivo.\n(Usá el Vercel CLI, ya instalado, tengo cuenta en Vercel.)'] },
        ],
        debrief: ['Compará con lo que produjo el 1.1. Fijate cuánto más de vos hay en el resultado, y qué poco vino del prompt mismo.'],
        faq: ['¿Sin cuenta o CLI de Vercel? Pedile al agente que solo lo corra localmente y te diga cómo abrirlo.'],
        deeper: ['Cambiá el tema por algo de tu sector y mirá al agente reusar la misma estructura.'],
        interlude: { title: 'Interludio A · Qué acaba de pasar', body: ['El contexto le gana al prompt. El secreto no es la frase perfecta, es el material correcto al lado.'] },
        why: 'Casi todo proyecto de IA que falla, falla acá: el agente no tenía el contexto que solo tu operación tiene.',
      },
    },
  },
  {
    id: '2.1', act: 1, min: 30,
    i18n: {
      pt: {
        title: 'Ensine o agente', sub: 'Ensine algo novo ao seu agente.',
        intro: 'Em vez de explicar a mesma coisa toda vez, você ensina o agente uma vez e reusa para sempre. Aqui nasce a ideia de skill.',
        before: [{ h: 'Baixe o contexto', p: 'Em Arquivos, baixe moore-overview.md e arraste para a janela do chat do agente.' }],
        steps: [
          { h: 'Passo 1 · Gere uma apresentação', help: true, prompts: ['Crie uma apresentação sobre moore-overview.md (só 4 slides). Use pptxgenjs para gerar os slides.'] },
          { h: 'Passo 2 · Dê a marca (mesma conversa)', help: false, prompts: ['Aplique a identidade da marca: fundo cream, texto quase preto, acento graphite, tipografia sem serifa, muito espaço em branco. Assuma as cores, fontes e o clima.'] },
          { h: 'Passo 3 · Vire isso uma skill (mesma conversa)', help: false, p: 'Depois, apague a apresentação da pasta e rode o primeiro prompt de novo. Agora ele "one-shota" no estilo certo. Você acabou de ensinar algo ao agente.', prompts: ['Transforme tudo o que você aprendeu numa skill chamada create-moore-presentation. Garanta que ela seja sempre chamada ao criar uma apresentação, para termos uma marca uniforme.'] },
        ],
        debrief: ['Saída esperada: skill criada em ~/.claude/skills/create-moore-presentation/ e aparecendo na lista de skills, com um template que builda.'],
        faq: ['Sem internet para baixar o arquivo? Peça ao agente para criar um moore-overview.md curto a partir do que ele sabe e siga.'],
        deeper: ['Veja o starter create-moore-presentation.md em Arquivos e compare com o que o agente gerou.'],
        why: 'Esse é o pulo do gato da frente "de colaborador a super-colaborador": a pessoa codifica o conhecimento uma vez, e o agente aplica em escala.',
      },
      en: {
        title: 'Teach the agent', sub: 'Teach your agent something new.',
        intro: 'Instead of explaining the same thing every time, you teach the agent once and reuse forever. This is where the idea of a skill is born.',
        before: [{ h: 'Download the context', p: 'In Files, download moore-overview.md and drag it into the agent’s chat window.' }],
        steps: [
          { h: 'Step 1 · Generate a presentation', help: true, prompts: ['Create a presentation about moore-overview.md (just 4 slides). Use pptxgenjs to generate the slides.'] },
          { h: 'Step 2 · Give it the brand (same conversation)', help: false, prompts: ['Apply the brand identity: cream background, near-black text, graphite accent, sans-serif type, lots of white space. Take over the colors, fonts and vibe.'] },
          { h: 'Step 3 · Turn it into a skill (same conversation)', help: false, p: 'Then delete the presentation from the folder and run the first prompt again. Now it one-shots in the right style. You just taught the agent something.', prompts: ['Turn everything you learned into a skill called create-moore-presentation. Make sure it is always called when creating a presentation, so we have a uniform brand.'] },
        ],
        debrief: ['Expected output: a skill created at ~/.claude/skills/create-moore-presentation/ and appearing in the skills list, with a template that builds.'],
        faq: ['No internet to download the file? Ask the agent to create a short moore-overview.md from what it knows and continue.'],
        deeper: ['Check the create-moore-presentation.md starter in Files and compare with what the agent generated.'],
        why: 'This is the heart of "from collaborator to super-collaborator": you encode the knowledge once, and the agent applies it at scale.',
      },
      es: {
        title: 'Enseñá al agente', sub: 'Enseñale algo nuevo a tu agente.',
        intro: 'En vez de explicar lo mismo cada vez, le enseñás al agente una vez y reusás para siempre. Acá nace la idea de skill.',
        before: [{ h: 'Descargá el contexto', p: 'En Archivos, descargá moore-overview.md y arrastralo a la ventana de chat del agente.' }],
        steps: [
          { h: 'Paso 1 · Generá una presentación', help: true, prompts: ['Creá una presentación sobre moore-overview.md (solo 4 slides). Usá pptxgenjs para generar los slides.'] },
          { h: 'Paso 2 · Dale la marca (misma conversación)', help: false, prompts: ['Aplicá la identidad de marca: fondo cream, texto casi negro, acento graphite, tipografía sin serif, mucho espacio en blanco. Tomá los colores, fuentes y el clima.'] },
          { h: 'Paso 3 · Convertilo en una skill (misma conversación)', help: false, p: 'Después borrá la presentación de la carpeta y corré el primer prompt de nuevo. Ahora lo "one-shotea" en el estilo correcto. Acabás de enseñarle algo al agente.', prompts: ['Convertí todo lo que aprendiste en una skill llamada create-moore-presentation. Asegurate de que se llame siempre al crear una presentación, para tener una marca uniforme.'] },
        ],
        debrief: ['Salida esperada: una skill creada en ~/.claude/skills/create-moore-presentation/ y apareciendo en la lista de skills, con un template que buildea.'],
        faq: ['¿Sin internet para descargar el archivo? Pedile al agente que cree un moore-overview.md corto con lo que sabe y seguí.'],
        deeper: ['Mirá el starter create-moore-presentation.md en Archivos y comparalo con lo que generó el agente.'],
        why: 'Este es el corazón de "de colaborador a super-colaborador": codificás el conocimiento una vez, y el agente lo aplica en escala.',
      },
    },
  },
  {
    id: '2.2', act: 1, min: 25,
    i18n: {
      pt: {
        title: 'Explique a skill de volta', sub: 'Aprenda algo novo, do jeito fácil.',
        intro: 'Experimente como ficou fácil aprender algo novo. Aprender deixou de ser sobre o material, e passou a ser sobre saber o que você precisa aprender.',
        steps: [
          { h: 'Passo 1 · Peça para explicarem para você', help: false, prompts: ['Explique o conceito de "skill.md", visualize, sou de negócios e não de tecnologia, use palavras simples.', 'Agora me explique skills em geral, além do arquivo .md.'] },
          { h: 'Passo 2 · Crie o seu person.md', help: false, p: 'Faça um arquivo person.md de cinco linhas dizendo quem você é, o que você resolve no trabalho e como gosta de ser tratado. Salve perto de onde está trabalhando. Depois abra uma sessão nova.', prompts: ['Leia person.md, me explique skill.md e visualize.'] },
        ],
        debrief: ['Na segunda vez, o agente já fala com você, não com um usuário genérico. Esse é o efeito do person.md.'],
        faq: ['Não sabe o que pôr no person.md? Peça ao agente para te entrevistar em 5 perguntas e gerar o arquivo.'],
        deeper: ['Guarde o person.md, ele volta nos próximos exercícios.'],
        interlude: { title: 'Interlúdio B · Skills como memória durável', body: ['Skill e person.md são memória: o que o agente sabe sobre o mundo e sobre você, que fica entre as sessões.'] },
        why: 'O gargalo deixou de ser o conhecimento técnico, e passou a ser saber qual pergunta fazer.',
      },
      en: {
        title: 'Explain the skill back', sub: 'Learn something new, the easy way.',
        intro: 'Feel how easy it became to learn something new. Learning stopped being about the material and became about knowing what you need to learn.',
        steps: [
          { h: 'Step 1 · Ask it to explain to you', help: false, prompts: ['Explain the concept of "skill.md", visualize it, I am in business not in tech, keep the words simple.', 'Now also explain skills in general, beyond the .md file.'] },
          { h: 'Step 2 · Create your person.md', help: false, p: 'Make a five-line person.md saying who you are, what you solve at work and how you like to be spoken to. Save it next to where you are working. Then open a new session.', prompts: ['Read person.md, explain skill.md to me and visualize it.'] },
        ],
        debrief: ['The second time, the agent talks to you, not a generic user. That is the person.md effect.'],
        faq: ['Not sure what to put in person.md? Ask the agent to interview you in 5 questions and generate the file.'],
        deeper: ['Keep your person.md, it comes back in the next exercises.'],
        interlude: { title: 'Interlude B · Skills as durable memory', body: ['A skill and person.md are memory: what the agent knows about the world and about you, that persists between sessions.'] },
        why: 'The bottleneck stopped being technical knowledge and became knowing which question to ask.',
      },
      es: {
        title: 'Explicá la skill de vuelta', sub: 'Aprendé algo nuevo, de la forma fácil.',
        intro: 'Sentí lo fácil que se volvió aprender algo nuevo. Aprender dejó de ser sobre el material y pasó a ser sobre saber qué necesitás aprender.',
        steps: [
          { h: 'Paso 1 · Pedile que te explique', help: false, prompts: ['Explicá el concepto de "skill.md", visualizalo, soy de negocios y no de tecnología, usá palabras simples.', 'Ahora explicame skills en general, más allá del archivo .md.'] },
          { h: 'Paso 2 · Creá tu person.md', help: false, p: 'Hacé un person.md de cinco líneas diciendo quién sos, qué resolvés en el trabajo y cómo te gusta que te hablen. Guardalo cerca de donde trabajás. Después abrí una sesión nueva.', prompts: ['Leé person.md, explicame skill.md y visualizalo.'] },
        ],
        debrief: ['La segunda vez, el agente te habla a vos, no a un usuario genérico. Ese es el efecto del person.md.'],
        faq: ['¿No sabés qué poner en person.md? Pedile al agente que te entreviste en 5 preguntas y genere el archivo.'],
        deeper: ['Guardá tu person.md, vuelve en los próximos ejercicios.'],
        interlude: { title: 'Interludio B · Skills como memoria durable', body: ['Una skill y person.md son memoria: lo que el agente sabe del mundo y de vos, que persiste entre sesiones.'] },
        why: 'El cuello de botella dejó de ser el conocimiento técnico y pasó a ser saber qué pregunta hacer.',
      },
    },
  },
  {
    id: '2.3', act: 1, min: 30,
    i18n: {
      pt: {
        title: 'Vídeo de intro com Remotion', sub: 'Aprenda algo novo, com um vídeo.',
        intro: 'Experimente como é fácil aprender algo novo, agora gerando um VÍDEO. O agente usa Remotion para renderizar.',
        steps: [{ h: 'Passo 1 · Gere o vídeo', help: true, p: 'Troque <nome> pelo seu nome (você já tem <nome>.md do exercício 2.2). Veja uma intro de 4 cenas sobre você aparecer com um prompt.', prompts: ['Crie um vídeo apresentando <nome>.md usando Remotion. Máximo de 4 cenas.'] }],
        debrief: ['O agente instalou o Remotion, montou as cenas e renderizou. Você só descreveu o resultado.'],
        faq: ['Renderização travando? Peça ao agente para reduzir para 2 cenas e resolução menor.'],
        deeper: ['Peça uma trilha e uma transição entre cenas.'],
        why: 'O mesmo padrão de sempre: você dirige, o agente produz. Só que agora em vídeo.',
      },
      en: {
        title: 'Remotion intro video', sub: 'Learn something new, with a video.',
        intro: 'Feel how easy it is to learn something new, now by generating a VIDEO. The agent uses Remotion to render it.',
        steps: [{ h: 'Step 1 · Generate the video', help: true, p: 'Replace <name> with your name (you already have <name>.md from 2.2). Watch a 4-scene intro about you appear from one prompt.', prompts: ['Create a video introducing <name>.md using Remotion. Maximum 4 scenes.'] }],
        debrief: ['The agent installed Remotion, built the scenes and rendered it. You only described the outcome.'],
        faq: ['Rendering stalling? Ask the agent to cut to 2 scenes and a smaller resolution.'],
        deeper: ['Ask for a soundtrack and a transition between scenes.'],
        why: 'Same pattern as always: you direct, the agent produces. Now in video.',
      },
      es: {
        title: 'Video de intro con Remotion', sub: 'Aprendé algo nuevo, con un video.',
        intro: 'Sentí lo fácil que es aprender algo nuevo, ahora generando un VIDEO. El agente usa Remotion para renderizarlo.',
        steps: [{ h: 'Paso 1 · Generá el video', help: true, p: 'Cambiá <nombre> por tu nombre (ya tenés <nombre>.md del 2.2). Mirá una intro de 4 escenas sobre vos aparecer desde un prompt.', prompts: ['Creá un video presentando <nombre>.md usando Remotion. Máximo 4 escenas.'] }],
        debrief: ['El agente instaló Remotion, armó las escenas y renderizó. Vos solo describiste el resultado.'],
        faq: ['¿La renderización se traba? Pedile al agente que baje a 2 escenas y menor resolución.'],
        deeper: ['Pedí una música y una transición entre escenas.'],
        why: 'El mismo patrón de siempre: vos dirigís, el agente produce. Ahora en video.',
      },
    },
  },
  {
    id: '2.4', act: 1, min: 20,
    i18n: {
      pt: {
        title: 'E-mail no seu tom de voz', sub: 'Escreva no seu próprio tom.',
        intro: 'Todo mundo conhece o "isso parece IA". Dá para ver isso como defeito ou resolver dando ao agente a sua voz. Essa voz mora no seu <nome>.md.',
        steps: [{ h: 'Passo 1 · Peça o e-mail na sua voz', help: false, p: 'Depois pergunte a si mesmo: esse e-mail é algo que você escreveria?', prompts: ['Escreva um e-mail no meu tom de voz usando <nome>.md. A mensagem que quero passar: a forma como as empresas se organizam está prestes a mudar. Não aos poucos, de forma estrutural. Saímos de organogramas hierárquicos cheios de gargalos de aprovação rumo a organizações orientadas a processo, onde fluxos agênticos rodam em loops com checkpoints humanos. Me mostre o resultado aqui, não crie um rascunho de verdade.'] }],
        debrief: ['Se soou como você, o <nome>.md está bom. Se soou genérico, falta voz no arquivo.'],
        faq: ['Soou robótico? Adicione ao <nome>.md 3 frases suas reais para o agente calibrar.'],
        deeper: ['Crie uma skill /email que sempre usa o seu tom.'],
        why: 'O agente adianta o rascunho, você revisa e fecha. A pessoa fecha, o agente adianta.',
      },
      en: {
        title: 'Tone-of-voice email', sub: 'Write in your own voice.',
        intro: 'Everyone knows the "this sounds like AI". You can see it as a fault or fix it by giving the agent your voice. That voice lives in your <name>.md.',
        steps: [{ h: 'Step 1 · Ask for the email in your voice', help: false, p: 'Then ask yourself: is this email something you would write?', prompts: ['Draft an email in my tone of voice using <name>.md. The message I want to convey: the way companies are organized is about to change. Not incrementally, structurally. We are moving from hierarchical org charts full of approval bottlenecks toward process-oriented organizations, where agentic workflows run in loops with human checkpoints. Show me the result here, do not create a real draft.'] }],
        debrief: ['If it sounded like you, your <name>.md is good. If it sounded generic, the file lacks voice.'],
        faq: ['Sounded robotic? Add 3 real sentences of yours to <name>.md for the agent to calibrate.'],
        deeper: ['Create an /email skill that always uses your tone.'],
        why: 'The agent moves the draft forward, you review and close. The person closes, the agent gets you started.',
      },
      es: {
        title: 'Email en tu tono de voz', sub: 'Escribí en tu propia voz.',
        intro: 'Todos conocen el "esto parece IA". Lo podés ver como un defecto o resolverlo dándole al agente tu voz. Esa voz vive en tu <nombre>.md.',
        steps: [{ h: 'Paso 1 · Pedí el email en tu voz', help: false, p: 'Después preguntate: ¿este email es algo que vos escribirías?', prompts: ['Redactá un email en mi tono de voz usando <nombre>.md. El mensaje que quiero transmitir: la forma en que las empresas se organizan está por cambiar. No de a poco, de forma estructural. Pasamos de organigramas jerárquicos llenos de cuellos de botella de aprobación hacia organizaciones orientadas a proceso, donde flujos agénticos corren en loops con checkpoints humanos. Mostrame el resultado acá, no crees un borrador real.'] }],
        debrief: ['Si sonó como vos, tu <nombre>.md está bien. Si sonó genérico, al archivo le falta voz.'],
        faq: ['¿Sonó robótico? Agregá 3 frases reales tuyas a <nombre>.md para que el agente calibre.'],
        deeper: ['Creá una skill /email que siempre use tu tono.'],
        why: 'El agente adelanta el borrador, vos revisás y cerrás. La persona cierra, el agente adelanta.',
      },
    },
  },
  {
    id: '2.5', act: 1, min: 25,
    i18n: {
      pt: {
        title: 'Comando /check-mail', sub: 'Crie um comando a partir do seu fluxo.',
        intro: 'Quando algo vira rotina, você não quer reescrever o prompt toda vez. Vamos transformar um fluxo de checar e-mail em um comando de uma palavra.',
        before: [{ h: 'Conecte calendário e/ou e-mail', p: 'Conectores são pontes que deixam o agente ler o seu calendário ou caixa de entrada. Em configurações do Claude Code, conecte o Google e dê só os escopos com que você se sente confortável. Dá para revogar quando quiser.' }],
        steps: [
          { h: 'Passo 1 · Cheque seu e-mail', help: false, p: 'Depois ajuste: defina o que é importante para você, o que não é, e como quer o resumo. Se quiser, discuta com o agente o que ele acha melhor.', prompts: ['Cheque as últimas 24h do meu e-mail.'] },
          { h: 'Passo 2 · Vire um comando', help: false, p: 'Quando estiver feliz com o resumo, aplique a mágica.', prompts: ['Transforme o fluxo acima em um comando único: /check-mail. Salve em ~/.claude/commands/. Ele deve executar a checagem de uma vez, do jeito que descrevi.'] },
        ],
        debrief: ['O que era um prompt comprido virou um comando de uma palavra, que o time todo pode usar.'],
        faq: ['Não quer conectar e-mail? Faça o mesmo com um arquivo de texto colado: o aprendizado é o comando.'],
        deeper: ['Crie um /standup que resume calendário do dia e e-mails importantes juntos.'],
        why: 'Aqui você cruza do "usar" para o "automatizar": o fluxo não depende mais de você lembrar o prompt certo.',
      },
      en: {
        title: '/check-mail slash command', sub: 'Make a command from your workflow.',
        intro: 'When something becomes routine, you do not want to rewrite the prompt every time. Let us turn a check-your-email flow into a one-word command.',
        before: [{ h: 'Connect calendar and/or mail', p: 'Connectors are bridges that let the agent read your calendar or inbox. In Claude Code settings, connect Google and grant only the scopes you are comfortable with. You can revoke anytime.' }],
        steps: [
          { h: 'Step 1 · Check your email', help: false, p: 'Then tune it: define what is important to you, what is not, and how you want the summary. If you like, discuss with the agent what it thinks is best.', prompts: ['Check the last 24h of my email.'] },
          { h: 'Step 2 · Turn it into a command', help: false, p: 'When you are happy with the summary, apply the magic.', prompts: ['Turn the workflow above into a single command: /check-mail. Save it in ~/.claude/commands/. It should run the check in one go, the way I described.'] },
        ],
        debrief: ['What was a long prompt became a one-word command the whole team can use.'],
        faq: ['Do not want to connect email? Do the same with a pasted text file: the lesson is the command.'],
        deeper: ['Create a /standup that summarizes today’s calendar and important emails together.'],
        why: 'Here you cross from "use" to "automate": the flow no longer depends on you remembering the right prompt.',
      },
      es: {
        title: 'Comando /check-mail', sub: 'Hacé un comando a partir de tu flujo.',
        intro: 'Cuando algo se vuelve rutina, no querés reescribir el prompt cada vez. Vamos a convertir un flujo de revisar el mail en un comando de una palabra.',
        before: [{ h: 'Conectá calendario y/o mail', p: 'Los conectores son puentes que dejan al agente leer tu calendario o bandeja. En configuración de Claude Code, conectá Google y dale solo los permisos con los que estás cómodo. Podés revocar cuando quieras.' }],
        steps: [
          { h: 'Paso 1 · Revisá tu mail', help: false, p: 'Después ajustá: definí qué es importante para vos, qué no, y cómo querés el resumen. Si querés, discutí con el agente qué cree mejor.', prompts: ['Revisá las últimas 24h de mi mail.'] },
          { h: 'Paso 2 · Convertilo en un comando', help: false, p: 'Cuando estés conforme con el resumen, aplicá la magia.', prompts: ['Convertí el flujo de arriba en un único comando: /check-mail. Guardalo en ~/.claude/commands/. Debe ejecutar la revisión de una sola vez, como lo describí.'] },
        ],
        debrief: ['Lo que era un prompt largo se volvió un comando de una palabra que todo el equipo puede usar.'],
        faq: ['¿No querés conectar el mail? Hacé lo mismo con un archivo de texto pegado: la lección es el comando.'],
        deeper: ['Creá un /standup que resuma el calendario del día y los mails importantes juntos.'],
        why: 'Acá cruzás de "usar" a "automatizar": el flujo ya no depende de que recuerdes el prompt correcto.',
      },
    },
  },
  {
    id: '3.1', act: 1, min: 45,
    i18n: {
      pt: {
        title: 'Ver, criticar, iterar, publicar', sub: 'O loop profissional: iterar olhando.',
        intro: 'O 1.1 deu o WOW. O 1.2 mostrou que contexto vence o prompt. Agora vamos um nível além: deixe o agente ver o que construiu, criticar a própria saída e iterar. É o que separa o amador do profissional.',
        before: [{ h: 'Escolha UM artefato', p: 'A) Um jogo que simula algo do seu negócio. B) Um dashboard do seu domínio: baixe sample-ecommerce.csv em Arquivos (ou use dado seu), com gráficos e filtros. Algo que poderia viver na sua empresa na segunda-feira.' }],
        steps: [
          { h: 'Passo 1 · Comece junto com o agente', help: true, prompts: ['Leia <nome>.md. Quero fazer __________ usando __________. Me faça algumas perguntas para construirmos isso juntos. O objetivo é algo que mostre o poder da IA e que eu possa compartilhar com colegas via Vercel. A reação deles tem que ser "nossa, você fez isso?".'] },
          { h: 'Passo 2 · Em loop: veja e critique', help: false, p: 'Faça isto pelo menos duas vezes. Repare como você digita menos e muda mais.', prompts: ['Abra e examine o que você criou. Reflita sobre a própria criação e proponha três melhorias concretas.', 'Olhe o botão, está pequeno demais para clicar. Conserte.'] },
          { h: 'Passo 3 · Publique', help: false, prompts: ['Quando estiver bom, publique no Vercel e me dê a URL.'] },
        ],
        debrief: ['A qualidade veio da terceira iteração, não da primeira. Seu trabalho mudou de produzir para dirigir.'],
        faq: ['O agente não "vê" o resultado? Peça para ele abrir, tirar print e analisar o que aparece.'],
        deeper: ['Aprenda linguagem de design: peça ao agente referências e veja o produto melhorar.'],
        why: 'Quem se dá bem com IA não é quem escreve o prompt perfeito, é quem itera rápido e sabe dizer o que está errado.',
      },
      en: {
        title: 'See, critique, iterate, ship', sub: 'The professional loop: iterate by seeing.',
        intro: '1.1 gave the WOW. 1.2 showed context beats the prompt. Now one level further: let the agent see what it built, critique its own output and iterate. This is what separates amateur from professional use.',
        before: [{ h: 'Pick ONE artefact', p: 'A) A game that simulates something from your business. B) A dashboard for your domain: download sample-ecommerce.csv in Files (or use your own data), with charts and filters. Something that could live in your company on Monday.' }],
        steps: [
          { h: 'Step 1 · Start together with the agent', help: true, prompts: ['Read <name>.md. I want to build __________ using __________. Ask me a few questions so we build this together. The goal is something that shows the power of AI and that I can share with peers via Vercel. Their reaction must be "wow, did you build this?".'] },
          { h: 'Step 2 · In a loop: see and critique', help: false, p: 'Do this at least twice. Notice how much less you type and how much more changes.', prompts: ['Open and examine what you built. Reflect on your own creation and propose three concrete improvements.', 'Look at the button, it is too small to click. Fix it.'] },
          { h: 'Step 3 · Ship it', help: false, prompts: ['When it is good, deploy it to Vercel and give me the URL.'] },
        ],
        debrief: ['Quality came from the third iteration, not the first. Your job shifted from producing to directing.'],
        faq: ['The agent does not "see" the result? Ask it to open, screenshot and analyze what appears.'],
        deeper: ['Learn design language: ask the agent for references and watch the product improve.'],
        why: 'Those who do well with AI are not the ones who write the perfect prompt, but the ones who iterate fast and can say what is wrong.',
      },
      es: {
        title: 'Ver, criticar, iterar, publicar', sub: 'El loop profesional: iterar mirando.',
        intro: 'El 1.1 dio el WOW. El 1.2 mostró que el contexto le gana al prompt. Ahora un nivel más: dejá que el agente vea lo que construyó, critique su propia salida e itere. Es lo que separa al amateur del profesional.',
        before: [{ h: 'Elegí UN artefacto', p: 'A) Un juego que simula algo de tu negocio. B) Un dashboard de tu dominio: descargá sample-ecommerce.csv en Archivos (o usá dato tuyo), con gráficos y filtros. Algo que podría vivir en tu empresa el lunes.' }],
        steps: [
          { h: 'Paso 1 · Empezá junto con el agente', help: true, prompts: ['Leé <nombre>.md. Quiero construir __________ usando __________. Haceme algunas preguntas para construir esto juntos. El objetivo es algo que muestre el poder de la IA y que pueda compartir con colegas vía Vercel. Su reacción tiene que ser "guau, ¿esto lo hiciste vos?".'] },
          { h: 'Paso 2 · En loop: ver y criticar', help: false, p: 'Hacé esto al menos dos veces. Fijate cuánto menos escribís y cuánto más cambia.', prompts: ['Abrí y examiná lo que construiste. Reflexioná sobre tu propia creación y propone tres mejoras concretas.', 'Mirá el botón, es muy chico para hacer clic. Arreglalo.'] },
          { h: 'Paso 3 · Publicá', help: false, prompts: ['Cuando esté bueno, publicá en Vercel y dame la URL.'] },
        ],
        debrief: ['La calidad vino de la tercera iteración, no de la primera. Tu trabajo pasó de producir a dirigir.'],
        faq: ['¿El agente no "ve" el resultado? Pedile que lo abra, saque captura y analice lo que aparece.'],
        deeper: ['Aprendé lenguaje de diseño: pedile referencias al agente y mirá el producto mejorar.'],
        why: 'Los que andan bien con IA no son los que escriben el prompt perfecto, son los que iteran rápido y saben decir qué está mal.',
      },
    },
  },
  {
    id: '4', act: 2, min: 30,
    i18n: {
      pt: {
        title: 'Seu primeiro loop de pesquisa', sub: 'Crie o seu primeiro loop.',
        intro: 'Todo mundo gosta de deep research. Vamos pegar a ideia de pesquisa e deixar a IA iterar sobre ela em loop.',
        steps: [
          { h: 'Antes · veja sem loop', help: false, p: 'Rode isto para ver o "antes".', prompts: ['Busque na web sobre aplicações de IA agêntica em operações de negócio.'] },
          { h: 'Depois · coloque em loop', help: true, p: 'Agora a mesma busca, mas iterando sobre um único relatório.', prompts: ['Busque na web sobre "aplicações de IA agêntica em operações de negócio". Mantenha UM relatório em pesquisa.md, edite e reformule conforme aprende, não só adicione. A cada passada, pense em novos termos para preencher lacunas e achar direções novas, e itere. Faça 5 voltas. (não use a ferramenta /loop)'] },
          { h: 'Vire um comando', help: false, prompts: ['Transforme esse loop de pesquisa em um comando /pesquisa-loop em ~/.claude/commands/, que receba um tema e rode 5 voltas mantendo um único relatório.'] },
        ],
        debrief: ['O loop roda 5 iterações e para sozinho. O relatório fica melhor a cada volta, não maior.'],
        faq: ['Ele só vai adicionando texto? Reforce no prompt: reescreva e reorganize, não acrescente.'],
        deeper: ['Peça uma seção final de "lacunas e próximas buscas" para guiar a próxima rodada.'],
        why: 'É o começo da frente "um novo membro no time": o agente faz a tarefa de ponta a ponta e você aprova o que importa.',
      },
      en: {
        title: 'Your first research loop', sub: 'Build your first loop.',
        intro: 'Everyone loves deep research. Let us take the idea of research and let the AI iterate on it in a loop.',
        steps: [
          { h: 'Before · see it without a loop', help: false, p: 'Run this to see the "before".', prompts: ['Web search on applications of agentic AI in business operations.'] },
          { h: 'After · put it in a loop', help: true, p: 'Now the same search, but iterating over a single report.', prompts: ['Web search on "applications of agentic AI in business operations". Maintain ONE report at research.md, edit and reshape it as you learn, do not just append. After each pass, think of new terms to fill gaps and find new directions, and iterate. Loop 5 times. (do not use the /loop tool)'] },
          { h: 'Turn it into a command', help: false, prompts: ['Turn this research loop into a /research-loop command in ~/.claude/commands/, that takes a topic and runs 5 passes keeping a single report.'] },
        ],
        debrief: ['The loop runs 5 iterations and stops on its own. The report gets better each pass, not longer.'],
        faq: ['It just keeps appending? Reinforce in the prompt: rewrite and reorganize, do not add.'],
        deeper: ['Ask for a final "gaps and next searches" section to guide the next round.'],
        why: 'This is the start of "a new member of the team": the agent does the task end to end and you approve what matters.',
      },
      es: {
        title: 'Tu primer loop de research', sub: 'Construí tu primer loop.',
        intro: 'A todos nos gusta el deep research. Tomemos la idea de research y dejemos que la IA itere sobre ella en loop.',
        steps: [
          { h: 'Antes · miralo sin loop', help: false, p: 'Corré esto para ver el "antes".', prompts: ['Búsqueda web sobre aplicaciones de IA agéntica en operaciones de negocio.'] },
          { h: 'Después · ponelo en loop', help: true, p: 'Ahora la misma búsqueda, pero iterando sobre un único reporte.', prompts: ['Búsqueda web sobre "aplicaciones de IA agéntica en operaciones de negocio". Mantené UN reporte en research.md, editá y reformulá a medida que aprendés, no solo agregues. Después de cada pasada, pensá nuevos términos para cubrir huecos y encontrar direcciones nuevas, e iterá. Hacé 5 vueltas. (no uses la herramienta /loop)'] },
          { h: 'Convertilo en un comando', help: false, prompts: ['Convertí este loop de research en un comando /research-loop en ~/.claude/commands/, que reciba un tema y corra 5 pasadas manteniendo un único reporte.'] },
        ],
        debrief: ['El loop corre 5 iteraciones y para solo. El reporte mejora en cada vuelta, no se hace más largo.'],
        faq: ['¿Solo va agregando texto? Reforzá en el prompt: reescribí y reorganizá, no agregues.'],
        deeper: ['Pedí una sección final de "huecos y próximas búsquedas" para guiar la próxima ronda.'],
        why: 'Es el comienzo de "un nuevo miembro del equipo": el agente hace la tarea de punta a punta y vos aprobás lo que importa.',
      },
    },
  },
  {
    id: '5', act: 2, min: 60,
    i18n: {
      pt: {
        title: 'AutoResearch num modelo de propensão', sub: 'Seu primeiro loop que aprende.',
        intro: 'O exercício 4 repetiu a mesma tarefa N vezes. Este é diferente: o loop mede, muda uma variável e roda de novo, tentando bater o próprio score. É o AutoResearch mínimo viável, numa tarefa de machine learning que roda na CPU.',
        before: [{ h: 'Baixe o repositório', p: 'Em Arquivos, baixe autoresearch-edu.zip, descompacte em uma pasta e abra uma sessão nova do agente apontando para ela.' }],
        steps: [
          { h: 'Passo 1 · Confira que está no lugar certo', help: false, p: 'Você deve ver train.py, prepare.py, program.md e a pasta .claude/.', prompts: ['Que arquivos existem nesta pasta?'] },
          { h: 'Passo 2 · Rode o baseline', help: true, p: 'Instale as dependências, gere os dados e rode o baseline. Anote o val_auc e o test_auc, esse é o número a bater.', prompts: ['Instale as dependências do requirements.txt, rode python prepare.py e depois python train.py. Me mostre o val_auc e o test_auc.'] },
          { h: 'Passo 3 · Deixe o loop otimizar', help: false, p: 'O loop edita só a função build_pipeline(), seguindo program.md, e tenta subir o val_auc sem olhar o test_auc.', prompts: ['/autoresearch'] },
        ],
        debrief: ['O loop muda uma coisa por vez, roda, compara e mantém só o que melhora. No fim, o val_auc subiu acima do baseline.'],
        faq: ['Sem o comando /autoresearch? Ele está em .claude/commands/autoresearch.md no repo. Reabra a sessão na pasta certa.'],
        deeper: ['Peça ao agente para registrar cada iteração e o val_auc no fim de program.md.'],
        why: 'É a diferença entre repetir e aprender: o loop usa o próprio resultado para decidir o próximo passo. A pessoa define o alvo e confere o teste.',
      },
      en: {
        title: 'AutoResearch on a propensity model', sub: 'Your first loop that learns.',
        intro: 'Exercise 4 repeated the same task N times. This one is different: the loop measures, changes a variable and runs again, trying to beat its own score. It is the minimum viable AutoResearch, on a CPU-friendly machine learning task.',
        before: [{ h: 'Download the repository', p: 'In Files, download autoresearch-edu.zip, unzip it into a folder and open a new agent session pointing at it.' }],
        steps: [
          { h: 'Step 1 · Check you are in the right place', help: false, p: 'You should see train.py, prepare.py, program.md and the .claude/ folder.', prompts: ['What files are in this folder?'] },
          { h: 'Step 2 · Run the baseline', help: true, p: 'Install dependencies, generate the data and run the baseline. Note the val_auc and test_auc, that is the number to beat.', prompts: ['Install the dependencies from requirements.txt, run python prepare.py and then python train.py. Show me the val_auc and the test_auc.'] },
          { h: 'Step 3 · Let the loop optimize', help: false, p: 'The loop edits only build_pipeline(), following program.md, and tries to raise val_auc without looking at test_auc.', prompts: ['/autoresearch'] },
        ],
        debrief: ['The loop changes one thing at a time, runs, compares and keeps only what improves. By the end, val_auc rose above the baseline.'],
        faq: ['No /autoresearch command? It is at .claude/commands/autoresearch.md in the repo. Reopen the session in the right folder.'],
        deeper: ['Ask the agent to log each iteration and the val_auc at the end of program.md.'],
        why: 'It is the difference between repeating and learning: the loop uses its own result to decide the next step. The person sets the target and checks the test.',
      },
      es: {
        title: 'AutoResearch en un modelo de propensión', sub: 'Tu primer loop que aprende.',
        intro: 'El ejercicio 4 repitió la misma tarea N veces. Este es distinto: el loop mide, cambia una variable y corre de nuevo, tratando de superar su propio score. Es el AutoResearch mínimo viable, en una tarea de machine learning que corre en CPU.',
        before: [{ h: 'Descargá el repositorio', p: 'En Archivos, descargá autoresearch-edu.zip, descomprimilo en una carpeta y abrí una sesión nueva del agente apuntando a ella.' }],
        steps: [
          { h: 'Paso 1 · Verificá que estás en el lugar correcto', help: false, p: 'Deberías ver train.py, prepare.py, program.md y la carpeta .claude/.', prompts: ['¿Qué archivos hay en esta carpeta?'] },
          { h: 'Paso 2 · Corré el baseline', help: true, p: 'Instalá las dependencias, generá los datos y corré el baseline. Anotá el val_auc y el test_auc, ese es el número a superar.', prompts: ['Instalá las dependencias de requirements.txt, corré python prepare.py y después python train.py. Mostrame el val_auc y el test_auc.'] },
          { h: 'Paso 3 · Dejá que el loop optimice', help: false, p: 'El loop edita solo build_pipeline(), siguiendo program.md, y trata de subir el val_auc sin mirar el test_auc.', prompts: ['/autoresearch'] },
        ],
        debrief: ['El loop cambia una cosa por vez, corre, compara y mantiene solo lo que mejora. Al final, el val_auc subió por encima del baseline.'],
        faq: ['¿Sin el comando /autoresearch? Está en .claude/commands/autoresearch.md en el repo. Reabrí la sesión en la carpeta correcta.'],
        deeper: ['Pedile al agente que registre cada iteración y el val_auc al final de program.md.'],
        why: 'Es la diferencia entre repetir y aprender: el loop usa su propio resultado para decidir el próximo paso. La persona define el objetivo y chequea el test.',
      },
    },
  },
  {
    id: '6', act: 2, min: 75,
    i18n: {
      pt: {
        title: 'AutoResearch: construa o loop você mesmo', sub: 'Agora você monta o loop.',
        intro: 'No exercício 5 o loop já estava pronto, você rodou e assistiu. Desta vez você constrói. Mesma forma, alvo novo: um segundo objetivo no mesmo repositório, e o comando de loop é você que escreve.',
        before: [{ h: 'Use o mesmo repo', p: 'Continue no autoresearch-edu. Apague (ou ignore) o comando .claude/commands/autoresearch.md, você vai recriá-lo.' }],
        steps: [
          { h: 'Passo 1 · Defina um alvo novo', help: false, p: 'Peça ao agente para criar uma variação do baseline (outro alvo sintético ou outra métrica) e medir.', prompts: ['Crie uma variação do experimento: gere um segundo dataset sintético mais difícil em prepare.py (mais ruído e classes mais desbalanceadas) e ajuste train.py para medir nele também. Rode e me mostre o novo baseline.'] },
          { h: 'Passo 2 · Escreva o comando de loop', help: true, p: 'Agora você cria o /autoresearch do zero, com as regras de parada e de "uma mudança por vez".', prompts: ['Crie um comando /autoresearch em .claude/commands/ que: rode o baseline, depois itere 5 vezes mudando uma coisa por vez em build_pipeline(), mantenha só o que melhora o val_auc, registre cada iteração em program.md e no fim mostre o melhor pipeline e, só então, o test_auc.'] },
          { h: 'Passo 3 · Rode o seu loop', help: false, prompts: ['/autoresearch'] },
        ],
        debrief: ['Você não só rodou um loop, você desenhou um: alvo, regra de mudança, critério de parada e governança do que olhar quando.'],
        faq: ['O loop fica otimizando contra o teste? Deixe explícito no comando: nunca leia o test_auc durante a busca.'],
        deeper: ['Generalize o comando para receber qual variável mexer e quantas voltas.'],
        why: 'Construir o loop é o degrau "operar": você define o método e a régua, e o agente executa com você no controle.',
      },
      en: {
        title: 'AutoResearch: build the loop yourself', sub: 'Now you wire the loop.',
        intro: 'In exercise 5 the loop was already built, you ran it and watched. This time you build it. Same shape, new target: a second goal in the same repo, and you write the loop command.',
        before: [{ h: 'Use the same repo', p: 'Stay in autoresearch-edu. Delete (or ignore) the .claude/commands/autoresearch.md command, you will recreate it.' }],
        steps: [
          { h: 'Step 1 · Define a new target', help: false, p: 'Ask the agent to create a variation of the baseline (another synthetic target or metric) and measure it.', prompts: ['Create a variation of the experiment: generate a second, harder synthetic dataset in prepare.py (more noise and more imbalanced classes) and adjust train.py to measure on it too. Run it and show me the new baseline.'] },
          { h: 'Step 2 · Write the loop command', help: true, p: 'Now you create /autoresearch from scratch, with the stop rules and "one change at a time".', prompts: ['Create an /autoresearch command in .claude/commands/ that: runs the baseline, then iterates 5 times changing one thing at a time in build_pipeline(), keeps only what improves val_auc, logs each iteration in program.md and at the end shows the best pipeline and, only then, the test_auc.'] },
          { h: 'Step 3 · Run your loop', help: false, prompts: ['/autoresearch'] },
        ],
        debrief: ['You did not just run a loop, you designed one: target, change rule, stop criterion and the governance of what to look at when.'],
        faq: ['The loop optimizes against the test? Make it explicit in the command: never read test_auc during the search.'],
        deeper: ['Generalize the command to take which variable to change and how many passes.'],
        why: 'Building the loop is the "operate" rung: you set the method and the dial, and the agent executes with you in control.',
      },
      es: {
        title: 'AutoResearch: construí el loop vos mismo', sub: 'Ahora armás el loop.',
        intro: 'En el ejercicio 5 el loop ya estaba armado, lo corriste y miraste. Esta vez lo construís vos. Misma forma, objetivo nuevo: una segunda meta en el mismo repo, y el comando de loop lo escribís vos.',
        before: [{ h: 'Usá el mismo repo', p: 'Seguí en autoresearch-edu. Borrá (o ignorá) el comando .claude/commands/autoresearch.md, lo vas a recrear.' }],
        steps: [
          { h: 'Paso 1 · Definí un objetivo nuevo', help: false, p: 'Pedile al agente que cree una variación del baseline (otro objetivo sintético u otra métrica) y lo mida.', prompts: ['Creá una variación del experimento: generá un segundo dataset sintético más difícil en prepare.py (más ruido y clases más desbalanceadas) y ajustá train.py para medir en él también. Corré y mostrame el nuevo baseline.'] },
          { h: 'Paso 2 · Escribí el comando de loop', help: true, p: 'Ahora creás el /autoresearch desde cero, con las reglas de parada y de "un cambio por vez".', prompts: ['Creá un comando /autoresearch en .claude/commands/ que: corra el baseline, después itere 5 veces cambiando una cosa por vez en build_pipeline(), mantenga solo lo que mejora el val_auc, registre cada iteración en program.md y al final muestre el mejor pipeline y, recién ahí, el test_auc.'] },
          { h: 'Paso 3 · Corré tu loop', help: false, prompts: ['/autoresearch'] },
        ],
        debrief: ['No solo corriste un loop, diseñaste uno: objetivo, regla de cambio, criterio de parada y la gobernanza de qué mirar y cuándo.'],
        faq: ['¿El loop optimiza contra el test? Dejalo explícito en el comando: nunca leas el test_auc durante la búsqueda.'],
        deeper: ['Generalizá el comando para recibir qué variable tocar y cuántas vueltas.'],
        why: 'Construir el loop es el escalón "operar": vos definís el método y la perilla, y el agente ejecuta con vos al control.',
      },
    },
  },
];

const MD_FILES = [
  { name: 'moore-overview.md', href: 'assets/md/moore-overview.md', desc: { pt: 'Exercício 2.1 · contexto da Moore para arrastar no chat.', en: 'Exercise 2.1 · Moore context to drag into the chat.', es: 'Ejercicio 2.1 · contexto de Moore para arrastrar al chat.' } },
  { name: 'create-moore-presentation.md', href: 'assets/md/create-moore-presentation.md', desc: { pt: 'Exercício 2.1 · starter da skill de apresentação.', en: 'Exercise 2.1 · presentation skill starter.', es: 'Ejercicio 2.1 · starter de la skill de presentación.' } },
  { name: 'voz-moore.md', href: 'assets/md/voz-moore.md', desc: { pt: 'Exercícios 2.2 a 2.4 · exemplo de regras de tom de voz.', en: 'Exercises 2.2 to 2.4 · tone-of-voice rules example.', es: 'Ejercicios 2.2 a 2.4 · ejemplo de reglas de tono de voz.' } },
  { name: 'sample-ecommerce.csv', href: 'assets/md/sample-ecommerce.csv', desc: { pt: 'Exercício 3.1 · dataset sintético para dashboards.', en: 'Exercise 3.1 · synthetic dataset for dashboards.', es: 'Ejercicio 3.1 · dataset sintético para dashboards.' } },
  { name: 'snake-starter.html', href: 'assets/md/snake-starter.html', desc: { pt: 'Exercício 3.1 · starter de snake, se você pulou 1.1 / 1.2.', en: 'Exercise 3.1 · snake starter, if you skipped 1.1 / 1.2.', es: 'Ejercicio 3.1 · starter de snake, si salteaste 1.1 / 1.2.' } },
  { name: 'autoresearch-edu.zip', href: 'assets/md/autoresearch-edu.zip', desc: { pt: 'Exercícios 5 e 6 · repositório mínimo de AutoResearch.', en: 'Exercises 5 and 6 · minimal AutoResearch repository.', es: 'Ejercicios 5 y 6 · repositorio mínimo de AutoResearch.' } },
];

/* O Guia: onboarding linear de setup antes do curso. Checkpoints factuais
   (conta, app, contas, ferramentas de linha de comando). Copy original Moore. */
const MD_GUIDE = [
  { id: 1, t: { pt: { h: 'Conta Claude Pro ou Max', p: 'Precisa de uma conta paga pela cota de mensagens que o Claude Code usa. O plano grátis trava em poucos minutos.' }, en: { h: 'Claude Pro or Max account', p: 'A paid account is needed for the message quota Claude Code uses. The free tier blocks within minutes.' }, es: { h: 'Cuenta Claude Pro o Max', p: 'Necesitás una cuenta paga por la cuota de mensajes que usa Claude Code. El plan gratis se traba en pocos minutos.' } } },
  { id: 2, t: { pt: { h: 'App de desktop do Claude instalado', p: 'Mais rápido e com menos troca de contexto. Você vai deixar aberto a sessão inteira.' }, en: { h: 'Claude desktop app installed', p: 'Faster and less context switching. You will keep it open the whole session.' }, es: { h: 'App de escritorio de Claude instalada', p: 'Más rápido y con menos cambio de contexto. Lo vas a dejar abierto toda la sesión.' } } },
  { id: 3, t: { pt: { h: 'Conta no GitHub', p: 'Você vai versionar o seu trabalho em um repositório para conseguir publicar.' }, en: { h: 'GitHub account', p: 'You will push your work to a repository so you can deploy it.' }, es: { h: 'Cuenta en GitHub', p: 'Vas a versionar tu trabajo en un repositorio para poder publicarlo.' } } },
  { id: 4, t: { pt: { h: 'Conta no Vercel', p: 'Deploys em um clique. Você termina com uma URL real para compartilhar.' }, en: { h: 'Vercel account', p: 'One-click deploys. You finish with a real URL to share.' }, es: { h: 'Cuenta en Vercel', p: 'Deploys en un clic. Terminás con una URL real para compartir.' } } },
  { id: 5, t: { pt: { h: 'Gerenciador de pacotes', p: 'Homebrew no Mac, ou winget no Windows (já vem embutido).' }, en: { h: 'Package manager', p: 'Homebrew on Mac, or winget on Windows (built in).' }, es: { h: 'Gestor de paquetes', p: 'Homebrew en Mac, o winget en Windows (ya viene incluido).' } } },
  { id: 6, t: { pt: { h: 'Node instalado', p: 'Roda os builds em JavaScript da maioria dos exercícios.' }, en: { h: 'Node installed', p: 'Runs the JavaScript builds in most exercises.' }, es: { h: 'Node instalado', p: 'Corre los builds en JavaScript de la mayoría de los ejercicios.' } } },
  { id: 7, t: { pt: { h: 'npm instalado', p: 'Vem junto com o Node. Usado para instalar as dependências.' }, en: { h: 'npm installed', p: 'Bundled with Node. Used to install dependencies.' }, es: { h: 'npm instalado', p: 'Viene junto con Node. Se usa para instalar dependencias.' } } },
  { id: 8, t: { pt: { h: 'git instalado', p: 'É como o código vai e volta entre o seu computador e o GitHub.' }, en: { h: 'git installed', p: 'How code moves between your computer and GitHub.' }, es: { h: 'git instalado', p: 'Es cómo el código va y viene entre tu computadora y GitHub.' } } },
  { id: 9, t: { pt: { h: 'Vercel CLI instalado', p: 'Rode npm i -g vercel. Deixa você publicar direto do terminal.' }, en: { h: 'Vercel CLI installed', p: 'Run npm i -g vercel. Lets you ship straight from the terminal.' }, es: { h: 'Vercel CLI instalado', p: 'Corré npm i -g vercel. Te deja publicar directo desde la terminal.' } } },
];

/* Respostas fixas (hardcoded) do primeiro "Preciso de ajuda" por passo do guia.
   Funcionam sem API key. Onde o sistema importa, há texto por SO (mac/win); caso
   contrário, usa `any`. Resolvido por mdGuideAnswer(id, os, lang). */
const MD_GUIDE_HELP = {
  1: { pt: { any: 'Crie a conta em https://claude.ai e suba para um plano pago: Claude Pro (cerca de US$20 por mês) ou Max. O plano grátis trava em poucos minutos de sessão, então o pago é o que o Claude Code precisa.\n\nDeu certo quando: você consegue entrar em claude.ai com um plano pago ativo, não no grátis.' }, en: { any: 'Sign up at https://claude.ai and upgrade to a paid plan: Claude Pro (around US$20 a month) or Max. The free tier blocks within a few minutes of a session, so a paid plan is what Claude Code needs.\n\nDone when: you can log into claude.ai with an active paid plan, not the free tier.' }, es: { any: 'Creá la cuenta en https://claude.ai y subí a un plan pago: Claude Pro (unos US$20 por mes) o Max. El plan gratis se traba a los pocos minutos de sesión, así que el pago es lo que Claude Code necesita.\n\nListo cuando: podés entrar a claude.ai con un plan pago activo, no en el gratis.' } },
  2: { pt: { any: 'Baixe o app de desktop do Claude em https://claude.com/download, instale e abra. No Mac ele fica em Aplicativos; no Windows, no menu Iniciar. Ele embrulha o Claude Code e deixa tudo mais rápido, com menos troca de contexto.\n\nDeu certo quando: o app abre e você consegue iniciar uma sessão. Deixe aberto a sessão inteira.' }, en: { any: 'Download the Claude desktop app from https://claude.com/download, install and open it. On Mac it lands in Applications; on Windows, the Start menu. It wraps Claude Code and makes everything faster, with less context switching.\n\nDone when: the app opens and you can start a session. Keep it open the whole session.' }, es: { any: 'Descargá la app de escritorio de Claude en https://claude.com/download, instalá y abrila. En Mac queda en Aplicaciones; en Windows, en el menú Inicio. Envuelve a Claude Code y hace todo más rápido, con menos cambio de contexto.\n\nListo cuando: la app abre y podés iniciar una sesión. Dejala abierta toda la sesión.' } },
  3: { pt: { any: 'Vá em https://github.com e crie a conta (ou entre na sua). Depois configure uma chave SSH para que commits e pushes sejam sem senha durante o curso: gere a chave com ssh-keygen, e cole a chave pública em GitHub > Settings > SSH and GPG keys.\n\nDeu certo quando: ssh -T git@github.com responde com o seu usuário.' }, en: { any: 'Go to https://github.com and create an account (or sign in). Then set up an SSH key so commits and pushes are passwordless during the course: generate the key with ssh-keygen and paste the public key into GitHub > Settings > SSH and GPG keys.\n\nDone when: ssh -T git@github.com replies with your username.' }, es: { any: 'Andá a https://github.com y creá la cuenta (o entrá a la tuya). Después configurá una clave SSH para que commits y pushes sean sin contraseña durante el curso: generá la clave con ssh-keygen y pegá la clave pública en GitHub > Settings > SSH and GPG keys.\n\nListo cuando: ssh -T git@github.com responde con tu usuario.' } },
  4: { pt: { any: 'Vá em https://vercel.com e clique em "Continue with GitHub". Use a sua conta do GitHub (não crie um cadastro por e-mail) e dê permissão para os repositórios. O painel vai aparecer vazio, isso é esperado: você ainda não tem projetos.\n\nDeu certo quando: você cai no painel do Vercel sem projetos listados.' }, en: { any: 'Go to https://vercel.com and click "Continue with GitHub". Use your GitHub account (do not create an email signup) and grant access to your repositories. The dashboard shows up empty, which is expected: you have no projects yet.\n\nDone when: you land on the Vercel dashboard with no projects listed.' }, es: { any: 'Andá a https://vercel.com y hacé clic en "Continue with GitHub". Usá tu cuenta de GitHub (no crees un registro por email) y dale permiso a los repositorios. El panel va a aparecer vacío, eso es lo esperado: todavía no tenés proyectos.\n\nListo cuando: caés en el panel de Vercel sin proyectos listados.' } },
  5: {
    pt: { mac: 'No Mac, instale o Homebrew. Abra o Terminal e rode o instalador de https://brew.sh. No fim ele mostra duas linhas de PATH para colar, faça isso. Confirme com:\n\nbrew --version\n\nDeu certo quando: aparece Homebrew 4.x.', win: 'No Windows, o winget já vem embutido no Windows 10 e 11, não precisa instalar. Confirme abrindo o PowerShell e rodando:\n\nwinget --version\n\nDeu certo quando: aparece algo como v1.x.' },
    en: { mac: 'On Mac, install Homebrew. Open Terminal and run the installer from https://brew.sh. At the end it prints two PATH lines to paste, do that. Confirm with:\n\nbrew --version\n\nDone when: it prints Homebrew 4.x.', win: 'On Windows, winget is already built into Windows 10 and 11, no install needed. Confirm by opening PowerShell and running:\n\nwinget --version\n\nDone when: it prints something like v1.x.' },
    es: { mac: 'En Mac, instalá Homebrew. Abrí la Terminal y corré el instalador de https://brew.sh. Al final muestra dos líneas de PATH para pegar, hacelo. Confirmá con:\n\nbrew --version\n\nListo cuando: aparece Homebrew 4.x.', win: 'En Windows, winget ya viene incluido en Windows 10 y 11, no hace falta instalar. Confirmá abriendo PowerShell y corriendo:\n\nwinget --version\n\nListo cuando: aparece algo como v1.x.' },
  },
  6: {
    pt: { mac: 'No Mac, com o Homebrew pronto, instale o Node:\n\nbrew install node\n\nConfirme com node --version. Deu certo quando: aparece v18 ou maior (por exemplo v20.x).', win: 'No Windows, instale o Node pelo winget:\n\nwinget install OpenJS.NodeJS.LTS\n\nFeche e reabra o terminal, confirme com node --version. Deu certo quando: aparece v18 ou maior (por exemplo v20.x).' },
    en: { mac: 'On Mac, with Homebrew ready, install Node:\n\nbrew install node\n\nConfirm with node --version. Done when: it prints v18 or higher (for example v20.x).', win: 'On Windows, install Node via winget:\n\nwinget install OpenJS.NodeJS.LTS\n\nClose and reopen the terminal, confirm with node --version. Done when: it prints v18 or higher (for example v20.x).' },
    es: { mac: 'En Mac, con Homebrew listo, instalá Node:\n\nbrew install node\n\nConfirmá con node --version. Listo cuando: aparece v18 o mayor (por ejemplo v20.x).', win: 'En Windows, instalá Node con winget:\n\nwinget install OpenJS.NodeJS.LTS\n\nCerrá y reabrí la terminal, confirmá con node --version. Listo cuando: aparece v18 o mayor (por ejemplo v20.x).' },
  },
  7: { pt: { any: 'O npm vem junto com o Node, então se o passo anterior funcionou, ele já está aí. Confirme com:\n\nnpm --version\n\nDeu certo quando: aparece um número de versão (por exemplo 10.x). Se não aparecer, reinstale o Node.' }, en: { any: 'npm ships bundled with Node, so if the previous step worked, it is already there. Confirm with:\n\nnpm --version\n\nDone when: it prints a version number (for example 10.x). If it does not, reinstall Node.' }, es: { any: 'npm viene junto con Node, así que si el paso anterior funcionó, ya está. Confirmá con:\n\nnpm --version\n\nListo cuando: aparece un número de versión (por ejemplo 10.x). Si no aparece, reinstalá Node.' } },
  8: {
    pt: { mac: 'No Mac o git costuma já vir instalado. Confirme com git --version (serve 2.30 ou maior). Se não tiver, rode brew install git. Depois configure a sua identidade (use o e-mail da sua conta no GitHub):\n\ngit config --global user.name "Seu Nome"\ngit config --global user.email "voce@exemplo.com"\n\nDeu certo quando: git --version mostra a versão e os dois comandos rodam sem erro.', win: 'No Windows, instale o git pelo winget:\n\nwinget install Git.Git\n\nFeche e reabra o terminal, confirme com git --version (serve 2.30 ou maior). Depois configure a sua identidade (use o e-mail da sua conta no GitHub):\n\ngit config --global user.name "Seu Nome"\ngit config --global user.email "voce@exemplo.com"\n\nDeu certo quando: git --version mostra a versão e os dois comandos rodam sem erro.' },
    en: { mac: 'On Mac, git usually comes preinstalled. Confirm with git --version (2.30 or higher works). If you do not have it, run brew install git. Then set your identity (use the email tied to your GitHub account):\n\ngit config --global user.name "Your Name"\ngit config --global user.email "you@example.com"\n\nDone when: git --version shows the version and both commands run without error.', win: 'On Windows, install git via winget:\n\nwinget install Git.Git\n\nClose and reopen the terminal, confirm with git --version (2.30 or higher works). Then set your identity (use the email tied to your GitHub account):\n\ngit config --global user.name "Your Name"\ngit config --global user.email "you@example.com"\n\nDone when: git --version shows the version and both commands run without error.' },
    es: { mac: 'En Mac el git suele venir instalado. Confirmá con git --version (sirve 2.30 o mayor). Si no lo tenés, corré brew install git. Después configurá tu identidad (usá el email de tu cuenta en GitHub):\n\ngit config --global user.name "Tu Nombre"\ngit config --global user.email "vos@ejemplo.com"\n\nListo cuando: git --version muestra la versión y los dos comandos corren sin error.', win: 'En Windows, instalá git con winget:\n\nwinget install Git.Git\n\nCerrá y reabrí la terminal, confirmá con git --version (sirve 2.30 o mayor). Después configurá tu identidad (usá el email de tu cuenta en GitHub):\n\ngit config --global user.name "Tu Nombre"\ngit config --global user.email "vos@ejemplo.com"\n\nListo cuando: git --version muestra la versión y los dos comandos corren sin error.' },
  },
  9: { pt: { any: 'Com o npm pronto, instale o Vercel CLI de forma global:\n\nnpm i -g vercel\n\nConfirme com vercel --version (serve qualquer 33.x). Depois faça login com vercel login: abre o navegador, você entra com o GitHub e volta para o terminal como autenticado.\n\nDeu certo quando: vercel --version mostra a versão e vercel login termina autenticado.' }, en: { any: 'With npm ready, install the Vercel CLI globally:\n\nnpm i -g vercel\n\nConfirm with vercel --version (any 33.x works). Then sign in with vercel login: it opens the browser, you log in with GitHub and come back to the terminal as authenticated.\n\nDone when: vercel --version shows the version and vercel login finishes authenticated.' }, es: { any: 'Con npm listo, instalá el Vercel CLI de forma global:\n\nnpm i -g vercel\n\nConfirmá con vercel --version (sirve cualquier 33.x). Después logueate con vercel login: abre el navegador, entrás con GitHub y volvés a la terminal como autenticado.\n\nListo cuando: vercel --version muestra la versión y vercel login termina autenticado.' } },
};

function mdGuideAnswer(id, os, lang) {
  const e = MD_GUIDE_HELP[id];
  if (!e) return null;
  const L = e[lang] || e.pt;
  return (os === 'Windows' ? (L.win || L.any) : (L.mac || L.any)) || L.any || null;
}

const MD_GT = {
  pt: { eyebrow: 'O guia', welcome_h: 'Vamos preparar o terreno', welcome_p: 'Uma sequência curta para deixar a sua máquina pronta. Confirme cada item e a gente segue. Travou em algum, é só pedir ajuda.', ready: 'Pronto, vamos', back: 'Início', of: '/9', gotit: 'Sim, já tenho', needhelp: 'Preciso de ajuda', q: 'Já está configurado?', done_h: 'Tudo certo. Você está pronto.', done_p: 'Agora abra o app de desktop do Claude, que embrulha o Claude Code, e comece uma sessão nova. É lá que você passa o resto do tempo.', go_ex: 'Ir para os exercícios' },
  en: { eyebrow: 'The guide', welcome_h: 'Let us set the ground', welcome_p: 'A short sequence to get your machine ready. Confirm each item and we move on. Stuck on any, just ask for help.', ready: 'Ready, let us go', back: 'Home', of: '/9', gotit: 'Yes, I have it', needhelp: 'I need help', q: 'Got it set up?', done_h: 'All set. You are ready.', done_p: 'Now open the Claude desktop app, which wraps Claude Code, and start a new session. That is where you spend the rest of the time.', go_ex: 'Go to the exercises' },
  es: { eyebrow: 'La guía', welcome_h: 'Vamos a preparar el terreno', welcome_p: 'Una secuencia corta para dejar tu máquina lista. Confirmá cada ítem y seguimos. Si te trabás en alguno, pedí ayuda.', ready: 'Listo, vamos', back: 'Inicio', of: '/9', gotit: 'Sí, ya lo tengo', needhelp: 'Necesito ayuda', q: '¿Ya está configurado?', done_h: 'Todo listo. Estás listo.', done_p: 'Ahora abrí la app de escritorio de Claude, que envuelve Claude Code, y empezá una sesión nueva. Ahí pasás el resto del tiempo.', go_ex: 'Ir a los ejercicios' },
};

function mdGetDone() { try { return JSON.parse(window.localStorage.getItem('moore_md_done') || '[]'); } catch (e) { return []; } }
function mdSetDone(id) { try { const d = mdGetDone(); if (d.indexOf(id) < 0) d.push(id); window.localStorage.setItem('moore_md_done', JSON.stringify(d)); } catch (e) {} }
function mdGetGuideStep() { try { const v = window.localStorage.getItem('moore_md_guide_step'); return v == null ? null : parseInt(v, 10); } catch (e) { return null; } }
function mdSetGuideStep(n) { try { if (n == null) window.localStorage.removeItem('moore_md_guide_step'); else window.localStorage.setItem('moore_md_guide_step', String(n)); } catch (e) {} }

window.mdCourseList = MD_COURSE;

const CHAT_OFFLINE = {
  pt: 'O chat de ajuda ainda não está ligado neste ambiente. Enquanto isso, fale direto com a Moore pelo botão abaixo, a gente responde rápido.',
  en: 'The help chat is not switched on in this environment yet. In the meantime, talk to Moore through the button below, we reply fast.',
  es: 'El chat de ayuda todavía no está activo en este entorno. Mientras tanto, hablá directo con Moore por el botón de abajo, respondemos rápido.',
};

function mdGo(path) { window.history.pushState({}, '', path); window.dispatchEvent(new PopStateEvent('popstate')); window.scrollTo(0, 0); }

function MdCopy({ text, label, doneLabel }) {
  const [done, setDone] = useStateMd(false);
  const copy = () => { if (navigator.clipboard) { navigator.clipboard.writeText(text).then(() => { setDone(true); setTimeout(() => setDone(false), 1600); }).catch(() => {}); } };
  return <button className="md-copy" onClick={copy} type="button">{done ? doneLabel : label}</button>;
}

function MdReveal({ tag, label, children }) {
  return (
    <details className="md-reveal">
      <summary><span className="md-reveal-tag">{tag}</span> {label}</summary>
      <div className="md-reveal-body">{children}</div>
    </details>
  );
}

function MdChrome({ lang, children }) {
  const t = MD_T[lang] || MD_T.pt;
  const lp = (p) => window.localePath(p, lang);
  return (
    <div className="md-page">
      <header className="md-topnav">
        <div className="md-container md-topnav-inner">
          <a href={lp('/md')} data-spa="1" className="md-logo">Moore<span className="md-logo-dot">.</span><span className="md-logo-md">md</span></a>
          <nav className="md-topnav-links">
            <a href={lp('/md/exercicios')} data-spa="1">{t.nav_ex}</a>
            <a href={lp('/md/ajuda')} data-spa="1">{t.nav_help}</a>
            <a href={lp('/md/arquivos')} data-spa="1">{t.nav_files}</a>
          </nav>
        </div>
      </header>
      {children}
      <footer className="md-foot">
        <div className="md-container">
          <p className="md-disclaimer">{t.foot_disc}</p>
          <div className="md-foot-row">
            <a href={lp('/md')} data-spa="1" className="md-logo md-logo-sm">Moore<span className="md-logo-dot">.</span><span className="md-logo-md">md</span></a>
            <div className="md-foot-links">
              <a href={lp('/')} data-spa="1">{t.foot_site}</a>
              <a href={lp('/md/privacidade')} data-spa="1">{t.foot_priv}</a>
              <a href={lp('/md/termos')} data-spa="1">{t.foot_terms}</a>
            </div>
          </div>
        </div>
      </footer>
    </div>
  );
}

function MdHome({ lang }) {
  const t = MD_T[lang] || MD_T.pt;
  const lp = (p) => window.localePath(p, lang);
  return (
    <MdChrome lang={lang}>
      <section className="md-hero">
        <div className="md-container">
          <div className="md-eyebrow">{t.home_eyebrow}</div>
          <h1 className="md-display">{t.home_title}<span className="md-accent">.</span></h1>
          <p className="md-lead">{t.home_lead}</p>
          <div className="md-cta-row">
            <a href={lp('/md/guia')} data-spa="1" className="md-btn md-btn-primary">{t.home_cta1} <span aria-hidden="true">→</span></a>
            <a href={lp('/md/exercicios')} data-spa="1" className="md-btn-ghost">{t.home_cta2}</a>
          </div>
        </div>
      </section>
      <section className="md-container md-home-grid">
        <div className="md-home-col"><div className="md-eyebrow">{t.a1k}</div><h3 className="md-home-h">{t.a1h}</h3><p className="md-home-p">{t.a1p}</p></div>
        <div className="md-home-col"><div className="md-eyebrow">{t.a2k}</div><h3 className="md-home-h">{t.a2h}</h3><p className="md-home-p">{t.a2p}</p></div>
        <div className="md-home-col"><div className="md-eyebrow">{t.howk}</div><h3 className="md-home-h">{t.howh}</h3><p className="md-home-p">{t.howp} <a href={lp('/md/ajuda')} data-spa="1" className="md-inline">{t.howlink}</a>.</p></div>
      </section>
    </MdChrome>
  );
}

function MdIndex({ lang }) {
  const t = MD_T[lang] || MD_T.pt;
  const lp = (p) => window.localePath(p, lang);
  const done = mdGetDone();
  return (
    <MdChrome lang={lang}>
      <div className="md-container md-section">
        <div className="md-breadcrumb"><a href={lp('/md')} data-spa="1">{t.home_link}</a></div>
        <div className="md-eyebrow md-eyebrow-accent">{t.idx_eyebrow}</div>
        <h1 className="md-title-xl">{t.idx_a}<br /><span className="md-muted">{t.idx_b}</span></h1>
        <p className="md-lead md-lead-tight">{t.idx_lead}</p>
        {MD_ACTS.map((act) => (
          <div key={act.n} className="md-act">
            <div className="md-act-head"><span className="md-act-title">{act.title[lang]}</span><span className="md-act-note">{act.note[lang]}</span></div>
            <div className="md-ex-list">
              {MD_COURSE.filter((e) => e.act === act.n).map((e) => (
                <a key={e.id} href={lp('/md/exercicios/' + e.id)} data-spa="1" className="md-ex-row">
                  <span className="md-ex-num">{done.indexOf(e.id) >= 0 ? '✓' : e.id}</span>
                  <span className="md-ex-name">{(e.i18n[lang] || e.i18n.pt).title}</span>
                  <span className="md-ex-min">{e.min} {t.min.toLowerCase()}</span>
                  <span className="md-ex-chev" aria-hidden="true">›</span>
                </a>
              ))}
            </div>
          </div>
        ))}
      </div>
    </MdChrome>
  );
}

function MdExercise({ id, lang, onOpenContact }) {
  const t = MD_T[lang] || MD_T.pt;
  const lp = (p) => window.localePath(p, lang);
  const idx = MD_COURSE.findIndex((e) => e.id === id);
  const e = MD_COURSE[idx];
  const [isDone, setIsDone] = useStateMd(false);
  useEffectMd(() => { setIsDone(mdGetDone().indexOf(id) >= 0); }, [id]);
  if (!e) {
    return <MdChrome lang={lang}><div className="md-container md-section"><h1 className="md-title-xl">404</h1><p className="md-lead"><a href={lp('/md/exercicios')} data-spa="1" className="md-inline">{t.all_ex}</a></p></div></MdChrome>;
  }
  const c = e.i18n[lang] || e.i18n.pt;
  const act = MD_ACTS.find((a) => a.n === e.act);
  const prev = idx > 0 ? MD_COURSE[idx - 1] : null;
  const next = idx < MD_COURSE.length - 1 ? MD_COURSE[idx + 1] : null;
  const pos = idx + 1;
  const go = (path) => { window.history.pushState({}, '', path); window.dispatchEvent(new PopStateEvent('popstate')); window.scrollTo(0, 0); };
  const markDone = () => { mdSetDone(e.id); setIsDone(true); go(next ? lp('/md/exercicios/' + next.id) : lp('/md/exercicios')); };

  return (
    <MdChrome lang={lang}>
      <div className="md-container md-section md-ex">
        <div className="md-breadcrumb"><a href={lp('/md/exercicios')} data-spa="1">{t.all_ex}</a></div>
        <div className="md-ex-tag">{act.title[lang].split('·')[0].trim()} · {pos} {t.of} · {e.min} {t.min}</div>
        <div className="md-ex-id">{e.id}</div>
        <h1 className="md-title-xl">{c.title}</h1>
        <p className="md-ex-sub">{c.sub}</p>
        <p className="md-body">{c.intro}</p>

        {c.before ? (
          <div className="md-before">
            <h2 className="md-h2">{t.before}</h2>
            {c.before.map((b, i) => (<div key={i} className="md-before-item"><span className="md-before-num">{i + 1}</span><div><div className="md-before-h">{b.h}</div><p className="md-body">{b.p}</p></div></div>))}
          </div>
        ) : null}

        {c.steps.map((s, i) => (
          <div key={i} className="md-step">
            <h2 className="md-h2">{s.h}</h2>
            {s.help ? <button className="md-step-help" onClick={() => mdGo(lp('/md/chat/exercises/' + e.id))} type="button">{t.step_help}</button> : null}
            {s.p ? <p className="md-body">{s.p}</p> : null}
            {(s.prompts || []).map((pr, j) => (
              <div key={j} className="md-prompt">
                <div className="md-prompt-head"><span className="md-prompt-label">{j === 0 ? t.prompt_label : t.followup}</span><MdCopy text={pr} label={t.copy} doneLabel={t.copied} /></div>
                <pre className="md-prompt-body">{pr}</pre>
              </div>
            ))}
          </div>
        ))}

        <div className="md-reveals">
          {c.debrief ? <MdReveal tag={t.debrief_tag} label={t.debrief_label}>{c.debrief.map((x, i) => <p key={i}>{x}</p>)}</MdReveal> : null}
          {c.faq ? <MdReveal tag={t.faq_tag} label={t.faq_label}>{c.faq.map((x, i) => <p key={i}>{x}</p>)}</MdReveal> : null}
          {c.deeper ? <MdReveal tag={t.deeper_tag} label={t.deeper_label}>{c.deeper.map((x, i) => <p key={i}>{x}</p>)}</MdReveal> : null}
          {c.interlude ? <MdReveal tag={t.interlude_tag} label={c.interlude.title}>{c.interlude.body.map((x, i) => <p key={i}>{x}</p>)}</MdReveal> : null}
        </div>

        {c.why ? (<div className="md-why"><div className="md-eyebrow md-eyebrow-accent">{t.why_label}</div><p className="md-why-p">{c.why}</p></div>) : null}

        <div className="md-done-row">
          <button className="md-btn md-btn-primary" onClick={markDone} type="button">{isDone ? '✓ ' : ''}{t.mark_done}{next ? ', ' + t.next_to + ' ' + next.id : ', ' + t.conclude}</button>
        </div>

        <div className="md-prevnext">
          {prev ? <a href={lp('/md/exercicios/' + prev.id)} data-spa="1" className="md-pn"><span className="md-pn-dir">← {t.prev}</span><span className="md-pn-name">{(prev.i18n[lang] || prev.i18n.pt).title}</span></a> : <span />}
          {next ? <a href={lp('/md/exercicios/' + next.id)} data-spa="1" className="md-pn md-pn-next"><span className="md-pn-dir">{t.next} →</span><span className="md-pn-name">{(next.i18n[lang] || next.i18n.pt).title}</span></a> : <span />}
        </div>
      </div>

      <button className="md-help-pill" onClick={() => mdGo(lp('/md/chat/exercises/' + e.id))} type="button">{t.ask}</button>
    </MdChrome>
  );
}

function MdFiles({ lang }) {
  const t = MD_T[lang] || MD_T.pt;
  const lp = (p) => window.localePath(p, lang);
  return (
    <MdChrome lang={lang}>
      <div className="md-container md-section">
        <div className="md-breadcrumb"><a href={lp('/md')} data-spa="1">{t.home_link}</a></div>
        <div className="md-eyebrow md-eyebrow-accent">{t.nav_files}</div>
        <h1 className="md-title-xl">{t.files_title}</h1>
        <p className="md-lead md-lead-tight">{t.files_lead}</p>
        <div className="md-file-list">
          {MD_FILES.map((f) => (
            <a key={f.name} href={f.href} download className="md-file-row">
              <span className="md-file-name">{f.name}</span>
              <span className="md-file-desc">{f.desc[lang] || f.desc.pt}</span>
              <span className="md-file-dl" aria-hidden="true">↓</span>
            </a>
          ))}
        </div>
      </div>
    </MdChrome>
  );
}

function MdHelp({ lang, onOpenContact }) {
  const t = MD_T[lang] || MD_T.pt;
  const lp = (p) => window.localePath(p, lang);
  return (
    <MdChrome lang={lang}>
      <div className="md-container md-section">
        <div className="md-breadcrumb"><a href={lp('/md')} data-spa="1">{t.home_link}</a></div>
        <div className="md-eyebrow md-eyebrow-accent">{t.nav_help}</div>
        <h1 className="md-title-xl">{t.help_title}</h1>
        <p className="md-lead md-lead-tight">{t.help_lead}</p>
        <div className="md-help-cards">
          {t.help_cards.map((c) => (
            <a key={c.h} className="md-help-card" href={lp('/md/chat/' + c.mode)} data-spa="1">
              <span className="md-help-h">{c.h}</span><span className="md-help-p">{c.p}</span><span className="md-help-go" aria-hidden="true">{t.help_go}</span>
            </a>
          ))}
        </div>
      </div>
    </MdChrome>
  );
}

function MdLegal({ lang, kind }) {
  const t = MD_T[lang] || MD_T.pt;
  const lp = (p) => window.localePath(p, lang);
  const privacy = kind === 'privacy';
  const C = {
    pt: { pt: 'Privacidade', tt: 'Termos de uso',
      p: [['Este curso usa apenas cookies funcionais para lembrar o seu progresso e a sua preferência de idioma. Não há rastreamento, anúncios nem venda de dados.'], ['O que guardamos', 'O seu progresso fica salvo apenas no seu navegador (armazenamento local). Não enviamos isso para nenhum servidor.'], ['O que não guardamos', 'Não coletamos dados pessoais, não criamos perfil e não compartilhamos nada com terceiros para marketing.'], ['Contato', 'Dúvidas? Escreva para thiago@getmoore.ai.']],
      tm: [['Este é um ambiente de aprendizado da Moore AI, fornecido como está, para fins educacionais.'], ['Uso aceitável', 'Use ambientes de teste. Não suba dados confidenciais, de clientes ou não aprovados. Siga a política de TI e segurança da sua empresa.'], ['Ferramentas de terceiros', 'O curso menciona ferramentas como Claude Code e Codex. O uso delas segue os termos dos respectivos fornecedores.'], ['Sem garantias', 'As saídas de IA podem conter imprecisões. Revise antes de usar em qualquer contexto real.']] },
    en: { pt: 'Privacy', tt: 'Terms of use',
      p: [['This course uses only functional cookies to remember your progress and language preference. No tracking, no ads, no data selling.'], ['What we store', 'Your progress is saved only in your browser (local storage). We do not send it to any server.'], ['What we do not store', 'We do not collect personal data, build profiles, or share anything with third parties for marketing.'], ['Contact', 'Questions? Write to thiago@getmoore.ai.']],
      tm: [['This is a Moore AI learning environment, provided as is, for educational purposes.'], ['Acceptable use', 'Use sandbox environments. Do not upload confidential, customer, or unapproved data. Follow your organization’s IT and security policy.'], ['Third-party tools', 'The course mentions tools such as Claude Code and Codex. Their use follows the respective providers’ terms.'], ['No warranty', 'AI outputs may contain inaccuracies. Review before using in any real context.']] },
    es: { pt: 'Privacidad', tt: 'Términos de uso',
      p: [['Este curso usa solo cookies funcionales para recordar tu progreso y preferencia de idioma. Sin rastreo, sin anuncios, sin venta de datos.'], ['Qué guardamos', 'Tu progreso se guarda solo en tu navegador (almacenamiento local). No lo enviamos a ningún servidor.'], ['Qué no guardamos', 'No recolectamos datos personales, no creamos perfiles ni compartimos nada con terceros para marketing.'], ['Contacto', '¿Dudas? Escribí a thiago@getmoore.ai.']],
      tm: [['Este es un ambiente de aprendizaje de Moore AI, provisto como está, con fines educativos.'], ['Uso aceptable', 'Usá ambientes de prueba. No subas datos confidenciales, de clientes o no aprobados. Seguí la política de TI y seguridad de tu empresa.'], ['Herramientas de terceros', 'El curso menciona herramientas como Claude Code y Codex. Su uso sigue los términos de los respectivos proveedores.'], ['Sin garantías', 'Las salidas de IA pueden contener imprecisiones. Revisá antes de usar en cualquier contexto real.']] },
  };
  const L = C[lang] || C.pt;
  const blocks = privacy ? L.p : L.tm;
  return (
    <MdChrome lang={lang}>
      <div className="md-container md-section md-prose">
        <div className="md-breadcrumb"><a href={lp('/md')} data-spa="1">{t.home_link}</a></div>
        <h1 className="md-title-xl">{privacy ? L.pt : L.tt}</h1>
        {blocks.map((b, i) => (b.length === 1 ? <p key={i}>{b[0]}</p> : <React.Fragment key={i}><h2 className="md-h2">{b[0]}</h2><p>{b[1]}</p></React.Fragment>))}
      </div>
    </MdChrome>
  );
}

function MdChat({ lang, mode, ex, onOpenContact }) {
  const t = MD_T[lang] || MD_T.pt;
  const ct = t.chat;
  const lp = (p) => window.localePath(p, lang);
  const m = (mode === 'setup' || mode === 'exercises' || mode === 'general') ? mode : 'general';
  const [messages, setMessages] = useStateMd([]);
  const [input, setInput] = useStateMd('');
  const [loading, setLoading] = useStateMd(false);
  const [os, setOs] = useStateMd(null);
  const [needContact, setNeedContact] = useStateMd(false);
  const stepId = (m === 'setup' && ex) ? parseInt(ex, 10) : null;
  // Primeira resposta do "Preciso de ajuda" do guia: fixa (sem API), por passo e SO.
  useEffectMd(() => {
    if (m !== 'setup' || !stepId || !os) return;
    setMessages((cur) => {
      if (cur.length) return cur;
      const step = MD_GUIDE.filter((s) => s.id === stepId)[0];
      if (!step) return cur;
      const title = (step.t[lang] || step.t.pt).h;
      const userText = (ct.seed_user || '').replace('{n}', String(stepId)).replace('{title}', title);
      const answer = mdGuideAnswer(stepId, os, lang);
      const seeded = [{ role: 'user', content: userText }];
      if (answer) seeded.push({ role: 'assistant', content: answer });
      return seeded;
    });
  }, [stepId, os, m, lang]);
  const header = m === 'setup' ? ct.setup_h : m === 'exercises' ? ct.ex_h : ct.gen_h;
  const intro = m === 'setup' ? ct.setup_intro : m === 'exercises' ? ct.ex_intro : ct.gen_intro;
  const chips = m === 'exercises' ? ct.ex_chips.map((s) => s.replace('{n}', ex || '1.1')) : [];
  const backHref = (m === 'exercises' && ex) ? lp('/md/exercicios/' + ex) : lp('/md/ajuda');
  const backText = (m === 'exercises' && ex) ? (ct.back_ex + ' ' + ex) : t.nav_help;

  const send = (textArg) => {
    const text = String(textArg != null ? textArg : input).trim();
    if (!text || loading) return;
    const next = messages.concat([{ role: 'user', content: text }]);
    setMessages(next); setInput(''); setLoading(true); setNeedContact(false);
    fetch('/api/md-chat', { method: 'POST', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ messages: next, mode: m, lang: lang, ex: ex || null, os: os }) })
      .then((r) => (r.ok ? r.json() : Promise.reject(new Error('http'))))
      .then((d) => { setMessages((cur) => cur.concat([{ role: 'assistant', content: d.reply || (CHAT_OFFLINE[lang] || CHAT_OFFLINE.pt) }])); if (d.configured === false) setNeedContact(true); setLoading(false); })
      .catch(() => { setMessages((cur) => cur.concat([{ role: 'assistant', content: CHAT_OFFLINE[lang] || CHAT_OFFLINE.pt }])); setNeedContact(true); setLoading(false); });
  };
  const onKey = (ev) => { if (ev.key === 'Enter' && !ev.shiftKey) { ev.preventDefault(); send(); } };

  return (
    <MdChrome lang={lang}>
      <div className="md-container md-section md-chat">
        <div className="md-breadcrumb"><a href={backHref} data-spa="1">{backText}</a></div>
        <div className="md-eyebrow md-eyebrow-accent">{t.nav_help}</div>
        <h1 className="md-title-xl">{header}</h1>
        <p className="md-lead md-lead-tight">{intro}</p>

        {m === 'setup' && !os ? (
          <div className="md-os">
            <div className="md-os-q">{ct.os_q}</div>
            <div className="md-os-row">
              <button className="md-os-btn" type="button" onClick={() => setOs('Mac')}><span className="md-os-h">{ct.os_mac}</span><span className="md-os-sub">{ct.os_mac_sub}</span></button>
              <button className="md-os-btn" type="button" onClick={() => setOs('Windows')}><span className="md-os-h">{ct.os_win}</span><span className="md-os-sub">{ct.os_win_sub}</span></button>
            </div>
          </div>
        ) : (
          <div>
            <div className="md-chat-log">
              {messages.map((msg, i) => (<div key={i} className={'md-msg md-msg-' + msg.role}>{msg.content}</div>))}
              {loading ? <div className="md-msg md-msg-assistant md-msg-loading">{ct.sending}</div> : null}
              {needContact ? <button className="md-btn md-btn-primary md-chat-contact" type="button" onClick={onOpenContact}>{ct.contact} <span aria-hidden="true">→</span></button> : null}
              {m === 'setup' && stepId && messages.length ? <button className="md-back-checks" type="button" onClick={() => mdGo(lp('/md/guia'))}>{ct.back_checks}</button> : null}
            </div>
            {messages.length === 0 && chips.length ? (
              <div className="md-chips"><div className="md-chips-label">{ct.try_label}</div>{chips.map((c, i) => (<button key={i} className="md-chip" type="button" onClick={() => send(c)}>{c}</button>))}</div>
            ) : null}
            <div className="md-composer">
              <textarea className="md-composer-input" maxLength={500} rows={2} placeholder={ct.placeholder} value={input} onChange={(ev) => setInput(ev.target.value)} onKeyDown={onKey} />
              <button className="md-btn md-btn-primary" type="button" onClick={() => send()} disabled={loading || !input.trim()}>{loading ? ct.sending : ct.send}</button>
            </div>
            <p className="md-chat-disc">{ct.disclaimer}</p>
          </div>
        )}
      </div>
    </MdChrome>
  );
}

function MdGuide({ lang, onOpenContact }) {
  const g = MD_GT[lang] || MD_GT.pt;
  const lp = (p) => window.localePath(p, lang);
  const saved = mdGetGuideStep();
  const [stage, setStage] = useStateMd(saved != null ? 'steps' : 'welcome');
  const [cur, setCur] = useStateMd(saved != null ? Math.min(saved, MD_GUIDE.length - 1) : 0);
  const confirm = () => { if (cur + 1 >= MD_GUIDE.length) { setStage('done'); mdSetGuideStep(null); } else { const n = cur + 1; setCur(n); mdSetGuideStep(n); } };
  const checklist = (n) => (
    <div className="md-guide-checklist">{MD_GUIDE.slice(0, n).map((s) => (<div key={s.id} className="md-guide-chip">✓ {(s.t[lang] || s.t.pt).h}</div>))}</div>
  );
  return (
    <MdChrome lang={lang}>
      <div className="md-container md-section md-guide">
        <div className="md-breadcrumb"><a href={lp('/md')} data-spa="1">{g.back}</a></div>
        <div className="md-eyebrow md-eyebrow-accent">{g.eyebrow}</div>
        <h1 className="md-title-xl">{stage === 'done' ? g.done_h : g.welcome_h}</h1>
        {stage === 'welcome' ? (
          <div>
            <p className="md-lead md-lead-tight">{g.welcome_p}</p>
            <div className="md-done-row"><button className="md-btn md-btn-primary" type="button" onClick={() => { setStage('steps'); setCur(0); mdSetGuideStep(0); }}>{g.ready} <span aria-hidden="true">→</span></button></div>
          </div>
        ) : stage === 'done' ? (
          <div>
            {checklist(MD_GUIDE.length)}
            <p className="md-lead md-lead-tight">{g.done_p}</p>
            <div className="md-done-row"><a href={lp('/md/exercicios')} data-spa="1" className="md-btn md-btn-primary">{g.go_ex} <span aria-hidden="true">→</span></a></div>
          </div>
        ) : (
          <div>
            {checklist(cur)}
            <div className="md-guide-step">
              <div className="md-guide-num">{MD_GUIDE[cur].id}{g.of}</div>
              <h2 className="md-guide-h">{(MD_GUIDE[cur].t[lang] || MD_GUIDE[cur].t.pt).h}</h2>
              <p className="md-body">{(MD_GUIDE[cur].t[lang] || MD_GUIDE[cur].t.pt).p}</p>
              <p className="md-guide-q">{g.q}</p>
              <div className="md-guide-btns">
                <button className="md-btn md-btn-primary" type="button" onClick={confirm}>{g.gotit}</button>
                <button className="md-guide-help" type="button" onClick={() => { mdSetGuideStep(cur); mdGo(lp('/md/chat/setup/' + MD_GUIDE[cur].id)); }}>{g.needhelp}</button>
              </div>
            </div>
          </div>
        )}
      </div>
    </MdChrome>
  );
}

function Md({ sub, id, lang, mode, ex, onOpenContact }) {
  const l = (lang === 'en' || lang === 'es') ? lang : 'pt';
  if (sub === 'guide') return <MdGuide lang={l} onOpenContact={onOpenContact} />;
  if (sub === 'index') return <MdIndex lang={l} />;
  if (sub === 'exercise') return <MdExercise id={id} lang={l} onOpenContact={onOpenContact} />;
  if (sub === 'chat') return <MdChat lang={l} mode={mode} ex={ex} onOpenContact={onOpenContact} />;
  if (sub === 'files') return <MdFiles lang={l} />;
  if (sub === 'help') return <MdHelp lang={l} onOpenContact={onOpenContact} />;
  if (sub === 'privacy') return <MdLegal lang={l} kind="privacy" />;
  if (sub === 'terms') return <MdLegal lang={l} kind="terms" />;
  return <MdHome lang={l} />;
}

window.Md = Md;
