---
import BaseLayout from '../layouts/BaseLayout.astro';
import InstallTabs from '../components/InstallTabs.astro';

// Install page rebuilt 2026-04-26 for the AI-agent-first happy
// path.  Three steps: install -> connect agent -> ask.  The legacy
// CLI tour (kiln setup / verify / status / serve) is hidden because
// the agent's MCP runtime invokes those itself once the JSON config
// is pasted; users who want to drive manually find them in the docs
// + FAQ.  The advanced tabs (pipx / source / one-line installer)
// stay reachable behind a <details> disclosure so the happy path on
// top stays visually tight.
//
// Pro CTA routes to /pricing, NOT direct-to-Stripe, so the
// commercial-use modal in pricing.astro can route Etsy / Shopify
// sellers to Business instead of shipping them the wrong tier.

const mcpConfig = JSON.stringify({
  mcpServers: {
    kiln: {
      command: "python3",
      args: ["-m", "kiln", "serve"]
    }
  }
}, null, 2);

const mcpConfigCompact = JSON.stringify({
  mcpServers: {
    kiln: {
      command: "python3",
      args: ["-m", "kiln", "serve"]
    }
  }
});

const installHowToSchema = {
  '@type': 'HowTo',
  name: 'How to install Kiln for AI-powered 3D printing',
  description:
    'Install Kiln, connect any MCP-capable AI agent, and ask it to design and print an object.',
  totalTime: 'PT3M',
  step: [
    {
      '@type': 'HowToStep',
      name: 'Install Kiln',
      text: 'Install Kiln by pasting pip install kiln3d into your AI agent or terminal.',
      url: 'https://kiln3d.com/install',
    },
    {
      '@type': 'HowToStep',
      name: 'Connect your AI',
      text: 'Paste the Kiln MCP server config into Claude Desktop, Claude Code, Codex, or any MCP-capable agent.',
      url: 'https://kiln3d.com/install',
    },
    {
      '@type': 'HowToStep',
      name: 'Ask',
      text: 'Paste a sentence describing the object you want into your agent. Kiln designs, slices, and prints it.',
      url: 'https://kiln3d.com/install',
    },
  ],
};
---

<BaseLayout
  title="Install Kiln — AI 3D Printing Infrastructure"
  description="Install Kiln in three minutes on macOS, Windows, Linux, or WSL 2. Connect any MCP-capable AI agent (Claude Desktop, Claude Code, Codex) and ask it to make something."
  current="install"
  keywords={[
    'install kiln',
    'kiln setup',
    'kiln mcp server',
    '3d printer ai setup',
    'octoprint ai agent tools',
  ]}
  schema={installHowToSchema}
>
  <!-- Mini-hero — paradigm echo from the landing page.  One
       sentence, sized to match the .receipts-heading typography on
       index.astro so /install reads as the next sentence in the
       same conversation the visitor started one click ago. -->
  <section class="install-hero">
    <div class="container">
      <h1 class="install-headline">Three minutes. Then ask your AI to make something.</h1>
    </div>
  </section>

  <!-- Three steps — install, connect, ask.  Each step exposes one
       copyable line (or one config block) and zero extra ceremony. -->
  <section class="install-steps">
    <div class="container">
      <ol class="steps">
        <li>
          <div class="step-number">1</div>
          <div class="step-content">
            <h3>Install Kiln</h3>
            <p>Pick your platform &mdash; each tab has copy-paste commands.</p>
            <InstallTabs />
          </div>
        </li>
        <li>
          <div class="step-number">2</div>
          <div class="step-content">
            <h3>Connect your AI</h3>
            <p>Paste this into Claude Desktop, Claude Code, Codex, or any MCP-capable agent.</p>
            <div class="code-block">
              <button class="copy-btn" data-code={mcpConfigCompact}>Copy</button>
              <pre><code set:text={mcpConfig} /></pre>
            </div>
          </div>
        </li>
        <li>
          <div class="step-number">3</div>
          <div class="step-content">
            <h3>Ask</h3>
            <p>Paste any sentence like this into your agent.  Kiln does the rest.</p>
            <blockquote class="example-prompt">I have a Bambu A1, make me a coaster with my dog&rsquo;s photo on it</blockquote>
          </div>
        </li>
      </ol>
    </div>
  </section>

  <!-- Pro CTA — post-value, not pre-value.  Free tier covers the
       first prints; Pro is framed as graduation to the full
       workflow, not a gate.  Button routes to /pricing so the
       commercial-use modal there can move Etsy/Shopify sellers to
       Business.  Single button, single price; tier comparison
       happens at /pricing. -->
  <section class="pro-cta-section">
    <div class="container">
      <div class="pro-cta-card">
        <h2 class="pro-cta-headline">You&rsquo;re ready to print.</h2>
        <p class="pro-cta-body">
          Free covers your first prints.  Pro covers the rest of the
          workflow &mdash; version your designs, modify them mid-print,
          and leave the room while your agent handles the rest.
        </p>
        <a href="/pricing" class="btn pro-cta-btn">Get Pro &rarr;</a>
        <p class="pro-cta-price">$49 / month</p>
        <p class="pro-cta-signin">
          Or <a href="https://app.kiln3d.com/connect">sign in free &rarr;</a>
        </p>
      </div>
    </div>
  </section>

  <!-- Quiet footnote link — the page's last shout is the Pro CTA
       above; this is a one-line footnote that routes the stuck
       visitor to the canonical FAQ page rather than re-rendering
       the questions inline.  Anchor lands inside the Setup &
       Troubleshooting section so the visitor doesn't have to
       scroll past the General questions to find help. -->
  <section class="faq-link-section">
    <div class="container">
      <p class="faq-link">
        Stuck on install? <a href="/faq#setup-troubleshooting">See common questions &rarr;</a>
      </p>
    </div>
  </section>
