diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md
index f20a2268626fedc8f92156536dc6d3d80b571143..c35e0cfda709ec9dd3d8c07236f7b16d1051272b 100644
--- a/CONTRIBUTING.md
+++ b/CONTRIBUTING.md
@@ -1,4 +1,4 @@
-# Contributing to pyHMMER
+# Contributing to PyHMMER
 
 For bug fixes or new features, please file an issue before submitting a
 pull request. If the change isn't trivial, it may be best to wait for
diff --git a/README.md b/README.md
index 15a8d85e6a6f72b19c6b4f12cb0035a882a9eb16..6d8d524858f767aab9abae9094695976614eba3a 100644
--- a/README.md
+++ b/README.md
@@ -50,7 +50,7 @@ HMMER internals, which has the following advantages over CLI wrappers
   loaded in memory, for instance because you obtained them from another
   Python library (such as [Pyrodigal](https://github.com/althonos/pyrodigal)
   or [Biopython](https://biopython.org/)).
-- **no output formatting**: HMMER3 is notorious for its numerous output files
+- **no output parsing**: HMMER3 is notorious for its numerous output files
   and its fixed-width tabular output, which is hard to parse (even
   [`Bio.SearchIO.HmmerIO`](https://biopython.org/docs/dev/api/Bio.SearchIO.HmmerIO.html)
   is struggling on some sequences).
diff --git a/docs/_images/favicon.ico b/docs/_images/favicon.ico
new file mode 100644
index 0000000000000000000000000000000000000000..70b8e2e6e96286dd190a12c8d2bc8fba2d9057a2
Binary files /dev/null and b/docs/_images/favicon.ico differ
diff --git a/docs/_images/logo.png b/docs/_images/logo.png
new file mode 120000
index 0000000000000000000000000000000000000000..9811a578650f93dec75ce20b1b81bac53013b738
--- /dev/null
+++ b/docs/_images/logo.png
@@ -0,0 +1 @@
+../../static/logo.png
\ No newline at end of file
diff --git a/docs/_static/css/custom.css b/docs/_static/css/custom.css
new file mode 100644
index 0000000000000000000000000000000000000000..e1fb2599463b87abdf07418f865429e0379782ad
--- /dev/null
+++ b/docs/_static/css/custom.css
@@ -0,0 +1,3 @@
+code-data#setup span.caption-text {
+    display: none;
+}
\ No newline at end of file
diff --git a/docs/_static/js/custom-icon.js b/docs/_static/js/custom-icon.js
new file mode 100644
index 0000000000000000000000000000000000000000..035be992ed6a1e784e1ff8d5eec663582c1a0952
--- /dev/null
+++ b/docs/_static/js/custom-icon.js
@@ -0,0 +1,44 @@
+/*******************************************************************************
+ * Set a custom icon for pypi as it's not available in the fa built-in brands
+ */
+FontAwesome.library.add(
+  (faListOldStyle = {
+    prefix: "fa-custom",
+    iconName: "pypi",
+    icon: [
+      17.313, // viewBox width
+      19.807, // viewBox height
+      [], // ligature
+      "e001", // unicode codepoint - private use area
+      "m10.383 0.2-3.239 1.1769 3.1883 1.1614 3.239-1.1798zm-3.4152 1.2411-3.2362 1.1769 3.1855 1.1614 3.2369-1.1769zm6.7177 0.00281-3.2947 1.2009v3.8254l3.2947-1.1988zm-3.4145 1.2439-3.2926 1.1981v3.8254l0.17548-0.064132 3.1171-1.1347zm-6.6564 0.018325v3.8247l3.244 1.1805v-3.8254zm10.191 0.20931v2.3137l3.1777-1.1558zm3.2947 1.2425-3.2947 1.1988v3.8254l3.2947-1.1988zm-8.7058 0.45739c0.00929-1.931e-4 0.018327-2.977e-4 0.027485 0 0.25633 0.00851 0.4263 0.20713 0.42638 0.49826 1.953e-4 0.38532-0.29327 0.80469-0.65542 0.93662-0.36226 0.13215-0.65608-0.073306-0.65613-0.4588-6.28e-5 -0.38556 0.2938-0.80504 0.65613-0.93662 0.068422-0.024919 0.13655-0.038114 0.20156-0.039466zm5.2913 0.78369-3.2947 1.1988v3.8247l3.2947-1.1981zm-10.132 1.239-3.2362 1.1769 3.1883 1.1614 3.2362-1.1769zm6.7177 0.00213-3.2926 1.2016v3.8247l3.2926-1.2009zm-3.4124 1.2439-3.2947 1.1988v3.8254l3.2947-1.1988zm-6.6585 0.016195v3.8275l3.244 1.1805v-3.8254zm16.9 0.21143-3.2947 1.1988v3.8247l3.2947-1.1981zm-3.4145 1.2411-3.2926 1.2016v3.8247l3.2926-1.2009zm-3.4145 1.2411-3.2926 1.2016v3.8247l3.2926-1.2009zm-3.4124 1.2432-3.2947 1.1988v3.8254l3.2947-1.1988zm-6.6585 0.019027v3.8247l3.244 1.1805v-3.8254zm13.485 1.4497-3.2947 1.1988v3.8247l3.2947-1.1981zm-3.4145 1.2411-3.2926 1.2016v3.8247l3.2926-1.2009zm2.4018 0.38127c0.0093-1.83e-4 0.01833-3.16e-4 0.02749 0 0.25633 0.0085 0.4263 0.20713 0.42638 0.49826 1.97e-4 0.38532-0.29327 0.80469-0.65542 0.93662-0.36188 0.1316-0.65525-0.07375-0.65542-0.4588-1.95e-4 -0.38532 0.29328-0.80469 0.65542-0.93662 0.06842-0.02494 0.13655-0.03819 0.20156-0.03947zm-5.8142 0.86403-3.244 1.1805v1.4201l3.244 1.1805z", // svg path (https://simpleicons.org/icons/pypi.svg)
+    ],
+  }),
+);
+
+FontAwesome.library.add(
+  (faListOldStyle = {
+    prefix: "fa-custom",
+    iconName: "sword",
+    icon: [
+      256, // viewBox width
+      256, // viewBox height
+      [], // ligature
+      "e002", // unicode codepoint - private use area
+      "M221.65723,34.34326A8.00246,8.00246,0,0,0,216,32h-.02539l-63.79883.20117A8.00073,8.00073,0,0,0,146.0332,35.106L75.637,120.32275,67.31348,111.999A16.02162,16.02162,0,0,0,44.68555,112L32.001,124.68555A15.99888,15.99888,0,0,0,32,147.31348l20.88672,20.88769L22.94531,198.14258a16.01777,16.01777,0,0,0,.001,22.62695l12.28418,12.28418a16.00007,16.00007,0,0,0,22.62793,0L87.79883,203.1123,108.68652,224.001A16.02251,16.02251,0,0,0,131.31445,224L143.999,211.31445A15.99888,15.99888,0,0,0,144,188.68652l-8.32324-8.32324,85.21679-70.39648a8.00125,8.00125,0,0,0,2.90528-6.14258L224,40.02539A8.001,8.001,0,0,0,221.65723,34.34326Zm-13.84668,65.67822-83.49829,68.97706L111.314,156l54.34327-54.34277a8.00053,8.00053,0,0,0-11.31446-11.31446L100,144.686,87.00195,131.6875,155.97852,48.189l51.99609-.16357Z", // svg path (https://simpleicons.org/icons/pypi.svg)
+    ],
+  }),
+);
+
+FontAwesome.library.add(
+  (faListOldStyle = {
+    prefix: "fa-custom",
+    iconName: "knife",
+    icon: [
+      256, // viewBox width
+      256, // viewBox height
+      [], // ligature
+      "e003", // unicode codepoint - private use area
+      "M231.79883,32.2002a28.05536,28.05536,0,0,0-39.667.06933L18.27441,210.41211a8,8,0,0,0,3.92676,13.38281,155.06019,155.06019,0,0,0,34.957,4.00293c33.4209-.001,66.877-10.86914,98.32813-32.1748,31.74512-21.50391,50.14551-45.79981,50.91406-46.82325a8.00114,8.00114,0,0,0-.74316-10.457L186.919,119.60547l44.97753-47.90332A28.03445,28.03445,0,0,0,231.79883,32.2002ZM189.207,144.52148a225.51045,225.51045,0,0,1-43.10351,38.13184c-34.46973,23.23145-69.999,32.665-105.83887,28.13477l106.29492-108.915,23.30176,23.30175q.208.22852.43847.44434l.082.07617Z", // svg path (https://simpleicons.org/icons/pypi.svg)
+    ],
+  }),
+);
diff --git a/docs/api/daemon.rst b/docs/api/daemon/client.rst
similarity index 56%
rename from docs/api/daemon.rst
rename to docs/api/daemon/client.rst
index 1bc46f20f0edfc67b596c581a2f833c0a7a960bb..f934cc6fca99e4b226f1a4afcab4507b00481a16 100644
--- a/docs/api/daemon.rst
+++ b/docs/api/daemon/client.rst
@@ -1,24 +1,10 @@
-Daemon
-======
-
-.. currentmodule:: pyhmmer.daemon
-
-
-.. automodule:: pyhmmer.daemon
-
-
-
 Client
-------
+======
 
 .. autoclass:: pyhmmer.daemon.Client
    :special-members: __init__
    :members:
 
-
-IterativeSearch
----------------
-
 .. autoclass:: pyhmmer.daemon.IterativeSearch
    :special-members: __init__
-   :members:
+   :members:
\ No newline at end of file
diff --git a/docs/api/daemon/index.rst b/docs/api/daemon/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..cc096a25ba237e29f59ac1e80b274a442d4e831b
--- /dev/null
+++ b/docs/api/daemon/index.rst
@@ -0,0 +1,21 @@
+Daemon
+======
+
+.. currentmodule:: pyhmmer.daemon
+
+.. automodule:: pyhmmer.daemon
+
+
+Client
+------
+
+.. autosummary::
+
+   Client
+   IterativeSearch
+
+.. toctree::
+    :hidden:
+    :caption: Client
+
+    Client <client>
\ No newline at end of file
diff --git a/docs/api/easel.rst b/docs/api/easel.rst
deleted file mode 100644
index c290739186fcbabbee18451bc0ed596f11cb8714..0000000000000000000000000000000000000000
--- a/docs/api/easel.rst
+++ /dev/null
@@ -1,193 +0,0 @@
-Easel
-=====
-
-.. currentmodule:: pyhmmer.easel
-
-
-.. automodule:: pyhmmer.easel
-
-
-Data Structures
----------------
-
-Bitfield
-^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.Bitfield
-   :special-members: __init__
-   :members:
-
-KeyHash
-^^^^^^^
-
-.. autoclass:: pyhmmer.easel.KeyHash
-   :special-members: __init__
-   :members:
-
-
-Sequences
----------
-
-Sequence
-^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.Sequence
-   :members:
-
-TextSequence
-^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.TextSequence(Sequence)
-   :special-members: __init__
-   :members:
-
-DigitalSequence
-^^^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.DigitalSequence(Sequence)
-   :special-members: __init__
-   :members:
-
-
-Sequence Blocks
----------------
-
-SequenceBlock
-^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.SequenceBlock
-   :members:
-
-TextSequenceBlock
-^^^^^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.TextSequenceBlock(SequenceBlock)
-   :special-members: __init__
-   :members:
-
-DigitalSequenceBlock
-^^^^^^^^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.DigitalSequenceBlock(SequenceBlock)
-   :special-members: __init__
-   :members:
-
-
-SequenceFile
-------------
-
-SequenceFile
-^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.SequenceFile
-  :special-members: __init__
-  :members:
-
-
-Alignments
-----------
-
-MSA
-^^^
-
-.. autoclass:: pyhmmer.easel.MSA
-   :members:
-
-TextMSA
-^^^^^^^
-
-.. autoclass:: pyhmmer.easel.TextMSA(MSA)
-   :special-members: __init__
-   :members:
-
-DigitalMSA
-^^^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.DigitalMSA(MSA)
-   :special-members: __init__
-   :members:
-
-MSAFile
-^^^^^^^
-
-.. autoclass:: pyhmmer.easel.MSAFile
-   :special-members: __init__
-   :members:
-
-
-Linear Algebra
---------------
-
-Vector
-^^^^^^
-
-.. autoclass:: pyhmmer.easel.Vector
-   :members:
-
-VectorF
-^^^^^^^
-
-.. autoclass:: pyhmmer.easel.VectorF
-   :special-members: __init__
-   :members:
-
-VectorU8
-^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.VectorU8
-   :special-members: __init__
-   :members:
-
-Matrix
-^^^^^^
-
-.. autoclass:: pyhmmer.easel.Matrix
-   :members:
-
-MatrixF
-^^^^^^^
-
-.. autoclass:: pyhmmer.easel.MatrixF
-   :special-members: __init__
-   :members:
-
-MatrixU8
-^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.MatrixU8
-   :special-members: __init__
-   :members:
-
-
-Miscellaneous
--------------
-
-Alphabet
-^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.Alphabet
-   :members:
-
-GeneticCode
-^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.GeneticCode
-   :members:
-
-Randomness
-^^^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.Randomness
-   :special-members: __init__
-   :members:
-
-Sequence / Subsequence Index
-^^^^^^^^^^^^^^^^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.easel.SSIReader
-   :special-members: __init__
-   :members:
-
-.. autoclass:: pyhmmer.easel.SSIWriter
-   :special-members: __init__
-   :members:
diff --git a/docs/api/easel/block.rst b/docs/api/easel/block.rst
new file mode 100644
index 0000000000000000000000000000000000000000..1b8694725d0ae3f544302b196ebbce99702fa022
--- /dev/null
+++ b/docs/api/easel/block.rst
@@ -0,0 +1,13 @@
+Blocks
+======
+
+.. autoclass:: pyhmmer.easel.SequenceBlock
+   :members:
+
+.. autoclass:: pyhmmer.easel.TextSequenceBlock(SequenceBlock)
+   :members:
+   :special-members: __init__
+
+.. autoclass:: pyhmmer.easel.DigitalSequenceBlock(SequenceBlock)
+   :members:
+   :special-members: __init__
\ No newline at end of file
diff --git a/docs/api/easel/data.rst b/docs/api/easel/data.rst
new file mode 100644
index 0000000000000000000000000000000000000000..a4837795775ae6898152704a2d9e53352a81cb36
--- /dev/null
+++ b/docs/api/easel/data.rst
@@ -0,0 +1,10 @@
+Data Structures
+===============
+
+.. autoclass:: pyhmmer.easel.Bitfield
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.easel.KeyHash
+   :special-members: __init__
+   :members:
\ No newline at end of file
diff --git a/docs/api/easel/index.rst b/docs/api/easel/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..ad43314a8fd0af5b4438c68bb2dcac38c07ae0d0
--- /dev/null
+++ b/docs/api/easel/index.rst
@@ -0,0 +1,130 @@
+Easel
+=====
+
+.. currentmodule:: pyhmmer.easel
+
+
+.. automodule:: pyhmmer.easel
+
+
+Data Structures
+---------------
+
+.. autosummary::
+
+   Bitfield
+   KeyHash
+
+.. toctree::
+   :caption: Data Structures
+   :maxdepth: 1
+   :hidden:
+
+   Data Structures <data>
+
+
+Sequences
+---------
+
+.. autosummary::
+
+   Sequence
+   TextSequence
+   DigitalSequence
+
+.. toctree::
+   :caption: Sequences
+   :maxdepth: 1
+   :hidden:
+
+   Sequences <seq>
+
+
+Sequence Blocks
+---------------
+
+.. autosummary::
+
+   SequenceBlock
+   TextSequenceBlock
+   DigitalSequenceBlock
+
+.. toctree::
+   :caption: Sequence Blocks
+   :maxdepth: 1
+   :hidden:
+
+   Sequence Blocks <block>
+
+
+Alignments
+----------
+
+.. autosummary::
+
+   MSA
+   TextMSA
+   DigitalMSA
+
+.. toctree::
+   :caption: Alignments
+   :maxdepth: 1
+   :hidden:
+
+   Alignments <msa>
+
+
+Parsers
+-------
+
+.. autosummary::
+
+   SequenceFile
+   MSAFile
+
+.. toctree::
+   :caption: Parsers
+   :maxdepth: 1
+   :hidden:
+
+   Parsers <parsers>
+
+
+Linear Algebra
+--------------
+
+.. autosummary::
+
+   Vector
+   VectorF
+   VectorU8
+   Matrix
+   MatrixF
+   MatrixU8
+
+.. toctree::
+   :caption: Linear Algebra
+   :maxdepth: 1
+   :hidden:
+
+   Linear Algebra <linalg>
+
+
+Miscellaneous
+-------------
+
+.. autosummary::
+
+   Alphabet
+   GeneticCode
+   Randomness
+   SSIReader
+   SSIWriter
+
+.. toctree::
+   :caption: Miscellaneous
+   :maxdepth: 1
+   :hidden:
+
+   Miscellaneous <misc>
+
diff --git a/docs/api/easel/linalg.rst b/docs/api/easel/linalg.rst
new file mode 100644
index 0000000000000000000000000000000000000000..b87b137a9a4dbeffa1ea1e1e2b145e844815fcc0
--- /dev/null
+++ b/docs/api/easel/linalg.rst
@@ -0,0 +1,25 @@
+Linear Algebra
+==============
+
+.. autoclass:: pyhmmer.easel.Vector
+   :members:
+
+.. autoclass:: pyhmmer.easel.VectorF(Vector)
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.easel.VectorU8(Vector)
+   :special-members: __init__
+   :members:
+
+
+.. autoclass:: pyhmmer.easel.Matrix
+   :members:
+
+.. autoclass:: pyhmmer.easel.MatrixF
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.easel.MatrixU8
+   :special-members: __init__
+   :members:
\ No newline at end of file
diff --git a/docs/api/easel/misc.rst b/docs/api/easel/misc.rst
new file mode 100644
index 0000000000000000000000000000000000000000..79147463c49946d244e9026dd08591e23d46dfea
--- /dev/null
+++ b/docs/api/easel/misc.rst
@@ -0,0 +1,21 @@
+Miscellaneous
+=============
+
+.. autoclass:: pyhmmer.easel.Alphabet
+   :members:
+
+.. autoclass:: pyhmmer.easel.GeneticCode
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.easel.Randomness
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.easel.SSIReader
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.easel.SSIWriter
+   :special-members: __init__
+   :members:
diff --git a/docs/api/easel/msa.rst b/docs/api/easel/msa.rst
new file mode 100644
index 0000000000000000000000000000000000000000..c566bfbe11ea818e985c21a009138bfa81dad3b5
--- /dev/null
+++ b/docs/api/easel/msa.rst
@@ -0,0 +1,13 @@
+Alignments
+==========
+
+.. autoclass:: pyhmmer.easel.MSA
+   :members:
+
+.. autoclass:: pyhmmer.easel.TextMSA(MSA)
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.easel.DigitalMSA(MSA)
+   :special-members: __init__
+   :members:
\ No newline at end of file
diff --git a/docs/api/easel/parsers.rst b/docs/api/easel/parsers.rst
new file mode 100644
index 0000000000000000000000000000000000000000..32a8f66a3cd5ca7a00da77ab3404025a1789c6ee
--- /dev/null
+++ b/docs/api/easel/parsers.rst
@@ -0,0 +1,11 @@
+MSAFile
+=======
+
+.. autoclass:: pyhmmer.easel.SequenceFile
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.easel.MSAFile
+   :special-members: __init__
+   :members:
+
diff --git a/docs/api/easel/seq.rst b/docs/api/easel/seq.rst
new file mode 100644
index 0000000000000000000000000000000000000000..80979a19245636942a47608a111f21dfd6856861
--- /dev/null
+++ b/docs/api/easel/seq.rst
@@ -0,0 +1,13 @@
+Sequence
+========
+
+.. autoclass:: pyhmmer.easel.Sequence
+   :members:
+
+.. autoclass:: pyhmmer.easel.TextSequence
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.easel.DigitalSequence
+   :special-members: __init__
+   :members:
\ No newline at end of file
diff --git a/docs/api/errors.rst b/docs/api/errors.rst
deleted file mode 100644
index 77d0cd37432834a83efc29ca9f4ca865330985c8..0000000000000000000000000000000000000000
--- a/docs/api/errors.rst
+++ /dev/null
@@ -1,70 +0,0 @@
-Errors
-======
-
-.. currentmodule:: pyhmmer.errors
-
-.. automodule:: pyhmmer.errors
-
-
-AllocationError
----------------
-
-.. autoexception:: AllocationError(MemoryError)
-   :special-members: __init__
-   :members:
-
-
-UnexpectedError
----------------
-
-.. autoexception:: UnexpectedError(RuntimeError)
-   :special-members: __init__
-   :members:
-
-
-EaselError
-----------
-
-.. autoexception:: EaselError(RuntimeError)
-   :special-members: __init__
-   :members:
-
-
-AlphabetMismatch
-----------------
-
-.. autoexception:: AlphabetMismatch(ValueError)
-   :special-members: __init__
-   :members:
-
-
-ServerError
------------
-
-.. autoexception:: ServerError(RuntimeError)
-   :special-members: __init__
-   :members:
-
-
-MissingCutoffs
---------------
-
-.. autoexception:: MissingCutoffs(ValueError)
-   :special-members: __init__
-   :members:
-
-
-InvalidParameter
-----------------
-
-.. autoexception:: InvalidParameter(ValueError)
-   :special-members: __init__
-   :members:
-
-
-InvalidHMM
-----------
-
-.. autoexception:: InvalidHMM(ValueError)
-   :special-members: __init__
-   :members:
diff --git a/docs/api/errors/index.rst b/docs/api/errors/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..3c7c7cd14048f2445516628358bbc3048d650b42
--- /dev/null
+++ b/docs/api/errors/index.rst
@@ -0,0 +1,53 @@
+Errors
+======
+
+.. currentmodule:: pyhmmer.errors
+
+.. automodule:: pyhmmer.errors
+
+
+Memory Errors
+-------------
+
+.. autosummary::
+
+   AllocationError
+
+.. toctree::
+    :hidden:
+    :caption: Memory Errors
+
+    Memory Errors <mem>
+
+
+Value Errors
+------------
+
+.. autosummary::
+
+   AlphabetMismatch
+   MissingCutoffs
+   InvalidHMM
+   InvalidParameter
+
+.. toctree::
+    :hidden:
+    :caption: Memory Errors
+
+    Value Errors <value>
+
+
+Runtime Errors
+--------------
+
+.. autosummary::
+
+   UnexpectedError
+   EaselError
+   ServerError
+
+.. toctree::
+    :hidden:
+    :caption: Runtime Errors
+
+    Runtime Errors <runtime>
\ No newline at end of file
diff --git a/docs/api/errors/mem.rst b/docs/api/errors/mem.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f627122038e083db1563f98fd81a72f3167ac1d4
--- /dev/null
+++ b/docs/api/errors/mem.rst
@@ -0,0 +1,8 @@
+Memory Errors
+-------------
+
+.. currentmodule:: pyhmmer.errors
+
+.. autoexception:: AllocationError(MemoryError)
+   :special-members: __init__
+   :members:
diff --git a/docs/api/errors/runtime.rst b/docs/api/errors/runtime.rst
new file mode 100644
index 0000000000000000000000000000000000000000..ddb6019010348c9dd50e647ef708194bdd141e05
--- /dev/null
+++ b/docs/api/errors/runtime.rst
@@ -0,0 +1,16 @@
+Runtime Errors
+--------------
+
+.. currentmodule:: pyhmmer.errors
+
+.. autoexception:: UnexpectedError(RuntimeError)
+   :special-members: __init__
+   :members:
+
+.. autoexception:: EaselError(RuntimeError)
+   :special-members: __init__
+   :members:
+
+.. autoexception:: ServerError(RuntimeError)
+   :special-members: __init__
+   :members:
diff --git a/docs/api/errors/value.rst b/docs/api/errors/value.rst
new file mode 100644
index 0000000000000000000000000000000000000000..21b2e60a3c0cf18ee59577de7bbb3c6b80d45ae7
--- /dev/null
+++ b/docs/api/errors/value.rst
@@ -0,0 +1,20 @@
+Value Errors
+------------
+
+.. currentmodule:: pyhmmer.errors
+
+.. autoexception:: AlphabetMismatch(ValueError)
+   :special-members: __init__
+   :members:
+
+.. autoexception:: MissingCutoffs(ValueError)
+   :special-members: __init__
+   :members:
+
+.. autoexception:: InvalidHMM(ValueError)
+   :special-members: __init__
+   :members:
+
+.. autoexception:: InvalidParameter(ValueError)
+   :special-members: __init__
+   :members:
diff --git a/docs/api/hmmer.rst b/docs/api/hmmer.rst
deleted file mode 100644
index 668830835a68541044103b4f624de4c0afb7b004..0000000000000000000000000000000000000000
--- a/docs/api/hmmer.rst
+++ /dev/null
@@ -1,49 +0,0 @@
-HMMER
-=====
-
-.. currentmodule:: pyhmmer.hmmer
-
-
-.. automodule:: pyhmmer.hmmer
-
-
-hmmsearch
----------
-
-.. autofunction:: pyhmmer.hmmer.hmmsearch(queries, sequences, cpus=0, callback=None, **options)
-
-
-hmmscan
--------
-
-.. autofunction:: pyhmmer.hmmer.hmmscan(queries, profiles, cpus=0, callback=None, background=None, **options)
-
-
-phmmer
-------
-
-.. autofunction:: pyhmmer.hmmer.phmmer(queries, sequences, cpus=0, callback=None, builder=None, **options)
-
-
-nhmmer
-------
-
-.. autofunction:: pyhmmer.hmmer.nhmmer(queries, sequences, cpus=0, callback=None, builder=None, **options)
-
-
-hmmpress
---------
-
-.. autofunction:: pyhmmer.hmmer.hmmpress(hmms, output)
-
-
-hmmalign
---------
-
-.. autofunction:: pyhmmer.hmmer.hmmalign(hmm, sequences, trim=False, digitize=False, all_consensus_cols=True)
-
-
-jackhmmer
----------
-
-.. autofunction:: pyhmmer.hmmer.jackhmmer(queries, sequences, cpus=0, allback=None, builder=None, max_iterations=5, select_hits=None, checkpoints=False, **options)
diff --git a/docs/api/hmmer/index.rst b/docs/api/hmmer/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..0e0c8f3ee3923daf775002965a035c2668c7d978
--- /dev/null
+++ b/docs/api/hmmer/index.rst
@@ -0,0 +1,72 @@
+HMMER
+=====
+
+.. currentmodule:: pyhmmer.hmmer
+
+.. automodule:: pyhmmer.hmmer
+
+
+Profile Searches
+----------------
+
+.. toctree::
+    :hidden:
+    :caption: Sequence Searches
+
+    Sequence Searches <seq>
+
+.. autosummary::
+
+    hmmsearch
+    hmmscan
+
+
+Sequence Searches
+-----------------
+
+.. toctree::
+    :hidden:
+    :caption: Profile Searches
+
+    Profile Searches <profile>
+
+.. autosummary::
+
+    phmmer
+    nhmmer
+
+
+Iterative Searches
+------------------
+
+.. toctree::
+    :hidden:
+    :caption: Iterative Searches
+
+    IterativeSearch <iter>
+
+.. autosummary::
+
+    jackhmmer
+
+
+Utilities
+---------
+
+.. toctree::
+    :hidden:
+    :caption: Utilities
+
+    Utilities <utils>
+
+.. autosummary::
+
+    hmmpress
+    hmmalign
+
+
+
+
+
+
+
diff --git a/docs/api/hmmer/iter.rst b/docs/api/hmmer/iter.rst
new file mode 100644
index 0000000000000000000000000000000000000000..9f43fcbae2f67d6a60988bdb2eeeb90caae63380
--- /dev/null
+++ b/docs/api/hmmer/iter.rst
@@ -0,0 +1,6 @@
+Iterative Searches
+==================
+
+.. currentmodule:: pyhmmer.hmmer
+
+.. autofunction:: pyhmmer.hmmer.jackhmmer(queries, sequences, *, max_iterations=5, select_hits=None, checkpoints=False, cpus=0, callback=None, builder=None, **options)
diff --git a/docs/api/hmmer/profile.rst b/docs/api/hmmer/profile.rst
new file mode 100644
index 0000000000000000000000000000000000000000..32de1c374ead4854f7d65200e5b8765ae28994ac
--- /dev/null
+++ b/docs/api/hmmer/profile.rst
@@ -0,0 +1,6 @@
+Profile Searches
+================
+
+.. autofunction:: pyhmmer.hmmer.hmmsearch(queries, sequences, cpus=0, callback=None, **options)
+
+.. autofunction:: pyhmmer.hmmer.hmmscan(queries, profiles, cpus=0, callback=None, background=None, **options)
diff --git a/docs/api/hmmer/seq.rst b/docs/api/hmmer/seq.rst
new file mode 100644
index 0000000000000000000000000000000000000000..f40131fa29f412bdea67057a4d66295296846c55
--- /dev/null
+++ b/docs/api/hmmer/seq.rst
@@ -0,0 +1,6 @@
+Sequence Searches
+=================
+
+.. autofunction:: pyhmmer.hmmer.phmmer(queries, sequences, cpus=0, callback=None, builder=None, **options)
+
+.. autofunction:: pyhmmer.hmmer.nhmmer(queries, sequences, cpus=0, callback=None, builder=None, **options)
diff --git a/docs/api/hmmer/utils.rst b/docs/api/hmmer/utils.rst
new file mode 100644
index 0000000000000000000000000000000000000000..ff3d79ae3f95a36fb8ace67dc9529fbc8ff3cec9
--- /dev/null
+++ b/docs/api/hmmer/utils.rst
@@ -0,0 +1,6 @@
+Utilities
+=========
+
+.. autofunction:: pyhmmer.hmmer.hmmpress(hmms, output)
+
+.. autofunction:: pyhmmer.hmmer.hmmalign(hmm, sequences, trim=False, digitize=False, all_consensus_cols=True)
diff --git a/docs/api/index.rst b/docs/api/index.rst
index b7a35cba33841eead9e26653e991b0fd740a4e41..84dc9b764538f8467d6b7a973c4dcbb6290a6907 100644
--- a/docs/api/index.rst
+++ b/docs/api/index.rst
@@ -1,232 +1,16 @@
 API Reference
 ==============
 
-.. toctree::
-   :hidden:
-
-   hmmer <hmmer>
-   easel <easel>
-   plan7 <plan7>
-   daemon <daemon>
-   errors <errors>
-
-
 .. currentmodule:: pyhmmer
 
-.. automodule:: pyhmmer
-
-
-.. only:: html
-
-    HMMER
-    -----
-
-    .. autosummary::
-        :nosignatures:
-
-        pyhmmer.hmmer.hmmsearch
-        pyhmmer.hmmer.hmmscan
-        pyhmmer.hmmer.phmmer
-        pyhmmer.hmmer.nhmmer
-        pyhmmer.hmmer.hmmpress
-        pyhmmer.hmmer.hmmalign
-
-
-    Easel
-    -----
-
-    Data Structures
-    ^^^^^^^^^^^^^^^
-
-    .. autosummary::
-       :nosignatures:
-
-       pyhmmer.easel.Bitfield
-       pyhmmer.easel.KeyHash
-
-
-    Sequences
-    ^^^^^^^^^
-
-    .. autosummary::
-       :nosignatures:
-
-       pyhmmer.easel.Sequence
-       pyhmmer.easel.TextSequence
-       pyhmmer.easel.DigitalSequence
-
-
-    Sequence Blocks
-    ^^^^^^^^^^^^^^^
-
-    .. autosummary::
-       :nosignatures:
-
-       pyhmmer.easel.SequenceBlock
-       pyhmmer.easel.TextSequenceBlock
-       pyhmmer.easel.DigitalSequenceBlock
-
-
-    Sequence File
-    ^^^^^^^^^^^^^
-
-    .. autosummary::
-       :nosignatures:
-
-       pyhmmer.easel.SequenceFile
-
-
-    Alignments
-    ^^^^^^^^^^
-
-    .. autosummary::
-       :nosignatures:
-
-       pyhmmer.easel.MSA
-       pyhmmer.easel.TextMSA
-       pyhmmer.easel.DigitalMSA
-
-
-    Alignment File
-    ^^^^^^^^^^^^^^
-
-    .. autosummary::
-       :nosignatures:
-
-       pyhmmer.easel.MSAFile
-
-
-    Linear Algebra
-    ^^^^^^^^^^^^^^
-
-    .. autosummary::
-       :nosignatures:
-
-       pyhmmer.easel.Vector
-       pyhmmer.easel.VectorF
-       pyhmmer.easel.VectorU8
-       pyhmmer.easel.Matrix
-       pyhmmer.easel.MatrixF
-       pyhmmer.easel.MatrixU8
-
-
-    Miscellaneous
-    ^^^^^^^^^^^^^
+This section contains a complete reference of the API of the different 
+``pyhmmer`` modules.
 
-    .. autosummary::
-       :nosignatures:
-
-       pyhmmer.easel.Alphabet
-       pyhmmer.easel.Randomness
-       pyhmmer.easel.SSIReader
-       pyhmmer.easel.SSIWriter
-
-
-
-    Plan7
-    -----
-
-    Profile HMMs
-    ^^^^^^^^^^^^
-
-    .. autosummary::
-        :nosignatures:
-
-        pyhmmer.plan7.HMM
-        pyhmmer.plan7.Profile
-        pyhmmer.plan7.OptimizedProfile
-        pyhmmer.plan7.OptimizedProfileBlock
-
-
-    HMM Files
-    ^^^^^^^^^
-
-    .. autosummary::
-        :nosignatures:
-
-        pyhmmer.plan7.HMMFile
-        pyhmmer.plan7.HMMPressedFile
-
-
-    Pipelines
-    ^^^^^^^^^
-
-    .. autosummary::
-        :nosignatures:
-
-        pyhmmer.plan7.Pipeline
-        pyhmmer.plan7.LongTargetsPipeline
-        pyhmmer.plan7.Builder
-        pyhmmer.plan7.Background
-
-
-    Results
-    ^^^^^^^
-
-    .. autosummary::
-        :nosignatures:
-
-        pyhmmer.plan7.TopHits
-        pyhmmer.plan7.Hit
-        pyhmmer.plan7.Domains
-        pyhmmer.plan7.Domain
-        pyhmmer.plan7.Alignment
-
-
-    Traces
-    ^^^^^^^
-
-    .. autosummary::
-        :nosignatures:
-
-        pyhmmer.plan7.TraceAligner
-        pyhmmer.plan7.Traces
-        pyhmmer.plan7.Trace
-
-
-    Iterative Searches
-    ^^^^^^^^^^^^^^^^^^
-
-    .. autosummary::
-       :nosignatures:
-
-       pyhmmer.plan7.IterativeSearch
-       pyhmmer.plan7.IterationResult
-
-
-    Miscellaneous
-    ^^^^^^^^^^^^^
-
-    .. autosummary::
-        :nosignatures:
-
-        pyhmmer.plan7.Cutoffs
-        pyhmmer.plan7.EvalueParameters
-        pyhmmer.plan7.Offsets
-        pyhmmer.plan7.Transitions
-
-
-    Daemon
-    ------
-
-    .. autosummary::
-        :nosignatures:
-
-        pyhmmer.daemon.Client
-        pyhmmer.daemon.IterativeSearch
-
-
-    Errors
-    ------
-
-    .. autosummary::
-       :nosignatures:
+.. toctree::
+   :maxdepth: 2
 
-       pyhmmer.errors.AllocationError
-       pyhmmer.errors.UnexpectedError
-       pyhmmer.errors.EaselError
-       pyhmmer.errors.AlphabetMismatch
-       pyhmmer.errors.ServerError
-       pyhmmer.errors.MissingCutoffs
-       pyhmmer.errors.InvalidParameter
-       pyhmmer.errors.InvalidHMM
+   HMMER <hmmer/index>
+   Easel <easel/index>
+   Plan7 <plan7/index>
+   Daemon <daemon/index>
+   Errors <errors/index>
diff --git a/docs/api/plan7.rst b/docs/api/plan7.rst
deleted file mode 100644
index cf73b5462af141716a6cb9f3aca12673bc4ddcc0..0000000000000000000000000000000000000000
--- a/docs/api/plan7.rst
+++ /dev/null
@@ -1,219 +0,0 @@
-Plan7
-=====
-
-.. currentmodule:: pyhmmer.plan7
-
-
-.. automodule:: pyhmmer.plan7
-
-
-Profile HMMs
-------------
-
-HMM
-^^^
-
-.. autoclass:: pyhmmer.plan7.HMM
-   :special-members: __init__
-   :members:
-
-Profile
-^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.Profile
-   :special-members: __init__
-   :members:
-
-OptimizedProfile
-^^^^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.OptimizedProfile
-   :special-members: __init__
-   :members:
-
-
-OptimizedProfileBlock
-^^^^^^^^^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.OptimizedProfileBlock
-   :special-members: __init__
-   :members:
-
-
-HMM Files
----------
-
-HMMFile
-^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.HMMFile
-   :special-members: __init__
-   :members:
-
-HMMPressedFile
-^^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.HMMPressedFile
-   :special-members: __init__
-   :members:
-
-
-Pipelines
----------
-
-Pipeline
-^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.Pipeline
-   :special-members: __init__
-   :members:
-
-LongTargetsPipeline
-^^^^^^^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.LongTargetsPipeline(Pipeline)
-  :special-members: __init__
-  :members:
-
-
-Builder
-^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.Builder
-  :special-members: __init__
-  :members:
-
-
-Background
-^^^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.Background
-   :special-members: __init__
-   :members:
-
-
-
-Results
--------
-
-TopHits
-^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.TopHits
-   :special-members: __init__
-   :members:
-
-Hit
-^^^
-
-.. autoclass:: pyhmmer.plan7.Hit
-   :special-members: __init__
-   :members:
-
-Domains
-^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.Domains
-   :special-members: __init__
-   :members:
-
-Domain
-^^^^^^
-
-.. autoclass:: pyhmmer.plan7.Domain
-   :special-members: __init__
-   :members:
-
-Alignment
-^^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.Alignment
-   :special-members: __init__
-   :members:
-
-
-Traces
-------
-
-TraceAligner
-^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.TraceAligner
-   :special-members: __init__
-   :members:
-
-Traces
-^^^^^^
-
-.. autoclass:: pyhmmer.plan7.Traces
-   :special-members: __init__
-   :members:
-
-Trace
-^^^^^
-
-.. autoclass:: pyhmmer.plan7.Trace
-   :special-members: __init__
-   :members:
-
-
-Iterative Searches
-------------------
-
-IterativeSearch
-^^^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.IterativeSearch
-    :special-members: __init__
-    :members:
-
-
-IterationResult
-^^^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.IterationResult
-    :special-members: __init__
-    :members:
-
-
-Miscellaneous
--------------
-
-Cutoffs
-^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.Cutoffs
-   :members:
-
-EvalueParameters
-^^^^^^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.EvalueParameters
-   :members:
-
-Offsets
-^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.Offsets
-   :members:
-
-
-Transitions
-^^^^^^^^^^^
-
-.. autoclass:: pyhmmer.plan7.Transitions(enum.IntEnum)
-
-   .. autoattribute:: MM
-
-   .. autoattribute:: MI
-
-   .. autoattribute:: MD
-
-   .. autoattribute:: IM
-
-   .. autoattribute:: II
-
-   .. autoattribute:: DM
-
-   .. autoattribute:: DD
-
diff --git a/docs/api/plan7/hmms.rst b/docs/api/plan7/hmms.rst
new file mode 100644
index 0000000000000000000000000000000000000000..9f8aac62c7c8298603ed6d6a3cd36bcf72303b2b
--- /dev/null
+++ b/docs/api/plan7/hmms.rst
@@ -0,0 +1,18 @@
+Profile Hidden Markov Models
+============================
+
+.. autoclass:: pyhmmer.plan7.HMM
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.Profile
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.OptimizedProfile
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.OptimizedProfileBlock
+   :special-members: __init__
+   :members:
\ No newline at end of file
diff --git a/docs/api/plan7/index.rst b/docs/api/plan7/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..1fcee76a9c0d49c6fdcfa88d32f37052f52d422c
--- /dev/null
+++ b/docs/api/plan7/index.rst
@@ -0,0 +1,128 @@
+Plan7
+=====
+
+.. currentmodule:: pyhmmer.plan7
+
+.. automodule:: pyhmmer.plan7
+
+
+Profile Hidden Markov Models
+----------------------------
+
+.. autosummary::
+
+    HMM
+    Profile
+    OptimizedProfile
+    OptimizedProfileBlock
+
+.. toctree::
+    :caption: Profile Hidden Markov Models
+    :maxdepth: 1
+    :hidden:
+
+    Profile Hidden Markov Models <hmms>
+
+
+Parsers
+-------
+
+.. autosummary::
+
+    HMMFile
+    HMMPressedFile
+
+.. toctree::
+    :caption: Parsers
+    :maxdepth: 1
+    :hidden:
+
+    Parsers <parsers>
+
+
+Pipelines
+---------
+
+.. autosummary::
+
+    Pipeline
+    LongTargetsPipeline
+    Builder
+    Background
+
+.. toctree::
+    :caption: Pipelines
+    :maxdepth: 1
+    :hidden:
+
+    Pipelines <pli>
+
+
+Results
+-------
+
+.. autosummary::
+
+    TopHits
+    Hit
+    Domains
+    Domain
+    Alignment
+
+.. toctree::
+    :caption: Results
+    :maxdepth: 1
+    :hidden:
+
+    Results <results>
+
+
+Traces
+------
+
+.. autosummary::
+
+    TraceAligner
+    Traces
+    Trace
+
+.. toctree::
+    :caption: Traces
+    :maxdepth: 1
+    :hidden:
+
+    Traces <traces>
+
+
+Iterative Searches
+------------------
+
+.. autosummary::
+
+    IterativeSearch
+    IterationResult
+
+.. toctree::
+    :caption: Iterative Searches
+    :maxdepth: 1
+    :hidden:
+
+    Iterative Searches <iter>
+
+
+Miscellaneous
+-------------
+
+.. autosummary::
+
+    Cutoffs
+    EvalueParameters
+    Offsets
+    Transitions
+
+.. toctree::
+    :caption: Miscellaneous
+    :maxdepth: 1
+    :hidden:
+
+    Miscellaneous <misc>
diff --git a/docs/api/plan7/iter.rst b/docs/api/plan7/iter.rst
new file mode 100644
index 0000000000000000000000000000000000000000..9963777f1c82ff05c7c4ad0a8980e0ca34555ebf
--- /dev/null
+++ b/docs/api/plan7/iter.rst
@@ -0,0 +1,10 @@
+Iterative Searches
+==================
+
+.. autoclass:: pyhmmer.plan7.IterativeSearch
+    :special-members: __init__
+    :members:
+
+.. autoclass:: pyhmmer.plan7.IterationResult
+    :special-members: __init__
+    :members:
\ No newline at end of file
diff --git a/docs/api/plan7/misc.rst b/docs/api/plan7/misc.rst
new file mode 100644
index 0000000000000000000000000000000000000000..046e0b39d127995d12051da65d775ad1b8a2b9d2
--- /dev/null
+++ b/docs/api/plan7/misc.rst
@@ -0,0 +1,41 @@
+Miscellaneous
+=============
+
+.. autoclass:: pyhmmer.plan7.Cutoffs
+   :members:
+
+.. autoclass:: pyhmmer.plan7.EvalueParameters
+   :members:
+
+.. autoclass:: pyhmmer.plan7.Offsets
+   :members:
+
+.. autoclass:: pyhmmer.plan7.Transitions(enum.IntEnum)
+
+   .. autoattribute:: MM
+
+      :math:`M_{i} \to M_{i+1}`.
+   
+   .. autoattribute:: MI
+      
+      :math:`M_{i} \to I_{i+1}`.
+   
+   .. autoattribute:: MD
+      
+      :math:`M_{i} \to D_{i+1}`.
+   
+   .. autoattribute:: IM
+      
+      :math:`I_{i} \to M_{i+1}`.
+   
+   .. autoattribute:: II
+      
+      :math:`I_{i} \to I_{i+1}`.
+   
+   .. autoattribute:: DM
+
+      :math:`D_{i} \to M_{i+1}`.
+   
+   .. autoattribute:: DD
+
+      :math:`D_{i} \to D_{i+1}`.
diff --git a/docs/api/plan7/parsers.rst b/docs/api/plan7/parsers.rst
new file mode 100644
index 0000000000000000000000000000000000000000..9fdbbb1db61d229be535b1ccce2cc7071577d8ff
--- /dev/null
+++ b/docs/api/plan7/parsers.rst
@@ -0,0 +1,10 @@
+Parsers
+=======
+
+.. autoclass:: pyhmmer.plan7.HMMFile
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.HMMPressedFile
+   :special-members: __init__
+   :members:
\ No newline at end of file
diff --git a/docs/api/plan7/pli.rst b/docs/api/plan7/pli.rst
new file mode 100644
index 0000000000000000000000000000000000000000..cf1c75d6003b34923bd1bf691e3df8da2374b076
--- /dev/null
+++ b/docs/api/plan7/pli.rst
@@ -0,0 +1,18 @@
+Pipelines
+=========
+
+.. autoclass:: pyhmmer.plan7.Pipeline
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.LongTargetsPipeline(Pipeline)
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.Builder
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.Background
+   :special-members: __init__
+   :members:
\ No newline at end of file
diff --git a/docs/api/plan7/results.rst b/docs/api/plan7/results.rst
new file mode 100644
index 0000000000000000000000000000000000000000..6d6c7c1107c5b27ff714e12dcdde3afdb33b5963
--- /dev/null
+++ b/docs/api/plan7/results.rst
@@ -0,0 +1,22 @@
+Results
+=======
+
+.. autoclass:: pyhmmer.plan7.TopHits
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.Hit
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.Domains
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.Domain
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.Alignment
+   :special-members: __init__
+   :members:
\ No newline at end of file
diff --git a/docs/api/plan7/traces.rst b/docs/api/plan7/traces.rst
new file mode 100644
index 0000000000000000000000000000000000000000..6bdb50d9783e00f481f39052cb0a8a1d42cced16
--- /dev/null
+++ b/docs/api/plan7/traces.rst
@@ -0,0 +1,14 @@
+Traces
+======
+
+.. autoclass:: pyhmmer.plan7.TraceAligner
+   :special-members: __init__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.Traces
+   :special-members: __init__, __getitem__
+   :members:
+
+.. autoclass:: pyhmmer.plan7.Trace
+   :special-members: __init__
+   :members:
\ No newline at end of file
diff --git a/docs/changes.md b/docs/changes.md
deleted file mode 120000
index 04c99a55caae5d51f17666f554c2c8cea0aadfc0..0000000000000000000000000000000000000000
--- a/docs/changes.md
+++ /dev/null
@@ -1 +0,0 @@
-../CHANGELOG.md
\ No newline at end of file
diff --git a/docs/conf.py b/docs/conf.py
index 96a050886bfe489ce9b6d6ab3ecf209be9347917..60171386bb27e8916191dae214dc0381f7fecbcf 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -13,7 +13,6 @@ import sys
 import re
 import shutil
 import semantic_version
-import sphinx_bootstrap_theme
 
 # -- Path setup --------------------------------------------------------------
 
@@ -27,15 +26,6 @@ if os.getenv("READTHEDOCS", "False") != "True":
     sys.path.insert(0, project_dir)
 
 
-# -- Sphinx Setup ------------------------------------------------------------
-
-def setup(app):
-    # Add custom stylesheet
-    app.add_css_file("css/main.css")
-    # app.add_js_file("js/apitoc.js")
-    # app.add_js_file("js/example-admonition.js")
-
-
 # -- Project information -----------------------------------------------------
 
 import pyhmmer
@@ -81,7 +71,7 @@ extensions = [
     "sphinx.ext.mathjax",
     "sphinx.ext.todo",
     "sphinx.ext.extlinks",
-    "sphinx_bootstrap_theme",
+    "sphinx_design",
     "sphinxcontrib.jquery",
     "nbsphinx",
     "recommonmark",
@@ -114,59 +104,58 @@ default_role = "py:obj"
 # The theme to use for HTML and HTML Help pages.  See the documentation for
 # a list of builtin themes.
 #
-html_theme = 'bootstrap'
-
-# Add any paths that contain custom themes here, relative to this directory.
-html_theme_path = sphinx_bootstrap_theme.get_html_theme_path()
+html_theme = 'pydata_sphinx_theme'
 
 # Add any paths that contain custom static files (such as style sheets) here,
 # relative to this directory. They are copied after the builtin static files,
 # so a file named "default.css" will overwrite the builtin "default.css".
-html_static_path = ['_static']
+html_static_path = ['_static/js', '_static/bibtex', '_static/css']
+html_js_files = ["custom-icon.js"]
+html_css_files = ["custom.css"]
 
 # Theme options are theme-specific and customize the look and feel of a theme
 # further.  For a list of options available for each theme, see the
 # documentation.
 #
 html_theme_options = {
-    # Bootswatch (http://bootswatch.com/) theme.
-    "bootswatch_theme": "flatly",
-    # Choose Bootstrap version.
-    "bootstrap_version": "3",
-    # Tab name for entire site. (Default: "Site")
-    "navbar_site_name": "Documentation",
-    # HTML navbar class (Default: "navbar") to attach to <div> element.
-    # For black navbar, do "navbar navbar-inverse"
-    "navbar_class": "navbar",
-    # Render the next and previous page links in navbar. (Default: true)
-    "navbar_sidebarrel": True,
-    # Render the current pages TOC in the navbar. (Default: true)
-    "navbar_pagenav": False,
-    # A list of tuples containing pages or urls to link to.
-    "navbar_links": [
-        ("GitHub", cfgparser.get("metadata", "url").strip(), True)
-    ] + [
-        (k, v, True)
-        for k, v in project_urls.items()
-        if k in {"Zenodo", "PyPI"}
+    "external_links": [
+        {
+            "url": "https://doi.org/10.1093/bioinformatics/btad214",
+            "name": "Paper",
+        },
     ],
-    "admonition_use_panel": True,
+    "show_toc_level": 2,
+    "use_edit_page_button": True,
+    "icon_links": [
+        {
+            "name": "GitHub",
+            "url": "https://github.com/althonos/pyhmmer",
+            "icon": "fa-brands fa-github",
+        },
+        {
+            "name": "PyPI",
+            "url": "https://pypi.org/project/pyhmmer",
+            "icon": "fa-custom fa-pypi",
+        },
+    ],
+    "logo": {
+        "text": "PyHMMER",
+        "image_light": "_images/logo.png",
+        "image_dark": "_images/logo.png",
+    },
+    "navbar_align": "left",
+    "footer_start": ["copyright"],
+    "footer_center": ["sphinx-version"],
 }
 
-# Custom sidebar templates, must be a dictionary that maps document names
-# to template names.
-#
-# The default sidebars (for documents that don't match any pattern) are
-# defined by theme itself.  Builtin themes are using these templates by
-# default: ``['localtoc.html', 'relations.html', 'sourcelink.html',
-# 'searchbox.html']``.
-#
-html_sidebars = {
-    "*": ["localtoc.html"],
-    "api/*": ["localtoc.html"],
-    "examples/*": ["localtoc.html"],
+html_context = {
+    "github_user": "althonos",
+    "github_repo": "pyhmmer",
+    "github_version": "master",
+    "doc_path": "docs",
 }
 
+html_favicon = '_images/favicon.ico'
 
 # -- Options for HTMLHelp output ---------------------------------------------
 
@@ -203,6 +192,7 @@ napoleon_use_rtype = False
 autoclass_content = "class"
 autodoc_member_order = 'groupwise'
 autosummary_generate = []
+autodoc_typehints = 'none'
 
 # -- Options for intersphinx extension ---------------------------------------
 
diff --git a/docs/contributing.md b/docs/contributing.md
deleted file mode 120000
index 44fcc63439371c8c829df00eec6aedbdc4d0e4cd..0000000000000000000000000000000000000000
--- a/docs/contributing.md
+++ /dev/null
@@ -1 +0,0 @@
-../CONTRIBUTING.md
\ No newline at end of file
diff --git a/docs/examples/index.rst b/docs/examples/index.rst
index e143547da9235f3e309c03ae3377ec3cc990861f..6c370c073841ec91d833b1b6193dbf97d99155a1 100644
--- a/docs/examples/index.rst
+++ b/docs/examples/index.rst
@@ -9,10 +9,11 @@ examples, and running with the latest version of the PyHMMER interface.
 
 .. toctree::
    :maxdepth: 2
+   :caption: Analyses
 
    Build an HMM from an multiple sequence alignment <msa_to_hmm>
    Analyse the active site of an enzymatic domain <active_site>
-   Fetch Marker Genes from a genome <fetchmgs>
+   Fetch marker genes from a genome <fetchmgs>
    Run an iterative search to build a HMM for rhodopsins <iterative_search>
 
 
@@ -24,6 +25,7 @@ PyHMMER API in combination with Python and other Python libraries:
 
 .. toctree::
     :maxdepth: 2
+    :caption: Code & Data
 
     Recipes for extending PyHMMER <recipes>
     Create a Python package with embedded HMMs <embed_hmms>
diff --git a/docs/benchmarks.rst b/docs/guide/benchmarks.rst
similarity index 95%
rename from docs/benchmarks.rst
rename to docs/guide/benchmarks.rst
index f974ae0683ff59d9a32bfed77be8caa8d907c9a6..f0e2c67cc7197c50155564df48b20d5e0196550e 100644
--- a/docs/benchmarks.rst
+++ b/docs/guide/benchmarks.rst
@@ -16,7 +16,7 @@ the times for pressed HMMs, and dashed-lines the times for HMMs in text format.*
 v0.7.0 - 2022-12-04
 -------------------
 
-.. image:: _images/bench-v0.7.0.svg
+.. image:: /_images/bench-v0.7.0.svg
 
 Collections for storing HMMs and Sequences were updated to allow iterating 
 without the GIL. For `hmmscan`, the `OptimizedProfileBlock` store an array 
@@ -27,7 +27,7 @@ across different threads.
 v0.5.0 - 2022-03-14
 -------------------
 
-.. image:: _images/bench-v0.5.0.svg
+.. image:: /_images/bench-v0.5.0.svg
 
 A new dedicated collection has been added to store the target sequences of a
 `~pyhmmer.plan7.Pipeline`, saving some overhead if the same target sequences
@@ -37,7 +37,7 @@ are reused with multiple queries.
 v0.4.5 - 2021-07-19
 -------------------
 
-.. image:: _images/bench-v0.4.5.svg
+.. image:: /_images/bench-v0.4.5.svg
 
 By adding an extra requirement on the reference sequences passed to a `~pyhmmer.plan7.Pipeline`,
 the Cython code can now evaluate a single HMM against the entirety of the reference
@@ -59,7 +59,7 @@ optimal number of 5+1 threads (42.2s).
 v0.4.0 - 2021-06-05
 -------------------
 
-.. image:: _images/bench-v0.4.0.svg
+.. image:: /_images/bench-v0.4.0.svg
 
 The overhead of PyHMMER has been reduced, and has a much smaller effect when
 using a high number of threads.
@@ -79,7 +79,7 @@ speed up insertions by worker threads.
 v0.3.0 - 2021-03-11
 -------------------
 
-.. image:: _images/bench-v0.3.0.svg
+.. image:: /_images/bench-v0.3.0.svg
 
 The small number of proteins renders the HMMER parallelisation useless for
 any number of worker threads higher than 2 (because of the block size being
diff --git a/docs/guide/changes.md b/docs/guide/changes.md
new file mode 120000
index 0000000000000000000000000000000000000000..699cc9e7b7c5bf63c3549abe36e3eecf8efab625
--- /dev/null
+++ b/docs/guide/changes.md
@@ -0,0 +1 @@
+../../CHANGELOG.md
\ No newline at end of file
diff --git a/docs/guide/contributing.md b/docs/guide/contributing.md
new file mode 120000
index 0000000000000000000000000000000000000000..f939e75f21a8badb5c40f527abd0e098fe9bc472
--- /dev/null
+++ b/docs/guide/contributing.md
@@ -0,0 +1 @@
+../../CONTRIBUTING.md
\ No newline at end of file
diff --git a/docs/guide/copyright.rst b/docs/guide/copyright.rst
new file mode 100644
index 0000000000000000000000000000000000000000..e6e474de93fb9a6399c2af0d69fd5230e8fb6e6f
--- /dev/null
+++ b/docs/guide/copyright.rst
@@ -0,0 +1,200 @@
+Copyright Notice
+================
+
+PyHMMER
+-------
+
+The PyHMMER library is developed under the MIT license::
+
+    Copyright (c) 2020-2024 Martin Larralde <martin.larralde@embl.de>
+
+    Permission is hereby granted, free of charge, to any person obtaining a copy
+    of this software and associated documentation files (the "Software"), to deal
+    in the Software without restriction, including without limitation the rights
+    to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+    copies of the Software, and to permit persons to whom the Software is
+    furnished to do so, subject to the following conditions:
+
+    The above copyright notice and this permission notice shall be included in all
+    copies or substantial portions of the Software.
+
+    THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+    IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+    FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+    AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+    LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+    OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+    SOFTWARE.
+
+PyHMMER development was supported by the European Molecular Biology Laboratory; 
+the SFB 1371 of the German Research Foundation (Deutsche Forschungsgemeinschaft, DFG) 
+[grant number 395357507] and the Federal Ministry of Education and Research (BMBF) 
+[grant number 031L0181A].
+
+Easel
+-----
+
+PyHMMER distributes, builds and links to code from the Easel library, 
+redistributed under the terms of the BSD license::
+
+    Copyright (C) 1990-2023 Sean R. Eddy
+    Copyright (C) 2015-2023 President and Fellows of Harvard College
+    Copyright (C) 2000-2023 Howard Hughes Medical Institute
+    Copyright (C) 1995-2006 Washington University School of Medicine
+    Copyright (C) 1992-1995 MRC Laboratory of Molecular Biology, UK
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+
+    2. Redistributions in binary form must reproduce the above
+       copyright notice, this list of conditions and the following
+       disclaimer in the documentation and/or other materials provided
+       with the distribution.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+    COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+
+Easel's code includes contributions from members of the Eddy/Rivas
+laboratory at Harvard University, the HMMER and Infernal development
+teams, and other colleagues, including:
+
+- Tyler Camp
+- Nick Carter
+- Michael Farrar
+- Graeme Mitchison
+- Eric Nawrocki
+- Sam Petti
+- Elena Rivas
+- Travis Wheeler
+
+Easel also includes code we have incorporated from other sources and
+authors -- including public domain code, and licensed copyrighted
+code. Sources and licenses are noted in the appropriate places in
+individual files. Copyright holders and contributors include:
+
+- Barry W. Brown, James Lovato:        ``esl_random:esl_rnd_Gaussian()``
+- Bob Jenkins:                         ``esl_random::esl_rnd_mix3()``
+- Steven G. Johnson, and others:       autoconf macros in m4/
+- Martin Larralde:                     ARM Neon support
+- Kevin Lawler:                        ``esl_rand64::esl_rand64_Deal()``
+- Stephen Moshier:                     SIMD vectorized ``logf``, ``expf``
+- Takuji Nishimura, Makoto Matsumoto:  ``esl_random``, ``esl_rand64``
+- Julien Pommier:                      SIMD vectorized ``logf``,``expf``
+- David Robert Nadeau:                 ``esl_stopwatch``
+- Henry Spencer:                       ``esl_regexp``
+- David Wheeler:                       ``easel::esl_tmpfile()``
+- Free Software Foundation, Inc.:      ``configure``
+- FreeBSD:                             ``easel::esl_strsep()``
+- Sun Microsystems, Inc.:              ``esl_stats::esl_erfc()``
+
+Easel development is supported in part by the National Human Genome
+Research Institute of the US National Institutes of Health under grant
+number R01HG009116. The content is solely the responsibility of the
+authors and does not necessarily represent the official views of the
+National Institutes of Health.
+
+
+HMMER
+-----
+
+PyHMMER distributes, builds and links to code from the HMMER software,
+redistributed under the terms of the BSD-3-clause license::
+
+    Copyright (C) 1992-2023 Sean R. Eddy
+    Copyright (C) 2015-2023 President and Fellows of Harvard College
+    Copyright (C) 2000-2023 Howard Hughes Medical Institute
+    Copyright (C) 1995-2006 Washington University School of Medicine
+    Copyright (C) 1992-1995 MRC Laboratory of Molecular Biology
+
+    Redistribution and use in source and binary forms, with or without
+    modification, are permitted provided that the following conditions
+    are met:
+
+    1. Redistributions of source code must retain the above copyright
+       notice, this list of conditions and the following disclaimer.
+
+    2. Redistributions in binary form must reproduce the above
+       copyright notice, this list of conditions and the following
+       disclaimer in the documentation and/or other materials provided
+       with the distribution.
+
+    3. Neither the name of any copyright holder nor the names of
+       contributors may be used to endorse or promote products derived
+       from this software without specific prior written permission.
+
+    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+    "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
+    FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
+    COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+    INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+    (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
+    SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+    HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT,
+    STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
+    ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED
+    OF THE POSSIBILITY OF SUCH DAMAGE.
+
+The code includes contributions and input from current and past
+members of the HMMER development team, as well as other colleagues and
+sources, including:
+
+- Bill Arndt
+- Jeremy Buhler
+- Tyler Camp
+- Nick Carter
+- Sergi Castellano
+- Goran Ceric
+- Michael Farrar
+- Rob Finn
+- Ian Holmes
+- Bjarne Knudsen
+- Diana Kolbe
+- Martin Larralde
+- Erik Lindahl
+- Graeme Mitchison
+- Eric Nawrocki
+- Lee Newberg
+- Sam Petti
+- Elena Rivas
+- Walt Shands
+- Travis Wheeler
+
+HMMER also includes copyrighted and licensed code that has been
+incorporated from other sources, including:
+
+- Yuta Mori (libdivsufsort-lite)
+- Apple Computer
+- Free Software Foundation, Inc.
+- IBM TJ Watson Research Center
+- X Consortium
+
+HMMER uses the Easel software library, which has its own license and
+copyright information. See `Easel`_ section above.
+
+HMMER includes patent-pending SIMD technology under a nonexclusive
+license from the estate of Michael Farrar. You are sublicensed to use
+this technology specifically for the use, modification, and
+redistribution of HMMER.
+
+HMMER development is supported in part by the National Human Genome
+Research Institute of the US National Institutes of Health under grant
+number R01HG009116. The content is solely the responsibility of the
+authors and does not necessarily represent the official views of the
+National Institutes of Health.
+
+
diff --git a/docs/guide/index.rst b/docs/guide/index.rst
new file mode 100644
index 0000000000000000000000000000000000000000..6c5d7ddaa0b1c705ca1b4b4e2cec2d205c942821
--- /dev/null
+++ b/docs/guide/index.rst
@@ -0,0 +1,23 @@
+User Guide
+==========
+
+This section contains guides and documents about some aspects of PyHMMER, 
+including the rationale behind the parallelization strategy implemented 
+in `pyhmmer.hmmer`.
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Getting Started
+
+    Installation <install>
+    Publications <publications>
+    Performance <performance>
+
+.. toctree::
+   :maxdepth: 1
+   :caption: Resources
+
+   Contribution Guide <contributing>
+   Changelog <changes>
+   Benchmarks <benchmarks>
+   Copyright Notice <copyright>
diff --git a/docs/install.rst b/docs/guide/install.rst
similarity index 99%
rename from docs/install.rst
rename to docs/guide/install.rst
index b11ddbc289eabd1b03066ad5537020b10779ef7f..5d70cedd0763b8f953be1c8f3176a0c7260a6a7c 100644
--- a/docs/install.rst
+++ b/docs/guide/install.rst
@@ -1,14 +1,7 @@
 Installation
 ============
 
-.. note::
-
-    Wheels are provided for Linux and MacOS on x86-64 and NEON-enabled Arm platforms, 
-    but other machines will have to build the wheel from the source distribution. 
-    Building ``pyhmmer`` involves compiling HMMER3 and Easel, which requires a 
-    C compiler to be available.
-
-.. hint::
+.. caution::
 
     Windows is not supported by HMMER, so it is not possible to build PyHMMER
     on Windows as the moment. Consider using a Python install inside the 
@@ -27,7 +20,14 @@ one is available, or from source after compiling the Cython code :
 .. code:: console
 
     $ pip install --user pyhmmer
-    
+
+.. note::
+
+    Wheels are provided for Linux and MacOS on x86-64 and NEON-enabled Arm platforms, 
+    but other machines will have to build the wheel from the source distribution. 
+    Building ``pyhmmer`` involves compiling HMMER3 and Easel, which requires a 
+    C compiler to be available.
+
 
 Conda
 ^^^^^
diff --git a/docs/performance.rst b/docs/guide/performance.rst
similarity index 99%
rename from docs/performance.rst
rename to docs/guide/performance.rst
index c9de8f85df84144317403fb89da78b0d4d09d042..2e8968f5ee79ba8dd25851d4bdb978d77bbbaa7f 100644
--- a/docs/performance.rst
+++ b/docs/guide/performance.rst
@@ -77,7 +77,7 @@ we annotated proteins from representative genomes of the
 `Pfam <http://pfam.xfam.org/>`_ collection of HMMs. ``hmmsearch`` runs
 are shown in green, ``pyhmmer`` runs in blue.
 
-.. image:: _images/progenomes-v0.4.5.svg
+.. image:: /_images/progenomes-v0.4.5.svg
 
 *The proteins of each genomes were extracted into one FASTA file per genome,
 and we measured the runtime of either the* ``hmmsearch`` *binary or the*
diff --git a/docs/publications.rst b/docs/guide/publications.rst
similarity index 97%
rename from docs/publications.rst
rename to docs/guide/publications.rst
index 0f80b57dae4fb3225bb944eba7e92f27cdb014ac..89980acc7db2bdfd3aaee8bd5cc28637bdd62c31 100644
--- a/docs/publications.rst
+++ b/docs/guide/publications.rst
@@ -23,8 +23,8 @@ PyHMMER has been used in the following research works:
 - Bhandari, B.K., Goldman, N. *A generalised protein identification method for novel and diverse sequencing technologies* (preprint). bioRxiv. :doi:`10.1101/2024.02.29.582769`.
 - Carroll, L.M., M. Larralde, J.S. Fleck, R. Ponnudurai, A. Milanese, E. Cappio, G. Zeller, 2021. *Accurate de novo identification of biosynthetic gene clusters with GECCO* (preprint). bioRxiv. :doi:`10.1101/2021.05.03.442509`.
 - Ducarmon, Q.R., N. Karcher, H.L.P. Tytgat, O. Delannoy-Bruno, S. Pekel, F. Springer, C. Schudoma, G. Zeller. *Large-scale computational analyses of gut microbial CAZyme repertoires enabled by Cayman* (preprint). bioRxiv. :doi:`10.1101/2024.01.08.574624`.
-- Erdrich, S.H., Luthe, T., Kever, L., Roigé, B.B., Arsova, B., Davoudi, E., Frunzke, J. *Expanding the phage galaxy: Isolation and characterization of five novel Streptomyces siphoviruses Ankus, Byblos, DekoNeimoidia, Mandalore, and Naboo* (preprint). bioRxiv. :doi:`10.1101/2024.02.16.580700 `.
-- Erdrich, S.H., Schurr, U., Frunzke, J., Arsova, B. *Seed coating with phages for sustainable plant biocontrol of plant pathogens and influence of the seed coat mucilage* (preprint). bioRxiv. :doi:`10.1101/2024.01.12.575253 `.
+- Erdrich, S.H., Luthe, T., Kever, L., Roigé, B.B., Arsova, B., Davoudi, E., Frunzke, J. *Expanding the phage galaxy: Isolation and characterization of five novel Streptomyces siphoviruses Ankus, Byblos, DekoNeimoidia, Mandalore, and Naboo* (preprint). bioRxiv. :doi:`10.1101/2024.02.16.580700`.
+- Erdrich, S.H., Schurr, U., Frunzke, J., Arsova, B. *Seed coating with phages for sustainable plant biocontrol of plant pathogens and influence of the seed coat mucilage* (preprint). bioRxiv. :doi:`10.1101/2024.01.12.575253`.
 - Gaschignard, G., Millet, M., Bruley, A., Benzerara, K., Dezi, M., Skouri-Panet, F., Duprat, E., Callebaut, I. *AlphaFold2-guided description of CoBaHMA, a novel family of bacterial domains within the heavy-metal-associated superfamily*. Proteins. 2024 Jan 22. :doi:`10.1002/prot.26668`. :pmid:`38258321`.
 - Jamali, K., L. Käll, R. Zhang, A. Brown, D. Kimanius, S.H.W. Scheres, 2023. *Automated model building and protein identification in cryo-EM maps* (preprint). bioRxiv. :doi:`10.1101/2023.05.16.541002`.
 - Kautsar, S.A., J.J.J van der Hooft, D. de Ridder, M.H. Medema, 2021. *BiG-SLiCE: A highly scalable tool maps the diversity of 1.2 million biosynthetic gene clusters*. GigaScience 10, giaa154. :doi:`10.1093/gigascience/giaa154`.
diff --git a/docs/index.rst b/docs/index.rst
index 62b7c0e4fe6643e208655d2e1534e92dc98e0720..05543d4453679cb0ae76fed0ddf4cd74c4930891 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,5 +1,8 @@
-PyHMMER |Stars|
-===============
+|Logo| PyHMMER |Stars|
+======================
+
+.. |Logo| image:: /_images/logo.png
+   :scale: 40%
 
 .. |Stars| image:: https://img.shields.io/github/stars/althonos/pyhmmer.svg?style=social&maxAge=3600&label=Star
    :target: https://github.com/althonos/pyhmmer/stargazers
@@ -76,41 +79,45 @@ the `Eddy/Rivas Laboratory <http://eddylab.org/>`_ at Harvard University.
 language, that provides bindings to HMMER3. It directly interacts with the
 HMMER internals, which has the following advantages over CLI wrappers:
 
-- **single dependency**:
-  If your software or your analysis pipeline is
-  distributed as a Python package, you can add `pyhmmer` as a dependency to
-  your project, and stop worrying about the HMMER binaries being properly
-  setup on the end-user machine.
-- **no intermediate files**:
-  Everything happens in memory, in Python objects
-  you have control on, making it easier to pass your inputs to HMMER without
-  needing to write them to a temporary file. Output retrieval is also done
-  in memory, via instances of the `pyhmmer.plan7.TopHits` class.
-- **no input formatting**:
-  The Easel object model is exposed in the `pyhmmer.easel` module, and you
-  have the possibility to build a `~pyhmmer.easel.Sequence` object yourself to
-  pass to the HMMER pipeline. This is useful if your sequences are already
-  loaded in memory, for instance because you obtained them from another
-  Python library (such as `Pyrodigal <https://github.com/althonos/pyrodigal>`_
-  or `Biopython <https://biopython.org/>`_).
-- **no output formatting**:
-  HMMER3 is notorious for its numerous output files
-  and its fixed-width tabular output, which is hard to parse (even
-  `Bio.SearchIO.HmmerIO` is struggling on some sequences).
-- **efficient**:
-  Using `pyhmmer` to launch ``hmmsearch`` on sequences and HMMs in disk storage
-  is typically faster than directly using the ``hmmsearch`` binary.
-  `pyhmmer.hmmer.hmmsearch` uses a different parallelisation strategy compared to
-  the ``hmmsearch`` binary from HMMER, which helps getting the most of
-  multiple CPUs.
+.. grid:: 1 2 3 3
+   :gutter: 1
+
+   .. grid-item-card:: :fas:`battery-full` Batteries-included
+
+      Just add ``pyhmmer`` as a ``pip`` or ``conda`` dependency, no need
+      for the HMMER binaries or any external dependency.
+
+   .. grid-item-card:: :fas:`screwdriver-wrench` Flexible
+
+      Create input `~pyhmmer.easel.Sequence` and `~pyhmmer.plan7.HMM` objects
+      with the :doc:`API <api/index>`, or load them from a file.
+
+   .. grid-item-card:: :fas:`gears` Practical
+
+      Retrieve nested results as dedicated `~pyhmmer.plan7.TopHits` objects,
+      write them to a file, or use them for further Python analysis.
 
+   .. grid-item-card:: :fas:`gauge-high` Fast
+
+      Run `hmmsearch` in parallel using an efficient threading model, which
+      :doc:`outperforms <guide/benchmarks>` HMMER in some typical usecases.
+
+   .. grid-item-card:: :fas:`dolly` Shareable
+
+      :doc:`Distribute and load <examples/embed_hmms>` `~pyhmmer.plan7.HMM`
+      objects from inside a Python package to facilitate sharing analyses.
+
+   .. grid-item-card:: :fas:`eye` Transparent
+
+      Access the internals of a `~pyhmmer.plan7.HMM`, inspect the attributes
+      and manually edit transitions or emissions scores.
 
 Setup
 -----
 
 Run ``pip install pyhmmer`` in a shell to download the latest release and all
 its dependencies from PyPi, or have a look at the
-:doc:`Installation page <install>` to find other ways to install ``pyhmmer``.
+:doc:`Installation page <guide/install>` to find other ways to install ``pyhmmer``.
 
 
 Citation
@@ -119,7 +126,7 @@ Citation
 PyHMMER is scientific software, with a
 `published paper <https://doi.org/10.1093/bioinformatics/btad214>`_
 in the `Bioinformatics <https://academic.oup.com/bioinformatics>`_. Check the
-:doc:`Publications page <publications>` to see how to cite PyHMMER.
+:doc:`Publications page <guide/publications>` to see how to cite PyHMMER.
 
 
 Library
@@ -128,38 +135,124 @@ Library
 .. toctree::
    :maxdepth: 2
 
-   Installation <install>
+   User Guide <guide/index>
    Examples <examples/index>
-   Performance <performance>
-   Contributing <contributing>
-   Publications <publications>
-   Benchmarks <benchmarks>
    API Reference <api/index>
-   Changelog <changes>
 
 
 Related Projects
 ----------------
 
-Building a HMM from scratch? Then you may be interested in the `PyFAMSA <https://pypi.org/project/pyfamsa/>`_
-package, providing bindings to `FAMSA <https://github.com/refresh-bio/FAMSA>`_,
-a very fast multiple sequence aligner. In addition, you may want to trim alignments:
-in that case, consider `PytrimAl <https://pypi.org/project/pytrimal>`_, which
-wraps `trimAl 2.0 <https://github.com/inab/trimal/tree/2.0_RC>`_.
+The following Python libraries may be of interest for bioinformaticians.
+
+.. grid:: 1 3 5 5
+   :gutter: 1
+
+   .. grid-item-card:: :fas:`diamond` PyHMMER
+      :link: https://pyhmmer.readthedocs.io
+
+      Profile Hidden Markov Models (with HMMER).
+
+   .. grid-item-card:: :fas:`fire` Pyrodigal
+      :link: https://pyrodigal.readthedocs.io
+
+      Prokaryotic Gene Finding (with Prodigal).
+
+   .. grid-item-card:: :fas:`virus-covid` Pyrodigal-gv
+      :link: https://github.com/althonos/pyrodigal-gv
+
+      Pyrodigal for Giant Viruses.
+
+   .. grid-item-card:: :fas:`align-center` PyFAMSA
+      :link: https://pyfamsa.readthedocs.io
+
+      Multiple Sequence Alignment (with FAMSA).
+
+   .. grid-item-card:: :fas:`scissors` PytrimAl
+      :link: https://pytrimal.readthedocs.io
+
+      Alignment Trimming (with trimAl).
+
+   .. grid-item-card:: :fas:`music` LightMotif
+      :link: https://lightmotif.readthedocs.io
+
+      Platform-accelerated motif scoring.
+
+   .. grid-item-card:: :fas:`knife;fa-custom` Diced
+      :link: https://diced.readthedocs.io
+
+      CRISPR Detection (with MinCED).
+
+   .. grid-item-card:: :fas:`table-cells` Scoring Matrices
+      :link: https://scoring-matrices.readthedocs.io
+
+      Scoring matrices for Cython.
+
+   .. grid-item-card:: :fas:`chain` Pyskani
+      :link: https://pyskani.readthedocs.io
+
+      Average Nucleotide Identity (with skani).
+
+   .. grid-item-card:: :fas:`forward-fast` PyFastANI
+      :link: https://pyfastani.readthedocs.io
+
+      Average Nucleotide Identity (with FastANI).
+
+   .. grid-item-card:: :fas:`magnifying-glass` PyJess
+      :link: https://pyjess.readthedocs.io
+
+      Geometric Template Matching (with Jess).
+
+   .. grid-item-card:: :fas:`repeat` PyTantan
+      :link: https://pytantan.readthedocs.io
+
+      Tandem Repeat Masking (with Tantan).
+
+   .. grid-item-card:: :fas:`gem` PyOpal
+      :link: https://pyopal.readthedocs.io
+
+      Query/Database Aligner (with Opal).
+
+   .. grid-item-card:: :fas:`sword;fa-custom` PySWRD
+      :link: https://pyswrd.readthedocs.io
+
+      Database Heuristic Filtering (with SWORD).
+
+   .. grid-item-card:: :fas:`rocket` Mini3di
+      :link: https://github.com/althonos/mini3di
+
+      Protein structure to 3di in pure Python.
+
+   .. grid-item-card:: :fas:`calculator` ``peptides.py``
+      :link: https://peptides.readthedocs.io
+
+      Peptide descriptors for Python.
+
+   .. grid-item-card:: :fas:`diagram-project` Pronto
+      :link: https://pronto.readthedocs.io
+
+      Open Biomedical Ontologies for Python.
+
+   .. grid-item-card:: :fas:`box` NAFcodec
+      :link: https://nafcodec.readthedocs.io
+
+      Nucleotide Archival Format for Python.
+
+   .. grid-item-card:: :fas:`bank` ``gb-io.py``
+      :link: https://gb-io.readthedocs.io
 
-If despite of all the advantages listed earlier, you would rather use HMMER
-through its CLI, this package will not be of great help. You can instead check
-the `hmmer-py <https://github.com/EBI-Metagenomics/hmmer-py>`_ package developed
-by `Danilo Horta <https://github.com/horta>`_ at the `EMBL-EBI <https://www.ebi.ac.uk>`_.
+      Fast GenBank parser for Python (with ``gb-io``).
 
 
 License
 -------
 
 This library is provided under the `MIT License <https://choosealicense.com/licenses/mit/>`_.
-The HMMER3 and Easel code is available under
-the `BSD 3-clause <https://choosealicense.com/licenses/bsd-3-clause/>`_ license,
-which allows redistribution of their sources in the ``pyhmmer`` distribution.
+The Easel and HMMER3 codes are available under
+the `BSD <https://choosealicense.com/licenses/bsd-2-clause/>`_ and 
+`BSD 3-clause <https://choosealicense.com/licenses/bsd-3-clause/>`_ licenses
+respectively, which both allow redistribution of the sources in the 
+``pyhmmer`` distribution. See the :doc:`Copyright Notice <guide/copyright>` section for more information.
 
 *This project is in no way not affiliated, sponsored, or otherwise endorsed by
 the original* `HMMER <http://hmmer.org>`_ *authors. It was developed by*
diff --git a/docs/requirements.txt b/docs/requirements.txt
index 2769e34ec818ed22359115058ca28a961551a535..30ec6c62d35a62a01b2f56f77efbe397caf93ca9 100644
--- a/docs/requirements.txt
+++ b/docs/requirements.txt
@@ -11,9 +11,8 @@ ipython ~=7.19
 pygments ~=2.4
 nbsphinx ~=0.5
 sphinxcontrib-jquery ~=4.1
-
-# sphinx-bootstrap-theme ~=0.7 with patched admonition
-https://github.com/althonos/sphinx-bootstrap-theme/archive/master.zip
+sphinx-design
+pydata-sphinx-theme
 
 # dependencies to run the example notebook(s)
 biopython ==1.79
diff --git a/pyhmmer/daemon.pyx b/pyhmmer/daemon.pyx
index 099b04e904e7b2f9947a22ef6a33b3f64ce0e96f..db31f05cd756350b90a7d2effe843bdd6e86b086 100644
--- a/pyhmmer/daemon.pyx
+++ b/pyhmmer/daemon.pyx
@@ -107,7 +107,7 @@ cdef class Client:
         str address=DEFAULT_ADDRESS,
         uint16_t port=DEFAULT_PORT,
     ):
-        """__init__(self, address="127.0.0.1", port=51371)\n--
+        """__init__(self, address="127.0.0.1", port=51371)\n--\n
 
         Create a new `Client` connecting to the given HMMER daemon server.
 
@@ -144,10 +144,7 @@ cdef class Client:
     # --- C Methods ----------------------------------------------------------
 
     cdef bytearray _recvall(self, size_t message_size):
-        """_recvall(self, message_size)\n--
-
-        Receive exactly ``message_size`` bytes from ``self.socket``.
-
+        """Receive exactly ``message_size`` bytes from ``self.socket``.
         """
         cdef bytearray buffer = bytearray(message_size)
         cdef object    view   = memoryview(buffer)
@@ -169,9 +166,7 @@ cdef class Client:
         Pipeline pli,
         p7_pipemodes_e mode,
     ):
-        """_client(self, query, db, pli, mode)\n--
-
-        A generic implementation of the steps to communicate with the server.
+        """A generic implementation of the steps to communicate with the server.
 
         Arguments:
             query (`bytes`): A buffer storing the serialized query in
@@ -316,18 +311,12 @@ cdef class Client:
     # --- Python Methods -----------------------------------------------------
 
     def connect(self):
-        """connect(self)\n--
-
-        Connect the client to the HMMER daemon server.
-
+        """Connect the client to the HMMER daemon server.
         """
         self.socket.connect((self.address, self.port))
 
     def close(self):
-        """close(self)\n--
-
-        Close the connection to the HMMER daemon server.
-
+        """Close the connection to the HMMER daemon server.
         """
         self.socket.close()
 
@@ -338,9 +327,7 @@ cdef class Client:
         list ranges = None,
         **options
     ):
-        """search_seq(self, query, db=1, ranges=None, **options)\n--
-
-        Search the HMMER daemon database with a query sequence.
+        """Search the HMMER daemon database with a query sequence.
 
         Arguments:
             query (`~pyhmmer.easel.Sequence`): The sequence object to use
@@ -381,9 +368,7 @@ cdef class Client:
         list ranges = None,
         **options
     ):
-        """search_hmm(self, query, db=1, ranges=None, **options)\n--
-
-        Search the HMMER daemon database with a query HMM.
+        """Search the HMMER daemon database with a query HMM.
 
         Arguments:
             query (`~pyhmmer.easel.MSA`): The profile HMM object to use to
@@ -418,9 +403,7 @@ cdef class Client:
         return hits
 
     def scan_seq(self, Sequence query, uint64_t db = 1, **options):
-        """scan_seq(self, query, db=1, **options)\n--
-
-        Search the HMMER daemon database with a query sequence.
+        """Search the HMMER daemon database with a query sequence.
 
         Arguments:
             query (`~pyhmmer.easel.Sequence`): The sequence object to use
@@ -462,9 +445,7 @@ cdef class Client:
         object select_hits = None,
         **options
     ):
-        """iterate_seq(self, query, db=1, ranges=None, builder=None, select_hits=None, **options)\n--
-
-        Search iteratively against the daemon database with a query sequence.
+        """Search iteratively against the daemon database with a query sequence.
 
         Arguments:
             query (`~pyhmmer.easel.Sequence`): The sequence object to use
@@ -517,9 +498,7 @@ cdef class Client:
         object select_hits = None,
         **options
     ):
-        """iterate_hmm(self, query, db=1, ranges=None, builder=None, select_hits=None, **options)\n--
-
-        Search iteratively against the daemon database with a query HMM.
+        """Search iteratively against the daemon database with a query HMM.
 
         Arguments:
             query (`~pyhmmer.plan7.HMM`): The HMM object to use to query the
@@ -611,6 +590,15 @@ cdef class IterativeSearch(pyhmmer.plan7.IterativeSearch):
         object select_hits = None,
         dict options = None
     ):
+        """__init__(self, client, query, db, builder, ranges=None, select_hits=None, options=None)\n--\n
+
+        Create a new iterative search against the HMMER daemon.
+
+        Hint:
+            Use the `Client.iterate_hmm` method instead of creating this
+            object directly.
+
+        """
         self.client = client
         self.builder = builder
         self.select_hits = select_hits
diff --git a/pyhmmer/easel.pyx b/pyhmmer/easel.pyx
index 8d7910b1475498896a9fbe3b5123a7211f6762e7..aea2786c119da833276ef4d3190a7ece730280eb 100644
--- a/pyhmmer/easel.pyx
+++ b/pyhmmer/easel.pyx
@@ -470,15 +470,17 @@ cdef class GeneticCode:
         Alphabet nucleotide_alphabet not None = Alphabet.dna(),
         Alphabet amino_alphabet not None = Alphabet.amino(),
     ):
-        """Create a new genetic code for translating nucleotide sequences.
+        """__init__(self, translation_table=1, *, nucleotide_alphabet=None, amino_alphabet=None)\n--\n
+        
+        Create a new genetic code for translating nucleotide sequences.
 
         Arguments:
             translation_table (`int`): The translation table to use. Check the
                 `Wikipedia <https://w.wiki/47wo>`_ page listing all genetic
                 codes for the available values.
-            nucleotide_alphabet (`pyhmmer.easel.Alphabet`): The nucleotide
+            nucleotide_alphabet (`~pyhmmer.easel.Alphabet`): The nucleotide
                 alphabet from which to translate the sequence.
-            amino_alphabet (`pyhmmer.easel.Alphabet`): The target alphabet
+            amino_alphabet (`~pyhmmer.easel.Alphabet`): The target alphabet
                 into which to translate the sequence.
 
         """
@@ -579,7 +581,7 @@ cdef class GeneticCode:
                 `bytearray`, `~pyhmmer.easel.VectorU8`, etc.) may be given.
 
         Returns:
-            `pyhmmer.easel.VectorU8`: The translation of the input
+            `~pyhmmer.easel.VectorU8`: The translation of the input
             sequence, as a raw digital sequence.
 
         Raises:
@@ -707,7 +709,9 @@ cdef class Bitfield:
         libeasel.bitfield.esl_bitfield_Destroy(self._b)
 
     def __init__(self, object iterable):
-        """Create a new bitfield from an iterable of objects.
+        """__init__(self, iterable)\n--\n
+        
+        Create a new bitfield from an iterable of objects.
 
         Objects yielded by the iterable can be of any type and will be
         tested for truth before setting the corresponding field.
@@ -967,7 +971,10 @@ cdef class KeyHash:
         libeasel.keyhash.esl_keyhash_Destroy(self._kh)
 
     def __init__(self):
-        """Create a new empty key-hash collection.
+        """__init__(self)\n--\n
+        
+        Create a new empty key-hash collection.
+        
         """
         with nogil:
             if self._kh == NULL:
@@ -1235,7 +1242,10 @@ cdef class Vector:
         self._data = NULL
 
     def __init__(self, object iterable = ()):
-        """Create a new vector from the given iterable of values.
+        """__init__(self, iterable=())\n--\n
+        
+        Create a new vector from the given iterable of values.
+        
         """
         raise TypeError("Can't instantiate abstract class 'Vector'")
 
@@ -1486,7 +1496,10 @@ cdef class VectorF(Vector):
     # --- Magic methods ------------------------------------------------------
 
     def __init__(self, object iterable = ()):
-        """Create a new float vector from the given data.
+        """__init__(self, iterable=())\n--\n
+        
+        Create a new float vector from the given data.
+        
         """
         cdef int        n
         cdef size_t     i
@@ -1910,7 +1923,10 @@ cdef class VectorU8(Vector):
     # --- Magic methods ------------------------------------------------------
 
     def __init__(self, object iterable = ()):
-        """Create a new byte vector from the given data.
+        """__init__(self, iterable=())\n--\n
+        
+        Create a new byte vector from the given data.
+        
         """
         cdef int          n
         cdef size_t       i
@@ -2571,6 +2587,11 @@ cdef class MatrixF(Matrix):
     # --- Magic methods ------------------------------------------------------
 
     def __init__(self, object iterable = ()):
+        """__init__(self, iterable=())\n--\n
+
+        Create a new matrix from an iterable of rows.
+
+        """
         cdef int     i
         cdef int     j
         cdef size_t  m
@@ -2821,6 +2842,11 @@ cdef class MatrixU8(Matrix):
     # --- Magic methods ------------------------------------------------------
 
     def __init__(self, object iterable = ()):
+        """__init__(self, iterable=())\n--\n
+
+        Create a new matrix from an iterable of rows.
+
+        """
         cdef int       i
         cdef int       j
         cdef size_t    m
@@ -3487,7 +3513,9 @@ cdef class TextMSA(MSA):
         object sequences=None,
         bytes author=None,
     ):
-        """Create a new text-mode alignment with the given ``sequences``.
+        """__init__(self, name=None, description=None, accession=None, sequences=None, author=None)\n--\n
+        
+        Create a new text-mode alignment with the given ``sequences``.
 
         Arguments:
             name (`bytes`, optional): The name of the alignment, if any.
@@ -3814,7 +3842,9 @@ cdef class DigitalMSA(MSA):
         object sequences=None,
         bytes author=None,
     ):
-        """Create a new digital-mode alignment with the given ``sequences``.
+        """__init__(self, alphabet, name=None, description=None, accession=None, sequences=None, author=None)\n--\n
+        
+        Create a new digital-mode alignment with the given ``sequences``.
 
         Arguments:
             alphabet (`Alphabet`): The alphabet of the alignmed sequences.
@@ -4042,7 +4072,9 @@ cdef class MSAFile:
         bint digital = False,
         Alphabet alphabet = None,
     ):
-        """Create a new MSA file parser wrapping the given ``file``.
+        """__init__(self, file, format=None, *, digital=False, alphabet=False)\n--\n
+        
+        Create a new MSA file parser wrapping the given ``file``.
 
         Arguments:
             file (`str` or file-like object): Either the path to a file
@@ -4290,7 +4322,9 @@ cdef class Randomness:
         self._rng = NULL
 
     def __init__(self, object seed=None, bint fast=False):
-        """Create a new random number generator with the given seed.
+        """__init__(self, seed=None, fast=False)\n--\n
+        
+        Create a new random number generator with the given seed.
 
         Arguments:
             seed (`int`): The seed to initialize the generator with. If ``0``
@@ -4743,7 +4777,9 @@ cdef class TextSequence(Sequence):
         bytes source=None,
         dict  residue_markups=None,
     ):
-        """Create a new text-mode sequence with the given attributes.
+        """__init__(self, name=None, description=None, accession=None, sequence=None, source=None, residue_markups=None)\n--\n
+        
+        Create a new text-mode sequence with the given attributes.
 
         .. versionadded:: 0.10.4
             The ``residue_markups`` argument.
@@ -4937,7 +4973,9 @@ cdef class DigitalSequence(Sequence):
               bytes                 source          = None,
               dict                  residue_markups = None,
     ):
-        """Create a new digital-mode sequence with the given attributes.
+        """__init__(self, alphabet, name=None, description=None, accession=None, sequence=None, source=None, residue_markups=None)\n--\n
+        
+        Create a new digital-mode sequence with the given attributes.
 
         Raises:
             `ValueError`: When ``sequence`` contains digits outside the
@@ -5095,13 +5133,13 @@ cdef class DigitalSequence(Sequence):
         """Translate the sequence using the given genetic code.
 
         Arguments:
-            genetic_code (`pyhmmer.easel.GeneticCode`): The genetic code to
+            genetic_code (`~pyhmmer.easel.GeneticCode`): The genetic code to
                 use for translating the sequence. If none provided, the
                 default uses the standard translation table (1) and expects
                 DNA sequences.
 
         Returns:
-            `pyhmmer.easel.DigitalSequence`: The translation of the
+            `~pyhmmer.easel.DigitalSequence`: The translation of the
             input sequence, in digital mode.
 
         Raises:
@@ -5468,6 +5506,11 @@ cdef class TextSequenceBlock(SequenceBlock):
     # --- Magic methods ------------------------------------------------------
 
     def __init__(self, object iterable = ()):
+        """__init__(self, iterable=())\n--\n
+
+        Create a new block from an iterable of text sequences.
+
+        """
         self.clear()
         self.extend(iterable)
 
@@ -5598,7 +5641,9 @@ cdef class DigitalSequenceBlock(SequenceBlock):
         self.alphabet = alphabet
 
     def __init__(self, Alphabet alphabet not None, object iterable = ()):
-        """Create a new digital sequence block with the given alphabet.
+        """__init__(self, alphabet, iterable=())\n--\n
+        
+        Create a new digital sequence block with the given alphabet.
 
         Arguments:
             alphabet (`~pyhmmer.easel.Alphabet`): The alphabet to use for all
@@ -5716,17 +5761,17 @@ cdef class DigitalSequenceBlock(SequenceBlock):
         """Translate the sequence block using the given genetic code.
 
         Arguments:
-            genetic_code (`pyhmmer.easel.GeneticCode`): The genetic code to
+            genetic_code (`~pyhmmer.easel.GeneticCode`): The genetic code to
                 use for translating the sequence. If none provided, the
                 default uses the standard translation table (1) and expects
                 DNA sequences.
 
         Returns:
-            `pyhmmer.easel.DigitalSequenceBlock`: The translation of
+            `~pyhmmer.easel.DigitalSequenceBlock`: The translation of
             each sequence from the block, in digital mode.
 
         Raises:
-            `pyhmmer.errors.AlphabetMismatch`: When the ``genetic_code``
+            `~pyhmmer.errors.AlphabetMismatch`: When the ``genetic_code``
                 expects a different nucleotide alphabet than the one
                 currently for the sequences in the block.
             `ValueError`: When a sequence from the block could not be
@@ -5734,8 +5779,8 @@ cdef class DigitalSequenceBlock(SequenceBlock):
                 recognized, or because the sequence has an invalid length.
 
         See Also:
-            `pyhmmer.easel.DigitalSequence.translate` for more information
-            on how ambiguous nucleotides are handled.
+            `DigitalSequence.translate` for more information on how 
+            ambiguous nucleotides are handled.
 
         """
         assert self.alphabet is not None
@@ -6139,7 +6184,9 @@ cdef class SequenceFile:
         bint digital = False,
         Alphabet alphabet = None,
     ):
-        """Create a new sequence file parser wrapping the given ``file``.
+        """__init__(self, file, format=None, *, digital=False, alphabet=None)\n--\n
+        
+        Create a new sequence file parser wrapping the given ``file``.
 
         Arguments:
             file (`str` or file-like object): Either the path to a file
@@ -6577,7 +6624,9 @@ cdef class SSIReader:
         self._ssi = NULL
 
     def __init__(self, object file):
-        """Create a new SSI file reader for the file at the given location.
+        """__init__(self, file)\n--\n
+        
+        Create a new SSI file reader for the file at the given location.
 
         Arguments:
             file (`str`, `bytes` or `os.PathLike`): The path to a
@@ -6669,7 +6718,9 @@ cdef class SSIWriter:
         self._newssi = NULL
 
     def __init__(self, object file, bint exclusive = False):
-        """Create a new SSI file write for the file at the given location.
+        """__init__(self, file, exclusive=False)\n--\n
+        
+        Create a new SSI file write for the file at the given location.
 
         Arguments:
             file (`str`, `bytes` or `os.PathLike`): The path to a
diff --git a/pyhmmer/errors.pyx b/pyhmmer/errors.pyx
index 83178388dfdfb82d9ba2f299c805071d5d8bc41c..44126bfe1f59c6366a705ab8d70926202d14b5ce 100644
--- a/pyhmmer/errors.pyx
+++ b/pyhmmer/errors.pyx
@@ -49,6 +49,8 @@ class UnexpectedError(RuntimeError):
     """
 
     def __init__(self, int code, str function):
+        """__init__(self, code, function)\n--\n
+        """
         self.code = code
         self.function = function
 
@@ -68,6 +70,8 @@ class AllocationError(MemoryError):
     """
 
     def __init__(self, str ctype, size_t itemsize, size_t count=1):
+        """__init__(self, ctype, itemsize, count=1)\n--\n
+        """
         self.ctype = ctype
         self.itemsize = itemsize
         self.count = count
@@ -89,6 +93,8 @@ class EaselError(RuntimeError):
     """
 
     def __init__(self, int code, str message):
+        """__init__(self, code, message)\n--\n
+        """
         self.code = code
         self.message = message
 
@@ -124,6 +130,8 @@ class AlphabetMismatch(ValueError):
     """
 
     def __init__(self, expected, actual=None):
+        """__init__(self, expected, actual=None)\n--\n
+        """
         super().__init__(self)
         self.expected = expected
         self.actual = actual
@@ -150,6 +158,8 @@ class ServerError(RuntimeError):
     """
 
     def __init__(self, int code, str message):
+        """__init__(self, code, message)\n--\n
+        """
         self.code = code
         self.message = message
 
@@ -176,6 +186,8 @@ class MissingCutoffs(ValueError):
     """
 
     def __init__(self, str model_name = None, str bit_cutoffs = None):
+        """__init__(self, model_name=None, bit_cutoffs=None)\n--\n
+        """
         self.model_name = model_name
         self.bit_cutoffs = bit_cutoffs
 
@@ -203,6 +215,8 @@ class InvalidParameter(ValueError):
     """
 
     def __init__(self, str name, object value, *, list choices=None, str hint=None):
+        """__init__(self, name, value, *, choices=None, hint=None)\n--\n
+        """
         self.name = name
         self.value = value
         self.choices = choices
@@ -241,6 +255,8 @@ class InvalidHMM(ValueError):
     """
 
     def __init__(self, object hmm, str message):
+        """__init__(self, hmm, message)\n--\n
+        """
         super().__init__(hmm, message)
         self.message = message
         self.hmm = hmm
diff --git a/pyhmmer/plan7.pyx b/pyhmmer/plan7.pyx
index 6f8b873e0e1acec813cdc513747be85932c9863c..22a1c19b6957eee85d52511b7c05d2c0a5e9e26d 100644
--- a/pyhmmer/plan7.pyx
+++ b/pyhmmer/plan7.pyx
@@ -486,11 +486,13 @@ cdef class Background:
         self.uniform = False
 
     def __init__(self, Alphabet alphabet, bint uniform=False):
-        """Create a new background model for the given ``alphabet``.
+        """__init__(self, alphabet, uniform=False)\n--\n
+        
+        Create a new background model for the given ``alphabet``.
 
         Arguments:
-          alphabet (`pyhmmer.easel.Alphabet`): The alphabet to create the
-              background model with.
+          alphabet (`~pyhmmer.easel.Alphabet`): The alphabet to create 
+              the background model with.
           uniform (`bool`): Whether or not to create the null model with
               uniform frequencies. Defaults to `False`.
 
@@ -655,7 +657,9 @@ cdef class Builder:
         object window_length=None,
         object window_beta=None,
     ):
-        """Create a new sequence builder with the given configuration.
+        """__init__(self, alphabet, *, architecture="fast", weighting="pb", effective_number="entropy", prior_scheme="alphabet", symfrac=0.5, fragthres=0.5, wid=0.62, esigma=45.0, eid=0.62, EmL=200, EmN=200, EvL=200, EvN=200, EfL=100, EfN=200, Eft=0.04, seed=42, ere=None, popen=None, pextend=None, score_matrix=None, window_length=None, window_beta=None)\n--\n
+        
+        Create a new sequence builder with the given configuration.
 
         Arguments:
             alphabet (`~pyhmmer.easel.Alphabet`): The alphabet the builder
@@ -1157,6 +1161,8 @@ cdef class Cutoffs:
         self._is_profile = True
 
     def __init__(self, object owner):
+        """__init__(self, owner)\n--\n
+        """
         cdef str ty
         if isinstance(owner, Profile):
             self._cutoffs = &(<Profile> owner)._gm.cutoff
@@ -1693,6 +1699,8 @@ cdef class EvalueParameters:
         self._evparams = NULL
 
     def __init__(self, object owner):
+        """__init__(self, owner)\n--\n
+        """
         cdef str ty
         if isinstance(owner, Profile):
             self._evparams = &(<Profile> owner)._gm.evparam
@@ -2276,7 +2284,9 @@ cdef class HMM:
         self._hmm = NULL
 
     def __init__(self, Alphabet alphabet not None, int M, bytes name not None):
-        """Create a new HMM from scratch.
+        """__init__(self, alphabet, M, name)\n--\n
+        
+        Create a new HMM from scratch.
 
         Arguments:
             alphabet (`~pyhmmer.easel.Alphabet`): The alphabet of the model.
@@ -2755,7 +2765,7 @@ cdef class HMM:
         Columns correspond to the following transitions, in order:
         :math:`M_n \to M_{n+1}`, :math:`M_n \to I_n`, :math:`M_n \to D_{n+1}`,
         :math:`I_n \to I_n`, :math:`I_n \to M_{n+1}`, :math:`D_n \to D_{n+1}`,
-        :math:`D_n \to M_{n+1}`. Use the `~pyhmmer.plan7.Transitions` enum
+        :math:`D_n \to M_{n+1}`. Use the `pyhmmer.plan7.Transitions` enum
         instead of hardcoded indices to make your code more legible.
 
         Example:
@@ -3041,9 +3051,9 @@ cdef class HMM:
         """Calculate the match occupancy for each match state.
 
         Returns:
-            `~easel.VectorF`: A vector of size :math:`M+1` containing the
-            probability that each match state is used in a sample glocal
-            path through the model.
+            `~pyhmmer.easel.VectorF`: A vector of size :math:`M+1` 
+            containing the probability that each match state is used 
+            in a sample glocal path through the model.
 
         .. versionadded:: 0.4.10
 
@@ -3495,7 +3505,9 @@ cdef class HMMFile:
         self._name = None
 
     def __init__(self, object file, bint db = True):
-        """Create a new HMM reader from the given file.
+        """__init__(self, file, db=True)\n--\n
+        
+        Create a new HMM reader from the given file.
 
         Arguments:
             file (`str`, `bytes`, `os.PathLike` or file-like object): Either
@@ -3739,7 +3751,9 @@ cdef class HMMPressedFile:
         self._hfp = NULL
 
     def __init__(self, object file):
-        """Create a new pressed file from the given filename.
+        """__init__(self, file)\n--\n
+        
+        Create a new pressed file from the given filename.
 
         Arguments:
             file (`str`, `bytes` or `os.PathLike`): The path to the pressed
@@ -3949,6 +3963,8 @@ cdef class IterativeSearch:
         DigitalSequenceBlock targets,
         object select_hits = None,
     ):
