;; ---------------------------------------------------------------------------
;; Runtime Slicing
;; ---------------------------------------------------------------------------

(defcomp ()
  (~docs/page :title "Runtime Slicing"

    (~docs/section :title "The Problem" :id "problem"
      (p "sx-browser.js is the full SX client runtime — evaluator, parser, renderer, engine, morph, signals, routing, orchestration, boot. Every page loads all of it.")

      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "File")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Raw")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Gzipped")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Min+Gz")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "sx-browser.js")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "354KB")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "75KB")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "44KB"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "sx-ref.js")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "244KB")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "49KB")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "29KB"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "React + ReactDOM")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "—")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "—")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "~5KB + ~40KB")))))

      (p "Most pages are L0 (pure hypermedia — server renders, client morphs). They don't need the parser, the evaluator, the full primitive set, signals, or client-side routing. They need morph + swap + trigger dispatch. That's a fraction of the runtime.")
      (p "The runtime should be sliceable: each page declares what level it operates at, and the bootstrapper emits only the code that level requires."))

    ;; -----------------------------------------------------------------------
    ;; Tiers
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Tiers" :id "tiers"
      (p "Four tiers, matching the " (a :href "/sx/(geography.(reactive.(reactive-design)))" (~tw :tokens "text-violet-700 underline") "reactive islands") " levels:")

      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Tier")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "What")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Modules")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Target (min+gz)")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-semibold text-stone-800") "L0 Hypermedia")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Morph, swap, trigger dispatch, history")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-600") "engine, boot (partial)")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "~5KB"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-semibold text-stone-800") "L1 DOM Ops")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "L0 + toggle!, set-attr!, on-event, class-list ops")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-600") "+ DOM adapter (partial)")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "~8KB"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-semibold text-stone-800") "L2 Islands")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "L1 + signals, computed, effect, defisland hydration")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-600") "+ signals, DOM adapter (full)")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "~15KB"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-semibold text-stone-800") "L3 Full Eval")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "L2 + parser, evaluator, all primitives, client routing, component resolution")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-600") "everything")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "~44KB (current)")))))

      (p "90% of typical pages are L0. A blog post, a product listing, a checkout form — server renders, client morphs on navigation. The full evaluator only loads for pages that do client-side rendering or have reactive islands.")

      (div (~tw :tokens "rounded border border-amber-200 bg-amber-50 p-4 mt-4")
        (p (~tw :tokens "text-amber-900 font-medium") "Progressive loading")
        (p (~tw :tokens "text-amber-800") "A user navigating an L0 page downloads ~5KB. If they navigate to an L2 page (reactive island), the delta (~10KB) loads on demand. The runtime grows with need, never speculatively.")))

    ;; -----------------------------------------------------------------------
    ;; The slicer is SX
    ;; -----------------------------------------------------------------------

    (~docs/section :title "The Slicer is SX" :id "slicer-is-sx"
      (p "Per the " (a :href "/sx/(etc.(plan.self-hosting-bootstrapper))" (~tw :tokens "text-violet-700 underline") "self-hosting principle") ", the slicer is not a build tool — it's a spec module. " (code "slice.sx") " analyzes the spec's own dependency graph and determines which defines belong to which tier.")
      (p (code "js.sx") " (the self-hosting SX-to-JavaScript translator) already compiles the full spec. Slicing is a filter: " (code "js.sx") " translates only the defines that " (code "slice.sx") " selects for a given tier.")

      (~docs/code :src (highlight ";; slice.sx — determine which defines each tier needs\n;;\n;; Input: the full list of defines from all spec files\n;; Output: a filtered list for the requested tier\n\n(define tier-deps\n  ;; Which spec modules each tier requires\n  {:L0 (list \"engine\" \"boot-partial\")\n   :L1 (list \"engine\" \"boot-partial\" \"dom-partial\")\n   :L2 (list \"engine\" \"boot-partial\" \"dom-partial\"\n              \"signals\" \"dom-island\")\n   :L3 (list \"eval\" \"render\" \"parser\"\n              \"engine\" \"orchestration\" \"boot\"\n              \"dom\" \"signals\" \"router\")})\n\n(define slice-defines\n  (fn (tier all-defines)\n    ;; 1. Get the module list for this tier\n    ;; 2. Walk each define's dependency references\n    ;; 3. Include a define only if ALL its deps are\n    ;;    satisfiable within the tier's module set\n    ;; 4. Return the filtered define list\n    (let ((modules (get tier-deps tier)))\n      (filter\n        (fn (d) (tier-satisfies? modules (define-deps d)))\n        all-defines))))" "lisp"))

      (p "The pipeline becomes:")
      (ol (~tw :tokens "list-decimal pl-5 text-stone-700 space-y-2")
        (li (code "slice.sx") " analyzes the spec and produces a define list per tier")
        (li (code "js.sx") " translates each define list to JavaScript (same translator, different input)")
        (li "The bootstrapper wraps each tier's output with its platform interface (the hand-written JS glue)")
        (li "Output: one " (code ".js") " file per tier, or a single file with tier markers for runtime splitting"))

      (p "Because " (code "js.sx") " is self-hosting, slicing is just function composition: " (code "(js-translate-file (slice-defines :L0 all-defines))") ". No new translator. No new build tool. The same 1,382-line " (code "js.sx") " that produces the full runtime produces every tier."))

    ;; -----------------------------------------------------------------------
    ;; Dependency analysis
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Define-Level Dependency Analysis" :id "deps"
      (p "The slicer needs to know which defines reference which other defines. This is a simpler version of what " (code "deps.sx") " does for components — but at the define level, not the component level.")

      (~docs/code :src (highlight ";; Walk a define's body AST, collect all symbol references\n;; that resolve to other top-level defines.\n;;\n;; (define morph-children\n;;   (fn (old-node new-node)\n;;     ...uses morph-node, morph-attrs, create-element...))\n;;\n;; → deps: #{morph-node morph-attrs create-element}\n\n(define define-refs\n  (fn (body all-define-names)\n    ;; Collect all symbols in body that appear in all-define-names\n    (let ((refs (make-set)))\n      (walk-ast body\n        (fn (node)\n          (when (and (symbol? node)\n                     (set-has? all-define-names (symbol-name node)))\n            (set-add! refs (symbol-name node)))))\n      refs)))" "lisp"))

      (p "From these per-define deps, we build the full dependency graph and compute transitive closures. A tier's define set is the transitive closure of its entry points:")

      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Tier")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Entry points")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Pulls in")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-semibold text-stone-800") "L0")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-600") "morph-node, process-swap, dispatch-trigger, push-url")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "morph-attrs, morph-children, create-element, extract-swap-config — the morph/swap subgraph"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-semibold text-stone-800") "L1")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-600") "L0 + toggle-class!, set-attr!, add-event-listener!")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "DOM manipulation helpers — small subgraph"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-semibold text-stone-800") "L2")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-600") "L1 + signal, deref, reset!, computed, effect, render-dom-island")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Signal runtime + reactive DOM adapter"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-semibold text-stone-800") "L3")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-600") "L2 + eval-expr, sx-parse, render-to-dom, resolve-component-by-cid")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Everything — full evaluator, parser, all ~80 primitives"))))))

    ;; -----------------------------------------------------------------------
    ;; Platform interface slicing
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Platform Interface Slicing" :id "platform"
      (p "The bootstrapped code (from js.sx) is only half the story. Each define also depends on platform primitives — the hand-written JS glue that js.sx doesn't produce. These live in " (code "bootstrap_js.py") "'s PLATFORM_* blocks.")
      (p "The slicer must track platform deps too:")

      (~docs/code :src (highlight ";; Platform primitives referenced by tier\n;;\n;; L0 needs: createElement, setAttribute, morphAttrs,\n;;           fetch (for sx-get/post), pushState, replaceState\n;;\n;; L1 adds:  classList.toggle, addEventListener\n;;\n;; L2 adds:  createComment, createTextNode, domRemove,\n;;           domChildNodes — the reactive DOM primitives\n;;\n;; L3 adds:  everything in PLATFORM_PARSER_JS,\n;;           full DOM adapter, async IO bridge\n\n(define platform-deps\n  {:L0 (list :dom-morph :fetch :history)\n   :L1 (list :dom-morph :fetch :history :dom-events)\n   :L2 (list :dom-morph :fetch :history :dom-events\n             :dom-reactive :signal-constructors)\n   :L3 (list :dom-morph :fetch :history :dom-events\n             :dom-reactive :signal-constructors\n             :parser :evaluator :async-io)})" "lisp"))

      (p "The platform JS blocks in " (code "bootstrap_js.py") " are already organized by adapter (" (code "PLATFORM_DOM_JS") ", " (code "PLATFORM_ENGINE_PURE_JS") ", etc). Slicing further subdivides these into the minimal set each tier needs.")
      (p "This subdivision also happens in SX: " (code "slice.sx") " declares which platform blocks each tier requires. " (code "js.sx") " doesn't need to change — it translates defines. The bootstrapper script reads the slice spec and assembles the platform preamble accordingly."))

    ;; -----------------------------------------------------------------------
    ;; Progressive loading
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Progressive Loading" :id "progressive"
      (p "The simplest approach: one file per tier. The server knows each page's tier (from " (code "defpage") " metadata or component analysis) and serves the right script tag.")
      (p "Better: a base file (L0) that all pages load, plus tier deltas loaded on demand.")

      (~docs/code :src (highlight ";; Server emits the appropriate script for the page's tier\n;;\n;; L0 page (blog post, product listing):\n;;   <script src=\"/static/scripts/sx-L0.js\"></script>\n;;\n;; L2 page (reactive island):\n;;   <script src=\"/static/scripts/sx-L0.js\"></script>\n;;   <script src=\"/static/scripts/sx-L2-delta.js\"></script>\n;;\n;; Client-side navigation from L0 → L2:\n;;   1. L0 runtime handles the swap\n;;   2. New page declares tier=L2 in response header\n;;   3. L0 runtime loads sx-L2-delta.js dynamically\n;;   4. Island hydration proceeds\n\n(define page-tier\n  (fn (page)\n    ;; Analyze the page's component tree\n    ;; If any component is defisland → L2\n    ;; If any component uses on-event/toggle! → L1\n    ;; Otherwise → L0\n    (cond\n      ((page-has-islands? page)  :L2)\n      ((page-has-dom-ops? page)  :L1)\n      (true                      :L0))))" "lisp"))

      (~docs/subsection :title "SX-Tier Response Header"
        (p "The server includes the page's tier in the response:")
        (~docs/code :src (highlight "HTTP/1.1 200 OK\nSX-Tier: L0\nSX-Components: ~card:bafy...,~plans/environment-images/nav:bafy...\n\n;; or for an island page:\nSX-Tier: L2\nSX-Components: ~counter-island:bafy..." "http"))
        (p "On client-side navigation, the engine reads " (code "SX-Tier") " from the response. If the new page requires a higher tier than currently loaded, it fetches the delta script before processing the swap. The delta script registers its additional primitives and the swap proceeds."))

      (~docs/subsection :title "Cache Behavior"
        (p "Each tier file is content-hashed (like the current " (code "sx_js_hash") " mechanism). Cache-forever semantics. A user who visits any L0 page caches the L0 runtime permanently. If they later visit an L2 page, only the ~10KB delta downloads.")
        (p "Combined with " (a :href "/sx/(etc.(plan.environment-images))" (~tw :tokens "text-violet-700 underline") "environment images") ": the image CID includes the tier. An L0 image is smaller than an L3 image — it contains fewer primitives, no parser state, no evaluator. The standalone HTML bundle for an L0 page is tiny.")))

    ;; -----------------------------------------------------------------------
    ;; Automatic tier detection
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Automatic Tier Detection" :id "auto-detect"
      (p (code "deps.sx") " already classifies components as pure or IO-dependent. Extend it to classify pages by tier:")

      (~docs/code :src (highlight ";; Extend deps.sx with tier analysis\n;;\n;; Walk the page's component tree:\n;; - Any defisland → L2 minimum\n;; - Any on-event, toggle!, set-attr! call → L1 minimum  \n;; - Any client-eval'd component (SX wire + defcomp) → L3\n;; - Otherwise → L0\n;;\n;; The tier is the MAX of all components' requirements.\n\n(define component-tier\n  (fn (comp)\n    (cond\n      ((island? comp)                    :L2)\n      ((has-dom-ops? (component-body comp)) :L1)\n      (true                              :L0))))\n\n(define page-tier\n  (fn (page-def)\n    (let ((comp-tiers (map component-tier\n                       (page-all-components page-def))))\n      (max-tier comp-tiers))))" "lisp"))

      (p "This runs at registration time (same phase as " (code "compute_all_deps") "). Each " (code "PageDef") " gains a " (code "tier") " field. The server uses it to select the script tag. No manual annotation needed — the tier is derived from what the page actually uses."))

    ;; -----------------------------------------------------------------------
    ;; What L0 actually needs
    ;; -----------------------------------------------------------------------

    (~docs/section :title "What L0 Actually Needs" :id "l0-detail"
      (p "L0 is the critical tier — it's what most pages load. Every byte matters. Let's be precise about what it contains:")

      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Function")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Purpose")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Source")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-700") "morph-node")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "DOM diffing — update existing DOM from new HTML")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "engine.sx"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-700") "morph-attrs")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Attribute diffing on a single element")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "engine.sx"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-700") "morph-children")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Child node reconciliation")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "engine.sx"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-700") "process-swap")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Apply sx-swap directive (innerHTML, outerHTML, etc)")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "engine.sx"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-700") "dispatch-trigger")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Process sx-trigger attributes (click, submit, load, etc)")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "engine.sx"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-700") "sx-fetch")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Make sx-get/sx-post requests, process response")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "orchestration.sx"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-700") "push-url / replace-url")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "History management for sx-push-url")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "engine.sx"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-700") "boot-triggers")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Scan DOM for sx-* attributes, wire up event listeners")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "boot.sx"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-stone-700") "resolve-suspense")
              (td (~tw :tokens "px-3 py-2 text-stone-700") "Fill in streamed suspense slots")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "boot.sx")))))

      (p "That's roughly 20-30 defines from engine.sx + orchestration.sx + boot.sx, plus their transitive deps. No parser, no evaluator, no primitives beyond what those defines call internally. The platform JS is just: fetch wrapper, DOM helpers (createElement, setAttribute, morphing), history API, and event delegation.")

      (p "Target: " (strong "~5KB min+gz") " — competitive with htmx (10KB) while being semantically richer (morph-based, not innerHTML-based)."))

    ;; -----------------------------------------------------------------------
    ;; Build pipeline
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Build Pipeline" :id "pipeline"
      (p "The pipeline uses the same tools that already exist — " (code "js.sx") " for translation, " (code "bootstrap_js.py") " for platform assembly — but feeds them filtered define lists.")

      (~docs/code :src (highlight ";; Build all tiers\n;;\n;; 1. Load all spec .sx files\n;; 2. Extract all defines (same as current bootstrap)\n;; 3. Run slice.sx to partition defines by tier\n;; 4. For each tier:\n;;    a. js.sx translates the tier's define list\n;;    b. Platform assembler wraps with minimal platform JS\n;;    c. Output: sx-L{n}.js\n;; 5. Compute deltas: L1-delta = L1 - L0, L2-delta = L2 - L1, etc.\n\n;; The bootstrapper script orchestrates this:\n;;\n;; python bootstrap_js.py --tier L0 -o sx-L0.js\n;; python bootstrap_js.py --tier L1 --delta -o sx-L1-delta.js\n;; python bootstrap_js.py --tier L2 --delta -o sx-L2-delta.js\n;; python bootstrap_js.py -o sx-browser.js  # full (L3, backward compat)" "lisp"))

      (p "The " (code "--delta") " flag emits only the defines not present in the previous tier. The delta file calls " (code "Sx.extend()") " to register its additions into the already-loaded runtime.")

      (div (~tw :tokens "rounded border border-violet-200 bg-violet-50 p-4 mt-4")
        (p (~tw :tokens "text-violet-900 font-medium") "Self-hosting all the way")
        (p (~tw :tokens "text-violet-800") (code "slice.sx") " is spec. " (code "js.sx") " is spec. The bootstrapper script (" (code "bootstrap_js.py") ") is the thin host-specific glue that reads slice output, calls js.sx via the evaluator, and wraps with platform JS. The slicer could itself be bootstrapped to JavaScript and run in a browser build tool — but that's a future concern.")))

    ;; -----------------------------------------------------------------------
    ;; Spec modules
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Spec Modules" :id "spec-modules"
      (div (~tw :tokens "overflow-x-auto rounded border border-stone-200 mb-4")
        (table (~tw :tokens "w-full text-left text-sm")
          (thead (tr (~tw :tokens "border-b border-stone-200 bg-stone-100")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Module")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Functions")
            (th (~tw :tokens "px-3 py-2 font-medium text-stone-600") "Depends on")))
          (tbody
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "slice.sx")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "define-refs") ", " (code "define-dep-graph") ", " (code "slice-defines") ", " (code "tier-entry-points") ", " (code "page-tier") ", " (code "component-tier"))
              (td (~tw :tokens "px-3 py-2 text-stone-600") "deps.sx (component analysis), eval.sx (AST walking)"))
            (tr (~tw :tokens "border-b border-stone-100")
              (td (~tw :tokens "px-3 py-2 font-mono text-sm text-violet-700") "js.sx")
              (td (~tw :tokens "px-3 py-2 text-stone-700") (code "js-translate-file") " — already exists, unchanged")
              (td (~tw :tokens "px-3 py-2 text-stone-600") "eval.sx (runs on evaluator)")))))

      (p "One new spec file (" (code "slice.sx") "), one existing translator (" (code "js.sx") "), one modified host script (" (code "bootstrap_js.py") " gains " (code "--tier") " and " (code "--delta") " flags)."))

    ;; -----------------------------------------------------------------------
    ;; Relationships
    ;; -----------------------------------------------------------------------

    (~docs/section :title "Relationships" :id "relationships"
      (ul (~tw :tokens "list-disc pl-5 text-stone-700 space-y-1")
        (li (a :href "/sx/(etc.(plan.environment-images))" (~tw :tokens "text-violet-700 underline") "Environment Images") " — tiered images are smaller. An L0 image omits the parser, evaluator, and most primitives.")
        (li (a :href "/sx/(etc.(plan.content-addressed-components))" (~tw :tokens "text-violet-700 underline") "Content-Addressed Components") " — component CID resolution is L3-only. L0 pages don't resolve components client-side.")
        (li (a :href "/sx/(geography.(reactive.(reactive-design)))" (~tw :tokens "text-violet-700 underline") "Reactive Islands") " — L2 tier is defined by island presence. The signal runtime is the L1→L2 delta.")
        (li (a :href "/sx/(etc.(plan.isomorphic-architecture))" (~tw :tokens "text-violet-700 underline") "Isomorphic Architecture") " — client-side page rendering is L3. Most pages don't need it."))

      (div (~tw :tokens "rounded border border-amber-200 bg-amber-50 p-3 mt-2")
        (p (~tw :tokens "text-amber-800 text-sm") (strong "Depends on: ") (code "js.sx") " (complete), " (code "deps.sx") " (complete), " (code "bootstrap_js.py") " adapter selection (exists). " (strong "New: ") (code "slice.sx") " spec module.")))))