</BaseLayout>

<style>
  /* Mini-hero — single sentence sized to match the landing page's
     .receipts-heading so the visitor reads /install as the next
     beat in the same voice. */
  .install-hero {
    text-align: center;
    padding: 100px 0 64px;
  }
  .install-headline {
    font-size: clamp(28px, 4vw, 48px);
    font-weight: 800;
    line-height: 1.1;
    letter-spacing: -0.022em;
    color: var(--text);
    max-width: 780px;
    margin: 0 auto;
    text-wrap: balance;
  }

  /* Three-step list — same .step-number / .step-content shape the
     legacy install page used so the typography stays familiar. */
  .install-steps {
    padding: 16px 0 56px;
  }
  .steps {
    list-style: none;
    padding: 0;
    display: flex;
    flex-direction: column;
    gap: 0;
  }
  .steps li {
    display: flex;
    gap: 24px;
    padding: 36px 0;
    border-bottom: 1px solid var(--border);
  }
  .steps li:last-child {
    border-bottom: none;
  }
  .step-number {
    flex-shrink: 0;
    width: 36px;
    height: 36px;
    display: flex;
    align-items: center;
    justify-content: center;
    border-radius: 50%;
    background: rgba(255, 107, 43, 0.1);
    color: var(--accent);
    font-weight: 600;
    font-size: 14px;
    border: 1px solid rgba(255, 107, 43, 0.25);
  }
  .step-content {
    flex: 1;
    min-width: 0;
  }
  .step-content h3 {
    font-size: 17px;
    font-weight: 600;
    margin-bottom: 6px;
  }
  .step-content p {
    font-size: 14px;
    color: var(--text-muted);
    margin-bottom: 4px;
    line-height: 1.6;
  }
  .step-content .code-block {
    margin: 12px 0 0;
  }
  .step-content pre {
    margin: 0;
    white-space: pre;
  }
  .step-content pre code {
    font-family: var(--mono);
    font-size: 13px;
    line-height: 1.7;
    color: var(--text);
    background: transparent;
    padding: 0;
    border: none;
  }
  /* Example prompt (Step 3) — chat-bubble shape, accent left
     border, italic so the visitor parses it as "what you'd say to
     your AI" rather than as another code block. */
  .example-prompt {
    display: inline-block;
    margin: 14px 0 0;
    padding: 14px 22px;
    background: rgba(255, 107, 43, 0.06);
    border: 1px solid rgba(255, 107, 43, 0.2);
    border-left: 3px solid var(--accent);
    border-radius: 10px;
    font-style: italic;
    font-size: 15px;
    color: var(--text);
    line-height: 1.5;
    quotes: "\201C" "\201D";
  }
  .example-prompt::before { content: open-quote; }
  .example-prompt::after { content: close-quote; }

  /* Pro CTA card — single floating card, post-value placement.
     One button, one price, no tier table; tier comparison + the
     commercial-use modal both live at /pricing. */
  .pro-cta-section {
    padding: 16px 0 64px;
  }
  .pro-cta-card {
    max-width: 640px;
    margin: 0 auto;
    text-align: center;
    padding: 44px 36px;
    border: 1px solid var(--border);
    border-radius: 14px;
    background: var(--bg-card);
  }
  .pro-cta-headline {
    font-size: 28px;
    font-weight: 700;
    letter-spacing: -0.015em;
    margin: 0 0 16px;
    color: var(--text);
  }
  .pro-cta-body {
    font-size: 15px;
    color: var(--text-muted);
    line-height: 1.65;
    margin: 0 auto 24px;
    max-width: 480px;
    text-wrap: pretty;
  }
  .pro-cta-btn {
    display: inline-block;
    padding: 12px 28px;
    font-size: 15px;
    font-weight: 600;
  }
  .pro-cta-price {
    font-size: 13px !important;
    color: var(--text-muted);
    margin: 12px 0 0 !important;
    letter-spacing: 0.01em;
  }

  /* Free-tier escape hatch — sits below the Pro price line as a
     tertiary aside in the same eye-position as the Pro CTA button.
     Muted styling matches the .faq-link footnote pattern (dashed
     underline, text-muted, accent-on-hover) so it reads as "not
     ready yet, here's the free path" rather than as a second CTA
     competing with Get Pro. */
  .pro-cta-signin {
    font-size: 13px;
    color: var(--text-muted);
    margin: 10px 0 0;
    letter-spacing: 0.01em;
  }
  .pro-cta-signin a {
    color: var(--text-muted);
    text-decoration: none;
    border-bottom: 1px dashed var(--border);
    padding-bottom: 1px;
    transition: color 0.15s, border-color 0.15s;
  }
  .pro-cta-signin a:hover {
    color: var(--accent);
    border-bottom-color: var(--accent);
  }

  /* Quiet FAQ link footnote — sits below the Pro CTA + advanced
     install disclosure as a single muted line.  Centered, small,
     no border, no card.  It doesn't compete with the Pro
     CTA's confidence; reads like a polite aside. */
  .faq-link-section {
    padding: 8px 0 80px;
  }
  .faq-link {
    text-align: center;
    font-size: 14px;
    color: var(--text-muted);
    margin: 0;
  }
  .faq-link a {
    color: var(--text-muted);
    text-decoration: none;
    border-bottom: 1px dashed var(--border);
    padding-bottom: 1px;
    transition: color 0.15s, border-color 0.15s;
  }
  .faq-link a:hover {
    color: var(--accent);
    border-bottom-color: var(--accent);
  }

  @media (max-width: 640px) {
    .install-hero {
      padding: 72px 0 40px;
    }
    .steps li {
      flex-direction: column;
      gap: 12px;
      padding: 28px 0;
    }
    .pro-cta-card {
      padding: 32px 20px;
    }
    .pro-cta-headline {
      font-size: 24px;
    }
  }
</style>

<script>
  // Copy-to-clipboard for all code blocks on the page
  document.querySelectorAll('.copy-btn').forEach((btn) => {
    btn.addEventListener('click', async () => {
      const code = btn.getAttribute('data-code') || '';
      try {
        await navigator.clipboard.writeText(code);
        const original = btn.textContent;
        btn.textContent = 'Copied!';
        btn.style.borderColor = 'var(--accent)';
        btn.style.color = 'var(--accent)';
        setTimeout(() => {
          btn.textContent = original;
          btn.style.borderColor = '';
          btn.style.color = '';
        }, 1500);
      } catch {
        // Fallback for non-HTTPS contexts
        const textarea = document.createElement('textarea');
        textarea.value = code;
        textarea.style.position = 'fixed';
        textarea.style.opacity = '0';
        document.body.appendChild(textarea);
        textarea.select();
        document.execCommand('copy');
        document.body.removeChild(textarea);
        const original = btn.textContent;
        btn.textContent = 'Copied!';
        setTimeout(() => { btn.textContent = original; }, 1500);
      }
    });
  });
</script>
