 (defn- level-to-h [level]
   (keyword (str "h" level)))
 
-(defn subgenre-sexp [items fmt genre subgenre level]
-  [(heading (level-to-h level) subgenre [fmt genre subgenre])
+(defn subgenre-sexp [items fmt genre subgenre level numbers]
+  [(heading (level-to-h level) subgenre [fmt genre subgenre] numbers)
    (when-not (#{:kinder-und-jugendbücher} genre)
      (set-marker (layout/translations subgenre)))
    (entries-sexp items)])
 
-(defn subgenres-sexp [items fmt genre level]
-  (mapcat #(subgenre-sexp (get items %) fmt genre % level) (order (keys items))))
-
-(defn genre-sexp [items fmt genre level]
-  [(heading (level-to-h level) genre [fmt genre])
-   (set-marker (layout/translations genre))
-   (cond
-     (#{:kinder-und-jugendbücher} genre) (subgenres-sexp items fmt genre (inc level))
-     (#{:hörbuch} fmt) (subgenres-sexp items fmt genre (inc level))
-     :else (entries-sexp items))])
+(defn subgenres-sexp [items fmt genre level numbers]
+  (letfn [(numbered-subgenre [number subgenre]
+            (subgenre-sexp (get items subgenre) fmt genre subgenre level (add-number numbers number)))]
+    (apply concat (map-indexed #(numbered-subgenre %1 %2) (order (keys items))))))
+
+(defn genre-sexp
+  ([items fmt genre level]
+   (genre-sexp items fmt genre level []))
+  ([items fmt genre level numbers]
+   [(heading (level-to-h level) genre [fmt genre] numbers)
+    (set-marker (layout/translations genre))
+    (cond
+      (#{:kinder-und-jugendbücher} genre) (subgenres-sexp items fmt genre (inc level) numbers)
+      (#{:hörbuch} fmt) (subgenres-sexp items fmt genre (inc level) numbers)
+      :else (entries-sexp items))]))
 
 (defn format-sexp [items fmt level]
   [(heading (level-to-h level) fmt [fmt])

(defn- set-marker [title]
  [:fo:block {:keep-with-next "always"}
   [:fo:marker {:marker-class-name running-header-class-name} title]])

(defn- order
  "Return `items` ordered. Checks first if `items` are either a subset

  ([class attrs]
   (merge (*stylesheet* class {}) attrs)))

(defn- section-numbers [numbers]
  (when (not-empty numbers)
    (str (string/join "." numbers) ". ")))

(defn heading
  ([level title path]
   (heading level title path []))
  ([level title path numbers]
   [:fo:block (style level
                     {:id (hash path)})
    (section-numbers numbers)
    (layout/translations title)]))

(def ^:private running-header-class-name "running-header")

