/* global React, ReactDOM */
const { useState, useEffect, useRef } = React

const TWEAK_DEFAULTS = /*EDITMODE-BEGIN*/ {
  density: 'comfortable',
  accent: '#ED8C1F',
  heroStyle: 'split',
} /*EDITMODE-END*/

const SECTIONS = [
  { id: 'overview', label: 'Overview' },
  { id: 'quick-start', label: 'Quick start' },
  { id: 'connectors', label: 'Connect a client' },
  { id: 'authentication', label: 'Authentication' },
  { id: 'permissions', label: 'Permissions & user roles' },
  { id: 'endpoints', label: 'Endpoints & transport' },
  { id: 'capabilities', label: 'Tool capabilities' },
  { id: 'safety', label: 'Safe usage' },
  { id: 'gdpr', label: 'Guest data & GDPR' },
  { id: 'faq', label: 'FAQ' },
]

const N8N_OAUTH_JSON = `{
  "nodes": [
    {
      "parameters": {
        "endpointUrl": "https://mcp.apaleo.com/mcp",
        "authentication": "mcpOAuth2Api",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.mcpClientTool",
      "typeVersion": 1.2,
      "position": [752, 224],
      "id": "64321b60-7acd-4b74-9d69-76d12bb2a1e5",
      "name": "Apaleo MCP Client"
    }
  ],
  "connections": {
    "Apaleo MCP Client": { "ai_tool": [[]] }
  },
  "pinData": {},
  "meta": { "templateCredsSetupCompleted": true }
}`

const N8N_BEARER_JSON = `{
  "nodes": [
    {
      "parameters": {
        "endpointUrl": "https://mcp.apaleo.com/mcp",
        "serverTransport": "httpStreamable",
        "authentication": "bearerAuth",
        "include": "selected",
        "includeTools": "={{ [\\"ListProperties\\"] }}",
        "options": {}
      },
      "type": "@n8n/n8n-nodes-langchain.mcpClientTool",
      "typeVersion": 1.1,
      "position": [880, 688],
      "id": "8e32b074-cca1-46d9-a403-3cb18ae4ade5",
      "name": "MCP Client",
      "credentials": {
        "httpBearerAuth": { "id": "cznFyIx8gEmmmhtT", "name": "Test_Bearer" }
      }
    },
    {
      "parameters": {
        "method": "POST",
        "url": "https://identity.apaleo.com/connect/token",
        "authentication": "genericCredentialType",
        "genericAuthType": "httpBasicAuth",
        "sendBody": true,
        "contentType": "form-urlencoded",
        "specifyBody": "string",
        "body": "grant_type=client_credentials",
        "options": {}
      },
      "type": "n8n-nodes-base.httpRequest",
      "typeVersion": 4.2,
      "position": [96, 416],
      "id": "69a10f05-f1c2-45ae-b7fe-bfe82132e3a9",
      "name": "Get Access Token"
    }
  ],
  "connections": {
    "MCP Client": { "ai_tool": [[{ "node": "AI Agent", "type": "ai_tool", "index": 0 }]] },
    "Get Access Token": { "main": [[{ "node": "AI Agent", "type": "main", "index": 0 }]] }
  },
  "pinData": {},
  "meta": { "templateCredsSetupCompleted": true }
}`

// ── TOC (matches Claude-plugin docs pattern) ──
function TOC({ active }) {
  const [helpOpen, setHelpOpen] = useState(false)
  const popRef = useRef(null)
  useEffect(() => {
    if (!helpOpen) return
    const onDoc = (e) => {
      if (popRef.current && !popRef.current.contains(e.target))
        setHelpOpen(false)
    }
    const onKey = (e) => {
      if (e.key === 'Escape') setHelpOpen(false)
    }
    document.addEventListener('mousedown', onDoc)
    document.addEventListener('keydown', onKey)
    return () => {
      document.removeEventListener('mousedown', onDoc)
      document.removeEventListener('keydown', onKey)
    }
  }, [helpOpen])
  return (
    <nav className="toc">
      <div className="toc-label">On this page</div>
      <ul>
        {SECTIONS.map((s) => (
          <li key={s.id} className={active === s.id ? 'active' : ''}>
            <a href={`#${s.id}`}>{s.label}</a>
          </li>
        ))}
      </ul>
      <div
        className={`toc-foot toc-foot-pop ${helpOpen ? 'open' : ''}`}
        ref={popRef}
      >
        <div className="toc-foot-label">Need help?</div>
        <button
          type="button"
          className="toc-foot-link toc-foot-trigger"
          onClick={() => setHelpOpen((o) => !o)}
          aria-expanded={helpOpen}
          aria-haspopup="menu"
        >
          <MIcon name="mail" size={14} /> Contact the team
          <MIcon name="expand_more" size={14} />
        </button>
        <div className="toc-foot-menu" role="menu" aria-hidden={!helpOpen}>
          <a
            href="mailto:support@apaleo.com"
            role="menuitem"
            onClick={() => setHelpOpen(false)}
          >
            <span className="toc-foot-menu-ico">
              <MIcon name="mail" size={16} color="#ED8C1F" />
            </span>
            <span>
              <span className="toc-foot-menu-title">Email support</span>
              <span className="toc-foot-menu-sub">support@apaleo.com</span>
            </span>
          </a>
          <a
            href="https://apaleo.dev/index.html"
            target="_blank"
            rel="noreferrer"
            role="menuitem"
            onClick={() => setHelpOpen(false)}
          >
            <span className="toc-foot-menu-ico">
              <MIcon name="open_in_new" size={16} color="#ED8C1F" />
            </span>
            <span>
              <span className="toc-foot-menu-title">Developer portal</span>
              <span className="toc-foot-menu-sub">apaleo.dev</span>
            </span>
          </a>
        </div>
      </div>
    </nav>
  )
}

