diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml
index 3d6dbe7..e6e82bb 100644
--- a/.github/workflows/docs.yml
+++ b/.github/workflows/docs.yml
@@ -27,12 +27,25 @@ jobs:
# 3. Install Sphinx and dependencies
- name: Install Sphinx and dependencies
- run: pip install sphinx sphinx-rtd-theme
+ run: pip install sphinx sphinx-rtd-theme cairosvg pillow
# 4. Build Sphinx documentation
- name: Generate Sphinx docs
run: sphinx-build -b html docs docs/_build/html
+ # 4b. Install LaTeX and build the PDF (Yubico-style, pdflatex)
+ - name: Install LaTeX for PDF
+ run: |
+ sudo apt-get update
+ sudo apt-get install -y --no-install-recommends \
+ latexmk texlive-latex-recommended texlive-latex-extra \
+ texlive-fonts-recommended texlive-fonts-extra tex-gyre
+
+ - name: Build PDF (pdflatex)
+ run: |
+ sphinx-build -M latexpdf docs docs/_build
+ cp docs/_build/latex/cryptnox-cli.pdf docs/_build/html/cryptnox-cli.pdf
+
# 5. Deploy HTML documentation to GitHub Pages
- name: Deploy to GitHub Pages
uses: peaceiris/actions-gh-pages@v4
diff --git a/.gitignore b/.gitignore
index 8909dcb..29331b5 100644
--- a/.gitignore
+++ b/.gitignore
@@ -8,3 +8,4 @@ signature.sig
cardpub.pub
docs/_build/
*.lock
+docs/_static/cryptnox-logo-dark.png
diff --git a/dev-requirements.txt b/dev-requirements.txt
index ec683d3..d511bba 100644
--- a/dev-requirements.txt
+++ b/dev-requirements.txt
@@ -22,6 +22,8 @@ pywin32-ctypes==0.2.3; sys_platform == 'win32'
Sphinx>=7.3.7
sphinx-rtd-theme>=2.0.0
sphinx-autodoc-typehints>=2.1.0
+cairosvg>=2.7.0
+Pillow>=10.0.0
setuptools==78.1.1; python_version >= '3.9'
tomlkit==0.13.2; python_version >= '3.8'
typing-extensions==4.13.2; python_version >= '3.8'
diff --git a/docs/_static/cryptnox-logo.png b/docs/_static/cryptnox-logo.png
deleted file mode 100644
index b5d3148..0000000
Binary files a/docs/_static/cryptnox-logo.png and /dev/null differ
diff --git a/docs/_static/cryptnox-logo.svg b/docs/_static/cryptnox-logo.svg
new file mode 100644
index 0000000..9fed9ce
--- /dev/null
+++ b/docs/_static/cryptnox-logo.svg
@@ -0,0 +1,15 @@
+
diff --git a/docs/conf.py b/docs/conf.py
index 55811e9..143b696 100644
--- a/docs/conf.py
+++ b/docs/conf.py
@@ -11,6 +11,28 @@
sys.path.insert(0, os.path.abspath(".."))
+# Derive the navy PDF cover logo from the white HTML SVG at build time, so only the
+# SVG is a committed source asset (needs cairosvg + Pillow, both in the docs requirements).
+try:
+ import io as _io
+ import cairosvg
+ from PIL import Image as _Image
+except ImportError as _e:
+ raise RuntimeError(
+ "Docs build requires cairosvg and Pillow to generate the PDF cover logo; "
+ "install them (pip install cairosvg pillow)."
+ ) from _e
+_static = os.path.join(os.path.dirname(__file__), "_static")
+with open(os.path.join(_static, "cryptnox-logo.svg"), encoding="utf-8") as _f:
+ _svg = _f.read()
+_png = cairosvg.svg2png(
+ bytestring=_svg.replace('fill="white"', 'fill="#101f2e"').encode(),
+ output_width=1200, output_height=226,
+)
+_Image.open(_io.BytesIO(_png)).save(
+ os.path.join(_static, "cryptnox-logo-dark.png"), dpi=(400, 400)
+)
+
project = 'cryptnox-cli'
copyright = '2025, Cryptnox'
author = 'Cryptnox'
@@ -29,6 +51,11 @@
# Disable autosummary generation to prevent hangs
autosummary_generate = False
+# Show default args as written in source (e.g. wordlist=wordlist_english) instead
+# of expanding them — the mnemonic module defaults to the full 2048-word BIP39 list,
+# which otherwise floods signatures and forces near-blank pages in the PDF.
+autodoc_preserve_defaults = True
+
templates_path = ['_templates']
exclude_patterns = ['_build', 'Thumbs.db', '.DS_Store']
@@ -115,7 +142,7 @@
html_show_sphinx = False
# Logo configuration
-html_logo = "_static/cryptnox-logo.png"
+html_logo = "_static/cryptnox-logo.svg"
# Custom CSS and JS
html_css_files = [
@@ -141,3 +168,101 @@
'includehidden': True,
'titles_only': False
}
+
+# -- Options for PDF (LaTeX) output ------------------------------------------
+# Built by CI with pdflatex, same as Yubico's tech manual. Output: cryptnox-cli.pdf
+
+today = 'June 20, 2026' # fixed doc date on the cover
+
+latex_engine = 'pdflatex'
+latex_logo = '_static/cryptnox-logo-dark.png' # white logo is invisible on white PDF title page
+latex_domain_indices = False # no Python Module Index in the PDF (kept in HTML)
+latex_documents = [
+ ('index', 'cryptnox-cli.tex', 'Cryptnox CLI Manual', author, 'manual'),
+]
+latex_elements = {
+ 'papersize': 'a4paper',
+ 'pointsize': '11pt',
+ 'figure_align': 'H',
+ 'sphinxsetup': 'pre_border-radius=0pt', # sharp rectangle corners on code-block (CLI command) frames
+ 'extraclassoptions': 'oneside,openany', # no blank filler pages (web PDF)
+ 'printindex': '', # drop the general Index from the PDF (kept in HTML)
+ 'fncychap': '', # no fancy chapter rules; titlesec styles chapters instead
+ 'preamble': r'''
+% pdflatex can't render colour emoji; map the ones used in the docs to safe glyphs
+\usepackage{amssymb}
+\DeclareUnicodeCharacter{1F4B3}{}% credit card -> drop
+\DeclareUnicodeCharacter{FE0F}{}% variation selector -> drop
+\DeclareUnicodeCharacter{26A0}{\textbf{!}}% warning sign
+\DeclareUnicodeCharacter{2705}{\ensuremath{\checkmark}}% check mark
+% CLI commands / literals (\ttfamily) in Inconsolata
+\usepackage{inconsolata}
+% Left-align body text (ragged right instead of justified)
+\usepackage[document]{ragged2e}
+% Drop the "(continues on next page)" / "(continued from previous page)" labels (parens included) on code blocks
+\AtBeginDocument{\renewcommand*\sphinxstylecodecontinued[1]{}\renewcommand*\sphinxstylecodecontinues[1]{}}
+% Whole document in the sans font (TeX Gyre Heros)
+\renewcommand{\familydefault}{\sfdefault}
+% Sans-serif TOC entries
+\AtBeginDocument{\addtocontents{toc}{\protect\sffamily}}
+% Left-aligned chapter headings
+\usepackage{titlesec}
+\titleformat{\chapter}[hang]{\sffamily\bfseries\huge}{\thechapter}{1em}{}
+\titlespacing*{\chapter}{0pt}{0pt}{20pt}
+% Centered page header (manual title, no release) + copyright footer
+\usepackage{fancyhdr}
+\def\headruleskip{4pt}\def\footruleskip{4pt}% gap between header/footer text and rule
+\AtBeginDocument{%
+ \fancypagestyle{normal}{%
+ \fancyhf{}%
+ \fancyhead[C]{\sffamily\nouppercase{Cryptnox CLI Manual}}%
+ \fancyfoot[L]{\sffamily\copyright{} 2026 Cryptnox SA}%
+ \fancyfoot[R]{\sffamily\thepage}%
+ \renewcommand{\headrulewidth}{0.4pt}%
+ \renewcommand{\footrulewidth}{0.4pt}%
+ }%
+ \fancypagestyle{plain}{%
+ \fancyhf{}%
+ \fancyfoot[L]{\sffamily\copyright{} 2026 Cryptnox SA}%
+ \fancyfoot[R]{\sffamily\thepage}%
+ \renewcommand{\headrulewidth}{0pt}%
+ \renewcommand{\footrulewidth}{0.4pt}%
+ }%
+ \pagestyle{normal}%
+}
+% Centered title page (default is right-aligned); author line removed (logo brands it)
+\makeatletter
+\renewcommand{\sphinxmaketitle}{%
+ \let\sphinxrestorepageanchorsetting\relax
+ \ifHy@pageanchor\def\sphinxrestorepageanchorsetting{\Hy@pageanchortrue}\fi
+ \hypersetup{pageanchor=false}%
+ \begin{titlepage}%
+ \let\footnotesize\small \let\footnoterule\relax
+ \begingroup
+ \def\endgraf{ }\def\and{\& }%
+ \pdfstringdefDisableCommands{\def\\{, }}%
+ \hypersetup{pdfauthor={\@author}, pdftitle={\@title}}%
+ \endgroup
+ \noindent\rule{\textwidth}{1pt}\par
+ \begin{flushright}%
+ \vskip 1em%
+ \includegraphics[width=7cm]{cryptnox-logo-dark}\par
+ \vskip 2em%
+ {\LARGE\py@HeaderFamily \@title \par}%
+ \vskip 0.5em%
+ {\large\itshape \py@release\releaseinfo \par}%
+ \vfill
+ {\large \@date \par}%
+ \end{flushright}%
+ \@thanks
+ \end{titlepage}%
+ \setcounter{footnote}{0}%
+ \let\thanks\relax\let\maketitle\relax
+ \clearpage
+ \ifdefined\sphinxbackoftitlepage\sphinxbackoftitlepage\fi
+ \if@openright\cleardoublepage\else\clearpage\fi
+ \sphinxrestorepageanchorsetting
+}
+\makeatother
+''',
+}
diff --git a/docs/index.rst b/docs/index.rst
index fc19abd..f27d032 100644
--- a/docs/index.rst
+++ b/docs/index.rst
@@ -1,7 +1,11 @@
Cryptnox CLI Documentation
==========================
-Welcome to the technical documentation of Cryptnox CLI.
+.. only:: html
+
+ Welcome to the technical documentation of Cryptnox CLI.
+
+ 📄 `Download this documentation as PDF `__
.. toctree::
:maxdepth: 2