+        """__init__(self, pipeline, builder, query, targets, select_hits=None)\n--\n
+        """
         self.pipeline = pipeline
         self.background = pipeline.background
         self.builder = builder
@@ -4051,7 +4067,9 @@ cdef class OptimizedProfile:
         self.alphabet = None
 
     def __init__(self, int M, Alphabet alphabet):
-        """Create a new optimized profile from scratch.
+        """__init__(self, M, alphabet)\n--\n
+        
+        Create a new optimized profile from scratch.
 
         Once allocated, you must call the `~OptimizedProfile.convert`
         method with a `~plan7.Profile` object. It's actually easier to
@@ -4644,6 +4662,11 @@ cdef class OptimizedProfileBlock:
         self.alphabet = alphabet
 
     def __init__(self, Alphabet alphabet, object iterable = ()):
+        """__init__(self, alphabet, iterable=())\n--\n
+
+        Create a new block from an iterable of `OptimizedProfile` objects.
+
+        """
         if self._block == NULL:
             self._block = p7_oprofile_CreateBlock(8)
             if self._block == NULL:
@@ -4894,6 +4917,8 @@ cdef class Offsets:
         self._offs  = NULL
 
     def __init__(self, object owner):
+        """__init__(self, owner)\n--\n
+        """
         cdef str ty
 
         if isinstance(owner, Profile):