// ── Hero ──
function Hero({ heroStyle }) {
  return (
    <header className={`hero hero-${heroStyle}`}>
      <div className="hero-inner">
        <div className="hero-copy">
          <div className="hero-eyebrow">
            <span className="hero-eyebrow-text">Apaleo MCP server</span>
          </div>
          <h1 className="hero-title">
            Run your property from{' '}
            <span className="hero-em">Claude, ChatGPT, or your own tools</span>.
          </h1>
          <p className="hero-sub">
            The Apaleo MCP server lets AI assistants like Claude and ChatGPT
            work directly with your Apaleo data — check arrivals, pull reports,
            amend reservations, and more — using a secure sign-in, the
            permissions you set, and around 230 actions across booking, finance,
            inventory, and operations.
          </p>
          <div className="hero-actions">
            <a href="#quick-start" className="btn btn-primary">
              Get started <MIcon name="arrow_forward" size={16} />
            </a>
            <a href="#connectors" className="btn btn-secondary">
              Connect a client
            </a>
          </div>
          <div className="hero-meta hero-meta-tight">
            <span>
              <MIcon name="cable" size={14} /> Streamable HTTP
            </span>
            <span>
              <MIcon name="lock" size={14} /> OAuth 2.0
            </span>
            <span>
              <MIcon name="hub" size={14} /> ~230 tools
            </span>
          </div>
        </div>
        <div className="hero-visual">
          <div className="hero-terminal">
            <div className="hero-terminal-head">
              <span className="dots">
                <span />
                <span />
                <span />
              </span>
              <span>mcp.apaleo.com</span>
              <span className="pill">Streamable HTTP</span>
            </div>
            <div className="hero-terminal-body">
              <div className="row">
                <span className="com"># tools/list — abbreviated</span>
              </div>
              <div className="row">
                <span className="pun">{'{'}</span>
              </div>
              <div className="row">
                &nbsp;&nbsp;<span className="key">"server"</span>
                <span className="pun">:</span>{' '}
                <span className="str">"apaleo-mcp"</span>
                <span className="pun">,</span>
              </div>
              <div className="row">
                &nbsp;&nbsp;<span className="key">"transport"</span>
                <span className="pun">:</span>{' '}
                <span className="str">"http+stream"</span>
                <span className="pun">,</span>
              </div>
              <div className="row">
                &nbsp;&nbsp;<span className="key">"auth"</span>
                <span className="pun">:</span>{' '}
                <span className="str">"oauth2"</span>
                <span className="pun">,</span>
              </div>
              <div className="row">
                &nbsp;&nbsp;<span className="key">"tools"</span>
                <span className="pun">:</span> <span className="pun">[</span>
              </div>
              <div className="row">
                &nbsp;&nbsp;&nbsp;&nbsp;
                <span className="str">"ListProperties"</span>
                <span className="pun">,</span>
              </div>
              <div className="row">
                &nbsp;&nbsp;&nbsp;&nbsp;
                <span className="str">"GetReservation"</span>
                <span className="pun">,</span>
              </div>
              <div className="row">
                &nbsp;&nbsp;&nbsp;&nbsp;
                <span className="str">"AssignUnit"</span>
                <span className="pun">,</span>
              </div>
              <div className="row">
                &nbsp;&nbsp;&nbsp;&nbsp;
                <span className="str">"PostFolioCharges"</span>
                <span className="pun">,</span>
              </div>
              <div className="row">
                &nbsp;&nbsp;&nbsp;&nbsp;
                <span className="com">/* …226 more */</span>
              </div>
              <div className="row">
                &nbsp;&nbsp;<span className="pun">]</span>
              </div>
              <div className="row">
                <span className="pun">{'}'}</span>
              </div>
              <div className="row" style={{ marginTop: 8 }}>
                <span className="ok">✓ ready</span>{' '}
                <span className="com">— sign in via OAuth to call tools</span>
              </div>
            </div>
          </div>
        </div>
      </div>
    </header>
  )
}

// ── Connector tabs section ──
const CONNECTORS = [
  { id: 'claude', label: 'Claude', logo: 'claude' },
  { id: 'chatgpt', label: 'ChatGPT', logo: 'chatgpt' },
  { id: 'n8n', label: 'n8n', logo: 'n8n' },
]

// Animation embed that only loads (and thus starts playing) once scrolled into
// view — keeps the multi-MB bundle off the initial load and syncs playback to
// the reader reaching the section. The iframe stays hidden behind a calm
// placeholder until the bundle has finished booting and painted its first
// frame, so the unpack/compile/font-swap flash never shows.
function AnimFrame({ src, title }) {
  const ref = useRef(null)
  const stageMeta = useRef(null) // { root, rk, duration } — handle to the iframe's Stage
  const didInit = useRef(false)
  const [load, setLoad] = useState(false)
  const [ready, setReady] = useState(false)
  const [hasControls, setHasControls] = useState(false)
  const [playing, setPlaying] = useState(true)
  const [progress, setProgress] = useState(0)
  const playingRef = useRef(true) // mirrors state so the rAF loop skips no-op re-renders
  const progressRef = useRef(0)
  const draggingRef = useRef(false)
  const wasPlayingRef = useRef(false)
  const reduced =
    typeof matchMedia === 'function' &&
    matchMedia('(prefers-reduced-motion: reduce)').matches

  useEffect(() => {
    if (load || !ref.current) return
    const io = new IntersectionObserver(
      (entries) => {
        if (entries.some((e) => e.isIntersecting)) {
          setLoad(true)
          io.disconnect()
        }
      },
      { threshold: 0.35 },
    )
    io.observe(ref.current)
    return () => io.disconnect()
  }, [load])

  // ponytail: the exported animations run the design tool's <Stage> runtime,
  // which owns a play/pause/scrub timeline in React state but renders no
  // controls. Same-origin lets us reach its state hooks via the fiber to drive
  // the same player the roles demo (McpAccessDemo) has. Ceiling: depends on the
  // export's Stage hook order (time, playing, …); if that changes, readStage
  // returns null, controls stay hidden, and the animation just autoplays.
  const readStage = () => {
    const m = stageMeta.current
    if (!m) return null
    let stage = null,
      n = 0
    const stack = [m.root[m.rk]]
    while (stack.length) {
      const f = stack.pop()
      if (!f || n++ > 5000) break
      if (f.type && f.type.name === 'Stage') {
        stage = f
        break
      }
      if (f.child) stack.push(f.child)
      if (f.sibling) stack.push(f.sibling)
    }
    if (!stage) return null
    const hooks = []
    let h = stage.memoizedState
    while (h) {
      if (h.queue && typeof h.queue.dispatch === 'function') hooks.push(h)
      h = h.next
    }
    if (hooks.length < 2) return null
    return {
      time: hooks[0].memoizedState,
      playing: hooks[1].memoizedState,
      duration: m.duration,
      setTime: (v) => hooks[0].queue.dispatch(v),
      setPlaying: (v) => hooks[1].queue.dispatch(v),
    }
  }

  // Reveal only once the app has mounted: its loading placeholder is removed and
  // the scene has actually rendered content (Stage canvas or dc-runtime root).
  const onLoad = (e) => {
    const frame = e.target
    let tries = 0
    const check = () => {
      let done
      try {
        const d = frame.contentDocument
        done =
          !!d &&
          !d.getElementById('__bundler_thumbnail') &&
          (!!d.querySelector(
            'svg[data-om-exportable-video-with-duration-secs]',
          ) ||
            (!!d.querySelector('#dc-root') &&
              d.querySelector('#dc-root').querySelectorAll('*').length > 15))
      } catch {
        done = true
      } // cross-origin (shouldn't happen same-site): just show it
      if (done) {
        try {
          const d = frame.contentDocument
          const root = d && d.querySelector('#dc-root')
          const rk =
            root &&
            Object.keys(root).find((k) => k.startsWith('__reactContainer$'))
          const svg =
            d && d.querySelector('svg[data-om-exportable-video-with-duration-secs]')
          const duration = svg
            ? +svg.getAttribute('data-om-exportable-video-with-duration-secs') || 0
            : 0
          if (rk && duration > 0) stageMeta.current = { root, rk, duration }
        } catch {}
        setTimeout(() => setReady(true), 120) // let the first frame settle
      } else if (++tries < 200) setTimeout(check, 100)
      else setReady(true) // safety net (~20s)
    }
    check()
  }

  // rAF-sync the play button + scrub bar to the Stage timeline. rAF (not a
  // 100ms poll) keeps the fill gliding at frame rate; the refs gate setState so
  // an idle/paused animation triggers no re-renders.
  useEffect(() => {
    if (!ready) return
    let alive = true,
      raf
    const tick = () => {
      if (!alive) return
      const s = readStage()
      if (s) {
        setHasControls(true)
        if (!didInit.current) {
          didInit.current = true
          s.setTime(0) // Stage autoplays during boot — rewind so it always starts at 0
          if (reduced) s.setPlaying(false)
        }
        if (!draggingRef.current) {
          if (s.playing !== playingRef.current) {
            playingRef.current = s.playing
            setPlaying(s.playing)
          }
          const p = s.duration ? Math.min(1, s.time / s.duration) : 0
          if (Math.abs(p - progressRef.current) > 0.0005) {
            progressRef.current = p
            setProgress(p)
          }
        }
      }
      raf = requestAnimationFrame(tick)
    }
    raf = requestAnimationFrame(tick)
    return () => {
      alive = false
      cancelAnimationFrame(raf)
    }
  }, [ready])

  const togglePlay = () => {
    const s = readStage()
    if (!s) return
    const next = !s.playing
    // pressing play at the end replays from the start rather than sticking
    if (next && s.duration && s.time >= s.duration - 0.05) s.setTime(0)
    s.setPlaying(next)
  }
  const seekTo = (clientX, rect) => {
    const s = readStage()
    if (!s) return
    const frac = Math.max(0, Math.min(1, (clientX - rect.left) / rect.width))
    s.setTime(frac * s.duration)
    progressRef.current = frac
    setProgress(frac)
  }
  const onScrubDown = (e) => {
    const s = readStage()
    if (!s) return
    e.currentTarget.setPointerCapture(e.pointerId)
    draggingRef.current = true
    wasPlayingRef.current = s.playing
    if (s.playing) s.setPlaying(false) // pause while scrubbing so it doesn't fight the drag
    seekTo(e.clientX, e.currentTarget.getBoundingClientRect())
  }
  const onScrubMove = (e) => {
    if (draggingRef.current) seekTo(e.clientX, e.currentTarget.getBoundingClientRect())
  }
  const onScrubUp = (e) => {
    if (!draggingRef.current) return
    draggingRef.current = false
    try {
      e.currentTarget.releasePointerCapture(e.pointerId)
    } catch {}
    if (wasPlayingRef.current) {
      const s = readStage()
      if (s) s.setPlaying(true) // resume if it was playing before the drag
    }
  }

  return (
    <div ref={ref} className={`anim-frame${ready ? ' is-ready' : ''}`}>
      {load && <iframe src={src} title={title} onLoad={onLoad} />}
      {hasControls && (
        <div className="anim-controls">
          <button
            type="button"
            className="anim-play"
            aria-label={playing ? 'Pause' : 'Play'}
            onClick={togglePlay}
          >
            <MIcon name={playing ? 'pause' : 'play_arrow'} size={18} />
          </button>
          <div
            className="anim-scrub"
            onPointerDown={onScrubDown}
            onPointerMove={onScrubMove}
            onPointerUp={onScrubUp}
            onPointerCancel={onScrubUp}
          >
            <div className="anim-track">
              <div className="anim-fill" style={{ width: `${progress * 100}%` }}>
                <span className="anim-thumb" />
              </div>
            </div>
          </div>
        </div>
      )}
    </div>
  )
}

