;; Docs page content — fully self-contained, no Python intermediaries (defcomp ~sx-home-content () (div :id "main-content" :class "max-w-3xl mx-auto px-4 py-6" (highlight "(defcomp ~sx-header () (a :href \"/\" :sx-get \"/\" :sx-target \"#main-panel\" :sx-select \"#main-panel\" :sx-swap \"outerHTML\" :sx-push-url \"true\" :class \"block max-w-3xl mx-auto px-4 pt-8 pb-4 text-center no-underline\" (span :class \"text-4xl font-bold font-mono text-violet-700 block mb-2\" \"()\") (p :class \"text-lg text-stone-500 mb-1\" \"Framework free reactive hypermedia\") (p :class \"text-xs text-stone-400\" \"© Giles Bradshaw 2026\")))" "lisp"))) (defcomp ~docs-introduction-content () (~doc-page :title "Introduction" (~doc-section :title "What is sx?" :id "what" (p :class "text-stone-600" "sx is an s-expression language for building web UIs. It combines htmx's server-first hypermedia approach with React's component model. The server sends s-expression source code over the wire. The client parses, evaluates, and renders it to DOM.") (p :class "text-stone-600" "The same evaluator runs on both server (Python) and client (JavaScript). Components defined once render identically in both environments.")) (~doc-section :title "Design decisions" :id "design" (p :class "text-stone-600" "HTML elements are first-class: (div :class \"card\" (p \"hello\")) renders exactly what you'd expect. Components use defcomp with keyword parameters and optional children. The evaluator supports let bindings, conditionals, lambda, map/filter/reduce, and ~80 primitives.") (p :class "text-stone-600" "sx replaces the pattern of shipping a JS framework + build step + client-side router + state management library just to render some server data. For most applications, sx eliminates the need for JavaScript entirely — htmx attributes handle interactivity, hyperscript handles small behaviours, and the server handles everything else.")) (~doc-section :title "What sx is not" :id "not" (ul :class "space-y-2 text-stone-600" (li "Not a general-purpose programming language — it's a UI rendering language") (li "Not a full Lisp — it has macros, TCO, and delimited continuations, but no full call/cc") (li "Not production-hardened at scale — it runs one website"))))) (defcomp ~docs-getting-started-content () (~doc-page :title "Getting Started" (~doc-section :title "Minimal example" :id "minimal" (p :class "text-stone-600" "An sx response is s-expression source code with content type text/sx:") (~doc-code :code (highlight "(div :class \"p-4 bg-white rounded\"\n (h1 :class \"text-2xl font-bold\" \"Hello, world!\")\n (p \"This is rendered from an s-expression.\"))" "lisp")) (p :class "text-stone-600" "Add sx-get to any element to make it fetch and render sx:")) (~doc-section :title "Hypermedia attributes" :id "attrs" (p :class "text-stone-600" "Like htmx, sx adds attributes to HTML elements to trigger HTTP requests:") (~doc-code :code (highlight "(button\n :sx-get \"/api/data\"\n :sx-target \"#result\"\n :sx-swap \"innerHTML\"\n \"Load data\")" "lisp")) (p :class "text-stone-600" "sx-get, sx-post, sx-put, sx-delete, sx-patch — all work the same way. The response is parsed as sx and rendered into the target element.")))) (defcomp ~docs-components-content () (~doc-page :title "Components" (~doc-section :title "defcomp" :id "defcomp" (p :class "text-stone-600" "Components are defined with defcomp. They take keyword parameters and optional children:") (~doc-code :code (highlight "(defcomp ~card (&key title subtitle &rest children)\n (div :class \"border rounded p-4\"\n (h2 :class \"font-bold\" title)\n (when subtitle (p :class \"text-stone-500\" subtitle))\n (div :class \"mt-3\" children)))" "lisp")) (p :class "text-stone-600" "Use components with the ~ prefix:") (~doc-code :code (highlight "(~card :title \"My Card\" :subtitle \"A description\"\n (p \"First child\")\n (p \"Second child\"))" "lisp"))) (~doc-section :title "Component caching" :id "caching" (p :class "text-stone-600" "Component definitions are sent in a