@@ -5034,7 +5059,9 @@ cdef class Pipeline:
         object incdomT=None,
         str bit_cutoffs=None,
     ):
-        """Instantiate and configure a new accelerated comparison pipeline.
+        """__init__(self, alphabet, background=None, *, bias_filter=True, null2=True, seed=42, Z=None, domZ=None, F1=0.02, F2=1e-3, F3=1e-5, E=10.0, T=None, domE=10.0, domT=None, incE=0.01, incT=None, incdomE=0.01, incdomT=None, bit_cutoffs=None)\n--\n
+        
+        Instantiate and configure a new accelerated comparison pipeline.
 
         Arguments:
             alphabet (`~pyhmmer.easel.Alphabet`): The biological alphabet the
@@ -6509,7 +6536,9 @@ cdef class LongTargetsPipeline(Pipeline):
         object window_beta=None,
         **kwargs,
     ):
-        """Instantiate and configure a new long targets pipeline.
+        """__init__(self, alphabet, background=None, *, F1=0.02, F2=3e-3, F3=3e-5, strand=None, B1=100, B2=240, B3=1000, block_length=0x40000, window_length=None, window_beta=None, **kwargs)\n--\n
+        
+        Instantiate and configure a new long targets pipeline.
 
         Arguments:
             alphabet (`~pyhmmer.easel.Alphabet`): The biological alphabet the
