(defcomp (&key (comp-name :as string) (is-pure :as boolean) (io-refs :as list) (deps :as list) (source :as string))
  (details :class (str "rounded border "
                       (if is-pure "border-blue-200 bg-blue-50" "border-amber-200 bg-amber-50"))
    (summary (~tw :tokens "px-3 py-2 cursor-pointer hover:opacity-80 transition-opacity")
      (div (~tw :tokens "flex items-center justify-between")
        (div (~tw :tokens "flex items-center gap-2")
          (span :class (str "inline-block w-2 h-2 rounded-full "
                            (if is-pure "bg-blue-500" "bg-amber-500")))
          (span (~tw :tokens "font-mono text-sm font-medium text-stone-800") comp-name))
        (div (~tw :tokens "flex items-center gap-2")
          (when (not (empty? io-refs))
            (span (~tw :tokens "text-xs text-amber-700")
              (str "IO: " (join ", " io-refs))))
          (when (not (empty? deps))
            (span (~tw :tokens "text-xs text-stone-500")
              (str (len deps) " deps"))))))

    ;; SX source (shown when component expanded)
    (div (~tw :tokens "not-prose border-t border-stone-200 p-3 bg-stone-100 rounded-b")
      (pre (~tw :tokens "text-xs leading-relaxed whitespace-pre-wrap overflow-x-auto")
        (code (highlight source "lisp"))))))
