(defcomp ()
  (~docs/page :title "Components"
    (~docs/section :title "defcomp" :id "defcomp"
      (p (~tw :tokens "text-stone-600")
        "Components are defined with defcomp. They take keyword parameters and optional children:")
      (~docs/code :src (highlight "(defcomp ~docs-content/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 (~tw :tokens "text-stone-600")
        "Use components with the ~ prefix:")
      (~docs/code :src (highlight "(~docs-content/card :title \"My Card\" :subtitle \"A description\"\n  (p \"First child\")\n  (p \"Second child\"))" "lisp")))
    (~docs/section :title "Component caching" :id "caching"
      (p (~tw :tokens "text-stone-600")
        "Component definitions are sent in a <script type=\"text/sx\" data-components> block. The client caches them in localStorage keyed by a content hash. On subsequent page loads, the client sends an SX-Components header listing what it has. The server only sends definitions the client is missing.")
      (p (~tw :tokens "text-stone-600")
        "This means the first page load sends all component definitions (~5-15KB). Subsequent navigations send zero component bytes — just the page content."))
    (~docs/section :title "Parameters" :id "params"
      (p (~tw :tokens "text-stone-600")
        "&key declares keyword parameters. &rest children captures remaining positional arguments. Missing parameters evaluate to nil. Components always receive all declared parameters — use (when param ...) or (if param ... ...) to handle optional values."))))