@@ -7282,7 +7311,9 @@ cdef class Profile:
         self.alphabet = None
 
     def __init__(self, int M, Alphabet alphabet):
-        """Create a new profile for the given ``alphabet``.
+        """__init__(self, M, alphabet)\n--\n
+        
+        Create a new profile for the given ``alphabet``.
 
         Arguments:
             M (`int`): The length of the profile, i.e. the number of nodes.
@@ -7582,7 +7613,8 @@ cdef class ScoreData:
         self._sd = NULL
 
     def __init__(self, OptimizedProfile om, Profile gm = None):
-
+        """__init__(self, om, gm=None)\n--\n
+        """
         cdef P7_PROFILE*  _gm = NULL if gm is None else gm._gm
         cdef P7_OPROFILE* _om = om._om
 
@@ -7646,7 +7678,10 @@ cdef class TopHits:
         memset(&self._pli, 0, sizeof(P7_PIPELINE))
 
     def __init__(self):
-        """Create an empty `TopHits` instance.
+        """__init__(self)\n--\n
+        
+        Create an empty `TopHits` instance.
+        
         """
         with nogil:
             # free allocated memory (in case __init__ is called more than once)
@@ -8592,7 +8627,9 @@ cdef class Trace:
         self.traces = None
 
     def __init__(self, posteriors=False):
-        """Create a new `Trace` object.
+        """__init__(self, posteriors=False)\n--\n
+        
+        Create a new `Trace` object.
 
         Arguments:
             posteriors (`bool`): Whether or not to allocate additional memory
@@ -8714,6 +8751,14 @@ cdef class Traces:
     def __dealloc__(self):
         libhmmer.p7_trace.p7_trace_DestroyArray(self._traces, self._ntraces)
 
+    def __init__(self):
+        """__init__(self)\n--\n
+
+        Create an empty list of traces.
+
+        """
+        pass
+
     def __len__(self):
         return self._ntraces
 
diff --git a/static/logo.png b/static/logo.png
new file mode 100644
index 0000000000000000000000000000000000000000..bcbccea1b48213ad213fca4cdb6e88855dedc174
Binary files /dev/null and b/static/logo.png differ