diff --git a/README.md b/README.md
index 1d53cbd..97bea7d 100644
--- a/README.md
+++ b/README.md
@@ -1,153 +1,93 @@
-
+
ProgramVer
-A Python version of Microsoft's 'winver', built to be customizable, and to show copyright info and licenses.
+A Python version of Microsoft's winver — a copyright and licence window you drop into your own program.
-

-

-

-

-

-

-

-
-

-
-

-
-
+ Status •
Key Features •
- Download •
- How To Use •
+ Installation •
+ Usage •
+ Documentation •
Support •
Contributing •
- Changelog •
- Credits & Contributors
+ Credits •
+ License
-
+
-

+
-## Key Features
-
-* Display a version window.
-* Can be called and imported as a function.
-* Links to License text.
-* Links to EULA text.
-* Includes logo and Python Powered images.
-* Cross platform.
+## Status
-## Download
+**Currently broken as shipped.** `ProgramVer()` loads `imgs/dfdlogo.gif`, which is not in the repository, so the window fails before it appears. The two buttons read `LICENSE.txt` and `EULA.txt`, neither of which exists either.
-You can **[download](https://github.com/willtheorangeguy/ProgramVer/releases/latest) the source code** to run the scripts from the command line on Windows, macOS and Linux. **This will require [Python](https://www.python.org/downloads/).**
+The test suite passes — it mocks every file access and every widget — so CI is green and the program still cannot start. Details and suggested fixes are in [`docs/internal/known-issues.md`](docs/internal/known-issues.md).
-You can **[download](https://github.com/willtheorangeguy/ProgramVer/releases/latest) the latest executable version** of ProgramVer for Windows. **This does not require Python.**
+The template is sound and the customisation points are real; it needs its assets back.
-## How To Use
-
-To run the application, you can use [Git and the Python Interpreter](https://github.com/willtheorangeguy/ProgramVer/main/README.md#git), which allows you to clone and run the application, or [`pip`](https://github.com/willtheorangeguy/ProgramVer/main/README.md#pip) to create a command line application.
+## Key Features
-### Git
+- A `winver`-style window: logo, program name and version, trademark notice, licence blurb.
+- **Open License** and **Open EULA** buttons that display the full text in their own windows.
+- Importable as a function, so you can wire it to your own program's About menu.
+- Python-Powered badge included.
+- Pure standard library — Tkinter only.
+- Cross-platform.
-To clone and run this application, you'll need [Git](https://git-scm.com/downloads) and [Python](https://www.python.org/downloads/) installed on your computer. If you would rather not use Git, you can just download the script from GitHub above. From your command line:
+## Installation
```bash
-# Clone this repository
-$ git clone https://github.com/willtheorangeguy/ProgramVer
-
-# Go into the repository
-$ cd ProgramVer
-
-# Run the CLI
-$ python main.py
+git clone https://github.com/willtheorangeguy/ProgramVer
+cd ProgramVer
+python main.py
```
-### `pip`
+See [`docs/installation.md`](docs/installation.md), including what you need to supply before it runs.
-You can install the program from the [Python Package Index](https://pypi.org/project/programver/) through `pip`.
-
-```bash
-# Install via pip
-$ pip install programver
+## Usage
-# Run the CLI
-$ programver
+```python
+from main import ProgramVer
+ProgramVer()
```
-However, you may want to add the version window to your program. To do so, follow these steps:
+Every string in the window is meant to be edited for your project — see [`docs/configuration.md`](docs/configuration.md).
-1. Download the latest source code release from [GitHub Releases](https://github.com/willtheorangeguy/ProgramVer/releases/latest) page.
-2. Extract the source code files using a program like [7-Zip](https://www.7-zip.org/).
-3. Copy the `ProgramVer.py` file to your project's main directory.
-4. Import ProgramVer by adding `from ProgramVer import *` to your Python `import` statements.
-5. Call ProgramVer through the `ProgramVer()` function.
-6. Enjoy your new version window!
+## Documentation
-## Support
-
-Customization for ProgramVer can be found in the [`CUSTOMIZATION`](https://github.com/willtheorangeguy/ProgramVer/blob/master/docs/CUSTOMIZATION.md) doc. More documentation is available in the **[Documentation](https://github.com/willtheorangeguy/ProgramVer/tree/master/docs)** and on the **[Wiki](https://github.com/willtheorangeguy/ProgramVer/wiki)**. If more support is required, please open a **[GitHub Discussion](https://github.com/willtheorangeguy/ProgramVer/discussions)** or join our **[Discord](https://discord.gg/x3G8adwVUe)**.
-
-## Testing
-
-ProgramVer includes a comprehensive test suite to ensure code quality and reliability. The test suite achieves 100% code coverage for the main module.
+Full documentation lives in [`docs/`](docs/README.md):
+[Quickstart](docs/quickstart.md) · [Installation](docs/installation.md) · [Configuration](docs/configuration.md) · [Architecture](docs/architecture.md) · [Development](docs/development.md) · [Testing](docs/testing.md) · [FAQ](docs/faq.md) · [Troubleshooting](docs/troubleshooting.md) · [Roadmap](docs/roadmap.md)
-### Running Tests
-
-To run the test suite locally:
-
-```bash
-# Install test dependencies
-pip install -r requirements.txt
-
-# Run tests (Linux)
-xvfb-run -a python -m pytest tests/ -v
-
-# Run tests (Windows/macOS)
-python -m pytest tests/ -v
-
-# Run tests with coverage
-python -m pytest tests/ --cov=main --cov-report=term-missing
-```
-
-For more information about testing, see the [tests README](tests/README.md).
-
-### Continuous Integration
-
-Tests are automatically run on GitHub Actions for every push and pull request across:
+## Support
-- Operating Systems: Ubuntu, Windows, and macOS
-- Python Versions: 3.9, 3.10, 3.11, and 3.12
+Open a [GitHub Discussion](https://github.com/willtheorangeguy/ProgramVer/discussions), file an [issue](https://github.com/willtheorangeguy/ProgramVer/issues/new/choose), or join the [Discord](https://discord.gg/x3G8adwVUe).
## Contributing
Please contribute using [GitHub Flow](https://guides.github.com/introduction/flow). Create a branch, add commits, and [open a pull request](https://github.com/willtheorangeguy/ProgramVer/compare).
-Please read [`CONTRIBUTING`](https://github.com/willtheorangeguy/.github/blob/main/CONTRIBUTING.md) for details on our [`CODE OF CONDUCT`](https://github.com/willtheorangeguy/.github/blob/main/CODE_OF_CONDUCT.md), and the process for submitting pull requests to us.
-
-## Changelog
-
-See the [`CHANGELOG`](CHANGELOG.md) file for details.
+See the org-wide [Contributing Guide](https://github.com/willtheorangeguy/.github/blob/main/CONTRIBUTING.md) and [Code of Conduct](https://github.com/willtheorangeguy/.github/blob/main/CODE_OF_CONDUCT.md).
## Credits
@@ -172,16 +112,10 @@ This software uses the following open source packages, projects, services or web
-## Contributors
-
-* [@willtheorangeguy](https://github.com/willtheorangeguy) - Sponsor on [PayPal](https://paypal.me/wvdg44?country.x=CA&locale.x=en_US)
-
-## You may also like...
-
-* [PyWorkout](https://github.com/willtheorangeguy/PyWorkout) - A minimal CLI to keep you inspired during your workout!
-* [PyAvatar](https://github.com/willtheorangeguy/PyAvatar) - Easily display all of your creative avatars to keep them consistent across websites.
-* [Periodic Table Info](https://github.com/willtheorangeguy/Periodic-Table-Info) - Print all the elements in the Periodic Table of the Elements, with an interactive prompt to learn more.
+Sponsor [@willtheorangeguy](https://github.com/willtheorangeguy) on [PayPal](https://paypal.me/wvdg44?country.x=CA&locale.x=en_US).
## License
-This project is licensed under the [MIT License](https://mit-license.org/) - see the [`LICENSE`](LICENSE.md) file for details.
+MIT — see [`LICENSE.md`](LICENSE.md).
+
+> Note the window itself currently displays a GPL blurb and a different copyright holder. That text is placeholder content meant to be replaced per project, but it does not match this repository's own licence — see [`docs/internal/known-issues.md`](docs/internal/known-issues.md).
diff --git a/docs/CUSTOMIZATION.md b/docs/CUSTOMIZATION.md
deleted file mode 100644
index a768e47..0000000
--- a/docs/CUSTOMIZATION.md
+++ /dev/null
@@ -1,56 +0,0 @@
-# ProgramVer Customization
-
-ProgramVer is designed to be highly customizable, in order to make the version window suit each individual project. The license and EULA texts can be changed, as well as the program name, version number and more.
-
-All of these instructions require [a text editor](https://code.visualstudio.com/) to be installed.
-
-## Set the License File and Text
-
-The version window can be configured to use a custom license file and text.
-
-1. _Line 11_: Replace the `'LICENSE.txt'` with the name (or path) to the license file.
-2. _Line 40_: Replace the text in between the single quotes (`'...'`) with the trademark/license blurb. For example, here is the one from `winver.exe`:
-
-```text
-© Microsoft Corporation. All rights reserved.
-```
-
-3. _Line 41_: Replace the text in between the triple double quotes (`"""..."""`) with the license blurb, if your license includes this. For example, the GNU Public License includes a section of text that should be included with each program:
-
-```text
-
- Copyright (C)
-
- This program is free software: you can redistribute it and/or modify
- it under the terms of the GNU General Public License as published by
- the Free Software Foundation, either version 3 of the License, or
- (at your option) any later version.
-
- This program is distributed in the hope that it will be useful,
- but WITHOUT ANY WARRANTY; without even the implied warranty of
- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
- GNU General Public License for more details.
-
- You should have received a copy of the GNU General Public License
- along with this program. If not, see .
-```
-
-## Set the EULA File
-
-The version window can be configured to use a custom EULA file.
-
-1. _Line 21_: Replace the `'EULA.txt'` with the name (or path) to the End User License Agreement file.
-
-## Set the Window Title
-
-The version window can be configured to have a custom title.
-
-1. _Line 33_: Replace the `'Copyright & Version Info for ProgramVer'` with the name of the project ProgramVer is being added to.
-2. _Line 39_: Replace the `'ProgramVer \n Version: 1.8.0 (Build 1080)'` with the program name and the version number.
-
-## Set the Images
-
-The version window can be configured to show a company logo and the Python Powered logo.
-
-1. _Line 35_: Replace the `'dfdlogo.gif'` with the name (or path) of the company logo image.
-2. _Line 36_: Replace the `'pythonpoweredlengthgif.gif'` with the name (or path) to another Python Powered image, or any other image that fits.
diff --git a/docs/README.md b/docs/README.md
index 9c2185a..229da3e 100644
--- a/docs/README.md
+++ b/docs/README.md
@@ -1,12 +1,57 @@
-# ProgramVer Documentation
+# ProgramVer — Documentation
-This folder includes all of the docs for ProgramVer. More can be found on the [wiki](https://github.com/willtheorangeguy/ProgramVer/wiki).
+A `winver`-style copyright and version window for your own Python programs: a logo, a version
+line, a trademark notice, a licence blurb, and buttons that open the full licence and EULA.
-```text
-├── docs
-| ├── images
-| ├── CUSTOMIZATION.md
-| ├── TESTING.md
-| ├── USAGE.md
-└── README.md
```
+ProgramVer/
+├── main.py get_resource_path, openLicense, openEULA, ProgramVer
+├── imgs/ the window's images
+├── tests/test_main.py
+└── docs/ this documentation
+```
+
+## Pages
+
+- [Quickstart](./quickstart.md) — run it, and what you must supply first
+- [Installation](./installation.md) — source, PyPI, executable
+- [Configuration](./configuration.md) — every string and image to change for your project
+- [Architecture](./architecture.md) — three functions, one window
+- [Development](./development.md) — packaging and style
+- [Testing](./testing.md) — the suite, and what it does not check
+- [FAQ](./faq.md) — why it fails, what to customise, why GPL text
+- [Troubleshooting](./troubleshooting.md) — missing files, blank windows
+- [Roadmap](./roadmap.md) — direction and non-goals
+- [Known issues](./internal/known-issues.md) — recorded defects
+
+## It does not run as shipped
+
+Three files the code needs are absent from the repository:
+
+| Wanted by | File | Present |
+|---|---|---|
+| `ProgramVer()` | `imgs/dfdlogo.gif` | **No** |
+| `openLicense()` | `LICENSE.txt` | **No** — the repo has `LICENSE.md` |
+| `openEULA()` | `EULA.txt` | **No** |
+
+The first stops the window opening at all. `MANIFEST.in` lists `imgs/dfdlogo.gif` for packaging,
+so it is expected to exist and does not.
+
+CI is green throughout, because the test suite mocks file access and every Tk widget. See
+[`internal/known-issues.md`](./internal/known-issues.md).
+
+## What it is for
+
+Microsoft's `winver` shows a small window with the product name, version, and licensing notice.
+ProgramVer is the same idea for a Python program: a function you call from an About menu that
+presents the same information, with the licence text one click away.
+
+The design assumption is that **you edit it**. Program name, version, trademark line, licence
+blurb, and the two document filenames are all literals in `main.py`, each with a
+`# change as needed` comment. That is the intended workflow — see
+[Configuration](./configuration.md).
+
+## Standard library only
+
+Tkinter and nothing else. Dropping `main.py` into a project adds no dependencies, which is the
+point of a component meant to be copied rather than depended on.
diff --git a/docs/TESTING.md b/docs/TESTING.md
deleted file mode 100644
index 4b17237..0000000
--- a/docs/TESTING.md
+++ /dev/null
@@ -1,100 +0,0 @@
-# ProgramVer Test Suite
-
-This directory contains the comprehensive test suite for ProgramVer.
-
-## Running Tests
-
-### Prerequisites
-
-Install the required testing dependencies:
-
-```bash
-pip install -r requirements.txt
-```
-
-On Linux systems, you'll also need to install tkinter and xvfb for headless GUI testing:
-
-```bash
-sudo apt-get install python3-tk xvfb
-```
-
-### Running All Tests
-
-To run all tests:
-
-```bash
-# On Linux (headless environment)
-xvfb-run -a python -m pytest tests/ -v
-
-# On Windows/macOS (with display)
-python -m pytest tests/ -v
-```
-
-### Running Tests with Coverage
-
-To run tests with coverage report:
-
-```bash
-# On Linux
-xvfb-run -a python -m pytest tests/ --cov=. --cov-report=term-missing --cov-report=html
-
-# On Windows/macOS
-python -m pytest tests/ --cov=. --cov-report=term-missing --cov-report=html
-```
-
-The HTML coverage report will be generated in the `htmlcov` directory.
-
-### Running Specific Tests
-
-To run a specific test file:
-
-```bash
-xvfb-run -a python -m pytest tests/test_main.py -v
-```
-
-To run a specific test class:
-
-```bash
-xvfb-run -a python -m pytest tests/test_main.py::TestOpenLicense -v
-```
-
-To run a specific test method:
-
-```bash
-xvfb-run -a python -m pytest tests/test_main.py::TestOpenLicense::test_openLicense_creates_window -v
-```
-
-## Test Structure
-
-The test suite is organized as follows:
-
-- `test_main.py` - Tests for the main ProgramVer module
- - `TestOpenLicense` - Tests for the openLicense function
- - `TestOpenEULA` - Tests for the openEULA function
- - `TestProgramVer` - Tests for the ProgramVer main function
- - `TestModuleIntegration` - Integration tests for the module
-
-## GitHub Actions Integration
-
-The test suite is automatically run on GitHub Actions for every push and pull request. The workflow:
-
-- Runs on Ubuntu, Windows, and macOS
-- Tests against Python 3.9, 3.10, 3.11, and 3.12
-- Generates coverage reports
-- Uploads coverage to Codecov (for master branch)
-
-See `.github/workflows/tests.yml` for the complete configuration.
-
-## Writing New Tests
-
-When adding new features to ProgramVer, please add corresponding tests following these guidelines:
-
-1. Create test classes that inherit from `unittest.TestCase`
-2. Use descriptive test method names that start with `test_`
-3. Use mocking for GUI components to avoid requiring a display
-4. Add docstrings to explain what each test verifies
-5. Ensure tests are independent and can run in any order
-
-## Coverage Goals
-
-We aim to maintain at least 90% code coverage for the main module. Currently, we have 100% coverage for `main.py`.
diff --git a/docs/USAGE.md b/docs/USAGE.md
deleted file mode 100644
index c802899..0000000
--- a/docs/USAGE.md
+++ /dev/null
@@ -1,26 +0,0 @@
-# ProgramVer Usage
-
-To install ProgramVer, you can use an executable package (Windows), run the scripts through Python (Windows, macOS, Linux), or install from the [Python Package Index](https://pypi.org/).
-
-## Executable Package
-
-1. To run the executable package, download the latest `.zip` file from [GitHub Releases](https://github.com/willtheorangeguy/ProgramVer/releases/latest) page.
-2. Extract the `.zip` file using a program like [7-Zip](https://www.7-zip.org/).
-3. _(Optional) Move the files to `C:\Program Files` and create a shortcut._
-4. Double click on `send.exe`.
-5. Enjoy the program!
-
-## Python Script
-
-1. To run the Python script, download the latest source code release from [GitHub Releases](https://github.com/willtheorangeguy/ProgramVer/releases/latest) page.
-2. Download and install [Python](https://www.python.org/downloads/).
-3. Extract the source code files using a program like [7-Zip](https://www.7-zip.org/).
-4. Double click on `send.py`, or right-click and open with IDLE and press `F5`.
-5. Enjoy the program!
-
-## Python Package Index (`pip`)
-
-1. Download and install [Python](https://www.python.org/downloads/).
-2. Open a terminal and run the command: `pip install lego-block-creator`.
-3. Start the program by running the command: `lego-block-creator`.
-4. Enjoy the program!
diff --git a/docs/architecture.md b/docs/architecture.md
new file mode 100644
index 0000000..71f966d
--- /dev/null
+++ b/docs/architecture.md
@@ -0,0 +1,69 @@
+# ProgramVer — Architecture
+
+One module, three functions, no dependencies.
+
+```
+main.py
+├── get_resource_path(filename) resolve against __file__
+├── openLicense() read LICENSE.txt → its own window
+├── openEULA() read EULA.txt → its own window
+└── ProgramVer() the main window, then mainloop()
+```
+
+## `get_resource_path`
+
+```python
+base_dir = os.path.dirname(os.path.abspath(__file__))
+return os.path.join(base_dir, filename)
+```
+
+Resolves against the **module**, not the working directory, so the window works wherever it is
+launched from and survives being copied into another project. Used for both images and both text
+files.
+
+## `ProgramVer()`
+
+Builds the window and calls `mainloop()` itself, so it **blocks** until closed. That makes it a
+drop-in call from a menu handler, and it means calling it from an existing Tkinter application
+starts a second event loop — see below.
+
+Widgets, top to bottom: logo, name and version, trademark notice, licence blurb, the two
+buttons, and the Python-Powered badge at the bottom.
+
+Note that neither `PhotoImage` is bound to a lasting reference. They survive because they are
+locals of a function that blocks in `mainloop()` — if `ProgramVer()` were refactored to return
+the window instead, both images would be garbage-collected and the labels would render blank
+with no error.
+
+## `openLicense` and `openEULA`
+
+Identical in shape: construct a `Tk()`, read a text file, insert it into a `Text` widget, pack.
+
+Two things follow. Neither calls `mainloop()` — they rely on the main window's loop, which works
+because they are invoked from a button callback inside it. And both construct a second `Tk()`
+root rather than a `Toplevel()`; Tkinter supports one true root per process, so closing the
+wrong window can take the others with it.
+
+Neither file is present in the repository. See
+[`internal/known-issues.md`](./internal/known-issues.md).
+
+## Why it is a template, not a library
+
+Every displayed string is a literal, each marked `# change as needed`. There is no parameter, no
+config object, and no settings file. The intended workflow is copying `main.py` into your project
+and editing it.
+
+That is a reasonable design for a component this small — a configurable version would need a
+schema for something a developer edits once — but it does mean the shipped defaults are visible
+to anyone who forgets to change them.
+
+## Standard library only
+
+Tkinter and `os`. Nothing to install, and nothing added to the dependency tree of whatever
+project copies it in.
+
+## What breaks it
+
+The design is sound; three files it opens are absent. `imgs/dfdlogo.gif` stops the window
+entirely, and the two `.txt` files break a button each. `MANIFEST.in` lists the image for
+packaging, so its absence is an omission rather than a decision.
diff --git a/docs/configuration.md b/docs/configuration.md
new file mode 100644
index 0000000..d8e92e5
--- /dev/null
+++ b/docs/configuration.md
@@ -0,0 +1,80 @@
+# ProgramVer — Configuration
+
+ProgramVer is a template. There is no config file — you edit `main.py`, and every editable
+string carries a `# change as needed` comment.
+
+Earlier documentation gave **line numbers** for these edits. They no longer match the file, so
+this page names the symbols instead.
+
+## The window title
+
+```python
+window.title("Copyright & Version Info for ProgramVer")
+```
+
+In `ProgramVer()`. Use your program's name.
+
+## Program name and version
+
+```python
+info = Label(window, text="ProgramVer \n Version: 1.9.0 (Build #)")
+```
+
+Hardcoded. Reading it from your package metadata
+(`importlib.metadata.version("yourpackage")`) keeps it from drifting after a release.
+
+## Trademark notice
+
+```python
+trademarks = Label(window, text="Copyright (C) 2017 - 2024 Dog Face Development Co. ...")
+```
+
+Placeholder text naming a different company, and dated 2024. Replace it. The `winver` equivalent
+is a single line:
+
+```text
+© Microsoft Corporation. All rights reserved.
+```
+
+## Licence blurb
+
+```python
+licenseblurb = Label(window, text="""...GNU General Public License...""")
+```
+
+The shipped text is the GPL v3 notice for "Dog Face Development Company", while **this repository
+is MIT**. For a tool whose purpose is displaying licence information, showing the wrong licence
+is worth fixing before anything else — see
+[`internal/known-issues.md`](./internal/known-issues.md).
+
+Use the notice your own licence recommends. MIT does not require one in-window; GPL does.
+
+## The licence and EULA files
+
+```python
+license_path = get_resource_path("LICENSE.txt") # in openLicense
+eula_path = get_resource_path("EULA.txt") # in openEULA
+```
+
+Both are read as plain text with UTF-8 encoding and shown in a `Text` widget. Neither file is in
+this repository — supply them, or repoint the calls at files you have.
+
+If you point `openLicense` at a Markdown file, note it is displayed raw, with no rendering.
+
+## Images
+
+| Image | Path | Shown |
+|---|---|---|
+| Your logo | `imgs/dfdlogo.gif` | Top |
+| Python-Powered badge | `imgs/pythonpoweredlengthgif.gif` | Bottom |
+
+**GIF or PNG only** — Tkinter's `PhotoImage` reads nothing else without Pillow. Both are loaded
+through `get_resource_path`, so they resolve relative to the module.
+
+Remember `MANIFEST.in` if you add images and intend to package them.
+
+## Layout
+
+Everything is `pack`ed: logo, info, trademarks, blurb, and buttons from the top; the Python badge
+at the bottom. Buttons get `pady=5`. There is no styling beyond Tkinter's defaults, deliberately —
+it is meant to look like a system dialog.
diff --git a/docs/development.md b/docs/development.md
new file mode 100644
index 0000000..647f89c
--- /dev/null
+++ b/docs/development.md
@@ -0,0 +1,77 @@
+# ProgramVer — Development
+
+## Setup
+
+```bash
+git clone https://github.com/willtheorangeguy/ProgramVer
+cd ProgramVer
+pip install -r requirements.txt
+python main.py
+```
+
+No runtime dependencies; `requirements.txt` is the tooling.
+
+## Commands
+
+```bash
+python main.py # run
+pytest # 14 tests
+pylint $(git ls-files '*.py') # what CI lints with
+```
+
+## Packaging
+
+`pyproject.toml`, `setup.py`, and `setup.cfg` all describe the package at version `1.9.0`. Two of
+them contain a mistake worth understanding before touching them:
+
+```python
+packages=find_packages(where="imgs"),
+package_dir={"": "imgs"},
+py_modules=["main"],
+```
+
+`imgs/` holds images, not Python packages, so `find_packages` finds nothing and the `package_dir`
+mapping points the root at a directory with no modules in it. Only `py_modules=["main"]` actually
+ships code. `setup.cfg` repeats the same mapping.
+
+`MANIFEST.in` lists `imgs/dfdlogo.gif` and `imgs/pythonpoweredlengthgif.gif`. The first is not in
+the repository. See [`internal/known-issues.md`](./internal/known-issues.md).
+
+Consolidating on `pyproject.toml` would remove the duplication and the chance of the three
+drifting.
+
+## Style
+
+- **Pylint**, with per-file disables at the top (`import-error`, `invalid-name`).
+- **Module docstring and copyright header** on every file.
+- **`get_resource_path` for every file access.** Never a bare relative path — it is what makes the
+ module portable into another project.
+- **GIF or PNG images.** Tkinter reads nothing else without Pillow, and Pillow would be the first
+ runtime dependency.
+
+## If you change the display strings
+
+They are the template's whole surface, and [Configuration](./configuration.md) names each by
+symbol. The old `CUSTOMIZATION.md` located them by **line number**, which had drifted out of
+date — avoid reintroducing that.
+
+## If you extend the tests
+
+Mock the display, not the filesystem. See [Testing](./testing.md) — the current suite mocks both,
+which is why it passes against missing files.
+
+## CI
+
+| Workflow | Does |
+|---|---|
+| `tests.yml` | pytest |
+| `pylint.yml` | Lint |
+| `codeql-analysis.yml` | Security scan |
+| `push-to-pypi.yml` | Publish on release |
+
+Nothing runs the built package, so a release that cannot start still publishes green.
+
+## Recording defects
+
+Bugs found while working here go in [`internal/known-issues.md`](./internal/known-issues.md)
+rather than being fixed in passing, unless fixing them is the job you are on.
diff --git a/docs/faq.md b/docs/faq.md
new file mode 100644
index 0000000..1292568
--- /dev/null
+++ b/docs/faq.md
@@ -0,0 +1,64 @@
+# ProgramVer — FAQ
+
+### It crashes on startup.
+
+`ProgramVer()` loads `imgs/dfdlogo.gif`, which is not in the repository, so Tkinter raises a
+`TclError` before the window appears. Supply your own logo at that path — GIF or PNG.
+
+Recorded in [`internal/known-issues.md`](./internal/known-issues.md).
+
+### The License and EULA buttons crash.
+
+They read `LICENSE.txt` and `EULA.txt`. Neither exists here — the repository ships `LICENSE.md`,
+and there is no EULA. Add plain-text files, or repoint the calls.
+
+### The tests pass, so how is it broken?
+
+The suite mocks every file read and every Tk widget, so it never touches the filesystem or a
+display. Every line runs; every line runs against a mock. See [Testing](./testing.md).
+
+### Why does the window show a GPL notice when the repo is MIT?
+
+The blurb, the trademark line, and the version are placeholder content for you to replace — each
+marked `# change as needed`. They name a different company and quote the GPL.
+
+For a tool whose purpose is displaying licence information, shipping the wrong licence as the
+default is worth fixing. Same known-issues file.
+
+### How do I use it in my program?
+
+```python
+from main import ProgramVer
+ProgramVer()
+```
+
+Copy `main.py` and `imgs/` into your project and edit the strings — see
+[Configuration](./configuration.md).
+
+### Earlier docs said to copy `ProgramVer.py`.
+
+There is no such file; the module is `main.py`. Renaming it on the way into your project makes
+the old instruction true.
+
+### Does it block?
+
+Yes. `ProgramVer()` calls `mainloop()` itself, so it returns when the window is closed. Calling
+it from an existing Tkinter app starts a second event loop — see
+[Architecture](./architecture.md).
+
+### Can I use a PNG or JPEG logo?
+
+PNG yes, JPEG no. Tkinter's `PhotoImage` reads GIF and PNG only; JPEG needs Pillow.
+
+### Does it need internet, or write anything?
+
+Neither. It reads local files and draws a window.
+
+### Why Tkinter?
+
+Because it is in the standard library. A version window that added a GUI dependency to every
+project it was copied into would not be worth copying.
+
+### Is there a Windows executable?
+
+Yes, attached to [releases](https://github.com/willtheorangeguy/ProgramVer/releases/latest).
diff --git a/docs/images/logo.png b/docs/images/logo.png
deleted file mode 100644
index f41c946..0000000
Binary files a/docs/images/logo.png and /dev/null differ
diff --git a/docs/images/welcome.png b/docs/images/welcome.png
deleted file mode 100644
index fb92697..0000000
Binary files a/docs/images/welcome.png and /dev/null differ
diff --git a/docs/installation.md b/docs/installation.md
new file mode 100644
index 0000000..e050d42
--- /dev/null
+++ b/docs/installation.md
@@ -0,0 +1,76 @@
+# ProgramVer — Installation
+
+## Requirements
+
+| | |
+|---|---|
+| Python | 3.x with Tkinter |
+| Dependencies | None at runtime |
+
+Tkinter is bundled on Windows and macOS; on Linux install `python3-tk` (Debian, Ubuntu) or
+`python3-tkinter` (Fedora).
+
+## From source
+
+```bash
+git clone https://github.com/willtheorangeguy/ProgramVer
+cd ProgramVer
+python main.py
+```
+
+You will need to supply `imgs/dfdlogo.gif`, `LICENSE.txt`, and `EULA.txt` — see
+[Quickstart](./quickstart.md).
+
+Resource paths are resolved against `main.py`'s own location via `get_resource_path`, so the
+working directory does not matter.
+
+## As a component in your own project
+
+The intended use. Copy `main.py` into your project and import it:
+
+```python
+from main import ProgramVer
+ProgramVer()
+```
+
+Copy `imgs/` alongside it, or repoint the image paths.
+
+Earlier documentation told you to copy `ProgramVer.py` and `from ProgramVer import *`. There is
+no `ProgramVer.py` in this repository — the module is `main.py`, and the function inside it is
+`ProgramVer`. Renaming the file to `programver.py` on the way in is reasonable, and then the old
+instruction becomes true.
+
+## From PyPI
+
+```bash
+pip install programver
+programver
+```
+
+Two caveats. The console script points at `main:ProgramVer`, which does call `mainloop()`, so it
+would work — if the image were present. And the packaging declares `imgs/` as the package root
+(`package_dir={"": "imgs"}`, `find_packages(where="imgs")`) where there are no Python packages
+at all; only `py_modules=["main"]` ships anything. See
+[`internal/known-issues.md`](./internal/known-issues.md).
+
+## Windows executable
+
+Attached to [releases](https://github.com/willtheorangeguy/ProgramVer/releases/latest), built
+with PyInstaller. Note that a one-file build unpacks to a temporary directory — `get_resource_path`
+resolves against `__file__`, which PyInstaller sets appropriately, so this should hold.
+
+## Verify
+
+```bash
+python main.py
+```
+
+The window appears with your logo. A `TclError` about `dfdlogo.gif` means the image is still
+missing; see [Troubleshooting](./troubleshooting.md).
+
+## Tests
+
+```bash
+pip install -r requirements.txt
+pytest
+```
diff --git a/docs/internal/known-issues.md b/docs/internal/known-issues.md
new file mode 100644
index 0000000..49b4b34
--- /dev/null
+++ b/docs/internal/known-issues.md
@@ -0,0 +1,95 @@
+# Known Issues — ProgramVer
+
+Concrete defects and gaps found while writing this repository's documentation in
+August 2026. **Nothing here was changed** — each one needs a code, configuration, or
+licensing decision rather than a documentation one.
+
+Ordered by severity. See [`docs/roadmap.md`](../roadmap.md) for the narrative version,
+which also covers deliberate non-goals.
+
+
+**6 open:** 2 high, 3 medium, 1 low.
+
+## 1. The window cannot open: imgs/dfdlogo.gif is not in the repository
+
+**Severity:** High
+**Where:** `main.py` -> `ProgramVer`, `MANIFEST.in`
+
+**What:** `ProgramVer()` calls `PhotoImage(file=get_resource_path("imgs/dfdlogo.gif"))` as the first of its two images. `imgs/` contains only `pythonpoweredlengthgif.gif` and an egg-info directory -- `dfdlogo.gif` is absent, and `git ls-files` does not list it. `MANIFEST.in` explicitly includes it for packaging, so its absence is an omission rather than a decision.
+
+**Why it matters:** Tkinter raises `TclError` on that line, before any widget is packed, so the program produces a traceback and no window at all. This is the only thing the package does: there is no degraded mode, no fallback image, and no other entry point. Every route -- `python main.py`, the `programver` console script, the PyInstaller build, and copying the module into another project -- fails identically. CI stays green throughout, because the test suite patches `main.PhotoImage`.
+
+**Suggested fix:** Restore or replace `imgs/dfdlogo.gif` (GIF or PNG; Tkinter reads nothing else without Pillow). Consider falling back to a text label when the image is missing, since this is a template others copy half-configured.
+
+## 2. Both document buttons read files that do not exist
+
+**Severity:** High
+**Where:** `main.py` -> `openLicense`, `openEULA`
+
+**What:** `openLicense` opens `get_resource_path("LICENSE.txt")` and `openEULA` opens `get_resource_path("EULA.txt")`, each with a bare `open(...)` and no guard. Neither file is in the repository: the licence here is `LICENSE.md`, and there is no EULA at all.
+
+**Why it matters:** The two buttons are half the window's function -- a version dialog whose entire value is making the licence one click away. Both raise `FileNotFoundError` from inside a Tk callback, which prints a traceback to the console and leaves the window looking unresponsive rather than reporting anything to the user. A `.md` file sitting next to a `.txt` reference is exactly the kind of near-miss that survives review.
+
+**Suggested fix:** Add plain-text `LICENSE.txt` and `EULA.txt`, or point the calls at files that exist. Either way, wrap the read and show the error in the window instead of the console -- a template will be copied into projects where these filenames are wrong.
+
+## 3. The test suite mocks the filesystem, so it passes against a program that cannot start
+
+**Severity:** Medium
+**Where:** `tests/test_main.py`
+
+**What:** All 14 tests patch `main.Tk`, `main.Text`, `main.Label`, `main.Button`, `main.PhotoImage`, and `builtins.open` (via `mock_open`). `test_get_resource_path` asserts only that the returned string **ends with** `dfdlogo.gif` -- never that the path resolves. Earlier documentation reported '100% code coverage for the main module'.
+
+**Why it matters:** Both High-severity issues above are missing files, and both are invisible to this suite by construction. The result is a repository whose badge, coverage figure, and CI all report health while the program raises before drawing a window. Mocking the display is necessary for headless CI; mocking the filesystem as well removes the only check that would have caught this, and the coverage number then actively misleads.
+
+**Suggested fix:** Add a test that the resources exist -- roughly four lines, no mocking:
+
+ for name in ("imgs/dfdlogo.gif", "imgs/pythonpoweredlengthgif.gif",
+ "LICENSE.txt", "EULA.txt"):
+ assert os.path.exists(get_resource_path(name)), name
+
+Keep mocking Tk; stop mocking `open` in tests whose purpose is to prove a file is read.
+
+## 4. The window displays a GPL notice and another company's copyright, in an MIT repository
+
+**Severity:** Medium
+**Where:** `main.py` -> `trademarks`, `licenseblurb`, `info` labels; `LICENSE.md`
+
+**What:** The `trademarks` label reads 'Copyright (C) 2017 - 2024 Dog Face Development Co. All rights reserved in all countries', and `licenseblurb` renders the GNU GPL v3 notice for 'Dog Face Development Company'. `LICENSE.md` in this repository is **MIT, Copyright 2026 willtheorangeguy**. Each label carries a `# change as needed` comment, so the text is placeholder by design.
+
+**Why it matters:** The program's single purpose is displaying accurate copyright and licence information, and its default output is neither -- wrong licence, wrong holder, wrong year. Anyone who copies the template and forgets one label ships a false licence claim in their own About box, which is the specific failure this tool exists to prevent. The `# change as needed` comments make the intent clear in the source and are invisible in the running window.
+
+**Suggested fix:** Make the defaults match this repository -- MIT, willtheorangeguy, the current year -- so an unedited copy is at least self-consistent. Better still, derive the name and version from package metadata and read the notice from the licence file, leaving less to be forgotten.
+
+## 5. Packaging declares imgs/ as the package root, where there are no packages
+
+**Severity:** Medium
+**Where:** `setup.py`, `setup.cfg`
+
+**What:** `setup.py` has `packages=find_packages(where="imgs")` and `package_dir={"": "imgs"}`; `setup.cfg` repeats `package_dir = \n = imgs` with `packages = find:` under `where = imgs`. `imgs/` contains image files and an egg-info directory -- no Python packages. `find_packages` therefore returns an empty list, and only `py_modules=["main"]` ships any code. A third description of the same package exists in `pyproject.toml`.
+
+**Why it matters:** The build succeeds and publishes, which is why this has survived: the wheel happens to contain the one module that matters, by a different mechanism than the one the configuration appears to be using. Anyone adding a real package later will find it silently excluded, and the `package_dir` mapping makes the failure hard to read -- setuptools will look for modules under `imgs/`. Three overlapping build descriptions make it likelier that a fix lands in the file that is not being read.
+
+**Suggested fix:** Drop the `package_dir` and `find_packages` lines -- this is a single-module project and `py_modules` is the correct declaration. Then consolidate on `pyproject.toml` and delete `setup.py` and `setup.cfg`.
+
+## 6. The README's integration instructions name a file that does not exist
+
+**Severity:** Low
+**Where:** `README.md` (corrected in this pass), `docs/CUSTOMIZATION.md` (removed in this pass)
+
+**What:** The How To Use section instructed: 'Copy the `ProgramVer.py` file to your project's main directory', then 'add `from ProgramVer import *`' and 'call ProgramVer through the `ProgramVer()` function'. There is no `ProgramVer.py` -- the module is `main.py`. Separately, `docs/CUSTOMIZATION.md` located each editable string by line number ('_Line 11_', '_Line 40_'), and those no longer match `main.py`.
+
+**Why it matters:** Copying the module into another project is the documented primary use, and the instructions for it name the wrong file -- so a reader either copies nothing or copies `main.py` and finds the import line wrong too. The line-number references fail more quietly: they point at real lines containing different code, so someone following them edits the wrong string and gets a window that still shows the old text.
+
+**Suggested fix:** Fixed in this pass -- the README and `docs/configuration.md` now name `main.py` and locate each editable string by symbol rather than line number. Renaming the module to `programver.py` would make the original instructions true and is worth considering, since `main.py` is a poor name for a file meant to be dropped into someone else's project.
+
+
+---
+
+## Also, across every repository
+
+**`.bandit` is present on disk but untracked in git.** Verified in PyWorkout, treklogger,
+skyscanner-cli, booking-cli, piggy, and aibot — the config file exists locally in each but
+`git ls-files` does not know about it, so none of it reached GitHub.
+
+The August 2026 security sweep therefore looks complete locally and landed nowhere. Worth
+checking across all 44 repositories it covered.
diff --git a/docs/quickstart.md b/docs/quickstart.md
new file mode 100644
index 0000000..1c521bb
--- /dev/null
+++ b/docs/quickstart.md
@@ -0,0 +1,70 @@
+# ProgramVer — Quickstart
+
+## Before it will run
+
+The repository is missing three files the code opens. Supply them first:
+
+| File | Used by | Notes |
+|---|---|---|
+| `imgs/dfdlogo.gif` | `ProgramVer()` | Your logo. **GIF or PNG only** — Tkinter reads nothing else |
+| `LICENSE.txt` | **Open License** button | Plain text; the repo ships `LICENSE.md` |
+| `EULA.txt` | **Open EULA** button | Plain text |
+
+Without the first, the window does not open at all. See
+[`internal/known-issues.md`](./internal/known-issues.md).
+
+## Run it
+
+```bash
+git clone https://github.com/willtheorangeguy/ProgramVer
+cd ProgramVer
+python main.py
+```
+
+## What you get
+
+A window titled *Copyright & Version Info for ProgramVer*, containing:
+
+- Your logo
+- The program name and version
+- A trademark notice
+- A licence blurb
+- **Open License** and **Open EULA** buttons
+- The Python-Powered badge
+
+## Use it in your own program
+
+```python
+from main import ProgramVer
+
+ProgramVer() # opens the window and blocks until it is closed
+```
+
+`ProgramVer()` calls `mainloop()` itself, so it blocks. Calling it from an existing Tkinter app
+means running a second event loop — see [Architecture](./architecture.md).
+
+## Make it yours
+
+Every string in the window is a literal in `main.py` marked `# change as needed`:
+
+| Change | Where |
+|---|---|
+| Window title | `window.title(...)` in `ProgramVer` |
+| Name and version | The `info` label |
+| Trademark notice | The `trademarks` label |
+| Licence summary | The `licenseblurb` label |
+| Licence file | `get_resource_path("LICENSE.txt")` in `openLicense` |
+| EULA file | `get_resource_path("EULA.txt")` in `openEULA` |
+| Logo | `imgs/dfdlogo.gif` |
+
+The shipped text names a different company and quotes the GPL, while this repository is MIT. It
+is placeholder content — replace all of it. See [Configuration](./configuration.md).
+
+## Tests
+
+```bash
+pip install -r requirements.txt
+pytest
+```
+
+14 tests, passing. Read [Testing](./testing.md) before reading anything into that.
diff --git a/docs/roadmap.md b/docs/roadmap.md
new file mode 100644
index 0000000..418d29c
--- /dev/null
+++ b/docs/roadmap.md
@@ -0,0 +1,54 @@
+# ProgramVer — Roadmap
+
+Direction, not a schedule. Defects are in
+[`internal/known-issues.md`](./internal/known-issues.md).
+
+## Where it is
+
+A working template that does not currently run, because three files it opens are absent.
+Everything else — the layout, the customisation points, the resource resolution — is sound.
+
+## Considered
+
+**Restoring the missing files.** `imgs/dfdlogo.gif`, `LICENSE.txt`, and `EULA.txt`. The first
+alone is the difference between a program that starts and one that does not.
+
+**A test that the resources exist.** Four lines, no mocking, and it would have caught all three.
+
+**Defaults that match this repository.** The window shows a GPL notice and another company's
+copyright while the repo is MIT — placeholder text that a tool for displaying licences should
+not ship.
+
+**Reading the version from package metadata** rather than a hardcoded string, so a release bump
+reaches the window.
+
+**Fixing the packaging.** `package_dir={"": "imgs"}` and `find_packages(where="imgs")` point at a
+directory with no packages.
+
+**`Toplevel()` for the licence and EULA windows** instead of second `Tk()` roots.
+
+**Graceful degradation.** A missing logo could render a placeholder and a missing licence file an
+explanatory message, rather than a traceback — for a template others will copy half-configured,
+that is friendlier than failing hard.
+
+## Non-goals
+
+**A configuration file.** Editing the literals is the workflow; a schema for values a developer
+sets once would be more machinery than the component.
+
+**A GUI toolkit dependency.** Tkinter is in the standard library, and staying there is what makes
+this safe to copy into any project.
+
+**Rich text or Markdown rendering.** The licence is displayed as plain text in a `Text` widget.
+Rendering would mean a dependency, for a document nobody reads carefully in a dialog.
+
+**Becoming a general About-box framework.** It shows version and licence information. Update
+checks, credits screens, and telemetry consent are all different things.
+
+## Contributing
+
+Issues and pull requests welcome — see the
+[Contributing Guide](https://github.com/willtheorangeguy/.github/blob/main/CONTRIBUTING.md) or
+the [Discord](https://discord.gg/x3G8adwVUe).
+
+Adding `imgs/dfdlogo.gif` is the smallest change that turns this back into a working program.
diff --git a/docs/testing.md b/docs/testing.md
new file mode 100644
index 0000000..bdd0946
--- /dev/null
+++ b/docs/testing.md
@@ -0,0 +1,56 @@
+# ProgramVer — Testing
+
+```bash
+pip install -r requirements.txt
+pytest
+```
+
+14 tests, passing, in about a tenth of a second.
+
+## What is covered
+
+`tests/test_main.py` exercises all four functions:
+
+| Test group | Asserts |
+|---|---|
+| `get_resource_path` | The returned path ends with the requested filename |
+| `openLicense` | A window is created and a file is opened |
+| `openEULA` | The same, for the EULA |
+| `ProgramVer` | The widgets are constructed and packed |
+
+`unittest.mock` supplies `mock_open` for file reads and patches `main.Tk`, `main.Text`,
+`main.Label`, `main.Button`, and `main.PhotoImage`.
+
+## What is not covered, and it matters here
+
+Mocking every file read and every widget is what lets the suite run headless in CI. It also means
+the suite passes on a program that cannot start.
+
+Concretely: `test_get_resource_path` asserts the returned string **ends with** `dfdlogo.gif`. It
+never checks that the file exists — and it does not. `test_openLicense_creates_window` patches
+`builtins.open` with `mock_open`, so `LICENSE.txt` being absent is invisible.
+
+So "100% coverage of the main module", as earlier documentation put it, is true and says nothing
+about whether the program works. Every line executes; every line executes against a mock.
+
+## Worth adding
+
+A test that the files the code opens are actually in the repository:
+
+```python
+def test_required_resources_exist(self):
+ for name in ("imgs/dfdlogo.gif", "imgs/pythonpoweredlengthgif.gif",
+ "LICENSE.txt", "EULA.txt"):
+ self.assertTrue(os.path.exists(get_resource_path(name)), name)
+```
+
+Four lines, no mocking, and it would have caught all three of this repository's High-severity
+issues. Recorded in [`internal/known-issues.md`](./internal/known-issues.md).
+
+The general point is worth keeping in mind when extending the suite: mock the **display**, not
+the **filesystem**. The display cannot be exercised in CI; the filesystem can.
+
+## CI
+
+`.github/workflows/tests.yml` runs the suite on push and pull request. `pylint.yml` lints,
+`codeql-analysis.yml` scans, `push-to-pypi.yml` publishes on release.
diff --git a/docs/troubleshooting.md b/docs/troubleshooting.md
new file mode 100644
index 0000000..b15176e
--- /dev/null
+++ b/docs/troubleshooting.md
@@ -0,0 +1,67 @@
+# ProgramVer — Troubleshooting
+
+## `TclError: couldn't open ".../imgs/dfdlogo.gif"`
+
+The file is not in the repository, and the code needs it before the window can appear. Supply
+your own logo at `imgs/dfdlogo.gif` — GIF or PNG.
+
+Recorded in [`internal/known-issues.md`](./internal/known-issues.md). `MANIFEST.in` lists it, so
+it is expected to exist.
+
+## `FileNotFoundError: LICENSE.txt` / `EULA.txt`
+
+The **Open License** and **Open EULA** buttons read those exact filenames. Neither is in the
+repository. Add them as plain text, or edit `openLicense` and `openEULA` to point at files you
+have — the repository's own licence is `LICENSE.md`.
+
+## `TclError: couldn't recognize data in image file`
+
+The image is not a GIF or PNG. Tkinter reads nothing else without Pillow.
+
+## A label is blank where an image should be
+
+Tkinter keeps no Python reference to a `PhotoImage`. In the current code they survive because
+`ProgramVer()` blocks in `mainloop()` and they stay in scope. If you refactor it to return the
+window, bind each image to a widget attribute (`label.image = img`) or they will vanish silently.
+
+## `ModuleNotFoundError: No module named 'tkinter'`
+
+A separate package on most Linux distributions:
+
+```bash
+sudo apt install python3-tk # Debian, Ubuntu
+sudo dnf install python3-tkinter # Fedora
+```
+
+## Closing the License window closed everything
+
+`openLicense` and `openEULA` each construct a second `Tk()` root rather than a `Toplevel()`.
+Multiple roots share one interpreter, so destroying the wrong one can take the others down. See
+[Architecture](./architecture.md).
+
+## The version or copyright is wrong
+
+They are placeholder literals in `main.py` — the shipped text names a different company and a
+2024 date. [Configuration](./configuration.md) names each by symbol.
+
+## `pip install programver` then `programver` fails
+
+The console script itself is wired correctly (`main:ProgramVer`, which does call `mainloop()`),
+but it fails on the missing image like any other route. The packaging also declares `imgs/` as
+the package root, which is wrong but harmless — only `py_modules=["main"]` ships code. See
+[`internal/known-issues.md`](./internal/known-issues.md).
+
+## Old docs referenced line numbers that do not match
+
+`docs/CUSTOMIZATION.md` located each editable string by line number, and the file has changed
+since. [Configuration](./configuration.md) names symbols instead.
+
+## Tests pass but the program does not run
+
+Expected, and the point of the [Testing](./testing.md) page: the suite mocks the filesystem as
+well as the display.
+
+## Still stuck
+
+[Open an issue](https://github.com/willtheorangeguy/ProgramVer/issues/new/choose) or ask on the
+[Discord](https://discord.gg/x3G8adwVUe), with your OS, Python version, and the traceback.