function ConnectorTabs() {
  const [active, setActive] = useState('claude')
  const [n8nMode, setN8nMode] = useState('oauth')
  return (
    <>
      <div className="connectors-tabs" role="tablist">
        {CONNECTORS.map((c) => (
          <button
            key={c.id}
            className={active === c.id ? 'is-active' : ''}
            onClick={() => setActive(c.id)}
            role="tab"
          >
            <BrandLogo name={c.logo} size={16} />
            {c.label}
          </button>
        ))}
      </div>

      {/* Claude */}
      <div
        className={`connector-panel ${active === 'claude' ? 'is-active' : ''}`}
      >
        <p className="sec-body">
          Connect the Apaleo MCP server as a remote custom connector in Claude.
        </p>
        <figure className="video-figure">
          <AnimFrame
            src="assets/claude-connect.html"
            title="Connecting Apaleo MCP in Claude"
          />
          <figcaption>
            <MIcon name="play_circle" size={16} />
            Walkthrough — adding Apaleo MCP as a remote connector in Claude.
          </figcaption>
        </figure>
        <ol className="sub-steps">
          <li>
            <span className="sub-num">1</span>
            <div>
              <div className="sub-title">Open Claude's connector page</div>
              <div className="sub-body">Add a new remote MCP connector.</div>
              <a
                className="step-cta"
                href="https://claude.ai/settings/connectors"
                target="_blank"
                rel="noreferrer"
              >
                <BrandLogo name="claude" size={14} />
                Open Claude connectors
                <MIcon name="open_in_new" size={14} />
              </a>
            </div>
          </li>
          <li>
            <span className="sub-num">2</span>
            <div>
              <div className="sub-title">Enter the connection details</div>
              <div className="kv">
                <div className="k">Name</div>
                <div>
                  <CopyCode mono={false} label="name">
                    Apaleo MCP
                  </CopyCode>
                </div>
                <div className="k">Remote MCP server URL</div>
                <div>
                  <CopyCode label="server URL">
                    https://mcp.apaleo.com/mcp
                  </CopyCode>
                </div>
                <div className="k">Client ID / Secret</div>
                <div>
                  Leave empty unless you want to use a specific client — see{' '}
                  <a href="#authentication">Authentication</a>.
                </div>
              </div>
            </div>
          </li>
          <li>
            <span className="sub-num">3</span>
            <div>
              <div className="sub-title">Connect &amp; approve</div>
              <div className="sub-body">
                Select the connection, press <kbd>Connect</kbd>, and approve the
                requested permissions on the redirected sign-in page.
              </div>
            </div>
          </li>
          <li>
            <span className="sub-num">4</span>
            <div>
              <div className="sub-title">
                Adjust tool permissions{' '}
                <span className="tag tag-warn" style={{ marginLeft: 6 }}>
                  Recommended
                </span>
              </div>
              <div className="sub-body">
                You can block specific tools entirely, or have Claude ask for
                approval before using them. Gate any write tool while you're
                experimenting.
              </div>
              <figure className="video-figure" style={{ marginTop: 12 }}>
                <AnimFrame
                  src="assets/tool-permissions.html"
                  title="Setting tool permissions for Apaleo MCP in Claude"
                />
                <figcaption>
                  <MIcon name="tune" size={16} />
                  Tool permissions — set each tool to <em>
                    Needs approval
                  </em> or <em>Blocked</em>.
                </figcaption>
              </figure>
            </div>
          </li>
        </ol>
        <Callout kind="info" title="Heads up">
          Claude's screens may look a little different over time, but you only
          ever need two things: the server URL above and your Apaleo sign-in.
        </Callout>
      </div>

      {/* ChatGPT */}
      <div
        className={`connector-panel ${active === 'chatgpt' ? 'is-active' : ''}`}
      >
        <p className="sec-body">
          Connect the Apaleo MCP server as a custom connector in ChatGPT.
        </p>
        <figure className="video-figure">
          <AnimFrame
            src="assets/chatgpt-connect.html"
            title="Connecting Apaleo MCP in ChatGPT"
          />
          <figcaption>
            <MIcon name="play_circle" size={16} />
            Walkthrough — adding Apaleo MCP as a custom connector in ChatGPT.
          </figcaption>
        </figure>
        <ol className="sub-steps">
          <li>
            <span className="sub-num">1</span>
            <div>
              <div className="sub-title">Enable Developer mode</div>
              <div className="sub-body">
                Open ChatGPT's <kbd>Advanced settings</kbd> and turn on
                Developer mode, then press <kbd>Create app</kbd>.
              </div>
              <a
                className="step-cta"
                href="https://chatgpt.com/#settings/Connectors"
                target="_blank"
                rel="noreferrer"
              >
                <BrandLogo name="chatgpt" size={14} />
                Open ChatGPT connectors
                <MIcon name="open_in_new" size={14} />
              </a>
            </div>
          </li>
          <li>
            <span className="sub-num">2</span>
            <div>
              <div className="sub-title">Enter the details</div>
              <div className="kv">
                <div className="k">Name</div>
                <div>
                  <CopyCode mono={false} label="name">
                    Apaleo MCP
                  </CopyCode>
                </div>
                <div className="k">MCP Server URL</div>
                <div>
                  <CopyCode label="server URL">
                    https://mcp.apaleo.com/mcp
                  </CopyCode>
                </div>
                <div className="k">Client ID / Secret</div>
                <div>
                  Leave empty unless using a specific client — see{' '}
                  <a href="#authentication">Authentication</a>.
                </div>
              </div>
            </div>
          </li>
          <li>
            <span className="sub-num">3</span>
            <div>
              <div className="sub-title">Approve permissions</div>
              <div className="sub-body">
                Approve the requested permissions on the redirected page. You're
                ready to go.
              </div>
            </div>
          </li>
          <li>
            <span className="sub-num">4</span>
            <div>
              <div className="sub-title">Use it inside a chat</div>
              <div className="sub-body">
                To specifically use Apaleo MCP, select it inside a conversation
                from the connector switcher.
              </div>
            </div>
          </li>
        </ol>
        <p className="sec-body">
          <a
            href="https://developers.openai.com/apps-sdk/deploy/connect-chatgpt"
            target="_blank"
            rel="noreferrer"
          >
            Official reference: ChatGPT Apps SDK{' '}
            <MIcon name="open_in_new" size={13} />
          </a>
        </p>
      </div>

      {/* n8n — OAuth or Bearer */}
      <div className={`connector-panel ${active === 'n8n' ? 'is-active' : ''}`}>
        <p className="sec-body">
          Two ways to connect from n8n: an interactive <strong>OAuth</strong>{' '}
          flow for personal workflows, or a{' '}
          <strong>service-to-service bearer</strong> flow for headless agents.
        </p>
        <div
          className="n8n-modes"
          role="tablist"
          aria-label="n8n connection modes"
        >
          <button
            type="button"
            role="tab"
            aria-selected={n8nMode === 'oauth'}
            className={`n8n-mode ${n8nMode === 'oauth' ? 'is-active' : ''}`}
            onClick={() => setN8nMode('oauth')}
          >
            <MIcon name="login" size={16} />
            <span>
              <span className="n8n-mode-title">OAuth</span>
              <span className="n8n-mode-sub">Interactive sign-in</span>
            </span>
          </button>
          <button
            type="button"
            role="tab"
            aria-selected={n8nMode === 'bearer'}
            className={`n8n-mode ${n8nMode === 'bearer' ? 'is-active' : ''}`}
            onClick={() => setN8nMode('bearer')}
          >
            <MIcon name="key" size={16} />
            <span>
              <span className="n8n-mode-title">Bearer token</span>
              <span className="n8n-mode-sub">Service-to-service</span>
            </span>
          </button>
        </div>

        {n8nMode === 'oauth' && (
          <div className="n8n-mode-panel">
            <ol className="sub-steps">
              <li>
                <span className="sub-num">1</span>
                <div>
                  <div className="sub-title">
                    Drop the MCP Client node into your workflow
                  </div>
                  <div className="sub-body">
                    Paste this JSON onto your canvas — it sets the endpoint and
                    auth type for you.
                  </div>
                  <CodeBlock lang="JSON · n8n node">{N8N_OAUTH_JSON}</CodeBlock>
                </div>
              </li>
              <li>
                <span className="sub-num">2</span>
                <div>
                  <div className="sub-title">Set up the credential</div>
                  <div className="sub-body">
                    Open the node and click <kbd>Set up credential</kbd>. When
                    prompted for the server URL, enter the base URL{' '}
                    <CopyCode label="base URL">
                      https://mcp.apaleo.com/
                    </CopyCode>{' '}
                    here — note there's no <code>/mcp</code> on the end, unlike
                    the endpoint everywhere else.
                  </div>
                </div>
              </li>
              <li>
                <span className="sub-num">3</span>
                <div>
                  <div className="sub-title">Connect &amp; approve</div>
                  <div className="sub-body">
                    Select the new connection, press <kbd>Connect</kbd>, and
                    approve the requested permissions on the redirected page.
                  </div>
                </div>
              </li>
            </ol>
          </div>
        )}

        {n8nMode === 'bearer' && (
          <div className="n8n-mode-panel">
            <p className="sec-body">
              For headless agents, drive MCP from n8n with a service-to-service
              client-credentials flow: an HTTP Request node fetches a token from
              the Apaleo identity server, then the MCP Client node uses it as a
              bearer token.
            </p>
            <Callout kind="info" title="Three credentials needed">
              <strong>HTTP Basic Auth</strong> (Apaleo Client ID / Secret),{' '}
              <strong>OpenAI API Key</strong> (or your model of choice), and a{' '}
              <strong>Bearer Auth</strong> credential whose token is the
              expression
              <code>{'{{$("Get Access Token").item.json.access_token}}'}</code>.
            </Callout>
            <CodeBlock lang="JSON · n8n workflow">{N8N_BEARER_JSON}</CodeBlock>

            <h4
              style={{
                margin: '24px 0 8px',
                font: '500 14px/20px var(--font-ui)',
                color: 'var(--fg1)',
                textTransform: 'uppercase',
                letterSpacing: '0.06em',
              }}
            >
              How the bearer flow works
            </h4>
            <ol className="sub-steps">
              <li>
                <span className="sub-num">1</span>
                <div>
                  <div className="sub-title">Get Access Token</div>
                  <div className="sub-body">
                    HTTP Basic Auth using your Apaleo Client ID + Secret,
                    hitting <code>POST</code>{' '}
                    <CopyCode label="token endpoint">
                      https://identity.apaleo.com/connect/token
                    </CopyCode>{' '}
                    with <code>grant_type=client_credentials</code>.
                  </div>
                </div>
              </li>
              <li>
                <span className="sub-num">2</span>
                <div>
                  <div className="sub-title">Bearer Auth credential</div>
                  <div className="sub-body">
                    References the token from step 1 via{' '}
                    <code>
                      {'{{$("Get Access Token").item.json.access_token}}'}
                    </code>
                    , so it auto-refreshes.
                  </div>
                </div>
              </li>
              <li>
                <span className="sub-num">3</span>
                <div>
                  <div className="sub-title">MCP Client node</div>
                  <div className="sub-body">
                    Uses Streamable HTTP transport against{' '}
                    <CopyCode label="server URL">
                      https://mcp.apaleo.com/mcp
                    </CopyCode>{' '}
                    with the bearer credential.
                  </div>
                </div>
              </li>
            </ol>
          </div>
        )}
      </div>
    </>
  )
}

