update dev & modernize tox
diff --git a/.github/CONTRIBUTING.md b/.github/CONTRIBUTING.md
index bc9f57d..afcb063 100644
--- a/.github/CONTRIBUTING.md
+++ b/.github/CONTRIBUTING.md
@@ -66,7 +66,7 @@
 
 Finally, **clone** your fork using one of the alternatives that you can copy-paste by pressing the big green button labeled `<> Code`.
 
-You can (and should) run our test suite using [*tox*](https://tox.wiki/) with the [*tox-uv*](https://github.com/tox-dev/tox-uv) plugin.
+You can (and should) run our test suite using [*tox*](https://tox.wiki/).
 The easiest way is to [install *uv*] which is needed in any case and then run `uv tool install --with tox-uv tox` to have it globally available or `uvx --with tox-uv tox` to use a temporary environment.
 
 ---
diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml
index f1bcc12..c1187d8 100644
--- a/.github/workflows/ci.yml
+++ b/.github/workflows/ci.yml
@@ -75,7 +75,7 @@
           fi
 
           echo DO_MYPY=$DO_MYPY >>$GITHUB_ENV
-          echo TOX_PYTHON=py$(echo $V | tr -d .) >>$GITHUB_ENV
+          echo TOX_PYTHON=$V >>$GITHUB_ENV
 
       - run: >
           uvx --with=tox-uv
diff --git a/pyproject.toml b/pyproject.toml
index b886fbf..4266c69 100644
--- a/pyproject.toml
+++ b/pyproject.toml
@@ -178,7 +178,7 @@
 source_pkgs = ["attr", "attrs"]
 
 [tool.coverage.paths]
-source = ["src", ".tox/py*/**/site-packages"]
+source = ["src", ".tox/*-tests/**/site-packages"]
 
 [tool.coverage.report]
 show_missing = true
diff --git a/tox.ini b/tox.ini
index 47548b4..4fe78fa 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,11 +1,12 @@
 # SPDX-License-Identifier: MIT
-
 [tox]
-min_version = 4.25.0
+requires =
+    tox>=4.47.1
+    tox-uv
 env_list =
     pre-commit,
-    py3{9-14}-tests,
-    py3{10-14}-mypy,
+    3.{9-14}-tests,
+    3.{10-14}-mypy,
     pypy3-tests,
     # Mypy needs to run within the respective Python version
     typing-{pyright,ty,pyrefly}
@@ -36,7 +37,7 @@
 commands = pytest tests/test_functional.py
 
 # Keep versions in-sync with coverage-combine.
-[testenv:py3{9,10,14}-tests]
+[testenv:3.{9,10,14}-tests]
 dependency_groups = cov
 # Python 3.6+ has a number of compile-time warnings on invalid string escapes.
 # PYTHONWARNINGS=d makes them visible during the tox run.
@@ -49,16 +50,15 @@
 # Split combine/report in 2 to avoid excessive "Combined data file ..." output.
 [testenv:coverage-combine]
 # Keep base_python in-sync with .python-version-default
-base_python = py314
-# Keep depends in-sync with testenv above that has the cov dependency group.
-depends = py3{9,10,14}-tests
+base_python = 3.14
+depends = *-tests
 skip_install = true
 dependency_groups = cov
 commands = coverage combine
 
 [testenv:coverage-report]
 # Keep base_python in-sync with .python-version-default
-base_python = py314
+base_python = 3.14
 depends = coverage-combine
 parallel_show_output = true
 skip_install = true
@@ -80,7 +80,7 @@
 [testenv:docs-{build,doctests,linkcheck}]
 runner = uv-venv-lock-runner
 # Keep base_python in-sync with .readthedocs.yaml.
-base_python = py313
+base_python = 3.13
 dependency_groups = docs
 commands =
     build: sphinx-build -n -T -W -b html -d {envtmpdir}/doctrees docs {posargs:docs/_build/}html