// ── App ──
function App() {
  const t = window.useTweaks
    ? window.useTweaks(TWEAK_DEFAULTS)
    : { tweaks: TWEAK_DEFAULTS, setTweak: () => {} }
  const tweaks = t.tweaks || TWEAK_DEFAULTS

  useEffect(() => {
    document.documentElement.style.setProperty('--accent', tweaks.accent)
    document.documentElement.dataset.density = tweaks.density
  }, [tweaks.accent, tweaks.density])

  const [active, setActive] = useState(SECTIONS[0].id)
  useEffect(() => {
    const onScroll = () => {
      const y = window.scrollY + 140
      let cur = SECTIONS[0].id
      for (const s of SECTIONS) {
        const el = document.getElementById(s.id)
        if (el && el.offsetTop <= y) cur = s.id
      }
      setActive(cur)
    }
    onScroll()
    window.addEventListener('scroll', onScroll, { passive: true })
    return () => window.removeEventListener('scroll', onScroll)
  }, [])

  const Tweaks = window.TweaksPanel
  const { TweakSection, TweakRadio, TweakColor } = window

  return (
    <div className="page">
      {/* Top bar */}
      <div className="topbar">
        <div className="topbar-inner">
          <div className="topbar-brand">
            <ApaleoMark size={22} />
            <span className="topbar-name">Apaleo</span>
            <span className="topbar-divider" />
            <span className="topbar-section">MCP · Docs</span>
          </div>
          <div className="topbar-nav">
            <a
              className="topbar-link"
              href="https://apaleo.dev/index.html"
              target="_blank"
              rel="noreferrer"
            >
              apaleo.dev
            </a>
            <a className="topbar-cta" href="#quick-start">
              Get started <MIcon name="arrow_forward" size={14} />
            </a>
          </div>
        </div>
      </div>

      <Hero heroStyle={tweaks.heroStyle} />

      <div className="body">
        <aside className="body-toc">
          <TOC active={active} />
        </aside>

        <main className="body-main">
          {/* Overview */}
          <section id="overview" className="sec">
            <div className="sec-eyebrow">
              <MIcon name="info" size={14} /> Overview
            </div>
            <h2 className="sec-title">
              One secure link between AI assistants and Apaleo
            </h2>
            <p className="sec-lead">
              The Apaleo MCP server connects AI assistants and automation tools
              to your Apaleo account through the Model Context Protocol, an open
              industry standard. Plug in Claude, ChatGPT, n8n, or any
              MCP-capable app and it can work with your property data — safely,
              and only within the permissions you grant.
            </p>
            <Callout kind="info" title="Access is self-serve">
              No sign-up with us needed:{' '}
              <a href="#connectors">connect a client</a> and sign in with your
              Apaleo user. What each person can see and do is controlled by
              their <a href="#permissions">MCP roles</a>.
            </Callout>

            <div className="example-prompts">
              <div className="example-prompts-label">
                <MIcon name="chat" size={14} color="#ED8C1F" /> Once connected,
                just ask
              </div>
              <div className="example-prompts-list">
                <span className="example-prompt">
                  "How many arrivals do we have tomorrow?"
                </span>
                <span className="example-prompt">
                  "What's our occupancy this weekend?"
                </span>
                <span className="example-prompt">
                  "Show last week's revenue by rate plan."
                </span>
                <span className="example-prompt">
                  "Which rooms are still unassigned for tonight?"
                </span>
              </div>
            </div>

            <div className="stat-row">
              <div>
                <div className="stat-num">
                  ~230<span className="small">tools</span>
                </div>
                <div className="stat-lbl">Across the Apaleo API</div>
              </div>
              <div>
                <div className="stat-num">
                  9<span className="small">domains</span>
                </div>
                <div className="stat-lbl">Operational coverage</div>
              </div>
              <div>
                <div className="stat-num">OAuth 2.0</div>
                <div className="stat-lbl">Scope-based access</div>
              </div>
            </div>
          </section>

          {/* Quick start */}
          <section id="quick-start" className="sec">
            <div className="sec-eyebrow">
              <MIcon name="rocket_launch" size={14} /> Quick start
            </div>
            <h2 className="sec-title">From zero to connected</h2>
            <p className="sec-lead">
              One quick step to a working connection — plus an optional test
              account so you can try things safely first.
            </p>

            <ol className="sub-steps">
              <li>
                <span className="sub-num">1</span>
                <div>
                  <div className="sub-title">
                    Create a developer account{' '}
                    <span className="tag tag-warn" style={{ marginLeft: 6 }}>
                      Recommended
                    </span>
                  </div>
                  <div className="sub-body">
                    We recommend starting with a free Apaleo developer account —
                    it gives you a test property to try things out safely. It's
                    separate from any production hotel. If you already have an
                    Apaleo account, you can skip this and connect directly.
                  </div>
                  <div className="link-row">
                    <CodeChip mono={false}>
                      https://identity.apaleo.com/account/register-dev-account
                    </CodeChip>
                    <a
                      href="https://identity.apaleo.com/account/register-dev-account"
                      target="_blank"
                      rel="noreferrer"
                      className="icon-btn"
                      title="Open registration"
                    >
                      <MIcon name="open_in_new" size={16} />
                    </a>
                  </div>
                </div>
              </li>
              <li>
                <span className="sub-num">2</span>
                <div>
                  <div className="sub-title">Connect your client</div>
                  <div className="sub-body">
                    Pick the tool you want to drive Apaleo from. Each guide
                    takes 2–5 minutes.
                  </div>
                  <div className="connector-grid">
                    <a className="connector-card" href="#connectors">
                      <div className="connector-card-icon">
                        <BrandLogo name="claude" size={22} />
                      </div>
                      <div>
                        <div className="connector-card-title">Claude</div>
                        <div className="connector-card-sub">
                          Custom connector
                        </div>
                      </div>
                      <MIcon name="arrow_forward" size={16} />
                    </a>
                    <a className="connector-card" href="#connectors">
                      <div className="connector-card-icon">
                        <BrandLogo name="chatgpt" size={22} />
                      </div>
                      <div>
                        <div className="connector-card-title">ChatGPT</div>
                        <div className="connector-card-sub">Apps SDK</div>
                      </div>
                      <MIcon name="arrow_forward" size={16} />
                    </a>
                    <a className="connector-card" href="#connectors">
                      <div className="connector-card-icon">
                        <BrandLogo name="n8n" size={22} />
                      </div>
                      <div>
                        <div className="connector-card-title">n8n</div>
                        <div className="connector-card-sub">
                          OAuth or bearer token
                        </div>
                      </div>
                      <MIcon name="arrow_forward" size={16} />
                    </a>
                  </div>
                </div>
              </li>
            </ol>
          </section>

          {/* Connectors */}
          <section id="connectors" className="sec">
            <div className="sec-eyebrow">
              <MIcon name="cable" size={14} /> Connect a client
            </div>
            <h2 className="sec-title">Step-by-step connection guides</h2>
            <p className="sec-lead">
              Pick the tool you want to drive Apaleo from. UI labels in
              third-party tools change over time — the key inputs always stay
              the same: the MCP server URL and the OAuth sign-in flow.
            </p>
            <ConnectorTabs />
          </section>

          {/* Authentication */}
          <section id="authentication" className="sec">
            <div className="sec-eyebrow">
              <MIcon name="lock" size={14} /> Authentication
            </div>
            <h2 className="sec-title">
              OAuth 2.0, with optional custom clients
            </h2>
            <p className="sec-lead">
              Apaleo MCP authenticates against the Apaleo identity server. You
              can connect with the default flow, or register your own
              application for tighter scope control.
            </p>

            <Callout
              kind="info"
              title="What a user can do is controlled by roles"
            >
              Signing in through a connector requests the MCP scopes on the
              consent screen, but actual access is governed by the user's{' '}
              <strong>MCP roles</strong> and regular Apaleo roles — see{' '}
              <a href="#permissions">Permissions &amp; user roles</a>. To add
              extra guardrails, gate specific tools in your client's UI (see{' '}
              <a href="#connectors">Connect a client</a> step 4).
            </Callout>

            <h3
              style={{
                font: '500 18px/24px var(--font-ui)',
                color: 'var(--apaleo-navy)',
                margin: '24px 0 8px',
              }}
            >
              Default connector flow
            </h3>
            <p className="sec-body">
              For Claude, ChatGPT, and n8n (OAuth) you can leave the Client ID
              and Client Secret empty. The connector starts an OAuth sign-in
              flow against Apaleo and you approve scopes interactively. This is
              the recommended way to connect for almost everyone.
            </p>

            <h3
              style={{
                font: '500 18px/24px var(--font-ui)',
                color: 'var(--apaleo-navy)',
                margin: '32px 0 8px',
              }}
            >
              Machine-to-machine (custom app)
            </h3>
            <p className="sec-body">
              For headless, server-side automations (e.g. n8n with{' '}
              <code>client_credentials</code>) you can register your own custom
              app in the developer portal and use its Client ID / Secret in a
              bearer-token flow — see the n8n bearer example under{' '}
              <a href="#connectors">Connect a client</a>. For how custom apps
              work and why we recommend the connect clients for everything else,
              see the developer portal:{' '}
              <a
                href="https://apaleo.dev/guides/oauth-connection/simple-client.html#why-we-recommend-the-connect-clients"
                target="_blank"
                rel="noreferrer"
              >
                OAuth simple-client overview
              </a>{' '}
              and{' '}
              <a
                href="https://apaleo.dev/guides/oauth-connection/register-simple-client-app.html"
                target="_blank"
                rel="noreferrer"
              >
                Register a simple-client app
              </a>
              .
            </p>

            <h3
              style={{
                font: '500 18px/24px var(--font-ui)',
                color: 'var(--apaleo-navy)',
                margin: '32px 0 8px',
              }}
            >
              What you'll see in Apaleo admin
            </h3>
            <p className="sec-body">
              After your first OAuth connection, a new app called{' '}
              <strong>"MCP Server App"</strong> will appear in your Apaleo{' '}
              <em>Connected apps</em>. This is auto-created by the MCP server's
              OIDC proxy and is expected — do not delete it while the
              integration is active.
            </p>
            <p className="sec-body">
              The scopes currently granted to this auto-created app cover the
              capability areas listed under{' '}
              <a href="#capabilities">Tool capabilities</a> (availability,
              booking, finance, inventory, logs, operations, rate plans,
              reports, settings). The exact scope list is visible on the
              connected app itself in Apaleo admin.
            </p>
          </section>

          {/* Permissions & user roles */}
          <section id="permissions" className="sec">
            <div className="sec-eyebrow">
              <MIcon name="admin_panel_settings" size={14} /> Permissions &amp;
              user roles
            </div>
            <h2 className="sec-title">
              You decide who can use the MCP server — and what they can do
            </h2>
            <p className="sec-lead">
              Two user roles in Apaleo user management control access to the MCP
              server. Assign them per employee, right alongside the roles your
              team already has — like <kbd>Front Desk</kbd> or{' '}
              <kbd>Housekeeper</kbd>.
            </p>

            <table className="tbl">
              <thead>
                <tr>
                  <th style={{ width: '25%' }}>Role</th>
                  <th>What it allows</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>
                    <strong>MCP Read</strong>
                  </td>
                  <td>
                    View information through the AI assistant — arrivals,
                    reservations, reports, occupancy. Read-only: no changes
                    possible.
                  </td>
                </tr>
                <tr>
                  <td>
                    <strong>MCP Manage</strong>
                  </td>
                  <td>
                    Everything MCP Read allows, plus making changes — for
                    example amending a reservation or updating settings.
                  </td>
                </tr>
              </tbody>
            </table>

            <h3
              style={{
                font: '500 18px/24px var(--font-ui)',
                color: 'var(--apaleo-navy)',
                margin: '24px 0 8px',
              }}
            >
              MCP roles work together with regular Apaleo roles
            </h3>
            <p className="sec-body">
              An MCP role only unlocks the MCP server itself. What a user can
              actually see and change through the AI assistant is still limited
              by their regular Apaleo roles — someone with
              <kbd>MCP Manage</kbd> whose only Apaleo role is read-only (like{' '}
              <kbd>Housekeeper</kbd>) still can't change anything. A user can
              never do more through an AI assistant than they already can in
              apaleo.
            </p>
            <p className="sec-body">
              And without an MCP role, a user cannot use the MCP server at all —
              this applies to every user on the account (except the{' '}
              <kbd>Account Admin</kbd>).
            </p>

            <h3
              style={{
                font: '500 18px/24px var(--font-ui)',
                color: 'var(--apaleo-navy)',
                margin: '32px 0 8px',
              }}
            >
              How to give an employee access
            </h3>
            <figure className="video-figure">
              <McpAccessDemo />
              <figcaption>
                <MIcon name="play_circle" size={16} />
                Walkthrough — assigning the MCP Read and MCP Manage roles in
                Apaleo user management.
              </figcaption>
            </figure>
            <ol className="sub-steps">
              <li>
                <span className="sub-num">1</span>
                <div>
                  <div className="sub-title">
                    Open the user's roles in Apaleo
                  </div>
                  <div className="sub-body">
                    In Apaleo, go to <kbd>Settings</kbd> →{' '}
                    <kbd>User management</kbd>, select the employee, and open
                    their role assignment.
                  </div>
                </div>
              </li>
              <li>
                <span className="sub-num">2</span>
                <div>
                  <div className="sub-title">
                    Assign MCP Read and/or MCP Manage
                  </div>
                  <div className="sub-body">
                    Tick <strong>MCP Read</strong> for view-only access, or{' '}
                    <strong>MCP Manage</strong> to also allow changes, and save.
                    You can grant the role for the whole account or for specific
                    properties only.
                  </div>
                </div>
              </li>
              <li>
                <span className="sub-num">3</span>
                <div>
                  <div className="sub-title">Reconnect in the AI assistant</div>
                  <div className="sub-body">
                    The employee signs out of the Apaleo connector in Claude,
                    ChatGPT, or their other AI client and signs back in. The new
                    role takes effect from that point on.
                  </div>
                </div>
              </li>
            </ol>

            <Callout kind="info" title="Role changes need a fresh sign-in">
              Changes to a user's MCP roles apply after they reconnect (sign out
              and back in) in their AI client — an existing session keeps its
              previous access until then.
            </Callout>
          </section>

          {/* Endpoints */}
          <section id="endpoints" className="sec">
            <div className="sec-eyebrow">
              <MIcon name="api" size={14} /> Endpoints &amp; transport
            </div>
            <h2 className="sec-title">
              One production endpoint, Streamable HTTP
            </h2>
            <p className="sec-lead">
              All MCP traffic uses Streamable HTTP against a single production
              endpoint.
            </p>

            <table className="tbl">
              <thead>
                <tr>
                  <th style={{ width: '30%' }}>Purpose</th>
                  <th>URL</th>
                  <th style={{ width: '20%' }}>Notes</th>
                </tr>
              </thead>
              <tbody>
                <tr>
                  <td>MCP server</td>
                  <td>
                    <CopyCode label="server URL">
                      https://mcp.apaleo.com/mcp
                    </CopyCode>
                  </td>
                  <td>Production</td>
                </tr>
                <tr>
                  <td>OAuth token endpoint</td>
                  <td>
                    <CopyCode label="token endpoint">
                      https://identity.apaleo.com/connect/token
                    </CopyCode>
                  </td>
                  <td>Client-credentials flow</td>
                </tr>
                <tr>
                  <td>Developer portal</td>
                  <td>
                    <a
                      href="https://apaleo.dev/index.html"
                      target="_blank"
                      rel="noreferrer"
                    >
                      apaleo.dev
                    </a>
                  </td>
                  <td>Register apps</td>
                </tr>
              </tbody>
            </table>
          </section>

          {/* Capabilities */}
          <section id="capabilities" className="sec">
            <div className="sec-eyebrow">
              <MIcon name="build" size={14} /> Tool capabilities
            </div>
            <h2 className="sec-title">Coverage across the Apaleo API</h2>
            <p className="sec-lead">
              The MCP server exposes tools that map closely onto the public
              Apaleo API.
            </p>

            <div className="capability-grid">
              <div>
                <div className="cap-ico">
                  <MIcon name="event_available" size={16} color="#ED8C1F" />
                </div>
                <div>
                  <div className="cap-title">
                    Availability <span className="cap-tag">V1</span>
                  </div>
                  <div className="cap-sub">capacity, ARI, restrictions</div>
                </div>
              </div>
              <div>
                <div className="cap-ico">
                  <MIcon name="bookmark_added" size={16} color="#ED8C1F" />
                </div>
                <div>
                  <div className="cap-title">
                    Booking <span className="cap-tag">V1</span>
                  </div>
                  <div className="cap-sub">reservations, blocks, groups</div>
                </div>
              </div>
              <div>
                <div className="cap-ico">
                  <MIcon name="payments" size={16} color="#ED8C1F" />
                </div>
                <div>
                  <div className="cap-title">
                    Finance <span className="cap-tag">V1</span>
                  </div>
                  <div className="cap-sub">folios, charges, payments</div>
                </div>
              </div>
              <div>
                <div className="cap-ico">
                  <MIcon name="hotel" size={16} color="#ED8C1F" />
                </div>
                <div>
                  <div className="cap-title">
                    Inventory <span className="cap-tag">V1</span>
                  </div>
                  <div className="cap-sub">units, unit groups, services</div>
                </div>
              </div>
              <div>
                <div className="cap-ico">
                  <MIcon name="history" size={16} color="#ED8C1F" />
                </div>
                <div>
                  <div className="cap-title">
                    Logs <span className="cap-tag">V1</span>
                  </div>
                  <div className="cap-sub">audit trail, change history</div>
                </div>
              </div>
              <div>
                <div className="cap-ico">
                  <MIcon name="support_agent" size={16} color="#ED8C1F" />
                </div>
                <div>
                  <div className="cap-title">
                    Operations <span className="cap-tag">V1</span>
                  </div>
                  <div className="cap-sub">
                    arrivals, in-house, housekeeping
                  </div>
                </div>
              </div>
              <div>
                <div className="cap-ico">
                  <MIcon name="price_change" size={16} color="#ED8C1F" />
                </div>
                <div>
                  <div className="cap-title">
                    Rate plans <span className="cap-tag">V1</span>
                  </div>
                  <div className="cap-sub">pricing rules, restrictions</div>
                </div>
              </div>
              <div>
                <div className="cap-ico">
                  <MIcon name="monitoring" size={16} color="#ED8C1F" />
                </div>
                <div>
                  <div className="cap-title">
                    Reports <span className="cap-tag">V1</span>
                  </div>
                  <div className="cap-sub">occupancy, revenue, statistics</div>
                </div>
              </div>
              <div>
                <div className="cap-ico">
                  <MIcon name="settings" size={16} color="#ED8C1F" />
                </div>
                <div>
                  <div className="cap-title">
                    Settings <span className="cap-tag">V1</span>
                  </div>
                  <div className="cap-sub">
                    property setup, taxes, currencies
                  </div>
                </div>
              </div>
            </div>

            <p className="sec-body">
              A list of every tool, its description, and its JSON schema is
              available through any MCP inspector, or via the{' '}
              <code>tools/list</code> JSON-RPC method.
            </p>
          </section>

          {/* Safety */}
          <section id="safety" className="sec">
            <div className="sec-eyebrow">
              <MIcon name="shield" size={14} /> Safe usage
            </div>
            <h2 className="sec-title">Practical guardrails</h2>
            <p className="sec-lead">
              For both technical operators and hotel teams running MCP-driven
              automations.
            </p>

            <div className="safe-cols">
              <div className="safe-card">
                <h3>
                  <MIcon name="terminal" size={18} color="#ED8C1F" /> For
                  technical teams
                </h3>
                <p className="safe-sub">
                  If you're integrating MCP into agents, workflows, or
                  back-office tooling.
                </p>
                <ul>
                  <li>
                    Start with a <strong>test property</strong> before pointing
                    MCP at live data — a free developer account gives you one.
                  </li>
                  <li>
                    Give users only the MCP role they need —{' '}
                    <strong>MCP Read</strong> unless they really need to make
                    changes (see{' '}
                    <a href="#permissions">Permissions &amp; user roles</a>).
                  </li>
                  <li>
                    Restrict what the agent can do in your client's settings —
                    Claude lets you block individual tools or set them to{' '}
                    <em>Needs approval</em>; ChatGPT asks you to confirm actions
                    before they run.
                  </li>
                  <li>
                    For long-running automations, fetch tokens via the{' '}
                    <a href="#connectors">client-credentials flow</a> instead of
                    pasting bearer tokens.
                  </li>
                  <li>
                    Log every tool invocation (input + output) to your own audit
                    store.
                  </li>
                  <li>
                    Treat MCP responses as untrusted input downstream — sanitize
                    before re-prompting.
                  </li>
                </ul>
              </div>
              <div className="safe-card">
                <h3>
                  <MIcon name="hotel" size={18} color="#ED8C1F" /> For hotel
                  teams &amp; ops
                </h3>
                <p className="safe-sub">
                  If you're using MCP through Claude, ChatGPT, or another
                  assistant.
                </p>
                <ul>
                  <li>
                    Try new workflows on a <strong>test property</strong> first,
                    before pointing the assistant at live data.
                  </li>
                  <li>
                    Never paste real guest data, payment info, or PII into a
                    chat window.
                  </li>
                  <li>
                    Start with read-only flows (arrivals, occupancy reports)
                    before enabling writes.
                  </li>
                  <li>
                    In Claude / ChatGPT, configure{' '}
                    <strong>tool permissions</strong> in the connector settings
                    to require approval before any write/delete action. In
                    Claude this is under the connector's{' '}
                    <em>Tool permissions</em> panel; gate the write/delete
                    category at minimum.
                  </li>
                  <li>
                    Keep a human in the loop for refunds, rate plan edits, and
                    reservation cancellations.
                  </li>
                </ul>
              </div>
            </div>
          </section>

          {/* GDPR */}
          <section id="gdpr" className="sec">
            <div className="sec-eyebrow">
              <span
                style={{ fontSize: 16, lineHeight: 1, marginRight: 2 }}
                aria-hidden="true"
              >
                🇪🇺
              </span>
              Data protection
            </div>
            <h2 className="sec-title">Using guest data (GDPR)</h2>
            <p className="sec-lead">
              If you plan to process guest personal data through your AI
              assistant, treat its provider like any other data processor and
              get the basics in place first.
            </p>

            <div
              className="gdpr-grid"
              style={{
                display: 'grid',
                gridTemplateColumns: 'repeat(auto-fit, minmax(280px, 1fr))',
                gap: 16,
                marginTop: 24,
                marginBottom: 24,
              }}
            >
              <div
                style={{
                  padding: 20,
                  borderRadius: 12,
                  border: '1px solid var(--border)',
                  background: 'var(--bg2)',
                }}
              >
                <h3
                  style={{
                    margin: '0 0 8px',
                    font: '500 16px/22px var(--font-ui)',
                    color: 'var(--apaleo-navy)',
                    display: 'flex',
                    alignItems: 'center',
                    gap: 8,
                  }}
                >
                  <MIcon name="gavel" size={18} color="#ED8C1F" /> Use a plan
                  that includes a DPA
                </h3>
                <p
                  style={{
                    margin: 0,
                    font: '400 14px/22px var(--font-ui)',
                    color: 'var(--fg2)',
                  }}
                >
                  Most AI providers offer a Data Processing Agreement (DPA) on
                  their business and enterprise tiers, but not on consumer plans
                  — and a consumer plan generally isn't a suitable basis for
                  processing guest personal data. Whichever assistant you use —
                  Claude, ChatGPT, Microsoft Copilot, Gemini, or another — check
                  that provider's own terms to confirm a DPA is in place and who
                  acts as the data processor. As one example, with Claude the
                  Team, Enterprise, and API plans include a DPA through{' '}
                  <a
                    href="https://www.anthropic.com/legal"
                    target="_blank"
                    rel="noreferrer"
                  >
                    Anthropic's Commercial Terms
                  </a>
                  , while the Free, Pro, and Max plans do not.
                </p>
              </div>
              <div
                style={{
                  padding: 20,
                  borderRadius: 12,
                  border: '1px solid var(--border)',
                  background: 'var(--bg2)',
                }}
              >
                <h3
                  style={{
                    margin: '0 0 8px',
                    font: '500 16px/22px var(--font-ui)',
                    color: 'var(--apaleo-navy)',
                    display: 'flex',
                    alignItems: 'center',
                    gap: 8,
                  }}
                >
                  <MIcon name="tune" size={18} color="#ED8C1F" /> Limit what the
                  AI can touch
                </h3>
                <p
                  style={{
                    margin: 0,
                    font: '400 14px/22px var(--font-ui)',
                    color: 'var(--fg2)',
                  }}
                >
                  Enable only the tools you actually need, and keep write tools
                  blocked or set to <em>Needs approval</em>. See{' '}
                  <a href="#connectors">Connect a client → step 4</a> and{' '}
                  <a href="#safety">Safe usage</a>.
                </p>
              </div>
              <div
                style={{
                  padding: 20,
                  borderRadius: 12,
                  border: '1px solid var(--border)',
                  background: 'var(--bg2)',
                }}
              >
                <h3
                  style={{
                    margin: '0 0 8px',
                    font: '500 16px/22px var(--font-ui)',
                    color: 'var(--apaleo-navy)',
                    display: 'flex',
                    alignItems: 'center',
                    gap: 8,
                  }}
                >
                  <MIcon name="filter_alt" size={18} color="#ED8C1F" /> Minimise
                  data
                </h3>
                <p
                  style={{
                    margin: 0,
                    font: '400 14px/22px var(--font-ui)',
                    color: 'var(--fg2)',
                  }}
                >
                  Only share guest data needed for the task at hand. Avoid
                  pasting personal data into prompts when you don't have to —
                  see the PII bullet in <a href="#safety">Safe usage</a>.
                </p>
              </div>
              <div
                style={{
                  padding: 20,
                  borderRadius: 12,
                  border: '1px solid var(--border)',
                  background: 'var(--bg2)',
                }}
              >
                <h3
                  style={{
                    margin: '0 0 8px',
                    font: '500 16px/22px var(--font-ui)',
                    color: 'var(--apaleo-navy)',
                    display: 'flex',
                    alignItems: 'center',
                    gap: 8,
                  }}
                >
                  <MIcon name="verified_user" size={18} color="#ED8C1F" /> For a
                  stronger position
                </h3>
                <p
                  style={{
                    margin: 0,
                    font: '400 14px/22px var(--font-ui)',
                    color: 'var(--fg2)',
                  }}
                >
                  Consider a <strong>Data Protection Impact Assessment</strong>,
                  a <strong>transfer assessment</strong> for data leaving the
                  EU, and <strong>Zero Data Retention</strong>, and keep your
                  setup documented.
                </p>
              </div>
            </div>

            <Callout kind="info" title="Not legal advice">
              This is general guidance to help you know what to look for, not
              legal advice. Your specific obligations depend on your own
              circumstances — review them with your legal or data protection
              team and check your AI provider's current terms and DPA directly.
            </Callout>
          </section>

          {/* FAQ */}
          <section id="faq" className="sec">
            <div className="sec-eyebrow">
              <MIcon name="help" size={14} /> FAQ
            </div>
            <h2 className="sec-title">Frequently asked</h2>
            <p className="sec-lead">
              If you're stuck, start here. Most issues come down to scopes or
              hitting a stale connector.
            </p>

            <div className="faqs">
              <FAQ q="How do I get access?">
                It's self-serve — no sign-up with us needed. Connect your client
                to{' '}
                <CopyCode label="server URL">
                  https://mcp.apaleo.com/mcp
                </CopyCode>{' '}
                and sign in with your Apaleo user. Your account owner controls
                who can use it via <a href="#permissions">MCP user roles</a>.
              </FAQ>
              <FAQ q="Can I use MCP on a live hotel?">
                Yes. Use <a href="#permissions">MCP user roles</a> to control
                who can do what, and keep a human in the loop for any
                write/delete actions — see <a href="#safety">Safe usage</a>.
              </FAQ>
              <FAQ q="Why does my client ask for a Client ID and Secret?">
                You can leave them empty for the default OAuth flow. They are
                only relevant in the machine-to-machine flow — see{' '}
                <a href="#authentication">Authentication</a>.
              </FAQ>
              <FAQ q="The assistant says 'something went wrong'">
                Usually a permissions issue. First check the user's{' '}
                <a href="#permissions">MCP roles</a> — write tools need{' '}
                <strong>MCP Manage</strong>, and role changes only apply after
                reconnecting. Then disconnect, reconnect, and approve every
                requested scope this time.
              </FAQ>
              <FAQ q="What's the MCP server URL?">
                <CopyCode label="server URL">
                  https://mcp.apaleo.com/mcp
                </CopyCode>{' '}
                — that's the single production endpoint for all MCP traffic.
              </FAQ>
            </div>
          </section>

          <footer className="page-foot">
            <div className="foot-thanks">
              <MIcon name="favorite" size={16} color="#ED8C1F" />
              <span>
                Questions or feedback? We'd love to hear how you're using MCP.
              </span>
            </div>
            <div className="foot-links">
              <a href="mailto:support@apaleo.com">support@apaleo.com</a>
              <span className="foot-sep">·</span>
              <a
                href="https://apaleo.dev/index.html"
                target="_blank"
                rel="noreferrer"
              >
                apaleo.dev
              </a>
            </div>
          </footer>
        </main>
      </div>

      {/* Tweaks panel */}
      {Tweaks && (
        <Tweaks title="Tweaks">
          <TweakSection title="Layout">
            <TweakRadio
              label="Density"
              value={tweaks.density}
              onChange={(v) => t.setTweak('density', v)}
              options={[
                { value: 'comfortable', label: 'Comfortable' },
                { value: 'compact', label: 'Compact' },
              ]}
            />

            <TweakRadio
              label="Hero style"
              value={tweaks.heroStyle}
              onChange={(v) => t.setTweak('heroStyle', v)}
              options={[
                { value: 'split', label: 'Split' },
                { value: 'centered', label: 'Centered' },
              ]}
            />
          </TweakSection>
          <TweakSection title="Color">
            <TweakColor
              label="Accent"
              value={tweaks.accent}
              onChange={(v) => t.setTweak('accent', v)}
              options={['#ED8C1F', '#D97757', '#19213B', '#23a566']}
            />
          </TweakSection>
        </Tweaks>
      )}
    </div>
  )
}

ReactDOM.createRoot(document.getElementById('root')).render(<App />)
