% \iffalse
%<*internal|cls>
%<cls>% ChkTeX's prose-oriented rules do not understand expl3 or embedded Lua.
%<cls>% chktex-file 1
%<cls>% chktex-file 8
%<cls>% chktex-file 9
%<cls>% chktex-file 13
%<cls>% chktex-file 18
%<cls>% chktex-file 24
%<cls>% chktex-file 26
%<cls>% chktex-file 27
%<cls>% chktex-file 32
%<cls>% chktex-file 36
%<cls>% chktex-file 37
%<cls>% chktex-file 39
\def\dfgVersion{0.1.0}
\def\dfgVersionDate{2026-08-03}
%</internal|cls>
%<*internal>
\iffalse
%</internal>
%<*changelog>
## CHANGELOG
### 2026-08-03 version 0.1.0
harden dynamic collaboration plots and project-area counts, preserve deterministic row and edge order, keep inactive nodes white, and add configurable colors for arbitrary project areas
suppress redundant zero decimal parts in numeric and EUR output while preserving explicitly fractional values
populate the section 2.1.1 direct-cost overview from project-local existing-funds declarations, classify applicant affiliations from the CRC metadata, present aggregated monetary table values as full integer euros with the note “Figures in EUR”, retain informational existing-instrumentation costs as “Figures in thousands”, and preserve decimals for those costs and explicit animal-housing rates
restore siunitx model alignment in guarded tagged numeric columns and use compact slash-separated project references inside table cells while retaining natural-language joins in prose
prepare the first CTAN release with a portable installer, synchronized release metadata, explicit LPPL 1.3c licensing, reproducible archive and clean-install checks, and CI release artifacts

### 2026-08-02 version 0.0.53
generate collaboration heatmap and arc-diagram rows dynamically from project areas, support optional project-area metadata with ID-prefix fallback, cycle colors for additional areas, and document the resulting behavior

### 2026-08-02 version 0.0.52
release the complete project-template, funding-calculation, TOC, and converter updates, including half-year staff-cost calculation, compact project TOC numbers, complete active-project examples, and focused regression coverage

### 2026-08-02 version 0.0.51
generate a self-contained project-collaboration regression file from the DTX, extend the dummy proposal metadata with explicit collaboration, list, ending, and reference-only cases, show both collaboration plot calls in the dummy project chapter, and document the collaboration metadata relationship and dispatcher syntax
keep project numbers compact in the table of contents so section titles retain their normal indentation
apply half-year factors to automatically calculated staff costs in years 1 and 5, test the resulting four-year salary total across five funding columns, and show both automatic and explicit staff-cost entries in every active generated project example and converted project template

### 2026-08-02 version 0.0.50
add compact project-collaboration heatmaps and equal-peak arc diagrams with labeled nodes, tight project-area rules, ending/reference-only filtering, and hvFloat captions, a common plot dispatcher for collaboration and Gantt graphics, mirrored marginal leaders, and safe expansion of funding-source metadata

### 2026-08-02 version 0.0.49
keep table marginalia fixed to their row anchors, place them safely in the outer margin, and format their sums consistently

### 2026-08-01 version 0.0.48
add running marginal totals to the central funding overview tables and keep marginal annotations inside the page

### 2026-08-01 version 0.0.47
omit redundant zero decimal parts from monetary values in the requested-funding project table

### 2026-08-01 version 0.0.46
forward the xparse no-value sentinel correctly so |\getProjectPI| works in focused project builds

### 2026-08-01 version 0.0.45
make |\getProject| share the first-reference PI expansion and per-section state of |\getProjectPI| when |projectPIOncePerSection=true|

### 2026-08-01 version 0.0.44
move the two alternating provenance-label levels closer together

### 2026-08-01 version 0.0.43
omit an empty staff academic degree cleanly instead of displaying and warning about a missing value

### 2026-08-01 version 0.0.42
keep alternating provenance labels strictly zero-width, zero-height, and zero-depth so they never alter prose line spacing or table-row height

### 2026-08-01 version 0.0.41
distinguish multiple unnamed staff vacancies by their role metadata when checking requested-funding rosters for duplicates

### 2026-08-01 version 0.0.40
alternate successive provenance tags across two vertical levels and reserve table-cell headroom so rules do not obscure the labels
make the CI build portable to minimal runners that do not provide an external |time| command

### 2026-08-01 version 0.0.39
show project PIs only on the first |\getProjectPI| reference to each project per section by default, with a configurable opt-out

### 2026-08-01 version 0.0.38
join comma-separated project references from |\getProject| as a natural-language list

### 2026-08-01 version 0.0.37
add compile-based GitLab CI validation and a latest-only Pages deployment of the local dummy proposal
extract generated files with plain LuaTeX so clean CI clones need neither a pre-generated installer nor a full documentation build

### 2026-08-01 version 0.0.36
mark reference-only projects with an asterisk and a local legend in generated tables and lists while retaining the explicit prose wording

### 2026-08-01 version 0.0.35
restore provenance tags for direct database values and calculated results, with independently suppressible table-cell tags

### 2026-08-01 version 0.0.34
show the standard skipped-item notice for generated tables and lists in focused project builds
apply the same fast-mode notice to direct |\OverviewExistingStaffTable| calls
support comma-separated applicant affiliations in title-page metadata, funding totals, section labels, and existing-staff headings
reuse a referenced person's category and organisation in staff rows when no row-level override is supplied
use |positionText| consistently for the staff roster while retaining |position| as a compatibility alias
add institution abbreviations and use them as compact labels in generated tables while retaining full names in legends
render work-package names only at the top level and start sub-workpackage prose without an extra space

### 2026-07-30 version 0.0.33
add orthogonal |consider-for-lists| and |reference-only| project controls
exclude non-considered projects from generated project aggregates and active-project counts
add cached |\getProjectCount| totals for all active projects and the A, B, and Q areas
mark reference-only projects as former projects without creating broken project-section links
add a consolidated information-retrieval command reference to the documentation and proposal README

### 2026-07-30 version 0.0.32
rename the focused-project switches to |fastcompile-project-show-images| and |fastcompile-project-show-publications|
apply the selected graphics draft state explicitly after |graphicx| loads so image toggling is reliable
enable real project images in the active focused-project proposal configuration

### 2026-07-30 version 0.0.31
keep sub-workpackage names bold and join their following prose into the same paragraph
add an opt-in |fastcompile-project-images| switch for rendering project figures during focused drafting
identify fast project drafts with a running project header and a hook-based page watermark

### 2026-07-30 version 0.0.30
add a dedicated |fastcompile-project| text-drafting mode that skips metadata databases, calculated project headers, and auxiliary funding restoration
add an independent |project-publications| switch for project publication headings, nocite lists, bibliographies, reports, and result lists
use draft graphics, hyperlinks, and microtypography in project-fast mode while retaining authored project prose, sections, labels, aims, and work packages
provide database-free fallbacks for project/person references and silence per-item skip output in project-fast builds
make final-mode precedence effective before metadata and package setup, and add public fast-project/publication conditionals
avoid registering bibliography sources or reading stale bbl data when project-fast publication output is disabled
add no-Data-Hub fast project make targets for publication-free and publication-enabled drafting

### 2026-07-20 version 0.0.29
add an empty-page-style project-overview backmatter page to the generated proposal template
improve DOCX conversion of project placeholders and general work-package and subwork-package structures
seed converted project files with requested-staff examples and float barriers around publication and diversity sections
keep Gantt charts directly after the work packages with strict |h| placement and a following float barrier
move salary and animal-housing rates into validated |changeSettings| keys and remove the separate generated |dfg-salaries.tex| file
add configurable CRC and affiliation logo paths and retain the former salary and housing commands as expandable compatibility accessors
map W2/W3 professorial funding to the shared configurable rate
clarify requested-staff applicability rules, validate DFG categories, and use visible no-value backgrounds without alternating row colors
separate research and non-research staff groups with a conditional horizontal rule while retaining one row-spanning label per group
print resolved existing-staff surnames in bold and format job-description lead-ins as number, academic degree, first name, and last name
replace an empty requested-instrumentation overview table with a funding-period-specific explanatory sentence
make proposal CI builds reproducible with pinned images, a single Data Hub refresh job, parallel smoke checks, and clean authoritative builds
keep live DOI lookups opt-in and preserve generated Data Hub file timestamps when their contents are unchanged
support unnamed staff vacancies with |lastname={TBA}| without requiring a synthetic first name or academic degree
make generated-class Flymake diagnostics useful by suppressing ChkTeX's expl3/Lua false positives and fixing the remaining typography warnings
remove the unused |l3keys2e| dependency and replace |pdftexcmds| timing with the kernel-native expl3 timer

### 2026-07-18 version 0.0.28
add the DFG project-level RequestedFundingStaff roster with four official staff groups, continuous numbering, institution/affiliation legends, and job descriptions
extend the existing staff key family with validated roster metadata and resilient missing-reference diagnostics
calculate omitted yearly staff sums from DFG salary constants, percentage, and quantity while retaining explicit sums as overrides
document the roster schema, table call, automatic staff-cost formula, and a complete four-group example
polish the staff roster typography and spacing and resolve institutions with their parent-affiliation legend
render roster categories as personnel categories such as Prof, PhD, and Research rather than salary-table descriptions
extract a focused regression test for the staff roster and automatic salary totals as local/test.tex
reuse existing RequestedFundingStaff rows for the chapter-2 overview of existing staff, grouped by DFG category and affiliation
fix the CV smoke-build target to use the generated crc-cv.tex filename

### 2026-07-17 version 0.0.27
replace repeated requested-funding database sums with incremental LaTeX3 property-list indexes
reduce each project funding table from five filtered database traversals to one
preserve the optional conversion-missing bibliography when generating release classes
document the funding-cache architecture, correctness guarantees, and complete-proposal benchmark

### 2026-07-16 version 0.0.26
add project-local report references and result lists for quality-assured publications, other results, and patents

### 2026-07-14 version 0.0.25
configure biblatex styles and additional options separately for CV and proposal documents
load bibliography customization before biblatex so style settings take effect

### 2026-07-14 version 0.0.24
emphasize bibliography aliases for every PI assigned to a project

### 2026-07-03 version 0.0.23
collect all institutions from comma-separated PI institution references in the participating institutions list

### 2026-06-24 version 0.0.22 
rename documentclass for compatibility reason to dfg-crc.cls

### 2026-06-23 version 0.0.21
reuse the standard institution-list formatter in the project leaders table

### 2026-06-22 version 0.0.20
add more vertical spacing between multiple institutions in standard institution lists
avoid a leading institution-list line break when the institution name is empty
expand user documentation for institution metadata, compilation, generated files, and release steps
enable open-access markers in biblatex output and document manual BibTeX fallback annotations
enable LuaTeX socket support in makefile builds for DOI API lookup
load open-access bibliography markers only for final documents

### 2026-06-15 version 0.0.19
align optional CV table layout with mandatory CV entries
add and document CRC/TRR reference commands

### 2026-06-11 version 0.0.18
extend documentation for PI and project helper commands
make documentation examples more coherent and concrete
fix typos and stale yes/no key documentation

### 2026-06-10 version 0.0.17
small functional fix for cv, adding missing spaces
change font of section headers in cv

### 2026-06-08 version 0.0.16 
put the test for existing cv-database at proper position, so there is no error when calling dfgCV directly.

### 2026-05-29 version 0.0.15dev
cv: test for empty start and end

### 2026-05-29 version 0.0.14
rename all 'true/false' to 'yes/no' since xlsx cannot handle it. 

### 2026-05-25 version 0.0.13
fix dfgTOCprojectPart now properly working with bookmarks.

### 2026-05-23 version 0.0.12 
calculate overview of requested instrumentation and staff from the various projects. no dedicated database is needed. 

### 2026-05-23 version 0.0.11
change symbol of last shared authorship, so it is easier to differentiate. Fallback if there is no cv for a PI of current funding period. Add a version information on the titlepage.

### 2026-05-13 version 0.0.10
adjusting addEntry when cv-bool active.

### 2026-05-12 version 0.0.9
renaming -name- to -positionText- for being streamlined.

### 2026-05-10 version 0.0.7
improving bibliography stuff for cv section 

### 2026-05-07 version 0.0.6 
various optimizations regarding runtime creating tables 

### 2026-05-04 version 0.0.5
a lot of refactoring to speed up compiling tables, putting PI information into tcolorboxes for better handling (raster)

### 2026-05-01 version 0.0.4
working on more efficient code like reducing database queries.

### 2026-03-11 version 0.0.3
documentation extended

### 2026-03-11 version 0.0.3
documentation extended

### 2026-02-14 version 0.0.2
intensive documentation <br>
more funding tables added

### 2026-01-05 version 0.0.1
initial setup <br>

%</changelog>
%<*driver>
\preparesFile{\jobname.dtx}
%</driver>
%<@@=dfg>
%<*readme>
# dfg-crc — Collaborative Research Centre proposal class

Current release: **0.1.0 (2026-08-03)**.

The `dfg-crc` LuaLaTeX class provides the proposal and CV structure for a
German Research Foundation (DFG) Collaborative Research Centre (CRC). It uses
structured metadata to generate project heads, staff and funding tables,
project lists, collaboration plots, Gantt charts, and proposal-wide totals.

This is an independent, unofficial template. It is not published, endorsed,
or maintained by the DFG; applicants remain responsible for checking the
current DFG forms and programme rules.

The supplied proposal template is designed for five calendar years and
supports one or more applicant universities. The project types `research`,
`service`, `mgk`, and `admin` are supported; see the documentation for the
corresponding metadata and generated sections.

It is appreciated when in the colophon of your proposal a reference to this
template and its author is given.

## Requirements

The class requires LuaLaTeX and a LaTeX kernel dated 2022-06-01 or newer.
Biber is required for bibliographies. The default setup uses Noto Serif,
Roboto, and the example images supplied by the `mwe` bundle. A full
[TeX Live](https://tug.org/texlive/) installation is recommended and contains
the class's runtime dependencies.

Repository: <https://gitlab.git.nrw/rpdm/projects-and-services/dfg-crc-template>

Issue tracker:
<https://gitlab.git.nrw/rpdm/projects-and-services/dfg-crc-template/-/issues>

## Installation

TeX Live and MiKTeX installations obtained after the first CTAN release can
install `dfg-crc` through their normal package managers. To install from the
CTAN source archive manually, run:

```
luatex crc-proposal-documentation-and-code.ins
```

This generates `dfg-crc.cls`. Move it into a directory searched by TeX, or
keep it beside the proposal's main `.tex` file. The complete generated example
proposal is maintained in the repository and can be extracted with
`make files`.

## Start the program from the repository

For a first local compile, generate the derived files and then compile the
proposal and CV examples from the `local/` folder.

```
make files
cd local
latexmk -lualatex crc-proposal.tex
latexmk -lualatex crc-cv.tex
```

The class is designed for LuaLaTeX. Use `lualatex` or `latexmk -lualatex`;
do not call `LaTeX` with a capital `L`.

Useful make targets:

> `make files`: extracts `dfg-crc.cls` and the local template files from
the documented source. <br>
> `make update-class TARGET_DIR=/path/to/proposal-worktree`: regenerates and
copies only `dfg-crc.cls` into a separate Git worktree. <br>
> `make test`: compiles the generated template test document. <br>
> `make test-direct-costs`: compiles the focused two-pass regression for DFG
> table 2.1.1. <br>
> `make proposal-example`: compiles the generated local proposal example. <br>
> `make cv-example`: compiles the generated local CV example. <br>
> `make check`: runs the test and compiles both examples. <br>
> `make doc`: builds the implementation and user documentation. <br>
> `make ctan-check`: builds the curated CTAN archive and verifies a clean
installer extraction and minimal LuaLaTeX compile. <br>
> `make ctan-validate`: runs the official online CTAN validator without
submitting the archive.

For a focused project-text build, select the project with `\includeonly` and
use these class options:

```tex
\documentclass[
  fastcompile-project=true,
  fastcompile-project-show-images=false,
  fastcompile-project-show-publications=false,
  english
]{dfg-crc}
```

`fastcompile-project` skips metadata loading, `\addEntry` execution,
calculated project heads, generated tables/lists, Gantt charts, embedded
graphics, and other front-matter work while retaining authored sections,
paragraphs, aims, work packages, labels, and citation commands. Skipped
generated tables and lists retain the same visible placeholder and
log note as ordinary `fastcompile` builds. Set
`fastcompile-project-show-images=true` to render images encountered in the selected
project while retaining the other fast-mode reductions. Set
`fastcompile-project-show-publications=true` when the selected project's publication headings,
explicit `\nocite` entries, and bibliography should be included. Wrap optional
metadata and front matter with `\dfgIfFastCompileProjectF{...}` so those files
are not even read in this mode. With publications disabled, bibliography source
files and stale `.bbl` data are also left unread; inline citations display their
keys as lightweight drafting markers. Compile a document using these options
with its own build command; the template Makefile deliberately operates only on
the generated test and example documents in `local/`.

## Template validation workflow

Run `make check` to regenerate the template files, compile the test document,
and compile both local examples. Run `make all` to perform those checks and
build the complete implementation and user documentation. These targets use
only files maintained or generated by this repository.

GitLab CI runs the same compile-based checks for branches and merge requests.
After a successful default-branch pipeline, GitLab Pages publishes the newest
generated `local/crc-proposal.pdf`. The Pages site is rebuilt from an empty
`public/` directory each time and therefore exposes only the latest dummy
proposal, not an archive of earlier PDFs. CI job artifacts retain the current
logs and example outputs temporarily for diagnosing failed pipelines.

## Updating a separate proposal repository

Edit the maintained `.dtx` source, then install the regenerated class into a
separately controlled proposal worktree:

```
make update-class TARGET_DIR=/path/to/proposal-worktree
```

The target verifies that `TARGET_DIR` is the root of a different Git worktree,
copies only `dfg-crc.cls`, and shows its resulting Git status. It does not store
the destination, inspect its remote, commit, or push. Review and commit the
class update from inside that proposal repository.

## Repository boundary

This repository is intentionally limited to the reusable proposal template.
Project-specific source, synchronization configuration, credentials, remote
identifiers, and private working copies must remain in separately controlled
repositories or local worktrees and must not be added here as submodules.

## Structure of the files and folders

The maintained source is `crc-proposal-documentation-and-code.dtx`.
Generated files such as `local/dfg-crc.cls`, `local/test.tex`,
`local/test-existing-funds-direct-costs.tex`,
`local/test-project-collaboration.tex`, `README.md`, `CHANGELOG.md`, and the
local example files are extracted from that source.
Edit the `.dtx` for template or documentation changes, then regenerate the
derived files with `make files` or by building the documentation.

## Generated project templates

The generated `local/content/03_project.tex` is a small master file that loads
separate, complete project examples. They are intended to be copied and adapted
rather than reduced to a list of headings:

`03_project_A01.tex`: continuing research project (`project-status=C`).

`03_project_A02.tex`: new research project (`project-status=N`).

`03_project_B01.tex`: second continuing research-project example.

`03_project_B02.tex`: ending project (`project-status=E`), including the report
bibliography, the three published-result categories, and the staff roster for
the ending funding period.

`03_project_Q01.tex`: continuing service project.

`03_project_Q02.tex`: continuing Integrated Research Training Group
(`project-type=mgk`), including existing funds, fellowships, and global funds.

`03_project_Q03.tex`: central administrative project with its dedicated
documentation and funding structure.

Every example starts with `\printProjectHead{<id>}`. That command already
generates the general-information heading, project title, project leaders, and
the applicable contract and legal-information blocks from metadata. The source
files therefore begin with the first status-specific authored heading: `Summary`
for active projects and `Project history` for ending projects.

The generated proposal-wide example follows the February 2026 continuation
template, including the ecological-sustainability section, separate
coordinating and co-applicant universities, the current legal-issues wording,
and one rector, chancellor, or president signature per applicant university.

> `bib/`: all bibliography files.  <br>
> `content/`: all files which are part of the actual content of the proposal,
e.g. all project textfiles.  <br>
>  `figures`: folder contains all figures of the projects.  <br>
>  `img`: folder can be used for logo files etc.  <br>
>  `metadata`: if you collect all database entries in specific external  
  files, they are placed in this folder (e.g. `dfg-metadata.tex`).  <br>
> `preamble`: all files for the proposal and CV setup, especially
  `dfg-customization.tex` for customized things or re-newed settings.<br>

## Minimal metadata relationship

Most commands resolve data by following ids through the small databases:

```
person.ref-institution-id -> institution.id
institution.ref-affiliation-id -> affiliation.id
project.collaborations -> project.id
```

For example, a person may list one or more institution ids in
`ref-institution-id`. Each institution points to its parent affiliation via
`ref-affiliation-id`. Once this relationship exists, commands such as
`\dfgInstitutionList{<person-id>}` can print the institution and affiliation
data without further manual wiring.  Each institution can also provide an
`abbreviation`; generated table cells use this compact label while descriptive
lists and legends retain the full `name`.

The same relationship is reused by `RequestedFundingStaff`: when a staff row
contains `ref-person-id`, its category and institution are taken from the
person's `position` and `ref-institution-id` fields unless the staff row
explicitly overrides them.

Project collaboration plots follow the comma-separated project ids stored in
each project's `collaborations` field. Relations are undirected, so declaring
the same pair in both project rows is harmless but unnecessary. Ending,
reference-only, and list-excluded project rows remain available elsewhere but
are omitted from these plots.

## Information retrieval command overview

The following commands can be used directly in proposal text and tables. In
the signatures below, square brackets are optional and braces are mandatory.
The complete descriptions and examples are in
`crc-proposal-documentation-and-code.pdf`.

### General database access

Command `\getEntry` with `[database]` `{id}` `{field}` `[id-field]` prints one field from one
  database row.

Starred command `\getEntry*` with `[database]` `{id}`
`{assignments}` `[id-field]` fetches several fields in one lookup and assigns
them without printing. For example, fetch person `MM` with
`\getEntry*[person]{MM}` and pass the third argument
`{\theFirstName=firstname,\theLastName=lastname}`.

Command `\compareEntry` with `[database]` `{id}` `{field}` `{value}` `{true}`
  `{false}` chooses text or
  code according to a field comparison.

### People, institutions, and projects

Commands `\getName` and `\getFullName*` with `{person-id}` print the last name or full name;
  the star adds the academic degree.

Command `\getPI*` with `{person-id-list}` `[text]` prints a linked PI reference; the star includes
  first names.

Command `\getORCiD` with `[database]` `{person-id}` prints a linked, formatted ORCiD from a person row.

Command `\getORCiDvalue` with `[database]` `{person-id}` stores the unformatted ORCiD in
  `\theORCiDValue`.

Command `\dfgInstitutionList` with `[database]` `{person-id}` `[options]` prints institutions and
  parent affiliations assigned to a person.

Command `\getPersonInformation` with `[database]` `{person-id-list}` prints complete formatted
  PI/contact-information blocks.

Command `\getPIsWithRole` with `[database]` `{role}` `[options]` prints formatted current-period people
  carrying a given role.

Command `\getPIProject*` with `{person-id-list}` prints each PI with their assigned projects; the
  star includes first names.

Command `\getProjectPI*` with `{project-id-list}` prints each project with its assigned PIs; the
  star includes first names. By default, the shared first `\getProject` or
  `\getProjectPI` reference to a project within one section includes its PIs;
  later references print only the project. Set
  `projectPIOncePerSection=false` in `\changeSettings` to repeat the PI names.

Command `\getPIofProject` with `[properties]` `{project-id}` `[delimiter]` prints selected PI name
  properties for one project.

Command `\getProject` with `{project-id-list}` `[text]` prints a linked project
  reference. Optional `text` replaces the displayed project number while
  retaining its link target and is best used with a single project. A
  reference-only project is marked and deliberately left unlinked. Multiple
  projects are joined with commas and a final `and` in prose, but use compact
  slash separators inside table cells, for example `A02/B01`. With the
  default `projectPIOncePerSection=true`, this command shares
  `\getProjectPI`'s first-reference PI expansion and per-section state.

Command `\getProjectCount` with `[area]` prints the active, list-considered
project count; omit `area` for all projects. Any explicit or ID-derived
`project-area` value is accepted.

Command `\printPlot{{ProjectCollaboration}{A01}}` prints the default
collaboration heatmap for A01. Add `[layout=arc]` after
`{ProjectCollaboration}` for the compact arc layout. The optional
`project-area` field creates rows dynamically and falls back to the first
character of the project ID. Configure proposal-wide colors with
`collaborationAreaColors` and `collaborationAreaPalette` in `\changeSettings`,
or use the per-plot `area-colors` and `area-palette` options. Gantt charts use
the same dispatcher as `\printPlot{{Gantt}{A01}}`.

Command `\dfgResearchAreasList` with `{code}` prints a DFG research-area code and its description.

Commands `\getAim` and `\getWP` with `[project-id]` `{id-list}`
  cross-references to project aims or work packages; the current project is
  the default.

### Person statistics

Command `\getPositionGenderPhaseAmount` with `[database]` `{position}` `{gender}` `{period}` prints the number
  of people for one position/gender/period tuple.

Command `\getPositionPhaseTotal` with `[database]` `{position}` `{period}` prints the all-gender total for a
  position and funding period.

Command `\getGenderPhaseTotal` with `[database]` `{gender}` `{period}` prints the all-position total for a
  gender and funding period.

Command `\getPositionGenderPhasePercentage` with `[database]` `{position}` `{gender}` `{period}` prints the
  rounded integer percentage within one position.

Command `\getGenderPhasePercentage` with `[database]` `{gender}` `{period}` prints the rounded integer
  percentage across all counted positions.

### Funding and staff totals

The similarly named funding commands have different scopes: names ending in
`RequestedFunding` use the proposal-wide overview by default, while names
ending in `RequestedFunds` use project-level funding rows and require a
project id.

Command `\getCountRequestedStaff` with `[project]` `{year}` `{category}` prints the requested staff
  quantity for a category, optionally restricted to a project.

Command `\getSumRequestedFunding` with `[database]` `{year}` `{type}` prints the proposal-wide total for one
  funding type and one year; `{all}` as the year totals all five years.

Command `\getTotalSumRequestedFunding` with `[database]` `{year}` `{type}` prints the proposal-wide total
  with `{all}` as the type available for a grand total.

Command `\getSumPreviousRequestedFunding` with `[database]` `{year}` `{fields}` prints the previous-period
  total for one year row, or all rows with `{all}` as the year.

Command `\getSumRequestedFunds` with `[database]` `{project}` `{type}` `{sum-fields}` prints the project total
  for one funding type and one or several `sum-yearN` fields.

Command `\getTotalSumRequestedFunds` with `[database]` `{project}` `{sum-fields}` prints the project total
  across all funding types for the supplied `sum-yearN` fields.

Command `\getSumRequestedFundsInstrumentation` with `[project]` `{sum-fields}` prints the instrumentation
  total, proposal-wide or for the optional project.

Command `\getSumRequestedFundingDirectCosts` with `[database]` `{year}` `{group}` prints the direct-cost
  total for `applicant`, `participant`, `other-funds`, or `all`. Its default
  database is the auxiliary-file-backed
  `RequestedAndExistingFundingDirectCostsOverview`, and its displayed result
  is a full euro amount without decimal places.

Command `\getSumExistingFunds` with `[database]` `{project}` `{sum-fields}` prints the existing direct-cost
  funding for a project and the supplied year fields.

Typical calls are:

```tex
\getProjectCount[A]                            % active A projects
\getSumRequestedFunding{all}{staff}            % proposal-wide staff total
\getTotalSumRequestedFunding{all}{all}         % proposal-wide grand total
\getSumRequestedFunds{A02}{staff}{sum-year1}   % A02 staff total, year 1
\getTotalSumRequestedFunds{A02}{sum-year1}     % A02 grand total, year 1
```

Funding entries, including requested instrumentation, use EUR as their input
unit. Their tables state `Figures in EUR` and display whole euro amounts with
thousands separators. The non-aggregated `existingInstrumentation/cost` field
instead uses thousands of EUR and its table states `Figures in thousands`;
one decimal place is retained when supplied. Explicitly fractional
animal-housing rates also retain decimals, while the other monetary columns in
that table remain whole euros.

### Existing direct-cost support in section 2.1.1

Declare institutional and other existing direct-cost support once, next to
the corresponding project table:

```tex
\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id     = {B06},
  ref-affiliation-id = {aff1},
  financed-by        = {Faculty core support},
  sum = {
    year1 = {5000},
    year2 = {5000},
    year3 = {5000},
    year4 = {5000},
    year5 = {5000}
  }
}
```

The sums are stored and displayed in euros. Table 2.1.1 therefore prints
`5000` as `5,000`; monetary values are rounded to the nearest euro for display
and never acquire a redundant decimal part. An affiliation listed in
`meta/crc.ref-affiliation-id` contributes to the applicant-university column;
another affiliation contributes to the other-participating-institutions
column; and the special value `other-funds` contributes to Other funds.
`financed-by` is the human-readable funding-source description and does not
select the aggregate column.

The declarations may remain in project files even though section 2.1.1 comes
earlier. They are restored into a separate overview database through the
LaTeX auxiliary files. A normal multipass build such as `latexmk` is therefore
required after adding or changing a row; no duplicate chapter-2 declaration
is needed.

## Open-access markers in bibliography entries

The class loads `biblatex-ext-oa` so bibliography entries can show
open-access markers in final documents. The DOI API integration is only
available with LuaLaTeX. With LuaTeX 1.17.0 or newer, the socket library must
also be enabled on the command line, for example with `lualatex --socket`.
Provide the contact address required by the API in the customization file:

```tex
\changeSettings{
  doiAPIMail = researcher@example.org
}
```

The class enables DOI lookups only when `final=true`, `doiAPIMail` is not
empty, and LuaSocket is available. Otherwise it retains manual open-access
annotations without making network requests.

If the API-based open-access request does not work for a publication, add the
manual fallback annotation to the relevant `.bib` entry:

```
options         = {openaccess=auto},
doi+an:default  = {=openaccess},
```

## Troubleshooting

Use `latexmk -lualatex ...` or `lualatex ...`. The command `LaTeX` asks TeX for
a format named `LaTeX.fmt` and will usually fail.

If you see `Not allowed in LR mode`, check whether vertical material such as
`\vspace`, `\addvspace`, or a paragraph break was inserted inside a table cell
that only accepts horizontal material. Prefer the documented commands and
options instead of adding raw vertical spacing in table cells.

`Unknown database name` means the requested database has not been loaded or the
database name was misspelled. Check the relevant file in `metadata/` and make
sure it is input by the document class.

Missing-key or empty-value warnings mean the row exists, but the requested
field is empty. This is intentional for fields where the template needs to
alert you, such as missing ORCiD values.

If a change has no visible effect, check which `dfg-crc.cls` is being used.
Regenerate the class and local examples with `make files`, then compile the
relevant example again.

%<dev>## Maintainer release checklist
%<dev>
%<dev>1. Update `\dfgVersion`, `\dfgVersionDate`, the README release line,
%<dev>   changelog, and `dfg-crc.pkg` in one commit.
%<dev>2. Build the documentation and the CTAN archive, then run the portable
%<dev>   installer and minimal-class smoke test:
%<dev>
%<dev>   ```
%<dev>   make ctan-check
%<dev>   ```
%<dev>
%<dev>3. Run at least one proposal/CV smoke build from `local/`:
%<dev>
%<dev>   ```
%<dev>   cd local
%<dev>   latexmk -lualatex -g -halt-on-error crc-cv.tex
%<dev>   ```
%<dev>
%<dev>4. Before a public release, run the complete template check:
%<dev>
%<dev>   ```
%<dev>   make check
%<dev>   ```
%<dev>
%<dev>5. Optionally run the official online validator with
%<dev>   `make ctan-validate`.
%<dev>6. Review `git status --short`, `git diff --check`, and the archive file
%<dev>   list before committing and tagging the exact release version.
%<dev>
## Support

The current maintainer is
[Lukas C. Bossert](mailto:bossert@itc.rwth-aachen.de).

## License

This material is subject to the LaTeX Project Public License 1.3c or later.
The work has the LPPL maintenance status *maintained*. See `LICENCE.md` for the
complete notice.
%</readme>
%<*licence>
## LICENCE

Copyright 2026 Lukas C. Bossert
  
This work may be distributed and/or modified under the
conditions of the LaTeX Project Public License, either version 1.3c
of this license or any later version.
The latest version of this license is in
  https://www.latex-project.org/lppl.txt
and version 1.3c or later is part of all distributions of LaTeX
version 2005/12/01 or later.

This work has the LPPL maintenance status “maintained”.

The Current Maintainer of this work is Lukas C. Bossert.

This work consists of the source file
`crc-proposal-documentation-and-code.dtx`, the installer
`crc-proposal-documentation-and-code.ins`, the documentation files
`README.md`, `CHANGELOG.md`, and `LICENCE.md`, and the derived files
`dfg-crc.cls` and `dfg-crc.pdf`.
%</licence>
%<*internalbib>
%%
%% Encoding: UTF-8
%%
@InCollection{Hoare1973,
  author    = {Charles Antony Richard Hoare},
  title     = {Hints on programming language design},
  editor    = {C. Bunyan},
  booktitle = {Computer Systems Reliability},
  series    = {State of the Art Report},
  number    = {20},
  pages     = {193--216},
  year      = {1973},
  url       = {http://flint.cs.yale.edu/cs428/documentation/HintsPL.pdf},
  urlyear   = {2018},
  comment   = {\blockcquote[195]{Hoare1973}{Documentation must be regarded as an integral part of the process of design and coding. A good programming language will encourage and assist the programmer to write clear, self-documenting code, and even perhaps to develop and display a pleasant style of writing.}}
}
%</internalbib>
%<*internal>
\fi
\def\nameofplainTeX{plain}
\ifx\fmtname\nameofplainTeX\else
  \expandafter\begingroup
\fi
\iffalse
%</internal>
%<*install|devinstall>
%% crc-proposal-documentation-and-code.ins
%% Copyright 2026 Lukas C. Bossert
%%
%% This work may be distributed and/or modified under the conditions of the
%% LaTeX Project Public License, either version 1.3c of this license or (at
%% your option) any later version.
%%
%% \CharacterTable
%%  {Upper-case    \A\B\C\D\E\F\G\H\I\J\K\L\M\N\O\P\Q\R\S\T\U\V\W\X\Y\Z
%%   Lower-case    \a\b\c\d\e\f\g\h\i\j\k\l\m\n\o\p\q\r\s\t\u\v\w\x\y\z
%%   Digits        \0\1\2\3\4\5\6\7\8\9
%%   Exclamation   \!     Double quote  \"     Hash (number) \#
%%   Dollar        \$     Percent       \%     Ampersand     \&
%%   Acute accent  \'     Left paren    \(     Right paren   \)
%%   Asterisk      \*     Plus          \+     Comma         \,
%%   Minus         \-     Point         \.     Solidus       \/
%%   Colon         \:     Semicolon     \;     Less than     \<
%%   Equals        \=     Greater than  \>     Question mark \?
%%   Commercial at \@     Left bracket  \[     Backslash     \\
%%   Right bracket \]     Circumflex    \^     Underscore    \_
%%   Grave accent  \|     Left brace    \{     Vertical bar  \|
%%   Right brace   \}     Tilde         \~}

\input docstrip.tex
\keepsilent
\askforoverwritefalse
\catcode9=12
\preamble
------------------------------------------------------------------------
DFG CRC proposal class
Copyright: 2026 Lukas C. Bossert
Author:    Lukas C. Bossert
E-mail:    bossert@itc.rwth-aachen.de
License:   LaTeX Project Public License v1.3c or later
See:       https://www.latex-project.org/lppl.txt
------------------------------------------------------------------------

>>>>> DO NOT CHANGE THIS FILE >>> IT WILL BE OVERWRITTEN BY ANY UPDATE !

\endpreamble
\postamble
Copyright (C) 2026 Lukas C. Bossert
\endpostamble
%</install|devinstall>
%<*install>
\generate{
  \file{dfg-crc.cls}
    {\from{crc-proposal-documentation-and-code.dtx}{file,cls}}
}
%</install>
%<*devinstall>
\generate{
  \file{local/dfg-crc.cls}
    {\from{crc-proposal-documentation-and-code.dtx}{file,cls}}
}
\nopreamble
\nopostamble
\generate{
  \file{local/bib/dfg-base.bib}{\from{crc-proposal-documentation-and-code.dtx}{file,bib,base}}
  \file{local/bib/dfg-strings.bib}{\from{crc-proposal-documentation-and-code.dtx}{file,bib,strings}}
  \file{local/README.md}{\from{crc-proposal-documentation-and-code.dtx}{readme}}
  \file{local/CHANGELOG.md}{\from{crc-proposal-documentation-and-code.dtx}{changelog}}
  \file{local/LICENCE.md}{\from{crc-proposal-documentation-and-code.dtx}{licence}}
  \file{local/preamble/dfg-customization.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,custom}}
  \file{local/metadata/dfg-metadata.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,meta}}
  \file{local/metadata/dfg-metadata-cv.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,meta-cv}}
  \file{local/metadata/dfg-metadata-tables.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,meta-tables}}
  \file{local/test.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,test}}
  \file{local/test-existing-funds-direct-costs.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,test-existing-funds-direct-costs}}
  \file{local/test-project-collaboration.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,test-project-collaboration}}
%
% template adjusted below
%
  \file{local/crc-proposal.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,main}}
  \file{local/crc-cv.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,cv}}
  \file{local/content/00_titlepage.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,00}}
  \file{local/content/01_general-information.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,01}}
  \file{local/content/02_existing-funds-and-requested-funds.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,02}}
  \file{local/content/03_project.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03}}
  \file{local/content/03_project_A01.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-a01}}
  \file{local/content/03_project_A02.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-a02}}
  \file{local/content/03_project_B01.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-b01}}
  \file{local/content/03_project_B02.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-b02}}
  \file{local/content/03_project_Q01.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-q01}}
  \file{local/content/03_project_Q02.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-q02}}
  \file{local/content/03_project_Q03.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-q03}}
  \file{local/content/04_bylaws-of-the-crc.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,04}}
  \file{local/content/05_declarations.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,05}}
  \file{local/content/99_backmatter.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,99}}
}
%</devinstall>
%<install|devinstall>\endbatchfile
%<*internal>
\fi
\input docstrip.tex
\keepsilent
\askforoverwritefalse
\nopreamble
\nopostamble
\catcode9=12
\generate{
  \file{\jobname.bib}{\from{\jobname.dtx}{internalbib}}
  \file{README.md}{\from{\jobname.dtx}{readme,dev}}
  \file{CHANGELOG.md}{\from{\jobname.dtx}{changelog}}
  \file{LICENCE.md}{\from{\jobname.dtx}{licence}}
}
\usedir{source/latex/\jobname}
\generate{
  \file{\jobname.ins}{\from{\jobname.dtx}{install}}
  \file{\jobname-dev.ins}{\from{\jobname.dtx}{devinstall}}
}
\ifx\fmtname\nameofplainTeX
  \expandafter\endbatchfile
\else
  \expandafter\endgroup
\fi
%</internal>
%<*driver>
\providecommand*\InfoTeX{}
\documentclass{ltxdoc}
\usepackage{fontspec}
\defaultfontfeatures{Ligatures=TeX}
\setmainfont{Libertinus Serif}
\setsansfont{Libertinus Sans}
\setmonofont[Scale=0.95]{TeX Gyre Cursor}
\newfontfamily\listingsfont[%
  Ligatures={NoCommon, NoDiscretionary, NoRequired, NoContextual}
 ]{TeX Gyre Cursor}
\AtBeginDocument{
\setlength{\textwidth}{370pt}
\def\theCodelineNo{\color{codegray}\scriptsize\arabic{CodelineNo}\space}
\def\MacroFont{\listingsfont\footnotesize}
\def\AltMacroFont{\listingsfont\footnotesize}
\CodelineNumbered
%\CodelineIndex
%\EnableCrossrefs
\RecordChanges}

\usepackage[RGB]{xcolor}
\definecolor{codeblue}{RGB}{0,84,159}
\definecolor{codegreen}{RGB}{87,171,3}
\definecolor{codegray}{RGB}{156,158,159}
\definecolor{codepurple}{RGB}{161,16,53}
\definecolor{backcolour}{RGB}{142,186,229}

\usepackage{imakeidx}
\usepackage[listings,breakable,skins,most,documentation]{tcolorbox}
\tcbset{
  docexample/.add style={}{
    colframe=Definition, %codeblue,
    colback=white,
    fontupper=\ttfamily\normalsize,
    breakable,
enhanced jigsaw,
    documentation listing options={
      escapeinside={(*}{*)},
    }
  }
}
\PassOptionsToPackage{
  left=2cm,
  right=2cm,
  top=2cm,
  bottom=2cm
}{geometry}
\usepackage{minimalist}


\NewDocumentCommand{\dfgFile}{m}{\texttt{#1.tex}}
\usepackage{markdown}
% \markdownSetup{
%   % stripIndent=false,
%   contentBlocks=true,
%   contentLevel=block
% }
\usepackage[ngerman,english]{babel}

\usepackage[style=ext-authoryear-ecomp]{biblatex}

% NOTE: \hfuzz=100cm suppresses all overfull-hbox warnings in the documentation.
% Set to a smaller value (e.g. 5pt) to re-enable them during development.
\hfuzz=500pt
\addbibresource{\jobname.bib}

\usepackage{bookmark}
\usepackage{hyperxmp}
\usepackage{hyperref}
\hypersetup{colorlinks}

\usepackage{cleveref}

\crefformat{lstlisting}{#2example\ #1#3}
\Crefformat{lstlisting}{#2Example #1#3}
\crefmultiformat{lstlisting}{#2examples #1#3}{; #2#1#3}{; #2#1#3}{; #2#1#3}
\Crefmultiformat{lstlisting}{#2Examples #1#3}{; #2#1#3}{; #2#1#3}{; #2#1#3}
\Crefrangeformat{lstlisting}{#3Examples #1#4--#5#2#6}
\crefrangeformat{lstlisting}{#3examples #1#4--#5#2#6}


\author{Lukas C. Bossert\thanks{\texttt{\href{mailto:bossert@itc.rwth-aachen.de}{bossert@itc.rwth-aachen.de}}}}
\title{The \texttt{Collaborative Research Centre - Template}}
\date{\dfgVersion}
\begin{document}
\maketitle
\begin{abstract}
  This is the documentation for all the files
  which are needed to prepare a proposal and CV section for
  a proposal of the Funding Line by the DFG.

  Why is there a dedicated documentation?
  \blockcquote[195]{Hoare1973}{Documentation must be regarded as an integral part of the process of design and coding.
  	A good programming language will encourage and assist the programmer to write clear,
  	self-documenting code, and even perhaps to develop and display a pleasant style of writing.}
  \vfill\par
  This bundle has been last worked on and modified using \textbf{\InfoTeX}.\par
  \vfill
\end{abstract}
\tableofcontents
\markdownInput{README.md}
\markdownInput{CHANGELOG.md}
\markdownInput{LICENCE.md}

\clearpage
\section{User documentation}
In this section we provide all the relevant information for the writer to use
the template properly and understand its various customizations and
implementations of features.

There are certain mechanisms that will throw warnings or infos. You can and
should read them in the terminal or |.log|-file.
If your editor is not providing an aggregated collection you can see a condensed
overview using the commandline code:

\begin{dispListing*}{title={Command to retrieve all important log-messages}}
cat <filename>.log | grep 'Package dfg'
\end{dispListing*}

\subsection{Compiling and generated files}

The maintained source of this bundle is
\texttt{crc-proposal-documentation-and-code.dtx}.  Files such as
\texttt{local/dfg-crc.cls}, \texttt{README.md}, \texttt{CHANGELOG.md}, and
the example files in \texttt{local/} are generated from that source.  For
template or documentation changes, edit the |.dtx| file and regenerate the
derived files.

For a first local compile, use LuaLaTeX through \texttt{latexmk}:
\begin{dispListing*}{title={First local compile}}
make files
cd local
latexmk -lualatex crc-proposal.tex
latexmk -lualatex crc-cv.tex
\end{dispListing*}

The class expects LuaLaTeX.  Calling \texttt{LaTeX} with a capital \texttt{L}
asks TeX for a format file named \texttt{LaTeX.fmt}; use \texttt{lualatex} or
\texttt{latexmk -lualatex} instead.

If a change has no visible effect, check which generated class file is being
loaded.  Regenerate the class and local examples with \texttt{make files}, then
compile the relevant example again.

\subsection{Troubleshooting}

\begin{description}
  \item[\texttt{Unknown database name}] The database has not been loaded, or
    the database name was misspelled.  Check the relevant metadata file and
    whether it is input by the class.
  \item[Missing or empty key warnings] The row exists, but the requested field
    is empty.  This is intentional where the template needs to alert the user,
    for example for missing ORCiD values.
  \item[\texttt{Not allowed in LR mode}] Vertical material such as
    \cs{vspace}, \cs{addvspace}, or a paragraph break was inserted in a table
    place that only accepts horizontal material.  Prefer the documented table
    and list commands, or use options such as \texttt{narrow} for compact table
    output.
  \item[Stale output] Regenerate the class with \texttt{make files}, and check
    whether the document uses the generated class from \texttt{local/}.
\end{description}

\subsection{Release workflow for maintainers}

For a new release, update \cs{dfgVersion} and \cs{dfgVersionDate} at the top of
\texttt{crc-proposal-documentation-and-code.dtx}, the release line in the
README block, the changelog, and \texttt{dfg-crc.pkg}.  Keep these values in
one release commit.

\begin{dispListing*}{title={Release and CTAN checks}}
make ctan-check
make check
% Optional online validation without submission:
make ctan-validate
\end{dispListing*}

The first command builds the manual and the curated
\texttt{output/ctan/dfg-crc.zip}, verifies its exact allow-list, extracts it in
a clean temporary directory, runs the portable installer, and compiles a
minimal document against the resulting class.  The online target validates but
does not submit the archive.  Before committing, inspect
\texttt{git status --short}, run \texttt{git diff --check}, and review the ZIP
file list.

\subsection{Metadata, databases and keysets}
\label{doc:metadata}
The core of this template is to work as often and as many times as possible with
metadata. All the metadata is written to one or many databases that can be
sorted, filtered etc. and passed to the respective tables.

We are collecting information from the database using \refPkg{datatool}.


In the template there are some required information that belong to tables or are
generally needed. Therefor we provide some predefined databases names and their
respective keysets.

\paragraph{Databases}

We have these databases that are used and picked up by several commands by
default:
\begin{description}
  \item[meta] All the metainformation about the proposal
  \item[person] Everything that is related to a person
  \item[project] Anything that is related to a project
  \item[institution] Info about an institution, that is linked to:
  \item[affiliation] storing info about the affiliation
\end{description}
There are also more databases created on the fly but mainly used for project
specific purposes.
The examples below use one coherent sample dataset: \texttt{MM} and
\texttt{KM} are persons, \texttt{A01} is a project, \texttt{IAIS} is an
institution, and \texttt{RWTH} is the related affiliation.
\subsubsection{Keyset \textbf{person}}
\begin{dispListing*}{title={Example keyset to describe a person-entity.}}
(*\refCom{addEntry}*){person}{
  (*\refKey{id}*)                 = {MM},
  (*\refKey{firstname}*)          = {Max S.},
  (*\refKey{lastname}*)           = {Mustermann},
  (*\refKey{academicdegree}*)     = {Prof. Dr. rer. nat.},
  (*\refKey{gender}*)             = {m},
  (*\refKey{ref-institution-id}*) = {IAIS},
  (*\refKey{ref-project-id}*)     = {A01},
  (*\refKey{role}*)               = {PI,spokesperson},
  (*\refKey{position}*)           = {prof-W3},
  (*\refKey{positionText}*)       = {Professor of Microbial Systems},
  (*\refKey{period}*)             = {1},
  (*\refKey{name-alias}*)         = {{Max Mustermann},{M. S. Mustermann}},
  (*\refKey{orcid}*)              = {0000-0002-3555-7218},
  (*\refKey{email}*)              = {max.mustermann@example.edu},
  (*\refKey{phone}*)              = {+49 241 80 12345},
  (*\refKey{url}*)                = {https://example.edu/mm},
  (*\refKey{doctorateYear}*)      = {1995},
  (*\refKey{doctorate}*)          = {Dr. rer. nat.},
  (*\refKey{financed-by}*)        = {RWTH},
  (*\refKey{topic}*)              = {Host--microbiome interactions},
  (*\refKey{category}*)           = {prof},
  (*\refKey{dateDefense}*)        = {1995},
  (*\refKey{periodStart}*)        = {2025},
  (*\refKey{periodEnd}*)          = {2029},
  (*\refKey{contract-information}*) = {
    (*\refKey{C1}*)  = {yes},
    (*\refKey{C2}*)  = {no},
    (*\refKey{C3}*)  = {no},
    (*\refKey{C4}*)  = {yes},
  }
}
\end{dispListing*}
There are several keys you can and should use regarding a person.
They are described further done as an example on how to use \refCom{addEntry}
etc.
\begin{docKey}{email}{=\meta{string}}{}
Provide the email-address of the person.
\end{docKey}
\begin{docKey}{url}{=\meta{url}}{ }
URL of the persons academic/professional homepage (e.g. institute).
\end{docKey}

\begin{docKey}{phone}{=\meta{string}}{ }
Provide the phone number of the person.
\end{docKey}

\begin{docKey}{financed-by}{=\meta{string}}{ }
Describe the source of funding for the person’s e.g. position etc.
\end{docKey}

\begin{docKey}{topic}{=\meta{string}}{ }
Especially for the early career researchers describe their topic of research.
\end{docKey}

\begin{docKey}{category}{\docKeyChoices{groupLeader, prof , postDoc,medDoc,%
  	PhD,research,nonResearch,student,assistant}}{ }
\refKey{category} is used in various databases.
Mostly it is used to state the category of the person, but it is also used
then for the early career researchers.
\end{docKey}

\begin{docKey}{contract-information}{=\meta{key-values}}{}
Provide information about the person's contractual situation.
The \meta{key-value} is further specified with
\refKey{C1},
\refKey{C2},
\refKey{C2a},
\refKey{C2b},
\refKey{C3},
\refKey{C3a},
\refKey{C4},
\refKey{C4a}.
\end{docKey}

\begin{docKey}{C1}{\docKeyChoices{yes,no}}{}
This key collects the answer to \emph{Is the employment of the project leader(s) at the institution(s) indicated contractually secured for the duration of the proposed funding period?}
\end{docKey}
\begin{docKey}{C2}{\docKeyChoices{yes,no}}{}
This key collects the answer to \emph{Do any of the above mentioned persons hold fixed-term positions?}
\end{docKey}

\begin{docKey}{C2a}{=\meta{YYYY-MM-DD}}{}
If key \refKey{C2} has been answered with \meta{yes}, this question \emph{End
date of fixed-term contract:\meta{YYYY-MM-DD} } requires \meta{YYYY-MM-DD} as
answer, too.
\end{docKey}
\begin{docKey}{C2b}{\meta{YYYY-MM-DD}}{}
If key \refKey{C2} has been answered with \meta{yes}, this question
\emph{Further employment is planned until \meta{YYYY-MM-DD}} requires
\meta{YYYY-MM-DD} as answer, too.
\end{docKey}
\begin{docKey}{C3}{\docKeyChoices{yes,no}}{}
This key collects the answer to \emph{Will one or more of the above-mentioned persons retire during the proposed funding period?}.
\end{docKey}
\begin{docKey}{C3a}{=\meta{YYYY-MM-DD}}{}
If key \refKey{C3} has been answered with \meta{yes}, this question
\emph{anticipated retirement date: \meta{YYYY-MM-DD} } requires \meta{YYYY-MM-DD} as
answer, too.
\end{docKey}

\begin{docKey}{C4}{\docKeyChoices{yes,no}}{}
This key collects the answer to \emph{Funding for the position(s) of the project leader(s) at the institution(s) indicated is covered by core support (state funds or similar):}
\end{docKey}
\begin{docKey}{C4a}{=\meta{string}}{}
If key \refKey{C4} has been answered with \meta{no},
this key provides type and source of funding.
\end{docKey}

Following keys are mainly used for the CV-section but are closely tight to the person:
\begin{docKey}{orcid}{=\meta{0000-0000-0000-0000}}{}
  The individual string with the ORCiD.
  This value is also required for \refCom{getORCiD}.
\end{docKey}
\begin{docKey}{name-alias}{=\meta{string}}{ }
  More versions of the person's name.
  The various aliases for \refKey{name-alias} are also described under
  \refCom{addboldnames}.
\end{docKey}
\begin{docKeys}
{
  {doc name = doctorateYear,
  	doc parameter = {=\meta{YYYY}}},
  {doc name = doctorate,
  	doc parameter = {=\meta{string}}},
  {doc name = degree-programme,
  	doc parameter = {=\meta{string}}},
}
Providing information about the doctorate.
\end{docKeys}



\subsubsection{Database entries for a \textbf{cv}}
\label{sec:doc:cv-basic}
The header of the CV section is (partly) based on the information you parse to
the document using the \refCom{addEntry} command with the keyset \textbf{person}:
Keys like \refKey{name-alias}, \refKey{orcid},
\refKey{doctorate}, \refKey{degree-programme},
\refKey{url} are used especially for the CV-section.

Let’s assume we have a person with the following information:

\begin{dispListing*}{title={Partly person-entity dataset focussing on its CV-entry.}}
  (*\refCom{addEntry}*){person}{
  	(*\refKey{id}*)             ={MM},
  	(*\refKey{firstname}*)      ={Max S.},
  	(*\refKey{lastname}*)       ={Mustermann},
  	(*\refKey{academicdegree}*) ={Prof. Dr. rer. nat.},
  	(*\refKey{role}*)           ={PI},
    \ldots
  	(*\refKey{name-alias}*)       ={{Maxi Mustermann},{Maximilian Mustermann}},
  	(*\refKey{orcid}*)            ={0000-0002-3555-7218},
  	(*\refKey{doctorateYear}*)    ={1995},
    (*\refKey{doctorate}*)        ={Dr. rer. nat.},
    (*\refKey{degree-programme}*) ={Biology},
    (*\refKey{url}*)              ={https://example.edu/mm},
  }
\end{dispListing*}


This set of information is unique to a person and therefore only needs to be
parsed once.

In the cv we need more dedicated information about the person. This is done
with a separate keyset so it will not clutter the person-entry too much.
You can have multiple of the following entries below for a person.
Most important stages should be indicated with |cv-type=mandatory|.
If you state |cv-type=supplement| you only need to
use the key |description|, same goes for |cv-type=activities| which will then be
in a different section, and last |cv-type=supervision|.
There are more sections with further information about the PI.
All the information go to the database \meta{cv}.

\begin{docKey}{ref-person-id}{=\meta{id}}{}
  Use the \meta{id} of the person to whom this entry belongs to.
\end{docKey}

\begin{docKey}{description}{=\meta{string}}{}
  Further description of the current entry.
\end{docKey}


\begin{docKey}{cv-type}{\docKeyChoices{mandatory,supplement,
  		activities,supervision,
  		distinction,other}}{}
  Specifying the type of one CV entry with additional information.
  Each CV of a person needs to have a \meta{mandatory} entry
  (as part of \emph{Qualification and Career}).
\end{docKey}

\begin{docKeys}[doc parameter = {=\marg{date}}]
  {
  	{
  		doc name = periodStart,
  		doc description = starting date
  	},
  	{
  		doc name = periodEnd,
  		doc description = ending date
  	},
  	{
  		doc name = dateDefense,
  		doc description = date of the defense of the thesis
  	},
  }
  Specifying the time span of an event. The \meta{date} should be given in an IS8601-form.
\end{docKeys}

Some information comes from the block described above, but for the \emph{Stages} you
need to describe them separately using the keys
\refKey{ref-person-id},
\refKey{cv-type},
\refKey{periodStart},
\refKey{periodEnd},
\refKey{name},
\refKey{position},
\refKey{positionText},
\refKey{description},
\refKey{ref-institution-id}.


\begin{dispListing*}{title={Example dataset-entry for a mandatory person-cv-entity.}}
  (*\refCom{addEntry}*){cv}{
  	(*\refKey{ref-person-id}*)      ={MM},
  	(*\refKey{cv-type}*)        ={mandatory},
  	(*\refKey{periodStart}*)        ={1995},
  	(*\refKey{periodEnd}*)          ={1998},
  	(*\refKey{position}*)            ={prof-W3},
    (*\refKey{positionText}*)           ={Professor of Microbial Systems},
    (*\refKey{description}*)        ={Established an independent research group on host--microbiome interactions.},
  	(*\refKey{ref-institution-id}*) ={IAIS},
  }
\end{dispListing*}

For each stage on the career path repeat the
\cs{addEntry}\marg{cv}\marg{ \ldots, type={mandatory}, \ldots}-block.


There are five more blocks to which a researcher can provide information. For
each block and for each entry within one block you need to create an entry.

\begin{description}
  \item[supplement:]   Supplementary Career Information
  \item[activities:]   Activities in the Research System
  \item[supervision:]  Supervision of Researchers in Early Career Phases
  \item[distinction:]  Academic Distinctions
  \item[other:]        Other Information
\end{description}
Here is a more concrete example
\begin{dispListing*}{title={Example dataset-entry for a common CV-entity}}
  (*\refCom{addEntry}*){cv}{
    (*\refKey{ref-person-id}*)      ={MM},
    (*\refKey{cv-type}*)            ={supplement},
    (*\refKey{description}*)        ={Member of the university research council since 2024.},
  }
\end{dispListing*}

\begin{docCommand}{dfgCV}{\marg{person-id}}
  Print the complete CV for one person.  The command expects a dedicated
  \texttt{cv-}\meta{person-id} database and combines the header, mandatory
  career stages, optional CV sections, selected publications, and the data
  privacy statement.
\end{docCommand}

\begin{docCommand}{dfgCVsection}{\oarg{database}}
  Print the CVs for all PIs in the current funding period.  The
  \meta{database} defaults to \texttt{person}; persons are sorted by lastname
  and firstname before their CVs are printed with \refCom{dfgCV}.
\end{docCommand}

\subsubsection{Keyset \textbf{project}}
Following keys are required to describe a project.
\begin{dispListing*}{title=Example dataset-entry to describe a project-entity.}
  (*\refCom{addEntry}*){project}{
    (*\refKey{id}*) = {A01},
    (*\refKey{number}*) = {A01},
    (*\refKey{name}*)   = {Microbial metabolism in barrier tissues},
    (*\refKey{project-type}*)   = {research},
    (*\refKey{project-status}*) = {N},
    (*\refKey{project-area}*)   = {A},
    (*\refKey{consider-for-lists}*) = {true},
    (*\refKey{reference-only}*) = {false},
    (*\refKey{research-area}*) = {1.11-01,1.11-03},
    (*\refKey{ref-person-id}*) = {MM,KM},
    (*\refKey{collaborations}*) = {A02,B01,Q01},
  	(*\refKey{legal-issues}*)  = {
      (*\refKey{L1}*)  = {yes},
      (*\refKey{L1a}*) = {yes},
      (*\refKey{L2}*)  = {no},
      (*\refKey{L2a}*) = {},
      (*\refKey{L3}*)  = {yes},
      (*\refKey{L4}*)  = {no},
      (*\refKey{L5}*)  = {no},
      (*\refKey{L5a}*) = {},
      (*\refKey{L6}*)  = {no},
      (*\refKey{L7}*)  = {no},
      (*\refKey{L7a}*) = {},
  	}
  }
\end{dispListing*}

Other required keys are \refKey{id}, \refKey{name},
\refKey{number}, \refKey{ref-person-id}.
\begin{docKey}{project-type}{\docKeyChoices{research,service,mgk,admin}}{}
  Hereby you specify the type of the project.
  \meta{research} stands for a classical research project,
  \meta{service} is service project,
  \meta{mgk} is an integrated graduate college,
  \meta{admin} is an administrative project.
\end{docKey}

\begin{docKey}{project-status}{\docKeyChoices{N,E,C}}{}
  Define the status of the project, where \meta{N} means a \emph{new} project,
  \meta{E} stands for \emph{ending} and \meta{C} for \emph{continuing} project.
  The generated local proposal contains complete, separate source examples for
  all three statuses.  Continuing projects use \enquote{Project progress to
  date}, new projects use \enquote{Research rationale}, and ending projects use
  the shorter \enquote{Project history}, \enquote{Published project results},
  and \enquote{Funding} structure.  In every case \refCom{printProjectHead}
  supplies the preceding general-information section from metadata.
\end{docKey}

\begin{docKey}{project-area}{=\meta{area-id}}{}
  Assign the project to a collaboration-plot area such as \texttt{A},
  \texttt{B}, or \texttt{Q}.  Any number of area identifiers is supported.
  If the key is omitted or empty, the first character of the project ID is
  used for compatibility with existing metadata (for example, \texttt{A01}
  belongs to area \texttt{A}).
\end{docKey}

\begin{docKey}{consider-for-lists}{\docKeyChoices{true,false}}{}
  Control whether the project participates in automatically generated project
  lists, project overview tables, research-area aggregates, and project counts.
  The default is \texttt{true}.  Setting this key to \texttt{false} does not
  remove the database row, so the project remains available to explicit
  reference commands such as \refCom{getProject}.
\end{docKey}

\begin{docKey}{reference-only}{\docKeyChoices{true,false}}{}
  Declare that the project exists only so historical or external project ids
  can be referenced.  The default is \texttt{false}.  A reference-only project
  is printed without a hyperlink because it has no project section that could
  provide a link target.  In prose it receives the explicit
  \enquote{former project} indicator.  Generated tables and lists instead append
  a compact superscript asterisk and add a local \enquote{Former project} legend
  when at least one such project occurs.  This key is independent of
  \refKey{consider-for-lists}: an ending project with a real project section can
  be excluded from lists without becoming reference-only.
\end{docKey}

\begin{docKey}{research-area}{=\meta{ticklist}}{}
  Collect all research areas (according to the DFG list) in a comma-separated structure.
\end{docKey}

\begin{docKey}{collaborations}{=\meta{project-id-list}}{}
  List the other CRC projects collaborating with this project.  Collaborations
  are treated as undirected and duplicate declarations are collapsed, so the
  reverse relation does not need to be repeated.  The project collaboration
  plot reads its edges from this field and its nodes from the same
  \texttt{project} database.  Its default heatmap shows all active projects and
  highlights the focus project and its direct collaborators.  The optional arc
  layout uses the same active projects on one axis.  Ending, reference-only,
  and |consider-for-lists=false| projects are omitted, as are edges to those
  intentionally excluded nodes.
  All arcs reach one common peak height, so their horizontal span does not imply
  collaboration strength or weight.  Project identifiers are printed inside
  the nodes, and in the arc layout each project-area rule spans its complete
  contiguous group of nodes.
\end{docKey}

\begin{docKey}{legal-issues}{=\meta{further key-values}}{}
  Provide information about the project's legal issues.
  The \meta{key-value} is further specified with
  \refKey{L1},
  \refKey{L1a},
  \refKey{L2},
  \refKey{L2a},
  \refKey{L3},
  \refKey{L4},
  \refKey{L5},
  \refKey{L5a}.
  \refKey{L6}.
  \refKey{L7}.
  \refKey{L7a}.
\end{docKey}

\begin{docKey}{L1}{\docKeyChoices{yes,no}}{}
  This key records whether the project requires compliance with
  discipline-specific research ethics guidelines.
\end{docKey}
\begin{docKey}{L1a}{\docKeyChoices{yes,no}}{}
  If key \refKey{L1} has been answered with \meta{yes}, this statement
  records whether a statement from the responsible ethics committee is
  required and will be obtained before funding starts.
\end{docKey}

\begin{docKey}{L2}{\docKeyChoices{yes,no}}{}
  This key collects the answer to \emph{clinical trials}
\end{docKey}
\begin{docKey}{L2a}{\docKeyChoices{yes,no}}{}
  If key \refKey{L2} has been answered with \meta{yes}, this statement
  \emph{A copy of the studies’ registration is included with the proposal} requires an answer, too.
\end{docKey}

\begin{docKey}{L3}{\docKeyChoices{yes,no}}{}
  This key collects the answer to \emph{experiments involving vertebrates}
\end{docKey}

\begin{docKey}{L4}{\docKeyChoices{yes,no}}{}
  This key collects the answer to \emph{experiments involving recombinant DNA}
\end{docKey}


\begin{docKey}{L5}{\docKeyChoices{yes,no}}{}
  This key collects the answer to \emph{research involving human embryonic stem cells}
\end{docKey}
\begin{docKey}{L5a}{\docKeyChoices{yes,no}}{}
  If key \refKey{L5} has been answered with \meta{yes}, this statement
  \emph{Legal authorization has been obtained} requires an answer, too.
\end{docKey}

\begin{docKey}{L6}{\docKeyChoices{yes,no}}{}
  This key collects the answer to \emph{research concerning the Convention on Biological Diversity}
\end{docKey}

\begin{docKey}{L7}{\docKeyChoices{yes,no}}{}
  This key collects the answer to \emph{investigations involving dual use research of concern}
\end{docKey}
\begin{docKey}{L7a}{\docKeyChoices{yes,no}}{}
  If key \refKey{L7} has been answered with \meta{yes}, this statement
  \emph{A copy of the statement by the institution’s research ethics committee is included with the proposal} requires an answer, too.
\end{docKey}

\subsubsection{Keyset \textbf{institution}}
An institution describes the organisational unit a person belongs to, for
example an institute, department, centre, or clinic.  It is linked to its parent
affiliation through \refKey{ref-affiliation-id}.  The \refKey{abbreviation}
is the compact, reader-facing label used in generated table cells; the internal
\refKey{id} is never intended as display text.  Full institution lists and
legends continue to use \refKey{name}.  For compatibility, a missing
\refKey{abbreviation} falls back to \refKey{name}.  The \refKey{name} key may
be left empty when the affiliation itself is the relevant institution-level
text; in that case institution-list commands start with the affiliation name.

\begin{dispListing*}{title=Example dataset-entry to describe an institution-entity.}
  (*\refCom{addEntry}*){institution}{
    (*\refKey{id}*) = {IAIS},
    (*\refKey{name}*) = {Institute for Applied Immunology and Systems Biology},
    (*\refKey{abbreviation}*) = {IAIS},
    (*\refKey{ref-affiliation-id}*) = {RWTH},
  }
\end{dispListing*}

\begin{dispListing*}{title={Institution without a separate institution name.}}
  (*\refCom{addEntry}*){institution}{
    (*\refKey{id}*) = {RWTH-main},
    (*\refKey{name}*) = {},
    (*\refKey{abbreviation}*) = {RWTH},
    (*\refKey{ref-affiliation-id}*) = {RWTH},
  }
\end{dispListing*}

\begin{dispListing*}{title={Person with multiple institutions.}}
  (*\refCom{addEntry}*){person}{
    (*\refKey{id}*) = {MM},
    (*\refKey{firstname}*) = {Maria},
    (*\refKey{lastname}*) = {Muster},
    (*\refKey{ref-institution-id}*) = {IAIS,RWTH-main},
  }
\end{dispListing*}

In standard institution lists, multiple institutions are printed as separate
paragraphs with a small vertical gap.  In \texttt{narrow} mode, they are joined
inline with semicolons.  The \texttt{abbreviation} option selects institution
abbreviations (with a full-name fallback); generated compact tables enable this
option automatically.

\subsubsection{Keyset \textbf{affiliation}}
Following keys are required to describe an affiliation.

\begin{dispListing*}{title=Example dataset-entry to describe an affiliation-entity.}
  (*\refCom{addEntry}*){affiliation}{
    (*\refKey{id}*)             = {RWTH},
    (*\refKey{name}*)           = {Rheinisch-Westfälische Technische Hochschule Aachen},
    (*\refKey{abbreviation}*)   = {RWTH Aachen University},
    (*\refKey{addressStreet}*)  = {Templergraben 55},
    (*\refKey{addressZIP}*)     = {52062},
    (*\refKey{location}*)       = {Aachen},
    (*\refKey{country}*)        = {Germany}
  }
\end{dispListing*}

\begin{docKey}{abbreviation}{=\meta{string}}{}
  In addition to \refKey{name} provide an abbreviated version of this affiliation.
\end{docKey}

\begin{docKey}{addressStreet}{=\meta{string}}{}
  Specify the street of the affiliation.
\end{docKey}

\begin{docKey}{addressZIP}{=\meta{string}}{}
  Specify the ZIP code of the affiliation.
\end{docKey}

\begin{docKey}{location}{=\meta{string}}{}
  Specify the location (city) of the affiliation.
\end{docKey}

\begin{docKey}{country}{=\meta{string}}{}
  Specify the country the affiliation is located at.
\end{docKey}

\subsubsection{Keyset \textbf{funding}}

Each row represents one funding line.  For a staff row, the class can derive
the annual amount from the declared personnel category, percentage, and yearly
quantity.  For other funding types, annual values continue to be supplied
with \refKey{sum}.

\begin{dispListing*}{title={Complete dataset for a funding entity. Not all keys
  			are always required.}}
  (*\refCom{addEntry}*)[funding]{RequestedFunding}{
    (*\refKey{id}*)                 = {A01-staff-prof},
    (*\refKey{ref-project-id}*)     = {A01},
    (*\refKey{ref-affiliation-id}*) = {RWTH},
    (*\refKey{financed-by}*)        = {DFG},
    (*\refKey{funding-type}*)       = {staff},
    (*\refKey{percentage}*)         = {100},
    (*\refKey{category}*)           = {prof},
  	(*\refKey{quantity}*)           = {
      { year1 = {1} },
      { year2 = {1} },
      { year3 = {1} },
      { year4 = {1} },
      { year5 = {1} },
  	},
  	(*\refKey{sum}*) = {
      { year1 = {1000} },
      { year2 = {1000} },
      { year3 = {1000} },
      { year4 = {1000} },
      { year5 = {1000} },
  	},
    (*\refKey{year}*)               = {2026},
    (*\refKey{applicant}*)          = {5000},
    (*\refKey{participant}*)        = {2000},
    (*\refKey{other-funds}*)        = {0},
    (*\refKey{staff}*)              = {5000},
    (*\refKey{costs}*)              = {1200},
    (*\refKey{instrumentation}*)    = {0},
    (*\refKey{fellowships}*)        = {0},
    (*\refKey{globalfunds}*)        = {0}
  }
\end{dispListing*}

Not all of the above mentioned keys are necessary for each funding table.
We will provide examples for the various funding databases and their required
keysets.

\begin{docKey}{funding-type}{\docKeyChoices{staff, costs, fellowships,
  		globalfunds, instrumentation}}{}
  Define the type of this funding according to the predefined set. This is
  important since different features are activated depending on the value of this key.
\end{docKey}

\begin{docKey}{percentage}{=\meta{number}}{}
  This is only relevant when \refKey{funding-type} is set to |staff|.
  State the percentage of a full position, for example |100| for a full
  position or |65| for a 65\% position.  Integer and decimal values are
  accepted by the automatic calculation.
\end{docKey}

\begin{docKey}{category}{\docKeyChoices{groupLeader, prof, prof-W2, prof-W3,%
		postDoc,medDoc,PhD,research,nonResearch,student,assistant}}{}
  This is only relevant when \refKey{funding-type} is set to |staff|.
  Describe the kind of the required person. Depending on this \meta{category}
  the matching |salary@...| setting is used.  The categories |prof|,
  |prof-W2|, and |prof-W3| all use \refKey{salary@prof}; the other category
  names correspond directly to their setting names below.
\end{docKey}

\begin{docKey}{quantity}{=\meta{key=value}}{}
  This is a key that enables further \meta{key-values} with a predefined subset
  |year1| through |year5|. State how many positions of the
  \refKey{category} are required in each year. Decimal quantities are
  supported, for example |year1={0.5}| for half a position.
\end{docKey}

\begin{docKey}{sum}{=\meta{key=value}}{}
  This is a key that enables further \meta{key-values} with a predefined subset
  for the individual years. State the sum for a person for a certain
  \refKey{category}.  For |funding-type=staff| this key is optional: every
  omitted yearly sum is calculated from the salary setting for
  \refKey{category}, \refKey{percentage}, and that year's
  \refKey{quantity}.  Because the five-year CRC period starts and ends with a
  half-year, automatically calculated amounts for |year1| and |year5| receive
  an additional factor of |0.5|; |year2| through |year4| use the complete
  annual rate.  The result is rounded to the nearest euro.  An explicit yearly
  sum remains an override, so existing declarations and exceptional personnel
  costs keep their stated value.
\end{docKey}

For every omitted staff sum, the class applies
\[
  \operatorname{round}\left(
    \text{salary(category)} \times
    \frac{\text{percentage}}{100} \times
    \text{quantity(year)} \times
    \text{period-factor(year)}, 0
  \right).
\]
Here, \(\text{period-factor}=0.5\) for |year1| and |year5| and \(1\) for
|year2|--|year4|.  Thus the two half-years together count as one complete
salary year.
The calculation is performed when the row is added and the result is stored in
the normal |sum-year1| through |sum-year5| fields.  Funding tables therefore
use calculated and explicitly supplied amounts in exactly the same way.  A
missing salary setting, percentage, or valid quantity produces a warning
instead of silently inventing an amount.

\begin{dispListing*}{title={Staff funding with automatically calculated sums.}}
(*\refCom{addEntry}*)[funding]{RequestedFunding}{
  (*\refKey{ref-project-id}*) = {A01},
  (*\refKey{funding-type}*)   = {staff},
  (*\refKey{category}*)       = {PhD},
  (*\refKey{percentage}*)     = {65},
  (*\refKey{quantity}*)       = {
    year1 = {1}, year2 = {1}, year3 = {1},
    year4 = {1}, year5 = {1}
  }
}
\end{dispListing*}

\begin{docKey}{year}{=\meta{integer}}{}
  State the year as integer. Actually only relevant in combination with
  \refKey{applicant}, \refKey{participant}, \refKey{other-funds}, \refKey{staff}, \refKey{costs}, \refKey{instrumentation}, \refKey{fellowships}, \refKey{globalfunds}.
\end{docKey}


\begin{docKey}{applicant}{=\meta{integer}}{}
  State the sum of direct costs for the applicant institution.
\end{docKey}

\begin{docKey}{participant}{=\meta{integer}}{}
  State the sum of direct costs for any other participating (i.e. not-applicant) institution.
\end{docKey}


\begin{docKey}{other-funds}{=\meta{integer}}{}
  State the sum of direct costs when neither the applicant nor a participating
  institution is covering the costs.
\end{docKey}

\begin{docKey}{staff}{=\meta{integer}}{}
  State the \meta{sum} of staff for the previous funding phase.
  This is a fixed sum and therefore not necessary to calculate the sum like we do
  with \refKey{category} etc.
\end{docKey}

\begin{docKey}{costs}{=\meta{integer}}{}
  State the \meta{sum} of direct costs for the previous funding phase.
  This is a fixed sum and therefore not necessary to calculate the sum like we do
  with \refKey{category} etc.
\end{docKey}


\begin{docKey}{instrumentation}{=\meta{integer}}{}
  State the \meta{sum} of instrumentation for the previous funding phase.
  This is a fixed sum and therefore not necessary to calculate the sum like we do
  with \refKey{category} etc.
\end{docKey}


\begin{docKey}{fellowships}{=\meta{integer}}{}
  State the \meta{sum} of staff for the previous funding phase.
  This is a fixed sum and therefore not necessary to calculate the sum like we do
  with \refKey{category} etc.
\end{docKey}


\begin{docKey}{globalfunds}{=\meta{integer}}{}
  State the \meta{sum} of globalfunds for the previous funding phase.
  This is a fixed sum and therefore not necessary to calculate the sum like we do
  with \refKey{category} etc.
\end{docKey}

\subsubsection{Keyset \textbf{staff}: requested-funding roster}

The |staff| key family also supplies the project-level roster required by the
DFG section \enquote{Requested funding for staff}.  These records use the fixed
database |RequestedFundingStaff| and are independent of the monetary
|RequestedFunding| rows above.  The public output call is
\refCom{printTable}|{{RequestedFundingStaff}{A01}}|.

\begin{dispListing*}{title={Complete staff-roster declaration.}}
(*\refCom{addEntry}*)[staff]{RequestedFundingStaff}{
  (*\refKey{ref-project-id}*)     = {A01},
  (*\refKey{funding-status}*)     = {existing},
  (*\refKey{staff-type}*)         = {research},
  (*\refKey{ref-person-id}*)      = {MM},
  (*\refKey{field-of-research}*)  = {Microbiology},
  (*\refKey{commitment}*)         = {8},
  (*\refKey{funding-source}*)     = {State funds},
  (*\refKey{description}*)        = {
    Leads the experimental work and supervises the research staff.
  }
}
\end{dispListing*}

\begin{docKey}{ref-project-id}{=\meta{project-id}}{}
  Required. Selects the project for which the roster row is printed.  The
  value must match the project argument in the table call.  For example, a
  row with |ref-project-id={A01}| is selected when |A01| is passed as the
  project argument to \refCom{printTable}.
\end{docKey}

\begin{docKeys}[
  doc parameter={=\meta{choice}}
]{
  {doc name=funding-status,
   doc parameter={\docKeyChoices{existing,requested}}},
  {doc name=staff-type,
   doc parameter={\docKeyChoices{research,nonResearch}}}
}
  These two required keys select one of the four official DFG groups.  Empty
  subgroups are omitted and declaration order is retained within each group.
  In a project with |project-status=E|, |funding-status=requested| denotes
  staff funded with approved grant money in the ending funding period; the
  table changes that group label and its job-description heading
  automatically.
\end{docKeys}

\begin{docKeys}[doc parameter={=\meta{string}}]{
  {doc name=ref-person-id},
  {doc name=firstname},
  {doc name=lastname},
  {doc name=academic-degree},
  {doc name=positionText}
}
  A resolvable \refKey{ref-person-id} obtains the name, academic degree,
  position, category, and organisation from the central |person| fields
  |firstname|, |lastname|, |academicdegree|, |positionText|, |position|,
  |ref-institution-id|, and the compatibility fallback |ref-affiliation-id|.
  Any explicitly supplied roster field overrides the central value. An empty
  or omitted \refKey{academic-degree} is silently left out of both the roster
  and the job-description heading. For an unnamed vacancy, use
  |lastname={TBA}|; |firstname| may then also be omitted, and both the roster
  and the job-description lead-in print a clean ``TBA'' marker. Multiple
  unnamed vacancies are distinguished by their category, position, field of
  research, and institution when duplicate records are checked. Either a
  person reference or at least a last name is required. For existing staff
  resolved through \refKey{ref-person-id}, the lastname is printed in bold in
  the roster.
  The former roster key |position| remains accepted as a compatibility alias
  for |positionText|.
\end{docKeys}

\begin{docKeys}[doc parameter={=\meta{string}}]{
  {doc name=field-of-research},
  {doc name=funding-source},
  {doc name=description}
}
  \refKey{field-of-research} supplies its table cell for every roster row.
  \refKey{funding-source} applies only to existing staff; the corresponding
  cell for requested staff is marked as not applicable.  \refKey{description}
  supplies the numbered text below the table and accepts ordinary paragraph
  material, citations, and other LaTeX commands.  Each description starts
  with its number followed by academic degree, first name, and last name.
  Missing applicable values are highlighted and reported in the log.
\end{docKeys}

\begin{docKey}{ref-institution-id}{=\meta{id-list}}{}
  Resolve one or more comma-separated institution ids through the central
  |institution| database.  Each institution's \refKey{abbreviation} is printed
  in the department/institution column; the full \refKey{name} is retained in
  the automatically generated legend together with its parent affiliation.
  Parent-affiliation abbreviations are checked and explained in first-use
  order.  This key may be omitted when a resolvable \refKey{ref-person-id}
  already supplies |person.ref-institution-id|; a value on the staff row acts
  as an explicit override.
\end{docKey}

\begin{docKey}{department}{=\meta{string}}{}
  Compatibility override for unstructured declarations.  When present, this
  text is printed directly and takes precedence over institution lookup.  New
  declarations should normally use \refKey{ref-institution-id}.
\end{docKey}

\begin{docKey}{ref-affiliation-id}{=\meta{affiliation-id}}{}
  Compatibility fallback used only when neither \refKey{department} nor
  \refKey{ref-institution-id} is supplied.  It prints the affiliation
  abbreviation and adds the affiliation to the legend.  New declarations
  should use \refKey{ref-institution-id} so the organisational unit and its
  parent affiliation remain separate structured data.
\end{docKey}

\begin{docKey}{commitment}{=\meta{number}}{}
  Project commitment in hours per week for existing staff.  The value may be
  a non-negative integer or decimal; no artificial upper limit is imposed.
  For requested staff the table cell is marked as not applicable.
\end{docKey}

\begin{docKey}{category}{\docKeyChoices{prof,groupLeader,postDoc,medDoc,
    PhD,research,nonResearch,student,assistant,prof-W2,prof-W3}}{}
  Required for requested staff unless it can be inherited from
  |person.position| through \refKey{ref-person-id}.  Only keys registered in
  \cs{g\_\_dfg\_dfg\_category\_names\_prop} are accepted, and the table
  expands each key to the label stored in that property; for example,
  |postDoc| prints \enquote{Postdoctoral researcher}.  Existing staff inherit
  the category for the chapter-2 overview when possible, but may still supply
  an explicit override; their Category cell in the project-level roster is
  marked as not applicable.
\end{docKey}

The table traverses |RequestedFundingStaff| only once for the selected project,
then assigns continuous sequence numbers in display order.  The same numbers
are reused below the table for the two job-description blocks.  Missing values,
unresolved references, and exact duplicate identities produce warnings and
visible placeholders without stopping compilation.

\paragraph{Reuse in chapter 2: overview of existing staff}

The same declarations also populate the proposal-wide table in section 2.1.2;
no separate totals database is needed.  The call is
\refCom{printTable}|{OverviewExistingStaff}|.  It selects only rows with
|funding-status={existing}|, counts one person per distinct parent affiliation,
and groups the values into the seven categories prescribed by the DFG form.
The mappings are |prof|, |prof-W2|, and |prof-W3| to Professors,
|groupLeader| to Junior research group leaders, |postDoc| to Postdoctoral
researchers, |PhD| to Doctoral researchers,
|research| and |medDoc| to Other research staff, |nonResearch| to Non-research
staff, and |student| and |assistant| to Student and graduate assistants.

The applicant affiliation or affiliations are read as a comma-separated list
from |meta.ref-affiliation-id| and printed first; other affiliations are
obtained from each row's |ref-institution-id|.  The group heading says
enquote{applicant university} for one id and enquote{applicant universities}
for several ids, spanning all corresponding columns.  Multiple institutions
belonging to the same affiliation count that person only once in that
affiliation column.  Since the project declarations normally occur after
chapter 2, the class transfers the rows through the |.aux| file.  The normal
multi-pass |latexmk| build therefore fills the table automatically on the next
pass.


\subsubsection{Adding information to a database}
\begin{docCommand}{addEntry}{\oarg{key-set}\marg{database}\marg{key=value}}
  Adds an entry to the database \meta{database} with the defined
  values from \meta{key=value}.
\end{docCommand}

You can omit the key-set-definition if the name of the database is the same as
of the key-set, like for \meta{person}.
Here is an example how to add some information about a person into the
respective database:
\begin{dispListing*}{title={Small example of how to add data to a database. Here
  			\meta{person} is the database \emph{and} the keyset.}}
  (*\refCom{addEntry}*){person}{
  	(*\refKey{id}*)        =MM,
  	(*\refKey{firstname}*) =Manfred,
  	(*\refKey{lastname}*)  =Mustermann
  }
\end{dispListing*}

Internally there is a new row added to the mentioned database (|person|). In
case the database has not yet existed it will create it on the fly.

For other databases you can proceed as this:
\begin{dispListing*}{title={Small example of how to add data to a database. Here
  			\meta{VIP} is the database \emph{while} using the keyset of \meta{person}.}}
  (*\refCom{addEntry}*)[person]{VIP}{
  	(*\refKey{id}*)        =person1,
  	(*\refKey{firstname}*)  =Kim,
  	(*\refKey{lastname}*)  =Muster
  }
\end{dispListing*}
In this case the person is stored in the database |VIP| (for whatever reason
this is important).

Following keys are available for the \meta{person}-keyset.

\begin{docKey}{id}{=\meta{unique string}}{}
  Any kind of a unique string that serves as an id, especially for commands
  like \refCom{getEntry}. Almost all databases require this key.
\end{docKey}

\begin{docKeys}[
  	doc parameter = {=\meta{string}}
  ]{
  	{ doc name = firstname },
  	{ doc name = lastname },
  	{ doc name = academicdegree },
  	{ doc name = gender,
  		doc parameter = {\docKeyChoices{f,m,d}}},
  	{ doc name = period,
  		doc parameter = {\docKeyChoices{1,2,3}},
  		doc description = multi choice!!},
  	{ doc name = role,
  		doc parameter = {\docKeyChoices{PI, spokesperson, manager,
  					steering-committee-member, rector}}},
  	{ doc name = position,
  		doc parameter = {\docKeyChoices{PhD, postDoc, groupLeader, research,
  					nonResearch, student, prof, prof-W2, prof-W3}}},
  	{ doc name = positionText,
  		doc parameter = {=\meta{string}},
  		doc description = {Specifying the position of the person, current or in the CV-section for the respective period.}},
  }
  Personal and individual \emph{required} information about a person.
\end{docKeys}

\begin{docKeys}[
  	doc parameter = {=\meta{string}}
  ]{
  	{ doc name = ref-institution-id },
  	{ doc name = ref-affiliation-id },
  	{ doc name = ref-project-id     },
  }
  Referencing to an external database with its dedicated \meta{id}.
  \textbf{Note:} When you reference using \refKey{ref-institution-id}, there
  is no need to explicitly reference the affiliation with \refKey{ref-affiliation-id}.
\end{docKeys}

The institution data is resolved through a two-step relationship.  A person
stores one or more institution ids in \refKey{ref-institution-id}; each
institution stores the id of its parent affiliation in
\refKey{ref-affiliation-id}.  Commands such as \refCom{dfgInstitutionList}
therefore follow this chain:
\[
  \texttt{person.ref-institution-id}
  \longrightarrow
  \texttt{institution.id}
  \longrightarrow
  \texttt{institution.ref-affiliation-id}
  \longrightarrow
  \texttt{affiliation.id}.
\]
The affiliation id usually does not need to be duplicated in the person entry.

For the database |meta| there are also dedicated keys.
The database |meta| contains specific information on the metalevel about the
CRC.
For the |meta| row with |id=crc|, \refKey{ref-affiliation-id} accepts one or
more comma-separated affiliation ids, for example |{aff1,aff2}|.  These are the
applicant or coordinating universities.  Their names and locations are
resolved in declaration order for the title page and related prose; applicant
funding totals include every listed id.
Besides \refKey{id}, \refKey{ref-affiliation-id} there are these dedicated keys:
\begin{docKeys}{
  	{doc name = name,
  		doc parameter = {=\meta{string}},
  		doc description = {applicable to other keysets, too.}},
  	{doc name = nameAddon,
  		doc parameter = {=\meta{string}}},
  	{doc name = number,
  		doc parameter = {=\meta{integer}}},
  	{doc name = fundingPeriodNumeral,
  		doc parameter = {\docKeyChoices{1,2,3}},
  	},
  	{doc name = fundedSince,
  		doc parameter = {=\meta{YYYY}}},
  	{doc name = fundingYears,
  		doc parameter = {=\meta{YYYY1,YYYY2,YYYY3,YYYY4,YYYY5}}},
  	{doc name = fundingYearsPrevious,
  		doc description = {applicable to 2nd and 3rd phases},
  		doc parameter = {=\meta{YYYY1,YYYY2,YYYY3,YYYY4,YYYY5}}},
  }
  Specify the core information of a CRC.
  The key \refKey{fundingPeriodNumeral} corresponds to \refKey{period}.
\end{docKeys}
\subsubsection{Retrieving and handling information from a database}
\label{sec:information-command-overview}

\paragraph{Information retrieval command overview}
The following overview groups the public commands by the information they
produce.  Square-bracket arguments are optional; brace arguments are
mandatory.  The detailed descriptions below explain formatting, warnings, and
fast-compilation behaviour.

\medskip
\noindent\textbf{General database access}
\begin{description}
  \item[\cs{getEntry}]
    \oarg{database}\marg{id}\marg{field}\oarg{id-field} prints one field from
    one row.
  \item[\cs{getEntry*}]
    \oarg{database}\marg{id}\marg{assignments}\oarg{id-field} retrieves
    several fields in one row lookup and assigns them to macros without
    printing.
  \item[\cs{compareEntry}]
    \oarg{database}\marg{id}\marg{field}\marg{value}\marg{true}\marg{false}
    selects content according to a field comparison.
\end{description}

\noindent\textbf{People, institutions, and projects}
\begin{description}
  \item[\cs{getName}, \cs{getFullName}]
    \marg{person-id} prints a person's lastname or full name; the starred
    full-name form adds the academic degree.
  \item[\cs{getPI}]
    \sarg\marg{person-id-list}\oarg{text} prints linked PI references; the
    star includes firstnames.
  \item[\cs{getORCiD}, \cs{getORCiDvalue}]
    \oarg{database}\marg{person-id}: the first prints a linked, formatted
    ORCiD; the second stores the raw value in \cs{theORCiDValue} for later
    formatting.
  \item[\cs{dfgInstitutionList}]
    \oarg{database}\marg{person-id}\oarg{options} prints a person's
    institutions and their parent affiliations.
  \item[\cs{getPersonInformation}]
    \oarg{database}\marg{person-id-list} prints complete PI/contact blocks.
  \item[\cs{getPIsWithRole}]
    \oarg{database}\marg{role}\oarg{raster-options} prints current-period
    people carrying the requested role.
  \item[\cs{getPIProject}, \cs{getProjectPI}]
    \sarg\marg{id-list} prints people with their assigned projects, or
    projects with their assigned people; the starred forms include firstnames.
  \item[\cs{getPIofProject}]
    \oarg{properties}\marg{project-id}\oarg{delimiter} prints selected PI
    name properties for one project.
  \item[\cs{getProject}]
    \marg{project-id-list}\oarg{text} prints project references.  Optional
    \meta{text} replaces the displayed project number while retaining the link
    target and is best used with a single project. With
    \refKey{projectPIOncePerSection}|=true|, it shares \cs{getProjectPI}'s
    first-reference PI expansion and state. A reference-only project is
    deliberately not linked. It is marked as \enquote{former project} in prose;
    inside \cs{printTable} and \cs{printList} output it receives an asterisk and
    the generated item receives a local legend.
  \item[\cs{getProjectCount}]
    \oarg{area} prints the number of active, list-considered projects.  Omit
    the area for the total, or pass \texttt{A}, \texttt{B}, or \texttt{Q}.
  \item[\cs{dfgResearchAreasList}]
    \marg{code} prints a DFG research-area code and its description.
  \item[\cs{getAim}, \cs{getWP}]
    \oarg{project-id}\marg{id-list} cross-references one or more project aims
    or work packages; the project id defaults to the current project.
\end{description}

\noindent\textbf{Person statistics}
\begin{description}
  \item[\cs{getPositionGenderPhaseAmount}]
    \oarg{database}\marg{position}\marg{gender}\marg{period} prints the count
    for one position/gender/period tuple.
  \item[\cs{getPositionPhaseTotal}]
    \oarg{database}\marg{position}\marg{period} prints the all-gender total.
  \item[\cs{getGenderPhaseTotal}]
    \oarg{database}\marg{gender}\marg{period} prints the all-position total.
  \item[\cs{getPositionGenderPhasePercentage}]
    \oarg{database}\marg{position}\marg{gender}\marg{period} prints the
    rounded integer percentage value within a position.
  \item[\cs{getGenderPhasePercentage}]
    \oarg{database}\marg{gender}\marg{period} prints the rounded integer
    percentage value across all counted positions.
\end{description}

\noindent\textbf{Funding and staff totals}

The near-identical funding names encode two different scopes.  Commands using
the singular name |RequestedFunding| use the proposal-wide
|RequestedFundingOverview| database by default.  Commands using the plural
name |RequestedFunds| use the project-level |RequestedFunding| database and
therefore require a project id.  In the signatures below,
\meta{sum-fields} means one or more fields such as |sum-year1| through
|sum-year5|.

\begin{description}
  \item[\cs{getCountRequestedStaff}]
    \oarg{project}\marg{year}\marg{category} prints the requested staff
    quantity, optionally restricted to one project.
  \item[\cs{getSumRequestedFunding}]
    \oarg{database}\marg{year}\marg{type} prints the proposal-wide total for
    one funding type; use |year=all| for all five years.
  \item[\cs{getTotalSumRequestedFunding}]
    \oarg{database}\marg{year}\marg{type} has the same proposal-wide scope and
    additionally accepts |type=all| for the grand total.
  \item[\cs{getSumPreviousRequestedFunding}]
    \oarg{database}\marg{year}\marg{fields} totals the selected columns in
    the previous-period database; |year=all| includes every row.
  \item[\cs{getSumRequestedFunds}]
    \oarg{database}\marg{project}\marg{type}\marg{sum-fields} prints a
    project total for one funding type.
  \item[\cs{getTotalSumRequestedFunds}]
    \oarg{database}\marg{project}\marg{sum-fields} prints a project total
    across all funding types.
  \item[\cs{getSumRequestedFundsInstrumentation}]
    \oarg{project}\marg{sum-fields} prints the proposal-wide instrumentation
    total or restricts it to the optional project.
  \item[\cs{getSumRequestedFundingDirectCosts}]
    \oarg{database}\marg{year}\marg{group} totals direct costs for
    |applicant|, |participant|, |other-funds|, or |all|.
  \item[\cs{getSumExistingFunds}]
    \oarg{database}\marg{project}\marg{sum-fields} prints existing direct-cost
    funding for one project.
\end{description}

\newpage
For example:
\begin{dispListing*}{title={Common project-count and funding queries.}}
  \getProjectCount[A]                            % active A projects
  \getSumRequestedFunding{all}{staff}            % proposal-wide staff total
  \getTotalSumRequestedFunding{all}{all}         % proposal-wide grand total
  \getSumRequestedFunds{A02}{staff}{sum-year1}   % A02 staff total, year 1
  \getTotalSumRequestedFunds{A02}{sum-year1}     % A02 grand total, year 1
\end{dispListing*}

You can get any kind of information back from any database using \refCom{getEntry}:
\begin{docCommand}{getEntry}{\oarg{database}\marg{value of
  		id}\marg{column}\oarg{alternative id-field}}
  Retrieve and typeset the value of \meta{column} from the row whose
  id-cell equals \meta{value of id}.

  The optional \meta{database} argument selects the \refPkg{datatool}
  database to query; it defaults to \cs{tmpLocalDB}, which is set by
  the surrounding context (typically by the table-generating command).
  The optional \meta{alternative id-field} argument names the column
  that holds the row identifier and defaults to \texttt{id}; supply a
  different name when the row is keyed on something other than the
  standard id column (for example \texttt{ref-project-id} or
  \texttt{number}).

  The retrieved value is wrapped in \cs{dfgShowTag} before being
  typeset, so when the \refKey{showtags} class option is active the
  output is annotated with a small overlay marker showing the
  originating database, id, and column.  When the option is inactive,
  the value is typeset plain.

  The command performs several checks and emits a warning to the log
  when something is wrong: a \texttt{database-name-not-given} warning
  if \meta{database} is empty, a \texttt{database-not-found} warning
  if no database with the given name exists, and a \texttt{missing-key}
  warning if the row exists but the requested cell is empty or
  undefined.  The last warning is suppressed during \refPkg{tabularray}'s
  measuring phase to avoid duplicate log entries.

  When the \texttt{fastcompile-project} class option is active, the lookup is
  skipped entirely and the row identifier is typeset as a quiet grey
  placeholder.  Starred multi-field lookups initialise their destination
  macros to empty values without touching a database.

  \medskip
  Examples:
  \begin{dispListing}
  	% fetch the lastname of person 42 from the |person| database
  	\getEntry[person]{42}{lastname}

  	% fetch the title of the project with number "A1"
  	\getEntry[project]{A1}{name}[number]

  	% inside a context where \tmpLocalDB is set to "person":
  	\getEntry{42}{firstname}
  \end{dispListing}


  When several columns from the same row are needed, prefer the starred
  form \refCom{getEntry*}, which performs only a single row lookup.
\end{docCommand}

\begin{docCommand}{getEntry*}{\oarg{database}\marg{value of
  		id}\marg{assignments}\oarg{alternative id-field}}
  Starred variant of \cs{getEntry}.  Retrieves multiple columns from the
  same row in a single lookup and assigns each value to the macro named
  on the left-hand side of the assignment.

  The \meta{assignments} argument is a comma-separated list of
  \meta{\textbackslash macro}\,\texttt{=}\,\meta{column} pairs.  For each
  pair, the value of \meta{column} for the row whose id-cell equals
  \meta{value of id} is stored in \meta{\textbackslash macro}.  Unlike
  the unstarred form, this variant does not print anything and does not
  wrap results in \cs{dfgShowTag} -- the caller is responsible for
  formatting the retrieved values.

  Missing fields trigger the same \texttt{missing-key} warning as the
  unstarred form (suppressed during \pkg{tabularray}'s measuring phase).

  \medskip
  Example:
  \begin{dispListing}
  	\getEntry*[person]{42}{
  		\theFirst  = firstname,
  		\theLast   = lastname,
  		\theDegree = academicdegree
  	}
  	\theDegree\space\theFirst\space\theLast
  \end{dispListing}
  This is preferable over multiple \cs{getEntry} calls when several
  fields from the same row are needed: the row is located once instead
  of once per field.
\end{docCommand}

\begin{docCommand}{tmpLocalDB}{\marg{database}}
  Define the database locally (e.g. within a group) so you don't need to repeat it
  as \oarg{database} for e.g. \refCom{getEntry}.
\end{docCommand}

Here is a concrete example how to do it. It will give you the last name of the
person (database |person|) that has the |id| |MM|.
\begin{dispListing*}{title = {Example how to get data from the database
  			\meta{person}.}}
  \getEntry[person]{MM}{lastname}
\end{dispListing*}
You can omit \oarg{person} in this case if \refCom{tmpLocalDB} is defined.
\begin{dispListing*}{title={Omit locally the database because it has been
  			defined before.}}
  \def\tmpLocalDB{person}
  \getEntry{MM}{lastname}
\end{dispListing*}

To quickly get a name of a person there is a dedicated command:
\begin{docCommand}{getName}{\marg{<id>}}
  Get last name of person that has the \meta{id}.
  This sets the database to \texttt{person}.
\end{docCommand}

\begin{docCommands}[
  	doc name = getFullName
  ]{
  	{doc parameter = \sarg\marg{id}},
  	{doc parameter = \marg{id}}
  }
  Get the full name of the person with the \meta{id}.
  The starred version adds the academic title in front.
\end{docCommands}

\begin{docCommands}[
    doc name = getPI
  ]{
    {doc parameter = \sarg\marg{id-list}},
    {doc parameter = \marg{id-list}},
    {doc parameter = \marg{id-list}\oarg{text}}
  }
  Reference one or multiple PIs from the \texttt{person} database.  The
  \meta{id-list} is a comma-separated list of person ids.  By default the
  command prints the lastname; the starred version also prints the firstname.
  With the optional \meta{text} argument, \meta{text} is printed instead, but
  the hyperlink still points to the PI.

  The printed name is typeset bold, coloured with \texttt{referencePI}, and
  linked to the corresponding person's row in
  \cs{printTable}|{ProjectLeaders}|.  Each row of that table provides the
  destination \texttt{pi:}\meta{id}.
\end{docCommands}

\begin{dispListing*}{title={Reference one or multiple PIs.}}
  \getPI{MM}
  \getPI*{MM,KM}
  \getPI{MM}[the spokesperson]
\end{dispListing*}

\begin{docCommand}{getProject}{\marg{id-list}\oarg{text}}
  Reference one or multiple projects from the \texttt{project} database.  The
  \meta{id-list} is a comma-separated list of project ids.  By default the
  command prints the project number; with the optional \meta{text} argument,
  \meta{text} is printed instead, but the hyperlink still points to the
  project.  In CV mode the command prints the same text without a hyperlink.
  Projects declared with \refKey{reference-only}|=true| are never hyperlinked;
  instead, \enquote{former project} is appended to make the missing project
  section explicit.

  The printed project reference is typeset bold and coloured according to the
  first letter of the project id. Multiple project references are joined as a
  natural-language list with commas and a final \enquote{and}. With
  \refKey{projectPIOncePerSection}|=true|, the command behaves like the
  unstarred \refCom{getProjectPI}: the first reference to each project in a
  section includes its PIs and later references use the compact project form.
  Generated tables and lists remain compact.
\end{docCommand}

\begin{dispListing*}{title={Reference one or multiple projects.}}
  \getProject{A01}
  \getProject{A01,B02}
  \getProject{A01,B02,Q01}
  \getProject{A01}[the first project]
\end{dispListing*}

\begin{docCommand}{getProjectCount}{\oarg{area}}
  Print the number of active projects.  A project is active when its
  \refKey{project-status} is \texttt{C} or \texttt{N} and
  \refKey{consider-for-lists} is \texttt{true} and
  \refKey{reference-only} is \texttt{false}.  With no optional argument all
  active projects are counted.  Any explicit \refKey{project-area} value may
  be supplied to restrict the result; where that metadata is absent, the first
  character of the project ID is used.  All area totals are computed together
  on first use and cached for subsequent calls.
\end{docCommand}

\begin{dispListing*}{title={Count active projects.}}
  \getProjectCount
  \getProjectCount[A]
  \getProjectCount[B]
  \getProjectCount[Q]
\end{dispListing*}

\begin{docCommands}[
    doc name = CRC
  ]{
    {doc parameter = \marg{crc-number}},
    {doc parameter = \sarg\marg{crc-number}},
    {doc parameter = \sarg\oarg{crc-title}\marg{crc-number}}
  }
  Print a CRC reference.  For the current CRC, identified by the
  \refKey{number} field of the \texttt{meta} entry with id \texttt{crc},
  the unstarred command prints the short form stored in \cs{thisCRC}; the
  starred command prints the long form with the CRC title.

  For a different CRC number, the unstarred command prints only the short
  reference, while the starred form prints a long reference.  If
  \meta{crc-title} is given, it is used as the title of the external CRC;
  otherwise the command falls back to the CRC number.
\end{docCommands}

\begin{docCommands}[
    doc name = TRR
  ]{
    {doc parameter = \marg{trr-number}},
    {doc parameter = \sarg\marg{trr-number}},
    {doc parameter = \sarg\oarg{trr-title}\marg{trr-number}}
  }
  Print a CRC/TRR reference.  The command follows the same rules as
  \refCom{CRC}, but uses \enquote{CRC/TRR} as the printed programme
  type.
\end{docCommands}

\begin{dispListing*}{title={Reference current and external CRCs.}}
  \CRC{1382}
  \CRC*{1382}
  \CRC{999}
  \CRC*[External CRC title]{999}
  \TRR{999}
  \TRR*[External CRC/TRR title]{999}
\end{dispListing*}

\begin{docCommands}[
    doc name = getPIProject
  ]{
    {doc parameter = \sarg\marg{person-id-list}},
    {doc parameter = \marg{person-id-list}}
  }
  Print one or multiple PIs together with their assigned projects.  The
  \meta{person-id-list} is a comma-separated list of ids from the
  \texttt{person} database.  For each PI, the command reads
  \refKey{ref-project-id} from the person entry and prints the referenced
  projects in parentheses using \cs{getProject}.

  The starred version prints firstnames in addition to lastnames.
\end{docCommands}

\begin{dispListing*}{title={Print PIs with their projects.}}
  \getPIProject{MM,KM}
  \getPIProject*{MM,KM}
\end{dispListing*}

\begin{docCommands}[
    doc name = getProjectPI
  ]{
    {doc parameter = \sarg\marg{project-id-list}},
    {doc parameter = \marg{project-id-list}}
  }
  Print one or multiple projects together with their assigned PIs.  The
  \meta{project-id-list} is a comma-separated list of ids from the
  \texttt{project} database.  For each project, the command reads
  \refKey{ref-person-id} from the project entry and prints the referenced PIs
  in parentheses using \refCom{getPI}.

  If a project id is identical to the current project established by
  \refCom{printProjectHead}, only the project itself is printed, just as with
  \refCom{getProject}; its PIs are omitted.  In a list containing several
  projects, this exception applies only to the matching project.

  By default, PI names are shown only for the first \refCom{getProject} or
  \refCom{getProjectPI} reference to each project within a section. Both
  commands share the same remembered state, and a new section resets it.
  Generated tables and lists remain compact. Set
  \refKey{projectPIOncePerSection}|=false| with \refCom{changeSettings} to make
  \refCom{getProject} always compact and \refCom{getProjectPI} always expanded.

  The starred version prints firstnames in addition to lastnames.
\end{docCommands}

\begin{dispListing*}{title={Print projects with their PIs.}}
  \getProjectPI{A01,B02}
  \getProjectPI*{A01,B02}
\end{dispListing*}

\begin{docCommand}{getPIofProject}{\oarg{properties}\marg{project-id}\oarg{delimiter}}
  Print the PIs assigned to a project.  The command reads
  \refKey{ref-person-id} from the project entry and then prints selected
  person fields from the \texttt{person} database.  The optional
  \meta{properties} argument is a comma-separated list of fields to print and
  defaults to \texttt{lastname}.  Typical values are
  \texttt{academicdegree}, \texttt{firstname}, and \texttt{lastname}.  The
  optional \meta{delimiter} separates multiple PIs and defaults to |\,/\,|.
\end{docCommand}

\begin{dispListing*}{title={Print the PIs of a project.}}
  \getPIofProject{A01}
  \getPIofProject[firstname,lastname]{A01}[, ]
\end{dispListing*}

\begin{docCommand}{getPIsWithRole}{\oarg{database}\marg{role}\oarg{raster-options}}
  Print all persons from \meta{database} with the given \meta{role} in PI
  boxes.  The database defaults to \texttt{person}.  Only persons belonging to
  the current funding period are shown.  The optional
  \meta{raster-options} are passed to the underlying \refPkg{tcolorbox}
  raster.
\end{docCommand}

\begin{dispListing*}{title={Print all PIs with a given role.}}
  \getPIsWithRole{spokesperson}[raster columns=1]
  \getPIsWithRole{steering-committee-member}
\end{dispListing*}

We can also compare values from a database against anything. This might be more
relevant for some use in the backend, but who knows if this becomes handy.


\begin{docCommand}{compareEntry}{\oarg{database}\marg{id}\marg{field}\marg{value}
  	\marg{true}\marg{false}}
  Compare an entry with the \meta{id} of \meta{database} against \meta{value}
  and show either \meta{true} or \meta{false}.
\end{docCommand}

For example if you want to have different results when the last name of the
person with the id is |MM|.

\begin{dispListing*}{title={Compare a database entry against something.}}
  (*\refCom{compareEntry}*)[person]{MM}{lastname}{Mustermann}
  {Yes, the name is Mustermann.}
  {No,  the name is not Mustermann.}
\end{dispListing*}

Or here is some concrete and real world example. We check if a person is coming
from the affiliation |RWTH|.
If the person comes from the |RWTH|, then we display the longname, if not, leave
it empty.
\begin{dispListing}
  (*\refCom{compareEntry}*)[MM]{ref-affiliation-id}{RWTH}
  {Rheinisch-Westfälische Technische Hochschule}
  {}
\end{dispListing}

\subsection{Filling tables from the template}
In this section we provide some insights how to fill the tables with the
required information.

\begin{docCommand}{printTable}{\oarg{options}\marg{name}}
  Print one of the predefined template tables.  The \meta{name} is the table
  base name without the suffix \texttt{Table}; for example
  \texttt{ProjectLeaders} calls \cs{ProjectLeadersTable}.  If \meta{name} is a
  braced list, the first item is used as the table base name and the remaining
  items are passed as arguments to that table command.
\end{docCommand}

\begin{docCommand}{printList}{\oarg{options}\marg{name}}
  Print one of the predefined template lists.  The \meta{name} is the list base
  name without the suffix \texttt{List}; for example
  \texttt{ParticipatingInstitutions} calls
  \cs{ParticipatingInstitutionsList}.  The optional \meta{options} are passed
  to the generated list command.
\end{docCommand}

\begin{docCommand}{printPlot}{\marg{plot specification}}
  Print one of the predefined vector plots.  As for \refCom{printTable}, a
  braced list uses its first item as the plot base name and passes the remaining
  items as arguments.  Plot-specific key--values follow the plot name; an
  optional final argument adds caption text.  For example,
  |\printPlot{{ProjectCollaboration}{B06}}| calls the project collaboration
  heatmap focused on B06, while |\printPlot{{Gantt}{B06}}| prints B06's Gantt
  chart.  Select the compact arc layout with
  |\printPlot{{ProjectCollaboration}[layout=arc]{B06}[Caption text]}|.  Heatmap
  columns use a shared dynamic box width based on the project area with the
  most projects, and inactive no-collaboration projects have white backgrounds.
  Project areas are read from the optional |project-area| field of each
  |project| entry; if it is absent, the first character of the project ID is
  used.  Rows are created for every distinct area, ordered by area and project
  ID.  The familiar A, B, and Q colors are retained; other areas use a rotating
  palette.  Override individual colors with
  |area-colors={C=orange,D=violet}| or replace the fallback palette with
  |area-palette={teal,brown,magenta}| in the plot options.  Use
  \refKey{collaborationAreaColors} and
  \refKey{collaborationAreaPalette} in \refCom{changeSettings} to apply the
  same customization to every collaboration plot.
\end{docCommand}

\begin{dispListing*}{title={Print predefined tables, lists, and plots.}}
  \printTable{ProjectLeaders}
  \printList{ParticipatingInstitutions}
  \printTable{{Projects}{A}{Microbiota and metabolic pathways}}
  \printTable{{RequestedFunding}{A01}}
  \printPlot{{ProjectCollaboration}{A01}}
  \printPlot{{Gantt}{A01}}
\end{dispListing*}

\begin{docCommand}{printProjectHead}{\marg{project-id}}
  Start the section for one project.  The command sets the current project,
  creates the project heading, resets project-local counters, starts a
  bibliography refsection, prints the project leaders, and prepares the
  project-specific thumbindex and headers.  Active research and service
  projects also receive the DFG research-areas heading from their
  efKey{research-area} metadata; ending, MGK, and administrative projects do
  not.  For every person id in the
  project's comma-separated \refKey{ref-person-id} value, all names stored in
  \refKey{name-alias} are registered as emphasized bibliography names.  An
  empty alias value is ignored.

  With \refKey{fastcompile-project}, the current-project state, counters,
  labels, a compact running header containing the project ID, and the optional
  bibliography refsection are prepared.  A light hook-based draft watermark is
  added to every shipped page; the calculated heading, project-leader cards,
  contract information, legal-issues table, thumb index, and table-of-contents
  entry are omitted.
\end{docCommand}

\begin{docCommand}{printProjectTail}{}
  Finish the current project section.  The command closes the bibliography
  refsection, resets bold bibliography names, restores the table-of-contents
  depth, and starts a new page.  In \refKey{fastcompile-project}, it only closes
  the optional publication refsection and does not force a page break.
\end{docCommand}

\begin{docCommand}{projectPublicationsHeading}{}
  Print the standard project-publications subsection heading only when
  \refKey{fastcompile-project-show-publications} is enabled.
\end{docCommand}

\begin{docCommand}{projectNocite}{\marg{entry keys}}
  Add project publication entries with \cs{nocite} only when
  \refKey{fastcompile-project-show-publications} is enabled.
\end{docCommand}

\begin{docCommand}{printProjectBibliography}{\oarg{biblatex options}}
  Print a project bibliography only when \refKey{fastcompile-project-show-publications} is
  enabled.  Use these three project-specific commands together so disabling
  publication output also removes its heading and explicit bibliography work.
\end{docCommand}

\begin{docCommand}{printProjectResults}{\marg{key-value list}}
  Print the three result categories required for an ending project.  The keys
  \texttt{quality-assured}, \texttt{other}, and \texttt{patents} each accept a
  comma-separated list of bibliography entry keys.  Use the literal value
  \texttt{none} when a category produced no results.  An omitted or empty key
  retains a drafting instruction instead, so an unfinished list is not
  accidentally reported as empty.

  Every non-empty category is placed in a separate \pkg{biblatex}
  reference segment within the reference section opened by
  \cs{printProjectHead}.  Consequently, category membership is local to the
  current project.  The command also places any pending floats before the
  result lists.

  The combined result-key list is written to the project's auxiliary file.
  On the next normal \LaTeX{} pass, a \texttt{projectReport} bibliography uses
  this list to omit report citations that are printed later as project
  results.  This follows the usual \pkg{biblatex} compilation cycle and does
  not require the entry keys to be duplicated in the report.
\end{docCommand}

\begin{docEnvironment}{projectReport}{}
  Isolate all citations in the project report in their own reference segment
  and print that segment's bibliography at the end of the environment.  Any
  entries assigned to \cs{printProjectResults} for the same project are
  omitted, because they are printed in the later result lists.  Place the
  environment immediately after the report subsection heading and label.
\end{docEnvironment}

\begin{dispListing*}{title={Print the published results of an ending project.}}
  \subsection{Report}
  \begin{projectReport}
    Report text with a general source \cite{general-source} and a project
    result \cite{article-key}.
  \end{projectReport}

  \subsection{Published project results}
  (*\refCom{printProjectResults}*){
    quality-assured = {article-key,book-key},
    other           = {dataset-key,software-key},
    patents         = none
  }
\end{dispListing*}

\begin{docCommand}{dfgTOCprojectPart}{\marg{letter}\oarg{label}\marg{title}}
  Add a project-area heading to the table of contents.  The \meta{letter}
  identifies the project area, \meta{label} defaults to \texttt{Project area},
  and \meta{title} is the text printed after the area label.
\end{docCommand}

\begin{dispListing*}{title={Wrap a project section.}}
  \dfgTOCprojectPart{A}{Microbiota and metabolic pathways}
  \printProjectHead{A01}
  \ldots
  \printProjectTail
\end{dispListing*}


\subsection{Adjustments and Customizations}
\label{doc:customization}

\subsubsection{Documentclass options}
\begin{docCommand}{documentclass}{\marg{key=value}}
  Adjust on a metalevel various options (e.g.
  \refKey{showmarginalia},
  \refKey{fastcompile},
  \refKey{fastcompile-project},
  \refKey{fastcompile-project-show-images},
  \refKey{fastcompile-project-show-publications},
  \refKey{showtags},
  \refKey{showtags-tables},
  \refKey{skip10pub},
  \refKey{cv},
  \refKey{final},
  \refKey{colorscheme})
  for the whole document. Not so much content
  wise but rather organisational.
\end{docCommand}

\begin{docKey}{showmarginalia}
  {\docKeyChoices{true,false}}
  {initially \texttt{false}.}
  Show further information in the marginpar area, esp. total sum in funding tables.
\end{docKey}

\begin{docKey}{fastcompile}
  {\docKeyChoices{true,false}}
  {initially \texttt{false}.}
  Skip generated tables and lists, role-card grids, Gantt charts, and the CV
  publication block.  Metadata and ordinary database-backed references remain
  available, making this the less aggressive compatibility mode.
\end{docKey}

\begin{docKey}{fastcompile-project}
  {\docKeyChoices{true,false}}
  {initially \texttt{false}.}
  Compile authored project text with minimal calculated framing.  This mode
  implies \refKey{fastcompile}, does not load metadata files or execute
  \cs{addEntry}, replaces the calculated project head with state-only setup,
  disables title/front-matter helpers when wrapped with
  \cs{dfgIfFastCompileProjectF}, and uses draft links.  Graphics also default
  to draft placeholders unless \refKey{fastcompile-project-show-images} is enabled.
  Database references fall back to their IDs so prose remains readable.  Generated
  tables and lists retain the same visible skipped-item notice as
  \refKey{fastcompile}.
\end{docKey}

\begin{docKey}{fastcompile-project-show-images}
  {\docKeyChoices{true,false}}
  {initially \texttt{false}.}
  Render images encountered in the selected project while
  \refKey{fastcompile-project} is active.  The metadata, calculated headings,
  generated tables and other fast-mode reductions remain disabled.  With the
  default value, \pkg{graphicx} stays in draft mode and displays image
  placeholders instead.
\end{docKey}

\begin{docKey}{fastcompile-project-show-publications}
  {\docKeyChoices{true,false}}
  {initially \texttt{false}.}
  Show or suppress project publication headings, explicit project \cs{nocite}
  lists, project bibliographies, report references, and ending-project result
  lists while \refKey{fastcompile-project} is active.  Ordinary and final builds
  always enable publication output.  When this option is false in focused
  project mode, inline citation commands render compact bibliography-key
  markers without requesting biber.
\end{docKey}
\begin{docKey}{showtags}
  {\docKeyChoices{true,false}}
  {initially \texttt{false}.}
  Annotate direct database values with their database, row identifier, and
  field, and calculated values with a concise calculation and source-database
  label.  Successive labels alternate between two vertical levels to keep
  adjacent annotations legible.  Both \refKey{fastcompile} and
  \refKey{fastcompile-project} force this option to \texttt{false}.
\end{docKey}
\begin{docKey}{showtags-tables}
  {\docKeyChoices{true,false}}
  {initially \texttt{true}.}
  Allow provenance tags inside generated table cells when \refKey{showtags} is
  enabled.  Set this to \texttt{false} to retain tags in prose and other output
  while keeping tables uncluttered.  It has no effect when \refKey{showtags} is
  disabled.
\end{docKey}
\begin{docKey}{skip10pub}
  {={\meta{\texttt{true}\textbar\texttt{false}}}}
  {initially \texttt{false}.}
  Especially in the CV part, it might take longer to compile the reference list
  with the 10 most important publications. With this set to \meta{true} the
  reference list will be skipped.
\end{docKey}

\begin{docKey}{colorscheme}
  {\docKeyChoices{rgb,cmyk}}
  {initially \texttt{cmyk}.}
  Set the colorscheme according to your needs. For a PDF that is meant for
  only being displayed on a screen, go with \meta{rgb}, for a printed version
  choose \meta{cmyk}.
\end{docKey}



\begin{docKey}{cv}
  {\docKeyChoices{true,false}}
  {initially \texttt{false}.}
  In the document which prints the CVs, set this option to \meta{true}, since
  it will show additional/needed text and modifications.
\end{docKey}


\begin{docKey}{final}
  {\docKeyChoices{true,false}}
  {initially \texttt{false}.}
  When your proposal has been finalised and is ready to be submitted, set this
  option to \meta{true} for the final compilation. The capitalized alias
  \texttt{Final} is accepted for compatibility. This option has
  consequences for
  \refKey{showmarginalia},
  \refKey{showtags},
  \refKey{fastcompile},
  \refKey{fastcompile-project},
  \refKey{skip10pub},
  \refKey{fastcompile-project-show-publications},
  \refKey{colorscheme}, and open-access markers in the bibliography. Open-access
  DOI API lookup is enabled only in final documents when \refKey{doiAPIMail}
  is non-empty and LuaSocket is available.
\end{docKey}

\begin{dispListing*}{title={Example configuration for documentclass mit \texttt{final}-flag}}
  \documentclass[
  	(*\refKey{final}*)           =true,
	% sets to false:
	(*\refKey{showmarginalia}*) =false,
    (*\refKey{showtags}*)       =false,
    (*\refKey{fastcompile}*)    =false,
    (*\refKey{fastcompile-project}*)=false,
  	(*\refKey{skip10pub}*)      =false,
    (*\refKey{fastcompile-project-show-publications}*)=true,
  	(*\refKey{colorscheme}*)    =cmyk
  ]{dfg-crc}
\end{dispListing*}

\subsubsection{Change default settings}
In the \dfgFile{preamble/dfg-customization} you can overwrite the default settings of
this documentclass.

\begin{docCommand}{changeSettings}{\marg{key=value}}
  Customize fonts, logo paths, colors, \refKey{thumbindex}, and other class
  defaults.  The former \cs{changeSetting} spelling remains available as a
  compatibility alias.
\end{docCommand}

The following keys are to be set or changed in \refCom{changeSettings}:

\begin{docKeys}[doc parameter={=\meta{file path}}]{
  {doc name=crcLogoPath,
   doc description=initially \texttt{example-image-a}},
  {doc name=affiliationLogoPath,
   doc description=initially \texttt{example-image-b}}
}
  Select the image files used by \cs{crcLogo} and \cs{affiliationLogo}.
  As with \cs{includegraphics}, the file extension may be omitted.
\end{docKeys}

\begin{docKey}{doiAPIMail}{=\meta{email address}}{initially empty}
  Set the contact address required by the DOI API used for automatic
  open-access markers.  Network lookup remains disabled unless this value is
  non-empty, the document uses |final=true|, and LuaLaTeX has socket support.
\end{docKey}

\begin{docKey}{projectPIOncePerSection}{\docKeyChoices{true,false}}{initially \texttt{true}}
  Show the PIs attached to a project only on that project's first shared
  \refCom{getProject} or \refCom{getProjectPI} reference in each section.
  Later references use the compact project form. Set this to \texttt{false} to
  keep \refCom{getProject} compact and repeat the PI names at every
  \refCom{getProjectPI} reference. References to the current project and
  references in generated tables and lists always remain compact.
\end{docKey}

\begin{docKeys}[doc parameter={=\meta{color list}}]{
  {doc name=collaborationAreaColors,
   doc description=initially \texttt{A=projectA,B=projectB,Q=projectQ}},
  {doc name=collaborationAreaPalette,
   doc description=initially a rotating seven-color palette}
}
  Set collaboration-area colors once for every collaboration plot.
  |collaborationAreaColors| is a key--value mapping such as
  |{A=projectA,B=projectB,C=orange}|.  Areas absent from that mapping receive
  colors from |collaborationAreaPalette| in deterministic area order.  The
  corresponding |area-colors| and |area-palette| plot options override these
  settings for one \refCom{printPlot} call.
\end{docKeys}

\begin{docKeys}[doc parameter={=\meta{euros per year}}]{
  {doc name=salary@prof,
   doc description=initially \texttt{123600}},
  {doc name=salary@groupLeader,
   doc description=initially \texttt{102300}},
  {doc name=salary@postDoc,
   doc description=initially \texttt{88200}},
  {doc name=salary@medDoc,
   doc description=initially \texttt{111000}},
  {doc name=salary@PhD,
   doc description=initially \texttt{81600}},
  {doc name=salary@research,
   doc description=initially \texttt{67200}},
  {doc name=salary@nonResearch,
   doc description=initially \texttt{60000}},
  {doc name=salary@student,
   doc description=initially \texttt{1}},
  {doc name=salary@assistant,
   doc description=initially \texttt{1}}
}
  Set the annual salary rates used to calculate requested staff funding when
  a funding entry omits its explicit yearly sums.  The professorial rate is
  shared by the |prof|, |prof-W2|, and |prof-W3| categories.
\end{docKeys}

\begin{docKeys}[doc parameter={=\meta{euros per animal and week}}]{
  {doc name=animalHousing@mouse,
   doc description=initially \texttt{0.75}},
  {doc name=animalHousing@mouseGnotobiotic,
   doc description=initially \texttt{3.9}},
  {doc name=animalHousing@rat,
   doc description=initially \texttt{1.4}}
}
  Set the weekly animal-housing rates used by the upkeep-of-laboratory-animals
  table.  All salary and animal-housing settings accept integer or decimal
  numbers.
\end{docKeys}

\begin{docKey}{thumbindex}{\docKeyChoices{true,false}}{initially \texttt{true}}
  Shows a thumbindex in the outer margin. This can be customized further.
\end{docKey}


Customize further all about the thumbindex. Modification done in
\dfgFile{dfg-customization}.
\begin{docKey}{thumbindex@pattern}{=\meta{int}}{initially \texttt{10}}
  Define how long the pattern of the \refKey{thumbindex} is until it starts again from
  the top of the page.
\end{docKey}

\begin{docKeys}[doc parameter = {=\meta{dim}}]{
  	{
  		doc name = thumbindex@topmargin,
  		doc description = initially \texttt{3cm},
  	},
  	{
  		doc name = thumbindex@bottommargin,
  		doc description = initially \texttt{3cm},
  	},
  }
  Define the distance from the \meta{topmargin} or the \meta{bottommargin} for the
  position of the first or last thumbindex.
\end{docKeys}


\begin{docKey}{thumbindex@width}{=\meta{dim}}{initially \texttt{1.2cm}}
  Define the \meta{width} of a thumbindex.
\end{docKey}

\begin{docKey}{thumbindex@font}{=\meta{ticklist}}{initially \texttt{\cs{bfseries}\cs{Huge}}}
  Define the \meta{font} style of the text in the thumbindex.
\end{docKey}

\begin{docKeys}[doc parameter = {=\meta{colorname}}]{
  	{
  		doc name =  color@thumbindex@bg,
  		doc description = initially \texttt{black},
  	},
  	{
  		doc name = color@thumbindex@font,
  		doc description = initially \texttt{white},
  	},
  }
  Define the color of the thumbindex: like the background color (\meta{bg}) or
  the color of the \meta{font}
\end{docKeys}

You can adjust any color in this template. In case you want to reuse a custom
color of e.g. your corporate design, set this up first:

\begin{dispListing}
  \definecolor{my-blue}{RGB}{0,84,159}
\end{dispListing}
Afterwards you can use |my-blue| to any of the colors below.

\begin{docKey}{color@reference@boldAuthor}{=\meta{colorname}}{initially \texttt{black}}
  Define the color of emphasized authors, esp. in the various project sections.
\end{docKey}

\begin{docKey}{color@table@headingsBG}{=\meta{colorname}}{initially \texttt{blue-50}}
  Define the background color of a table header (i.e. first row).
\end{docKey}

\begin{docKey}{color@table@headingsBGalt}{=\meta{colorname}}{initially \texttt{blue-25}}
  Define an alternative background color of a table header (i.e. for
  subdividing row).
\end{docKey}

\begin{docKey}{color@table@headingsFont}{=\meta{colorname}}{initially \texttt{black}}
  Define the color for the font in the header rows.
\end{docKey}

\begin{docKey}{color@table@rows}{=\meta{colorname}}{initially \texttt{black-10}}
  Define the color for alternating rows.
\end{docKey}


\begin{docKey}{color@table@rows}{=\meta{colorname}}{initially \texttt{black-25}}
  Define the color for inner table lines
\end{docKey}


\begin{docKey}{color@table@rows}{=\meta{colorname}}{initially \texttt{black}}
  Define the color for outer table lines
\end{docKey}


\begin{docKey}{color@table@noValue}{=\meta{colorname}}{initially \texttt{black-10}}
  Define the color for cells that are supposed to contain no value.
\end{docKey}

\begin{docKey}{color@table@firstColumn}{=\meta{colorname}}{initially \texttt{black-10}}
  Define the color for the first column. This is currently not supported.
\end{docKey}

\begin{docKey}{color@table@firstColumn}{=\meta{colorname}}{initially \texttt{black}}
  Depending on the color of the table heading, we need to modify the
  color of the hyperlink since it can be the same as the
  colorlink from \refPkg{hyperref}.
\end{docKey}

\begin{docKey}{color@table@firstColumn}{=\meta{colorname}}{initially \texttt{black}}
  Depending on the color of the table heading, we need to modify the
  color of the hyperlink since it can be the same as the
  colorlink from \refPkg{hyperref}.
\end{docKey}

\begin{docKeys}[
  	doc parameter = {=\meta{colorname}}
  ]{
  	{
  		doc name        = color@tags@font,
  		doc description = initially \texttt{red-100}
  	},
  	{
  		doc name        = color@tags@line,
  		doc description = initially \texttt{black-50}
  	},
  }
  Adjust the color of \meta{font} or \meta{line} when \refKey{showmarginalia} is activated.
\end{docKeys}

\begin{docKey}{color@item@i}{=\meta{colorname}}{initially \texttt{black}}
  Depending on the color of the table heading, we need to modify the
  color of the hyperlink since it can be the same as the
  colorlink from \refPkg{hyperref}.
\end{docKey}

\begin{docKey}{color@font@alternative}{=\meta{colorname}}{initially \texttt{black-50}}
  Define the alternative color for headline fonts, especially in the CV section, \refKey{cv}.
\end{docKey}

\begin{docKeys}[
  	doc parameter = {=\meta{colorname}}
  ]{
  	{
  		doc name        = color@gantt@frame,
  		doc description = initially \texttt{white}
  	},
  	{
  		doc name        = color@gantt@default,
  		doc description = initially \texttt{blue-25}
  	},
  	{
  		doc name        = color@gantt@alternative,
  		doc description = initially \texttt{green-25}
  	},
  	{
  		doc name        = color@gantt@crosshatch,
  		doc description = initially \texttt{black-10}
  	},
  	{
  		doc name        = color@gantt@important,
  		doc description = initially \texttt{red}
  	},
  	{
  		doc name        = color@gantt@stripe-one,
  		doc description = initially \texttt{blue-25}
  	},
  	{
  		doc name        = color@gantt@stripe-two,
  		doc description = initially \texttt{green-25}
  	},
  }
  Adjust the colors for the various styles of the gantt chart in the project
  section.
  The style |striped| is a alternating combination of
  \refKey{color@gantt@stripe-one} and \refKey{color@gantt@stripe-two}.
\end{docKeys}


\begin{docKeys}{
    {
      doc name        = biblatexstyleCV,
      doc parameter   = {=\meta{style}},
      doc description = initially \texttt{ext-numeric-comp}
    },
    {
      doc name        = biblatexstyleFeatureCV,
      doc parameter   = {=\meta{clist}},
      doc description = initially \texttt{sorting=none}
    },
    {
      doc name        = biblatexstyleProposal,
      doc parameter   = {=\meta{style}},
      doc description = initially \texttt{ext-authoryear-ecomp}
    },
    {
      doc name        = biblatexstyleFeatureProposal,
      doc parameter   = {=\meta{clist}},
      doc description = initially \texttt{dashed=false}
    },
  }
  Adjust the citation and bibliography style separately for standalone CVs
  and proposals.  The feature values are comma-separated additional
  \pkg{biblatex} package options.  Options shared by both modes, including
  \texttt{backend=biber}, \texttt{autocite=inline},
  \texttt{defernumbers=true}, \texttt{giveninits=true}, the citation-name
  limits, and \texttt{maxbibnames=99}, are supplied by the class.
  The class selects the CV pair when the document-class option
  \refKey{cv} is true and the proposal pair otherwise.  The legacy keys
  \texttt{biblatexstyle} and \texttt{biblatexstyleFeature} remain available;
  each applies its value to both modes.
\end{docKeys}

\begin{dispListing*}{title={Configure CV and proposal bibliographies independently.}}
  \changeSettings{
    biblatexstyleCV              = ext-numeric-comp,
    biblatexstyleFeatureCV       = {sorting=none},
    biblatexstyleProposal        = ext-authoryear-ecomp,
    biblatexstyleFeatureProposal = {dashed=false},
  }
\end{dispListing*}

\begin{docKey}{emphasizeAuthors}
  {\docKeyChoices{true,false}}
  {initially \texttt{true}.}
  Emphasize the authors in a e.g. project section when they are authors of a
  referenced publication.
\end{docKey}

\begin{docKeys}{
  	{
  		doc name        = font,
  		doc parameter = {=\meta{name}},
  		doc description = initially \texttt{Noto Serif}
  	},
  	{
  		doc name        = sansfont,
  		doc parameter = {=\meta{name}},
  		doc description = initially \texttt{Roboto Light}
  	},
  }
  Define the main font and the sansserif font.
\end{docKeys}

\begin{docKeys}{
  	{
  		doc name        = fontspec,
  		doc parameter = {=\meta{name}},
  		doc description = initially \texttt{none}
  	},
  	{
  		doc name        = sansfontspec,
  		doc parameter = {=\meta{name}},
  		doc description = initially \texttt{ItalicFont=Roboto-LightItalic,\\
  			BoldFont=Roboto-Medium,\\
  			BoldItalicFont=Roboto-Medium-Italic}
  	},
  }
  Customize font and sansserif font features.
\end{docKeys}

\subsection{Providing further commands}
\subsubsection{Aims and Workpackages}

For writing aims and workpackages we provide some special commands and features, including a gantt-chart.

\begin{docEnvironment}{aims}{}
  Environment to be used in a project section to summarize in a condensed way the aims of the project.
\end{docEnvironment}

\begin{docCommand}{addAim}{\marg{label}}
  Add an aim within the \refEnv{aims} environment. You can refer to this aim by using \refCom{getAim}\marg{label}.
\end{docCommand}

\begin{dispListing*}{title={Example use of \cs{addAim}}}
  \begin{aims}
    \addAim{A} Establish the first central objective of the project.
    \addAim{B} Develop the second central objective of the project.
    \addAim{C} Validate the results in the final objective.
  \end{aims}

  In \getAim{A,B,C} we define the project objectives.
\end{dispListing*}

\begin{docCommand}{getAim}{\marg{label}}
  Refer to an aim with the \marg{label} in the \refEnv{aims} environment.
  You can refer to multiple aims, too: |\getAim{A,B,C}|.

  The default is referencing the aims of the same project.
  You can also refer to an aim of a different project:
  \cs{getAim}\oarg{project-id}\marg{label}.
\end{docCommand}


\begin{docEnvironment}{workpackages}{}
  Environment to be used in a project section when workpackages are written.
  This environment contains all descriptions of the workpackages that are introduced by
  \refCom{addWP}.
\end{docEnvironment}

\begin{docCommand}{addWP}{\marg{label}\marg{key=values}}
  Add a workpackage with the \marg{label} to the list.
  Further specifications are done using \refKey{name},
  \refKey{description} (text is used for the Gantt chart printed with
  \refCom{printPlot}),
  \refKey{periodStart},
  \refKey{periodEnd},
  \refKey{style}.
  At the top level, the \refKey{name} value is printed as the bold work-package
  heading.  Sub-workpackages do not print a \refKey{name}; their authored prose
  starts directly after the list label.  Immediate source whitespace, including
  a blank line after \cs{addWP}, is consumed without inserting another space.
\end{docCommand}

\begin{dispListing*}{title={Example use of \cs{addWP}}}
  \begin{workpackages}
    \addWP{wp1}{
      name        = First workpackage,
      description = {The first workpackage for the Gantt chart},
      periodStart = 1,
      periodEnd   = 6,
      style       = alternative,
    }

    Here you describe the first workpackage in detail.

    \addWP{wp2}{
      name        = Second workpackage,
      description = {The second workpackage for the Gantt chart},
      periodStart = 7,
      periodEnd   = 12,
      style       = important,
    }
  \end{workpackages}
  In \getWP{wp1,wp2} we describe the project plan.
\end{dispListing*}


Furthermore you can adjust the color of referencing an aim.
By default it is the same color as \refKey{color@reference@boldAuthor}, but if you would like to change it, add
|\colorlet{referenceAim}|\marg{your-color}
to the begin of your document.

\begin{docCommand}{getWP}{\marg{label}}
  Refer to a workpackage with the \marg{label} in the \refEnv{workpackages} environment.
  You can refer to multiple workpackages, too: |\getWP{wp2,wp3,wp4}|.

  The default is referencing the workpackage of the same project.
  You can also refer to a workpackage of a different project:
  \cs{getWP}\oarg{project-id}\marg{label}.
\end{docCommand}



While some keys have been described already, here is what is missing so far:
\begin{docKey}{style}{\docKeyChoices{alternative,crosshatch,important,striped}}{initially: \texttt{default}}

  Define the style of the bar of this workpackage in the gantt-chart.

  For customizing the colors of the various styles have a look at:
  \refKey{color@gantt@default},
  \refKey{color@gantt@alternative},
  \refKey{color@gantt@crosshatch},
  \refKey{color@gantt@important},
  \refKey{color@gantt@stripe-one} and
  \refKey{color@gantt@stripe-two}.
\end{docKey}

\begin{docCommand}{printPlot}{\marg{plot specification}}
  Print a generated plot through the common dispatcher.  Use
  |\printPlot{{Gantt}{A01}}| for a project's Gantt chart and
  |\printPlot{{ProjectCollaboration}{A01}}| for its collaboration heatmap.
  The heatmap is the default; select the low arc diagram with |layout=arc|
  in the optional argument immediately after |{ProjectCollaboration}|.  The
  aliases |heatmap| and |arc-diagram| are also accepted as bare keys.  Every arc
  reaches the same peak height; its span identifies the connected project but
  does not encode a weight.  Project identifiers are printed inside the arc
  nodes, immediately above rules spanning their complete project areas.  Both
  plot types accept additional caption text after the project id, for example
  |\printPlot{{ProjectCollaboration}[layout=arc]{A01}[Caption text]}|.  Without
  additional caption text, the caption occupies the outer margin and the plot
  retains the complete text width, as does the default Gantt chart.  In the
  heatmap, the largest project area determines one shared dynamic box width;
  the measured width of the longest area label determines where its grid
  starts, and all columns fill the remaining text width.  Projects without a
  collaboration are retained with a white background in both layouts.
  Rows are ordered deterministically by |project-area| and project ID.  Use
  |area-colors={C=orange,D=violet}| for explicit mappings or
  |area-palette={teal,brown,magenta}| to customize colors assigned to all
  otherwise unmapped areas.
\end{docCommand}

\begin{docCommand}{printGantt}{\marg{project-id}\oarg{additional caption}}
  Compatibility alias for the former public spelling.  New documents should
  use |\printPlot{{Gantt}{A01}}| or
  |\printPlot{{Gantt}{A01}[Additional caption text]}|.
\end{docCommand}



\subsubsection{Thumbindex}
In your document you can use the following commands for displaying or switching
off a thumbindex \emph{locally}.
\begin{docCommand}{printThumbIndex}{\oarg{color}\marg{string}}
  Define locally the \meta{color} of the thumbindex and what to be displayed
  (\meta{string}).
  Be aware that you may need to execute this command before a \cs{clearpage} etc.
\end{docCommand}

\begin{docCommand}{printThumbIndexOff}{}
  From the next page on the thumbindex is switched off.
\end{docCommand}


\subsubsection{Boxes}
\begin{docEnvironment}{dfgBoxEnv}{\oarg{further specifications}}
  Box environment to be used for highlighting things
  To be used in \dfgFile{content}.
\end{docEnvironment}

% \begin{docEnvironment}{dfgTitleBox}{\oarg{further specifications}}
% Box environment to be used for e.g. a title page
% To be used in \dfgFile{content}
% \end{docEnvironment}

\begin{docEnvironment}{dfgSummaryBox}{\oarg{further specifications, e.g. `title=NN`}}
  Box environment to be used for e.g. summaries that are lists.
  Use \cs{item} for bulletpoints. To be used in \dfgFile{content}
\end{docEnvironment}

\begin{dispListing*}{title={Example use of a summary box}}
  \begin{dfgSummaryBox}[title={Spotlights: Moving Forward}]
  	\item New focus areas in the new funding period
  	\item Best research ever
  \end{dfgSummaryBox}
\end{dispListing*}

\begin{docCommand}{dfgBox}{\oarg{further specifications}}
  Box environment to be used for anything.
  To be used anywhere in the text.
\end{docCommand}
\begin{dispListing*}{title={Example of a minimal box }}
  \dfgBox[title={Important aspect}]
  {Be aware of researcher's results.}
\end{dispListing*}

\subsubsection{Title page and affiliation helpers}

\begin{docCommand}{dfgApplicantAffiliationsTF}{\marg{singular}\marg{plural}}
  Use \meta{singular} when |meta.ref-affiliation-id| contains one applicant
  affiliation and \meta{plural} when it contains several.  The title page,
  applicant-university section heading, bylaws, and declarations use this
  helper for their grammar.  \cs{theCRCaffiliation} and
  \cs{theCRCaffiliationLocation} contain the complete human-readable name and
  location lists.  The first id is the coordinating university and is exposed
  as \cs{theCRCCoordinatingAffiliation}; any remaining ids are exposed as
  \cs{theCRCOtherApplicantAffiliations}, matching the two separate fields on
  the DFG title page.
\end{docCommand}

\begin{docCommand}{crcLogo}{\oarg{graphics-options}}
  Print the CRC logo.  The optional \meta{graphics-options} are passed to
  \cs{includegraphics}.  The actual file is configured with
  \refKey{crcLogoPath} through \cs{changeSettings} and remains available as
  \cs{crcLogoPath}.
\end{docCommand}

\begin{docCommand}{affiliationLogo}{\oarg{graphics-options}}
  Print the affiliation logo.  The optional \meta{graphics-options} are passed
  to \cs{includegraphics}.  The actual file is configured with
  \refKey{affiliationLogoPath} through \cs{changeSettings} and remains
  available as \cs{affiliationLogoPath}.
\end{docCommand}

\begin{docCommand}{Hrule}{\oarg{key=value}}
  Print a configurable horizontal rule.  The available keys are
  \texttt{color}, \texttt{above}, \texttt{below}, and \texttt{thickness}.
\end{docCommand}

\begin{docCommand}{printSignature}{\oarg{database}\marg{id-description-pairs}}
  Print one signature block for each \marg{id}\marg{description} pair.  The
  \meta{database} defaults to \texttt{person}.  Inside \meta{description},
  \cs{theAffiliationOfRoleID} contains the person's affiliation id and can be
  used for further database lookups.
\end{docCommand}

\begin{docCommand}{printSignaturesWithRole}{\oarg{database}\marg{role}\marg{description}}
  Print a signature block for every current-period person with \meta{role}.
  This is used for the rector, chancellor, or president of every applicant
  university, so a proposal with several applicants does not require a
  hard-coded list of person ids.  Inside \meta{description},
  \cs{theAffiliationOfRoleID} refers to the affiliation of the current
  signatory.
\end{docCommand}

\begin{dispListing*}{title={Print signature blocks.}}
  \printSignature{
    {spokesperson}{(Spokesperson of \crc)}
    {rector}{(Rector of \getEntry[affiliation]{\theAffiliationOfRoleID}{name})}
  }
\end{dispListing*}

\begin{docCommand}{dfgInstitutionList}{\oarg{database}\marg{person-id}\oarg{options}}
  Print the institutions assigned to a person.  The \meta{database} defaults
  to \texttt{person}.  The command reads \refKey{ref-institution-id} from the
  person entry and then resolves the referenced entries in the
  \texttt{institution} and \texttt{affiliation} databases.  Options are
  \texttt{abbreviation}, \texttt{narrow}, \texttt{noaddress},
  \texttt{nozip}, and \texttt{nolocation}.

  In the standard layout, every institution prints the institution name,
  affiliation name, street, ZIP code, location, and country when these values
  are available.  If a person references more than one institution, the entries
  are separated by a paragraph break with a small vertical gap.  If an
  institution row has an empty \refKey{name}, the output starts directly with
  the affiliation name.

  \begin{description}
    \item[\texttt{abbreviation}] Use the institution's
      \refKey{abbreviation} instead of its full \refKey{name}.  If the
      abbreviation is absent, the full name is used for compatibility.
    \item[\texttt{narrow}] Print a compact inline form.  Fields inside one
      institution are separated by commas and multiple institutions by
      semicolons.  This is useful in narrow CV/table cells.
    \item[\texttt{noaddress}] Omit the street address.
    \item[\texttt{nozip}] Omit the ZIP code.
    \item[\texttt{nolocation}] Omit the location and country.
  \end{description}
\end{docCommand}

\begin{dispListing*}{title={Print institutions for a person.}}
  \dfgInstitutionList{MM}
  \dfgInstitutionList{MM}[abbreviation,noaddress,nolocation,nozip,narrow]
\end{dispListing*}

\begin{dispListing*}{title={Minimal metadata for institution-list output.}}
  (*\refCom{addEntry}*){affiliation}{
    (*\refKey{id}*)            = {RWTH},
    (*\refKey{name}*)          = {RWTH Aachen University},
    (*\refKey{addressStreet}*) = {Templergraben 55},
    (*\refKey{addressZIP}*)    = {52062},
    (*\refKey{location}*)      = {Aachen},
    (*\refKey{country}*)       = {Germany},
  }
  (*\refCom{addEntry}*){institution}{
    (*\refKey{id}*) = {IAIS},
    (*\refKey{name}*) = {Institute for Applied Immunology and Systems Biology},
    (*\refKey{abbreviation}*) = {IAIS},
    (*\refKey{ref-affiliation-id}*) = {RWTH},
  }
  (*\refCom{addEntry}*){person}{
    (*\refKey{id}*) = {MM},
    (*\refKey{ref-institution-id}*) = {IAIS},
  }
\end{dispListing*}

\begin{dispListing*}{title={One person with multiple institutions.}}
  (*\refCom{addEntry}*){person}{
    (*\refKey{id}*) = {MM},
    (*\refKey{ref-institution-id}*) = {IAIS,RWTH-main},
  }

  \dfgInstitutionList{MM}
  \dfgInstitutionList{MM}[abbreviation,narrow,noaddress,nozip,nolocation]
\end{dispListing*}

\begin{docCommand}{checkFile}{\marg{file}}
  Input \meta{file} if it exists.  If the file is missing, compilation
  continues and a warning is written to the log.  This is used for optional
  metadata, customization, and content files.
\end{docCommand}


\subsubsection{ORCiD}
The ORCiD is foremost used in the CV section and stated in the entry of a
person. So there is no need for a manual insertion of it. However you can do so
using one of two following commands.

\begin{docCommand}{ORCiD}{\marg{number}}
  Display the ORCiD with the given \meta{number}.
  Adding the ORCiD logo in front.
\end{docCommand}

\begin{docCommand}{getORCiD}{\marg{id}}
  Display the ORCiD of the person with the given \meta{id}
  If there is no |orcid|-entry in the database for this person, then a warning will be
  thrown and you can read about in the |.log|-file.
\end{docCommand}


\subsection{Best Practises and Suggestions}
\subsubsection{Figures}
For inserting figures we highly recommend to use the command from the package |hvfloat|.
\begin{docCommand}{hvFloat}{\sarg\oarg{options}+\marg{floattype}\marg{floatingobject}%
  	\oarg{shortcaption}\marg{longcaption}\marg{label}}
\end{docCommand}


\begin{dispListing}
  \hvFloat[% optional arguments
  	capPos   =bottom,
  	floatPos =!t
  ]
  {figure} % defining the environment
  {\includegraphics[width=\linewidth]{X01-figure-01}} % figure
  [FAIR]% shortcaption
  {The FAIR-principles} % long caption
  {fig:X01-figure-01} % label
\end{dispListing}

\subsection{Bibliography/Publication}
\subsubsection{Equal contribution}
In some cases it is very important to state that two or more authors
have contributed equally to a publication.
Take the following publication as example:
\begin{dispListing}
  Schneider, K.M.*, C. Elfers*, A. Ghallab, C.V. Schneider,
  E.J.C. Galvez, A. Mohs, W. Gui, L.S. Candels, T.H. Wirtz,
  S. Zuehlke, M. Spiteller, M. Myllys, A. Roulet, A.
  Ouzerdine, B. Lelouvier, K. Kilic, L. Liao, A. Nier, E.
  Latz, I. Bergheim, C.A. Thaiss, J.G. Hengstler, T.
  Strowig, and C. Trautwein. 2020. Intestinal Dysbiosis
  Amplifies Acetaminophen-Induced Acute Liver Injury. Cell.
  Mol. Gastroenterol. Hepatol. 11(4):909-933. *equal contribution
\end{dispListing}
The first authors have \texttt{equal contribution}.
In the bibtex-entry add \emph{two} lines:
\begin{dispListing}
  author+an       = {1=equal;2=equal},
  addendum        = equal,
\end{dispListing}
With \texttt{author+an} you annotate the authors, the numbers refer to the
position of the author in the authors's list.

The complete entry of the mentioned example looks like:

\begin{dispListing}
@article{schneider2020a,
  author          = {Schneider, Kai Markus and Elfers, Carsten and Ghallab,
  		Ahmed and Schneider, Carolin Victoria and Galvez, Eric J.C.
  		and Mohs, Antje and Gui, Wenfang and Candels, Lena Susanna and
  		Wirtz, Theresa Hildegard and Zuehlke, Sebastian and Spiteller,
  		Michael and Myllys, Maiju and Roulet, Alain and Ouzerdine,
  		Amirouche and Lelouvier, Benjamin and Kilic, Konrad and Liao,
  		Lijun and Nier, Anika and Latz, Eicke and Bergheim, Ina and
  		Thaiss, Christoph A. and Hengstler, Jan G. and Strowig, Till
  		and Trautwein, Christian},
  author+an       = {1=equal;2=equal},
  date            = 2020,
  title           = {Intestinal Dysbiosis Amplifies Acetaminophen-Induced Acute
  		Liver Injury},
  volume          = 11,
  pages           = {909--933},
  language        = {pt},
  journal         = {Cellular and Molecular Gastroenterology and Hepatology},
  doi             = {10.1016/j.jcmgh.2020.11.002},
  number          = 4,
  source          = {Crossref},
  url             = {https://doi.org/10.1016/j.jcmgh.2020.11.002},
  publisher       = {Elsevier BV},
  issn            = {2352-345X},
  date            = 2021,
  addendum        = equal,
}
\end{dispListing}
\subsubsection{Shared last authorship}
Very similar to the \texttt{equal contribution}-part there is also a way to
specify authors who \texttt{shared last authorship}.

In the bibtex-entry add \emph{two} lines:

\begin{dispListing}
  author+an       = {1=sharedLast;2=sharedLast},
  addendum        = sharedLast,
\end{dispListing}

Here is a complete example.

\begin{dispListing}
@Article{roessner2021a,
  Author          = {Roessner, P.M. and Cid, L.Llao and Lupar, E. and Roider,
  		T. and Bordas, M. and Schifflers, C. and Arseni, L. and
  		Gaupel, A.C. and Kilpert, F. and Krotschel, M. and
  		Arnold, S.J. and Sellner, L. and Colomer, D. and
  		Stilgenbauer, S. and Dietrich, S. and Lichter, P. and
  		Izcue, A. and Seiffert, M.},
  Date            = {2021},
  author+an       = {17=sharedLast;18=sharedLast},
  Addendum        = sharedLast,
  Keywords        = {MM-A},
  Title           = {{EOMES} and {IL}-10 regulate antitumor activity of T
  		regulatory type 1 {CD4(+)} T cells in chronic lymphocytic
  		leukemia},
  Volume          = {35},
  Pages           = {2311--2324},
  Language        = {en},
  JournalTitle    = {Leukemia}
}
\end{dispListing}


\subsubsection{Emphasizing authors}
\label{sec:doc:bold-authors}
You can have certain authors in bold letters in your bibliography section to
highlight e.g. the core people of the proposal.

\textbf{Notice:} This feature is automatically triggered (unless switched off, see \refKey{emphasizeAuthors})
for the CV section (see \ref{sec:doc:cv-basic}). We explain its function for additional use.


To add a person to the (sectioned) bibliography use \cs{addboldnames}.

\begin{docCommand}{addboldnames}{
  \marg{\brackets{nn},
  	\brackets{nn},
  	\brackets{nn}}
}

Displaying authors in an emphasized way.
\end{docCommand}

Notice that for each variation of a person’s name you have to add one set of
\marg{nn}.
For example you have an author with different spellings in your |.bib|-file, you
have to list all of them to get them in bold letters (or adjust the entries in
your |.bib|-file).

\begin{dispListing}
  \addboldnames{
  	{Max Mustermann},
  	{M. Mustermann},
  	{Mustermann, Max H.},
  	{Mustermann, Max Heinrich}
  }
\end{dispListing}

After a (sectioned) bibliography and you do not want to display the before
defined authors in bold letters anymore, you can use \cs{resetboldnames}:
\begin{docCommand}{resetboldnames}{}
  Switch off showing the under \refCom{addboldnames} defined names.
\end{docCommand}


In case you do not need to have authors in bold letters
you can disable the feature modification done in \dfgFile{dfg-customization}.


\subsubsection{Providing publication information}

Providing the most relevant publications is done through the referenced
|.bib|-file.
Within a bibtex-entry you need to add a keyword with certain values to it
preceeded with the ID of the person.

\begin{itemize}
  \item[-A:]Category A – Articles in peer-reviewed journals, contributions to
        peer-reviewed conferences or to anthology volumes, and book publications
  \item[-B:] Category B – Any other form of published results
\end{itemize}
For example:
\begin{dispListing}
  @article{...,
  		keywords = {<ID>-A},
  	}
\end{dispListing}

Of course several people can use the same reference for this section:

\begin{dispListing}
  @article{...,
  		keywords = {<ID1>-A, <ID2>-B, <ID3>-A},
  	}
\end{dispListing}

Open-access markers are handled by |biblatex-ext-oa|. If the API-based
open-access request does not work for a publication, add the fallback
annotation directly to the relevant |.bib| entry:

\begin{dispListing}
  @article{...,
  		options         = {openaccess=auto},
  		doi+an:default  = {=openaccess},
  	}
\end{dispListing}



\DocInput{\jobname.dtx}
\printbibliography
\end{document}
%</driver>
% \fi
% \section{Code Documentation}
% The following part is meant for developers. Don't worry if you might not
% understand parts of the code.
% We try to use as much \LaTeX3 as possible for a more granular data handling.
% \iffalse
%<*file>
%<*cls>
% \fi
% \subsection{Documentclass}
%
% The class requires the June 2022 LaTeX kernel, whose native
% \cs{ProcessKeyOptions} interface processes class options through expl3 key
% families.  \cs{ProvidesExplClass} declares the class to the kernel and
% simultaneously activates the \pkg{expl3} (LaTeX3) syntax, so every line
% from here onwards may use the \texttt{:}, \texttt{\_} and \texttt{@@}
% conventions of the L3 programming layer.
%
% The \meta{version} and \meta{date} values come from the single definition
% at the very top of the |.dtx| file (|\def\dfgVersion| etc.), so a version
% bump only ever needs to be made in one place.
%    \begin{macrocode}
\NeedsTeXFormat{LaTeX2e}[2022-06-01]
\ProvidesExplClass
{dfg-crc}
{\dfgVersionDate}
{\dfgVersion}
{Create DFG Collaborative Research Centre proposals and CVs}
%    \end{macrocode}
% \subsubsection{Message catalogue}
%
% All user-visible diagnostics are declared here once using \cs{msg\_new:nnn}
% from the L3 message system.  Centralising them serves several purposes:
% \begin{enumerate}
%   \item The exact wording of every log line can be reviewed and updated in
%         one place without searching through the entire code.
%   \item They are bound to the \texttt{dfg} module name, so a user can grep
%         the |.log| with |grep "Package dfg"| to see a condensed overview.
%   \item Using the L3 message system instead of raw |\PackageWarning| gives
%         consistent formatting, the file\/line context via
%         \cs{msg\_line\_context:}, and the ability to suppress or redirect
%         messages at a global level with \cs{msg\_redirect\_module:nnn}.
% \end{enumerate}
% The engine check fails early with a direct instruction instead of letting
% \pkg{fontspec} or a later \cs{directlua} call produce a less helpful error.
% The next message is emitted when an optional input file (e.g.\ a metadata
% or preamble fragment) cannot be found on the search path.  Compilation is
% not aborted, but the user is strongly warned.
%    \begin{macrocode}
\msg_new:nnn { dfg } { unsupported-engine }
{
  The~dfg-crc~class~requires~LuaLaTeX.^^J
  Compile~this~document~with~lualatex~or~latexmk~-lualatex.
}
\sys_if_engine_luatex:F
  { \msg_fatal:nn { dfg } { unsupported-engine } }

\msg_new:nnn { dfg } { file-not-found }
{ File~'#1'~not~found.^^J
  ~You~can~proceed~without~it~
  but~it~is~not~recommended.
}
%    \end{macrocode}
% \paragraph{database-not-found}
% Emitted by \refCom{getEntry}, \refCom{compareEntry} and each table command when the
% database name passed by the user does not exist in the datatool register.
% The most common cause is a typo in the database name, or calling a retrieval
% command before the corresponding \refCom{addEntry} block has been processed.
%    \begin{macrocode}
\msg_new:nnn { dfg } { database-not-found }
{ Unknown~ database~ name:~ #1^^J^^J
  Database~'#1'~not~found~\msg_line_context:.~
  Either~you~have~misspelled~it~or~
  ~the~database~has~not~yet~been~created.
}
%    \end{macrocode}
% \paragraph{database-name-not-given}
% Fired when the optional \meta{database} argument of \refCom{getEntry} is empty
% because \cs{tmpLocalDB} has not been set and no explicit database name was
% supplied.  The message text suggests two remedies: set \cs{tmpLocalDB} at
% the top of a section, or pass the database name inline.
%    \begin{macrocode}
\msg_new:nnn { dfg } { database-name-not-given }
{ Missing~ database~ name~ for~ entry:~ #1^^J ^^J
  You~forgot~to~pass~a~database~name~\msg_line_context:.~
  You~can~provide~a~name~with~ e.g.~ '\def\tmpLocalDB{<database>}'
  ~or~within~entries~like~
  '\getEntry[<database>]{<id>}{<field>}'.
}
%    \end{macrocode}
% \paragraph{biblatex-ext-oa-doiapi-unavailable}
% Warns when \pkg{biblatex-ext-oa}'s DOI API integration cannot be enabled
% because |socket.http| is not available in the current LuaTeX run.  The
% package is still loaded, so manual BibTeX annotations continue to work.
%    \begin{macrocode}
\msg_new:nnn { dfg } { biblatex-ext-oa-doiapi-unavailable }
{ biblatex-ext-oa~ DOI~ API~ lookup~ disabled:~ LuaSocket~ module~
  'socket.http'~ is~ not~ available~ in~ this~ LuaTeX~ run.~
  Compile~ with~ '--socket'~ to~ enable~ DOI~ API~ requests.~
  Open-access~ markers~ still~ work~ from~ manual~ BibTeX~ annotations.
}
%    \end{macrocode}
% \paragraph{biblatex-ext-oa-doiapi-email-missing}
% DOI lookups require a real contact address.  An empty default keeps network
% access opt-in and prevents all users of the class from sharing a placeholder
% or maintainer address.
%    \begin{macrocode}
\msg_new:nnn { dfg } { biblatex-ext-oa-doiapi-email-missing }
{ biblatex-ext-oa~ DOI~ API~ lookup~ disabled:~ no~contact~address~was~set.^^J
  Set~'doiAPIMail=<address>'~with~\string\changeSettings~to~enable~lookups.
  Open-access~markers~still~work~from~manual~BibTeX~annotations.
}
%    \end{macrocode}
% \paragraph{missing-orcid}
% Triggered specifically by \refCom{getORCiD} when the |orcid| field is absent
% or empty for the requested person.  The message body reproduces the exact
% \refCom{addEntry} snippet the user needs to fill in, lowering the barrier to
% fixing the data.
%    \begin{macrocode}
\msg_new:nnn { dfg } { missing-orcid }
{DB:~'#1';~ID:~'#2';~null/empty:~'orcid'.~^^J^^J
  The~ORCiD~for~the~person~with~the~ID~'#2'~has~not~been~given.~
  You~asked~for~it~\msg_line_context: ~^^J
  If~the~person~has~an~ORCiD, ~go~to~where~you~have~written~^^J
  \addEntry{#1}{^^J
  	id   =#2, ^^J
  	orcid=<INSERT~ORCID~HERE>^^J
  }
}
%    \end{macrocode}
% \paragraph{missing-key}
% Generic warning for any database field that is null or empty when
% \refCom{getEntry} tries to retrieve it.  The check is deliberately suppressed
% during the tabularray cell-measuring pass (|\lTblrMeasuringBool| is |true|)
% to prevent each cell from generating duplicate log entries — tabularray
% renders each cell twice for width calculation before the final output pass.
%
%    \begin{macrocode}
\msg_new:nnn { dfg } { missing-key }
{DB:~'#1';~ID:~'#2';~null/empty:~'#3'.^^J^^J
  In~ the~ database~ '#1', the~ key~ '#3'~ which~ belongs~ to~ the~ ID~ '#2'~
  is~ either~ null/not~ given~ or~ simply~ empty.~^^J
  You~ asked~ for~ it~ \msg_line_context:  }
%    \end{macrocode}
% \paragraph{item-skipped / \cs{dfgItemSkipped}}
% Tables built from the datatool databases are the most expensive part of
% each compilation run because they involve full database queries.  When
% either |fastcompile| mode is active, generated table/list commands call
% \cs{dfgItemSkipped} instead of rendering the real content.  This
% prints a red placeholder in the PDF and issues an |item-skipped| note to
% the log.  The colour |red| is overridden to |white| when |final=true|, so
% the placeholder is invisible in a submission build.
%    \begin{macrocode}
\msg_new:nnn { dfg } { item-skipped }
{Item~ #1~ skipped~ (compile-time).^^J
  To~ see~ the~ item,~ disable~ fast~ compilation^^J
  in~ the~ documentclass-options.^^J
  The~ item~ is~ \msg_line_context:  }
\NewDocumentCommand{\dfgItemSkipped}{m}{%
  \msg_note:nne {dfg}{item-skipped}{ #1 }
  \group_begin:
  \color{error}
  Item~ \emph{\normalcolor#1}~ skipped~ due~ to~ faster~ compilation.~\\
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  { To~ see~ the~ item,~ set~ \texttt{fastcompile-project=false}~(default)~ }
  { To~ see~ the~ item,~ set~ \texttt{fastcompile=false}~(default)~ }
  in~ the~ documentclass-options.
  \group_end:
}
%    \end{macrocode}
% \paragraph{research-area-not-found}
% The property list \cs{g\_@@\_dfg\_research\_areas\_prop} contains every
% DFG research area code from the official classification list.  When a code
% stored in the |project| database does not appear in that map the formatted
% label cannot be generated and this warning is raised.  The raw code is still
% printed so the proposal remains compilable.
%    \begin{macrocode}
\msg_new:nnn { dfg } { research-area-not-found }
{ Unknown~ research~ area:~ #1^^J^^J
  Doublecheck~ the~ research~ area~ in~ the~ database:~^^J
  \addEntry{project}{~^^J
  	research-area~ =~ {#1}~^^J
  }
}
%    \end{macrocode}
% \paragraph{item-not-matched}
% Raised as a generic fall-through in \cs{str\_case:VnF} dispatchers where
% a string value is not matched by any of the expected branches.
%    \begin{macrocode}
\msg_new:nnn { dfg } { item-not-matched }
{ The~ string~ '#1'~does~not~match.~^^J^^J
  Doublecheck~ your~input!~^^J
  The~ item~ is~ \msg_line_context:
}
%    \end{macrocode}
% \paragraph{unknown-key and invalid-value}
% These two messages are the default handlers wired into the
% |unknown .code:n| and |\meta{choice} / unknown .code:n| slots of every
% \cs{keys\_define:nn} block.  They give the user immediate feedback in
% the log whenever a key name is misspelled or a value is outside the
% permitted set, instead of silently ignoring the input or producing a
% cryptic low-level TeX error.
%    \begin{macrocode}
\msg_new:nnn { dfg } { unknown-key }
{
  Key~ '\l_keys_path_str'~ is~ unknown~ and~ being~ ignored.~^^J^^J
  You~passed~the~value~'#1'~ to~ that~ key.~^^J
  Doublecheck~for~spelling~errors.~^^J
  The~ item~ is~ \msg_line_context:
}
%    \end{macrocode}
%   Warning issued when a key receives a value outside its set of
%   permitted alternatives.  This message is the standard fallback for
%   keys defined with the \refPkg{l3keys} \texttt{.choices:nn} property
%   when their |/unknown| handler delegates to the dispatcher
%   \cs{person\_questions\_invalid:n}.  The two arguments are the rejected
%   value and a comma-separated list of the values that would have been
%   accepted.  The full key path is taken from \cs{l\_keys\_path\_str}, so
%   the warning identifies not only the offending value but also which
%   key was being set when the error occurred -- useful when the same
%   value name (such as |yes| or |1|) is plausible for several keys but
%   only valid for some of them.  The warning does not stop processing;
%   the database entry is simply not created for the rejected value, and
%   subsequent keys in the same \refCom{addEntry} call continue to be parsed.
%    \begin{macrocode}
\msg_new:nnn { dfg } { invalid-value }
{
  Invalid~value~'#1'~for~key~'\l_keys_path_str'.~^^J^^J
  Allowed~values~are:~'#2'.~^^J
  The~ item~ is~ \msg_line_context:
}
\msg_new:nnn { dfg } { invalid-project-count-area }
{
  No~active,~list-considered~projects~were~found~for~area~'#1'~in~
  \string\getProjectCount;~printing~0.
}
\msg_new:nnn { dfg } { collaboration-focus-not-found }
{
  Cannot~draw~the~project~collaboration~plot:~focus~project~'#1'~is~not~an~
  eligible~row~of~the~project~database.
}
\msg_new:nnn { dfg } { collaboration-target-not-found }
{
  Ignoring~collaboration~'#1--#2':~project~'#2'~is~not~an~eligible~row~of~
  the~project~database.
}
%    \end{macrocode}
%
%   Warning issued when a date-typed key receives a value that does not
%   match the ISO-8601 calendar-date shape \texttt{YYYY-MM-DD}.  Used by
%   the contract-information helper \cs{dfg\_contract\_date:nn} for the
%   fields \refKey{C2a}, \refKey{C2b}, and \refKey{C3a}, all of which
%   are expected to hold dates.  The two arguments are the field name
%   and the offending value.  The check is purely structural: it
%   verifies that the value consists of four digits, a hyphen, two
%   digits, a hyphen, and two digits, but it does not validate the
%   resulting date as a real calendar entry (so \texttt{2025-13-45}
%   passes the format check).  When the warning fires, the supplied
%   value is still recorded in the database so the typeset output makes
%   the malformed entry visible; this trades log-cleanliness for ease
%   of locating the source of the problem in the rendered document.
%    \begin{macrocode}
\msg_new:nnn { dfg } { invalid-date }
{ Field~ '#1'~ has~ value~ '#2'~ which~ is~ not~ a~ valid~ ISO-8601~ date~ (YYYY-MM-DD). }
%    \end{macrocode}
% \paragraph{Requested-funding staff diagnostics}
% The staff roster is deliberately permissive at output time: incomplete or
% unresolved records remain visible in the document while these messages make
% the underlying metadata problem searchable in the log.
%    \begin{macrocode}
\msg_new:nnn { dfg } { requested-staff-no-data }
{ No~RequestedFundingStaff~data~have~been~provided~for~project~'#1'. }
\msg_new:nnn { dfg } { requested-staff-required }
{ RequestedFundingStaff~entry~is~missing~required~metadata:~#1. }
\msg_new:nnn { dfg } { requested-staff-missing-field }
{ Project~'#1':~requested-funding~staff~#2~is~missing. }
\msg_new:nnn { dfg } { requested-staff-unresolved-person }
{ Project~'#1':~person~reference~'#2'~cannot~be~resolved. }
\msg_new:nnn { dfg } { requested-staff-unresolved-institution }
{ Project~'#1':~institution~reference~'#2'~cannot~be~resolved. }
\msg_new:nnn { dfg } { requested-staff-unresolved-affiliation }
{ Project~'#1':~affiliation~reference~'#2'~cannot~be~resolved. }
\msg_new:nnn { dfg } { requested-staff-missing-abbreviation }
{ Affiliation~'#1'~has~no~abbreviation;~its~full~name~is~used. }
\msg_new:nnn { dfg } { requested-staff-duplicate }
{ Duplicate~RequestedFundingStaff~entry~for~#1. }
\msg_new:nnn { dfg } { funding-staff-cost-unavailable }
{ Automatic~staff-cost~calculation~is~not~available~for~#1. }
\msg_new:nnn { dfg } { existing-staff-no-data }
{ No~existing~staff~rows~were~found~in~database~'#1'. }
\msg_new:nnn { dfg } { existing-staff-no-organisation }
{ Existing~staff~entry~'#1'~cannot~be~assigned~to~an~affiliation. }
%    \end{macrocode}
% 
% \begin{macro}{\StartTimer}
% \begin{macro}{\StopTimer}
%   A simple pair of profiling helpers for measuring how long a
%   stretch of \LaTeX{} code takes to execute.  Wrap the code under
%   investigation between |\StartTimer| and
%   |\StopTimer{|\meta{label}|}|; the elapsed time in milliseconds
%   is written to the terminal and the |.log| file, prefixed with
%   the supplied \meta{label} so several measurements in one run
%   can be told apart.
%
%   Typical use:
%   \begin{quote}
%     |\StartTimer|\\
%     |\ParticipatingInstitutionsList[count]|\\
%     |\StopTimer{ParticipatingInstitutionsList}|
%   \end{quote}
%   producing a line such as
%   \begin{quote}
%     |TIMING ParticipatingInstitutionsList: 115 ms|
%   \end{quote}
%   in the log.
%
%   Only one measurement can be in progress at any one time, since
%   the start time is held in a single shared integer variable.
%   For nested or overlapping measurements, define additional
%   counters or switch to the labelled-timer variant.
%
%   The implementation uses the kernel-native expl3 function
%   |\sys_timer:|, which abstracts over the engine-specific timer and avoids an
%   additional package dependency.
%    \begin{macrocode}
\int_new:N \l_@@_timer_int
%    \end{macrocode}
%   Storage for the start timestamp.  We use an |int| rather than a
%   |tl| so the later subtraction in |\int_eval:n| is unambiguous.
%    \begin{macrocode}
\NewDocumentCommand { \StartTimer } { }
{
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  { \int_set:Nn \l_@@_timer_int { \sys_timer: } }
}
%    \end{macrocode}
%   |\sys_timer:| expands to the time since job start in
%   \emph{scaled seconds} -- units of $1/65536$~s.  We capture
%   that raw value here and convert to milliseconds only at
%   reporting time, to keep the start-up overhead minimal.
%    \begin{macrocode}
\NewDocumentCommand { \StopTimer } { m }
{
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  {
    \iow_term:x
    {
      TIMING~#1:~
      \int_eval:n
      { ( \sys_timer: - \l_@@_timer_int ) * 1000 / 65536 }
      \c_space_tl ms
    }
  }
}
%    \end{macrocode}
%   The arithmetic computes elapsed scaled-seconds first, then
%   multiplies by~$1000$ before dividing by~$65536$.  Doing the
%   multiplication first preserves precision: a naive
%   |(now - start) / 65536 * 1000| would truncate sub-second
%   measurements to zero.  The result is an integer count of
%   milliseconds, accurate to roughly $\pm 1$~ms.
%
%   |\iow_term:x| writes to the terminal \emph{and} the log,
%   fully expanding its argument once -- which is what makes
%   |\int_eval:n| produce a literal number rather than the
%   unevaluated expression.  |\c_space_tl| inserts a real space
%   between the number and the |ms| unit; a literal space there
%   would be consumed by |expl3|'s tokenisation rules.
%
%   Note that the reported time is wall-clock and includes any
%   |\typeout|, file~I/O, or shell-escape work performed inside
%   the timed block.  For tight measurements of pure computation,
%   silence debugging output during the run, and take the second
%   of two consecutive timings to avoid first-run effects such
%   as font caching or |.aux| reads.
% \end{macro}
% \end{macro}
% \subsubsection{Documentclass Options}
%
% We have very few global options we use from the KOMAscript.
% But you can use any known option of the KOMAscript |scrbook|.
%    \begin{macrocode}
\PassOptionsToClass{
  fontsize  =10pt,
  twoside   =true,
  headings  =optiontoheadandtoc,
  parskip   =half-,
  numbers   =noenddot,
  toc       =indentunnumbered
}{scrbook}
%    \end{macrocode}
% \subsubsection{Class options (\texttt{dfg/class} key family)}
%
% All class-level toggles live in the |dfg/class| key family and are
% processed via \cs{ProcessKeyOptions}.  They control the two major compilation modes
% (\refKey{fastcompile}, \refKey{fastcompile-project}, \refKey{final}) plus
% several debugging and output flags.
%
% The general design principle is that every flag defaults to |false| or
% to a safe, submission-ready value.  Authors enable the helpers they need
% during drafting and simply remove them (or set |final=true|) before
% submitting.  Setting |final=true| enforces this by hard-resetting all
% drafting flags to |false| automatically.
%    \begin{macrocode}
\keys_define:nn { dfg / class }
{
%    \end{macrocode}
% \refKey{final}: Set to |true| immediately before submission.
% It forces |cmyk| colour model (required for print), silently sets
% |fastcompile=false|, |showtags=false|, |showmarginalia=false| and
% |skip10pub=false|, and turns the draft-green placeholder colour
% to white so it is invisible in the output.
%    \begin{macrocode}
final      .bool_set:N = \l_@@_class_final_bool,
final      .initial:n  = false,
Final      .meta:n     = { final = #1 },
Final      .default:n  = true,
%    \end{macrocode}
% \refKey{fastcompile}: When |true|, generated tables and lists are replaced by
% a placeholder.  It also suppresses role-card grids, the Gantt chart, and the
% ten-publications CV block while retaining metadata-backed prose references.
% Automatically disabled when |final=true|.
%    \begin{macrocode}
fastcompile   .bool_set:N = \l_@@_class_fastcompile_bool,
fastcompile   .initial:n  = false,
%    \end{macrocode}
% \refKey{fastcompile-project}: Aggressive project-text drafting mode.  It
% implies \refKey{fastcompile}, but additionally prevents metadata rows from
% being loaded or restored, replaces calculated project headings with a
% state-only setup, uses draft rendering for graphics and links, and provides
% literal fallbacks for database-backed references.  Authored sections,
% paragraphs, aims, work packages, labels, and inline citations remain.
% Automatically disabled when |final=true|.
%    \begin{macrocode}
fastcompile-project .bool_set:N = \l_@@_class_fastcompile_project_bool,
fastcompile-project .initial:n  = false,
%    \end{macrocode}
% \refKey{fastcompile-project-show-images}: Opt back into real image rendering while
% aggressive project drafting is active.  It has no effect on ordinary builds,
% where graphics are rendered normally.  Final mode resets it to |false|
% together with the other drafting controls.
%    \begin{macrocode}
fastcompile-project-show-images .bool_set:N = \l_@@_class_fastcompile_project_show_images_bool,
fastcompile-project-show-images .initial:n  = false,
%    \end{macrocode}
% \refKey{fastcompile-project-show-publications}: Controls the standard project publication
% heading, explicit project \cs{nocite} lists, project bibliographies,
% project-report references, and ending-project result lists during focused
% project drafting.  Ordinary and final builds force it to |true|.
%    \begin{macrocode}
fastcompile-project-show-publications .bool_set:N = \l_@@_class_fastcompile_project_show_publications_bool,
fastcompile-project-show-publications .initial:n  = false,
%    \end{macrocode}
% \refKey{showtags}: Enables provenance overlays for direct database values and
% concise source labels for calculated values.  Both fast-compilation modes and
% final mode disable it after option processing.
%    \begin{macrocode}
showtags   .bool_set:N = \l_@@_class_showtags_bool,
showtags   .initial:n  = false,
%    \end{macrocode}
% \refKey{showtags-tables}: Controls only provenance overlays rendered in table
% cells.  It defaults to |true|, but remains inert unless \refKey{showtags} is
% enabled.  Keeping it separate lets authors debug prose without widening or
% visually overloading dense generated tables.
%    \begin{macrocode}
showtags-tables  .bool_set:N = \l_@@_class_showtags_tables_bool,
showtags-tables  .initial:n  = true,
%    \end{macrocode}
% \refKey{showmarginalia}: Enables marginal notes that display running
% subtotals alongside the funding tables.  Useful for cross-checking
% calculated sums during data entry.  Disabled by |final=true|.
%    \begin{macrocode}
showmarginalia .bool_set:N = \l_@@_class_showmarginalia_bool,
showmarginalia .initial:n  = false,
%    \end{macrocode}
% \refKey{skip10pub}: Suppresses the mandatory ten-publication block in
% each CV section.  Because each bibliography list requires a full biber
% run and can take several seconds per PI, skipping it during early drafting
% significantly reduces compilation time.  Automatically disabled by |final=true|.
%    \begin{macrocode}
skip10pub  .bool_set:N = \l_@@_class_skipTENpublications_bool,
skip10pub  .initial:n  = false,
%    \end{macrocode}
% \refKey{colorscheme}: Passed directly to \cs{selectcolormodel} at
% \cs{AtBeginDocument}.  Use |cmyk| for press-quality PDF output (DFG
% submission default) or |RGB| for on-screen review.  Overridden to
% |cmyk| when |final=true|.
%    \begin{macrocode}
colorscheme .tl_set:N   =  \l_@@_class_color_model_tl,
colorscheme .initial:n  = cmyk,
%    \end{macrocode}
% \refKey{cv}: Set to |true| in the standalone CV document
% (|crc-cv.tex|).  When |true|, the class adjusts heading styles
% and suppresses proposal-specific front matter so the output is a
% self-contained curriculum vitae suitable for DFG submission.
%    \begin{macrocode}
cv   .bool_set:N = \l_@@_class_cv_bool,
cv   .initial:n  = false,
unknown .code:n = { \PassOptionsToClass{\CurrentOption}{scrbook} },
}
%    \end{macrocode}
% \subsection{Conditional execution based on class options}
%
% The class option |cv| toggles whether the document is rendered as a
% CV (curriculum vitae) supplement.  Internally this is stored in the
% expl3 boolean |\l_@@_class_cv_bool|.  Since end-user document files
% should not be required to wrap conditional content in
% |\ExplSyntaxOn|\,/\,|\ExplSyntaxOff|, the following three commands
% expose the switch through a conventional \LaTeX{} interface.
%
% \DescribeMacro{\dfgIfCV}
% |\dfgIfCV|\marg{true code}\marg{false code}\par
% Executes \meta{true code} if the |cv| option is active, otherwise
% \meta{false code}.  Use this when both branches need to produce
% content, for instance to switch between a full bibliography and a
% short selected-publications list:
% \begin{quote}
% |\dfgIfCV{\printbibliography[heading=none]}{\printshortbib}|
% \end{quote}
%
% \DescribeMacro{\dfgIfCVT}
% |\dfgIfCVT|\marg{true code}\par
% Shorthand for the common case where only the true branch matters.
% Typical use is gating a section that exists only in the CV variant:
% \begin{quote}
% |\dfgIfCVT{\par\textcolor{tableHeadingsFont}{Appendix:~Research~profiles}}|
% \end{quote}
% Equivalent to |\dfgIfCV{|\meta{true code}|}{}| but avoids the empty
% second argument and reads more naturally in document source.
%
% \DescribeMacro{\dfgIfCVF}
% |\dfgIfCVF|\marg{false code}\par
% Mirror image of |\dfgIfCVT|: executes \meta{false code} only when the
% |cv| option is \emph{not} active.  Useful for content that belongs in
% the main proposal but should be suppressed in the CV variant.
%
% None of these commands evaluates its arguments unless the relevant
% branch is taken, so wrapping expensive or side-effecting code is safe.
% All three are defined with |\NewDocumentCommand|, so their arguments
% are read as standard mandatory braced groups and may contain verbatim
% material only where the underlying typesetting context permits.
%
%    \begin{macrocode}
\NewDocumentCommand \dfgIfCV  { +m +m }
  { \bool_if:NTF \l_@@_class_cv_bool {#1} {#2} }
\NewDocumentCommand \dfgIfCVT { +m }
  { \bool_if:NT  \l_@@_class_cv_bool {#1} }
\NewDocumentCommand \dfgIfCVF { +m }
  { \bool_if:NF  \l_@@_class_cv_bool {#1} }

\NewDocumentCommand \dfgIfFinalF { +m }
  { \bool_if:NF  \l_@@_class_final_bool {#1} }
\NewDocumentCommand \dfgIfFastCompileProject { +m +m }
  { \bool_if:NTF \l_@@_class_fastcompile_project_bool {#1} {#2} }
\NewDocumentCommand \dfgIfFastCompileProjectT { +m }
  { \bool_if:NT \l_@@_class_fastcompile_project_bool {#1} }
\NewDocumentCommand \dfgIfFastCompileProjectF { +m }
  { \bool_if:NF \l_@@_class_fastcompile_project_bool {#1} }
\NewDocumentCommand \dfgIfProjectPublications { +m +m }
  { \bool_if:NTF \l_@@_class_fastcompile_project_show_publications_bool {#1} {#2} }
%    \end{macrocode}
% Unknown options are forwarded by the key handler above, so ordinary
% KOMA-Script options remain available without processing the class options a
% second time.  Finally process and execute all options and key-values.
%    \begin{macrocode}
\ProcessKeyOptions[ dfg / class ]
% Resolve mode precedence before any package, customisation, metadata, or
% auxiliary-file work can observe the drafting booleans.
\bool_if:NTF \l_@@_class_final_bool
{
  \bool_set_false:N \l_@@_class_fastcompile_bool
  \bool_set_false:N \l_@@_class_fastcompile_project_bool
  \bool_set_false:N \l_@@_class_fastcompile_project_show_images_bool
  \bool_set_false:N \l_@@_class_showtags_bool
  \bool_set_false:N \l_@@_class_showmarginalia_bool
  \bool_set_false:N \l_@@_class_skipTENpublications_bool
  \bool_set_true:N  \l_@@_class_fastcompile_project_show_publications_bool
}
{
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  {
    \bool_set_true:N  \l_@@_class_fastcompile_bool
    \bool_set_false:N \l_@@_class_showtags_bool
    \bool_set_false:N \l_@@_class_showmarginalia_bool
    \bool_set_true:N  \l_@@_class_skipTENpublications_bool
    \PassOptionsToPackage{draft}{hyperref}
    \PassOptionsToPackage{draft}{microtype}
  }
  { \bool_set_true:N \l_@@_class_fastcompile_project_show_publications_bool }
  \bool_if:NT \l_@@_class_fastcompile_bool
    { \bool_set_false:N \l_@@_class_showtags_bool }
}
\LoadClass{scrbook}
\PassOptionsToPackage{table}{xcolor} % getting rid of errors and conflicts.
\RequirePackage{xcolor}
%    \end{macrocode}
% \subsubsection{Colour palette}
%
% All colours follow the RWTH Aachen corporate-identity palette and are
% defined in all four models at once (|cmyk/RGB/HTML/gray|) using xcolor's
% multiple-model syntax.  This allows the same symbolic name to be used
% regardless of the active colour model chosen via |colorscheme=|.
%
% Each hue comes in five tints named |-100| (full) through |-10| (near
% white), matching the official RWTH tint steps.  This naming scheme is
% intentional: table headers, zebra stripes and box backgrounds are all
% specified in terms of these canonical names (e.g. |blue-50|, |black-10|),
% so a complete rebranding only requires changing the definitions here.
%
% The ORCiD brand green is also declared here since it is used by
% \cs{orcidIcon} throughout the document.
%    \begin{macrocode}
\definecolor{blue-100}{cmyk/RGB/HTML/gray}{1,.50,0,0/0,84,159/00549F/1}% primary
\definecolor{blue-75}{cmyk/RGB/HTML/gray}{.75,.38,0,0/64,127,183/407FB7/.75}%
\definecolor{blue-50}{cmyk/RGB/HTML/gray}{.45,.14,0,0/142,186,229/8EBAE5/.5}% secondary
\definecolor{blue-25}{cmyk/RGB/HTML/gray}{.23,.07,0,0/199,221,242/C7DDF2/.25}%
\definecolor{blue-10}{cmyk/RGB/HTML/gray}{.09,.03,0,0/232,241,250/E8F1FA/.1}%

\definecolor{black-100}{cmyk/RGB/HTML}{0,0,0,1/0,0,0/000000}%
\definecolor{black-75}{cmyk/RGB/HTML}{0,0,0,.75/100,101,103/646567}%
\definecolor{black-50}{cmyk/RGB/HTML}{0,0,0,.5/156,158,159/9C9E9F}%
\definecolor{black-25}{cmyk/RGB/HTML}{0,0,0,.25/207,209,210/CFD1D2}%
\definecolor{black-10}{cmyk/RGB/HTML}{0,0,0,.1/236,237,237/ECEDED}%

\definecolor{green-100}{cmyk/RGB/HTML}{.7,0,1,0/87,171,39/57AB27}%
\definecolor{green-75}{cmyk/RGB/HTML}{.52,0,.75,0/141,192,96/8DC060}%
\definecolor{green-50}{cmyk/RGB/HTML}{.35,0,.5,0/184,214,152/B8D698}%
\definecolor{green-25}{cmyk/RGB/HTML}{.18,0,.25,0/221,235,206/DDEBCE}%
\definecolor{green-10}{cmyk/RGB/HTML}{.07,0,.1,0/242,247,236/F2F7EC}%

\definecolor{red-100}{cmyk/RGB/HTML}{.15,1,1,0/204,7,30/CC071E}%
\definecolor{red-75}{cmyk/RGB/HTML}{.11,.75,.75,0/216,92,65/D85C41}%
\definecolor{red-50}{cmyk/RGB/HTML}{.8,.5,.5,0/230,150,121/E69679}%
\definecolor{red-25}{cmyk/RGB/HTML}{.4,.25,.25,0/243,205,187/F3CDBB}%
\definecolor{red-10}{cmyk/RGB/HTML}{.2,.1,.1,0/250,235,227/FAEBE3}%

\definecolor{bordeaux-100}{cmyk/RGB/HTML}{.25,1,.70,.20/161,16,53/A11035}%
\definecolor{bordeaux-75}{cmyk/RGB/HTML}{.19,.75,.52,15/182,82,86/B65256}%
\definecolor{bordeaux-50}{cmyk/RGB/HTML}{.13,.5,.35,.1/205,139,135/CD8B87}%
\definecolor{bordeaux-25}{cmyk/RGB/HTML}{.06,.25,.18,.05/229,197,192/E5C5C0}%
\definecolor{bordeaux-10}{cmyk/RGB/HTML}{.03,.1,.07,.02/245,232,229/F5E8E5}%

\definecolor{orcid}{cmyk/RGB}{0.15,0.00,0.59,0.20/174,205,84}
%    \end{macrocode}
% Let’s start with the common section on packages etc.
% \subsubsection{Customisation key family (\texttt{dfg/custom})}
% We provide as much as possible all settings to customize to your desire and
% needs.
% The customization is done with key-values, which we set up below.
%
%    \begin{macrocode}
\keys_define:nn { dfg / custom  }
{
  % You can pass any font you like (and |fontspec| will understand or is known to
  % your system). But since the DFG is requiring Arial, we set this as default.
  font                       .tl_set:N   = \l_@@_custom_font_tl,
  fontspec                   .tl_set:N   = \l_@@_custom_fontspec_tl,
  font                       .initial:n  = Noto Serif,
  sansfont                   .tl_set:N   = \l_@@_custom_sansfont_tl,
  sansfontspec               .tl_set:N   = \l_@@_custom_sansfontspec_tl,
  sansfont                   .initial:n  = Roboto Light,
  sansfontspec            .initial:n     = {
  		ItalicFont=Roboto-LightItalic,
  		BoldFont=Roboto-Medium,
  		BoldItalicFont=Roboto-Medium-Italic},
  % \paragraph{Logo paths}
  crcLogoPath                 .tl_set:N   = \l_@@_custom_crc_logo_path_tl,
  crcLogoPath                 .initial:n  = example-image-a,
  affiliationLogoPath         .tl_set:N   = \l_@@_custom_affiliation_logo_path_tl,
  affiliationLogoPath         .initial:n  = example-image-b,
  % \paragraph{Project-reference repetition}
  projectPIOncePerSection      .bool_set:N =
    \l_@@_custom_project_pi_once_per_section_bool,
  projectPIOncePerSection      .initial:n  = true,
  % Collaboration-plot area colors can be set once for the complete proposal.
  % Per-plot area-colors and area-palette options may override these defaults.
  collaborationAreaColors      .tl_set:N =
    \l_@@_custom_collaboration_area_colors_tl,
  collaborationAreaColors      .initial:n =
    { A=projectA, B=projectB, Q=projectQ!75!black },
  collaborationAreaPalette     .code:n =
    {
      \clist_if_empty:nF {#1}
        { \tl_set:Nn \l_@@_custom_collaboration_area_palette_tl {#1} }
    },
  collaborationAreaPalette     .initial:n =
    { orange!80!black, violet!75!black, teal!70!black,
      brown!75!black, magenta!70!black, cyan!70!black, lime!60!black },
  % \paragraph{DFG salary and animal-housing rates}
  salary@prof                 .fp_set:N   = \l_@@_custom_salary_prof_fp,
  salary@prof                 .initial:n  = 123600,
  salary@groupLeader          .fp_set:N   = \l_@@_custom_salary_group_leader_fp,
  salary@groupLeader          .initial:n  = 102300,
  salary@postDoc              .fp_set:N   = \l_@@_custom_salary_postdoc_fp,
  salary@postDoc              .initial:n  = 88200,
  salary@medDoc               .fp_set:N   = \l_@@_custom_salary_meddoc_fp,
  salary@medDoc               .initial:n  = 111000,
  salary@PhD                  .fp_set:N   = \l_@@_custom_salary_phd_fp,
  salary@PhD                  .initial:n  = 81600,
  salary@research             .fp_set:N   = \l_@@_custom_salary_research_fp,
  salary@research             .initial:n  = 67200,
  salary@nonResearch          .fp_set:N   = \l_@@_custom_salary_nonresearch_fp,
  salary@nonResearch          .initial:n  = 60000,
  salary@student              .fp_set:N   = \l_@@_custom_salary_student_fp,
  salary@student              .initial:n  = 1,
  salary@assistant            .fp_set:N   = \l_@@_custom_salary_assistant_fp,
  salary@assistant            .initial:n  = 1,
  animalHousing@mouse         .fp_set:N   = \l_@@_custom_animal_mouse_fp,
  animalHousing@mouse         .initial:n  = 0.75,
  animalHousing@mouseGnotobiotic .fp_set:N =
    \l_@@_custom_animal_mouse_gnotobiotic_fp,
  animalHousing@mouseGnotobiotic .initial:n = 3.9,
  animalHousing@rat           .fp_set:N   = \l_@@_custom_animal_rat_fp,
  animalHousing@rat           .initial:n  = 1.4,
  % \paragraph{Thumb-index keys}
  % These keys control the decorative side tab on the outer margin.
  % The index divides the page height (minus the two margin values) into
  % \meta{pattern} equal-height slots.  Each call to \cs{printThumbIndex}
  % advances the slot counter; when it reaches \meta{pattern} it wraps,
  % creating a repeating stripe aiding chapter navigation.
  %
  thumbindex                 .bool_set:N = \l_@@_custom_thumbindex_bool,
  thumbindex                 .initial:n  = true,
  %
  thumbindex@pattern         .int_set:N  = \l_@@_custom_thumbindexpattern_int,
  thumbindex@pattern         .initial:n  = 10,
  %
  thumbindex@topmargin .dim_set:N  = \l_@@_custom_thumbindex_topmargin_dim,
  thumbindex@topmargin .initial:n  = 3cm,
  %
  thumbindex@bottommargin .dim_set:N  = \l_@@_custom_thumbindex_bottommargin_dim,
  thumbindex@bottommargin .initial:n  = 3cm,
  %
  thumbindex@width     .dim_set:N  = \l_@@_custom_thumbindex_width_dim,
  thumbindex@width .initial:n  = 1.2cm,
  %
  thumbindex@font .tl_set:N = \l_@@_custom_thumbindex_font_tl,
  thumbindex@font .initial:n = \bfseries\Huge,
  % \paragraph{Bibliography keys}
  % |emphasizeAuthors|: when |true| (default), a bold-name mechanism is
  % activated that marks every PI's name in bold across all bibliography
  % and citation lists — the DFG-required visual distinction for CRC PIs.
  % CV and proposal bibliography styles and features are stored separately.
  %
  doiAPIMail                  .tl_set:N  = \l_@@_custom_doi_api_mail_tl,
  doiAPIMail                  .initial:n = {},
  %
  emphasizeAuthors           .bool_set:N = \l_@@_custom_emphasize_authors_bool,
  emphasizeAuthors           .initial:n  = true,
  %
  biblatexstyleCV                 .tl_set:N  = \l_@@_custom_biblatexstyle_cv_tl,
  biblatexstyleCV                 .initial:n = ext-numeric-comp,
  biblatexstyleFeatureCV          .tl_set:N  = \l_@@_custom_biblatexfeatures_cv_tl,
  biblatexstyleFeatureCV          .initial:n = {sorting=none},
  biblatexstyleProposal           .tl_set:N  = \l_@@_custom_biblatexstyle_proposal_tl,
  biblatexstyleProposal           .initial:n = ext-authoryear-ecomp,
  biblatexstyleFeatureProposal    .tl_set:N  = \l_@@_custom_biblatexfeatures_proposal_tl,
  biblatexstyleFeatureProposal    .initial:n = {dashed=false},
  % Compatibility: the former keys apply the supplied value to both modes.
  biblatexstyle .code:n =
    {
      \tl_set:Nn \l_@@_custom_biblatexstyle_cv_tl       {#1}
      \tl_set:Nn \l_@@_custom_biblatexstyle_proposal_tl {#1}
    },
  biblatexstyleFeature .code:n =
    {
      \tl_set:Nn \l_@@_custom_biblatexfeatures_cv_tl       {#1}
      \tl_set:Nn \l_@@_custom_biblatexfeatures_proposal_tl {#1}
    },
  % \paragraph{Colour keys}
  % All colour keys store a colour \emph{name} referencing an already-defined
  % xcolor colour (e.g.\ |blue-50|, |black-10|).  Actual \cs{colorlet}
  % bindings happen in \cs{AtBeginDocument} so preamble overrides are
  % processed first.  Groups: |color@gantt@*| for the five bar styles;
  % |color@table@*| for all table chrome; |color@thumbindex@*| for the
  % thumb tab; |color@tags@*| for the showtags debug annotations.
  %
  color@reference@boldAuthor .tl_set:N   = \l_@@_custom_referenceBoldAuthor_tl,
  color@reference@boldAuthor .initial:n  = black,

  color@gantt@frame      .tl_set:N    = \l_@@_custom_gantt_frame_tl,
  color@gantt@frame      .initial:n = {white},
  color@gantt@default    .tl_set:N    =\l_@@_custom_gantt_default_tl,
  color@gantt@default    .initial:n = {blue-25},
  color@gantt@alternative    .tl_set:N    =\l_@@_custom_gantt_alternative_tl,
  color@gantt@alternative    .initial:n = {green-25},
  color@gantt@crosshatch .tl_set:N    = \l_@@_custom_gantt_crosshatch_tl,
  color@gantt@crosshatch .initial:n = {black-10},
  color@gantt@important  .tl_set:N    = \l_@@_custom_gantt_important_tl,
  color@gantt@important  .initial:n = {red},
  color@gantt@stripe-one .tl_set:N    = \l_@@_custom_gantt_stripe_one_tl,
  color@gantt@stripe-one .initial:n = {blue-25},
  color@gantt@stripe-two .tl_set:N    = \l_@@_custom_gantt_stripe_two_tl,
  color@gantt@stripe-two .initial:n = {green-25},

  color@table@headingsBG     .tl_set:N   = \l_@@_custom_tableHeadingsBG_tl,
  color@table@headingsBG     .initial:n  = blue-50,
  color@table@headingsBGalt  .tl_set:N   = \l_@@_custom_tableHeadingsBGalt_tl,
  color@table@headingsBGalt  .initial:n  = black-25,
  color@table@headingsFont   .tl_set:N   = \l_@@_custom_tableHeadingsFont_tl,
  color@table@headingsFont   .initial:n  = black,
  color@table@rows           .tl_set:N   = \l_@@_custom_tableRows_tl,
  color@table@rows           .initial:n  = black-10,
  color@table@lines          .tl_set:N   = \l_@@_custom_tableLines_tl,
  color@table@lines          .initial:n  = black-10,
  color@table@outerLines     .tl_set:N   = \l_@@_custom_tableOuterLines_tl,
  color@table@outerLines     .initial:n  = black,
  color@table@noValue        .tl_set:N   = \l_@@_custom_tableNoValue_tl,
  color@table@noValue        .initial:n  = black-10,
  color@table@firstColumn    .tl_set:N   = \l_@@_custom_tableFirstColumn_tl,
  color@table@firstColumn    .initial:n  = black,
  color@table@link           .tl_set:N   = \l_@@_custom_tableLink_tl,
  color@table@link           .initial:n = black,
  color@table@contFootHead   .tl_set:N  = \l_@@_custom_tableContFootHead_tl,
  color@table@contFootHead   .initial:n = black,
  color@table@caption        .tl_set:N  = \l_@@_custom_tableCaption_tl,
  color@table@caption        .initial:n = black,
  color@thumbindex@bg        .tl_set:N  = \l_@@_custom_thumbIndexBG_tl,
  color@thumbindex@bg        .initial:n = black,
  color@thumbindex@font      .tl_set:N  = \l_@@_custom_thumbIndexFont_tl,
  color@thumbindex@font      .initial:n = white,
  color@tags@font            .tl_set:N  = \l_@@_custom_colorTagsFont_tl,
  color@tags@font            .initial:n = red-100,
  color@tags@line            .tl_set:N  = \l_@@_custom_colorTagsLine_tl,
  color@tags@line            .initial:n = black-50,
  % The alternative font color which is used e.g. for the CV headline.
  color@font@alternative     .tl_set:N  = \l_@@_custom_colorfontalternative_tl,
  color@font@alternative     .initial:n = black-50,

  color@item@i               .tl_set:N  = \l_@@_custom_color_item_i_tl,
  color@item@i               .initial:n = black,
  % That’s it with the key-values.
}
%    \end{macrocode}
% Bibliography package options must be fixed before \pkg{biblatex} is loaded.
% Consequently the customization file is read here, after all custom keys have
% been declared but before package loading.  It is not read a second time at the
% end of the class.
%    \begin{macrocode}
\NewDocumentCommand{\changeSettings}{m}
  { \keys_set:nn { dfg / custom } {#1} }
% Compatibility alias for proposals created before the command was pluralised.
\NewDocumentCommand{\changeSetting}{m}
  { \changeSettings{#1} }
% Compatibility accessors retained for the funding and animal-cost code.
\NewExpandableDocumentCommand{\dfgSalaryProf}{}
  { \fp_use:N \l_@@_custom_salary_prof_fp }
\NewExpandableDocumentCommand{\dfgSalaryGroupLeader}{}
  { \fp_use:N \l_@@_custom_salary_group_leader_fp }
\NewExpandableDocumentCommand{\dfgSalaryPostDoc}{}
  { \fp_use:N \l_@@_custom_salary_postdoc_fp }
\NewExpandableDocumentCommand{\dfgSalaryMedDoc}{}
  { \fp_use:N \l_@@_custom_salary_meddoc_fp }
\NewExpandableDocumentCommand{\dfgSalaryPhD}{}
  { \fp_use:N \l_@@_custom_salary_phd_fp }
\NewExpandableDocumentCommand{\dfgSalaryResearch}{}
  { \fp_use:N \l_@@_custom_salary_research_fp }
\NewExpandableDocumentCommand{\dfgSalaryNonResearch}{}
  { \fp_use:N \l_@@_custom_salary_nonresearch_fp }
\NewExpandableDocumentCommand{\dfgSalaryStudent}{}
  { \fp_use:N \l_@@_custom_salary_student_fp }
\NewExpandableDocumentCommand{\dfgSalaryAssistant}{}
  { \fp_use:N \l_@@_custom_salary_assistant_fp }
\NewExpandableDocumentCommand{\dfgMouseHousing}{}
  { \fp_use:N \l_@@_custom_animal_mouse_fp }
\NewExpandableDocumentCommand{\dfgMouseHousingGnotobiotic}{}
  { \fp_use:N \l_@@_custom_animal_mouse_gnotobiotic_fp }
\NewExpandableDocumentCommand{\dfgRatHousing}{}
  { \fp_use:N \l_@@_custom_animal_rat_fp }
\file_if_exist:nTF {preamble/dfg-customization.tex}
  { \ExplSyntaxOff \input{preamble/dfg-customization.tex} \ExplSyntaxOn }
  { \msg_warning:nnn { dfg } { file-not-found } {preamble/dfg-customization.tex} }
\bool_if:NT \l_@@_class_fastcompile_project_bool
{
  \bool_set_false:N \l_@@_custom_thumbindex_bool
  \bool_set_false:N \l_@@_custom_emphasize_authors_bool
}
%    \end{macrocode}
% \subsubsection{Colour binding at document start}
%
% The \cs{AtBeginDocument} hooks below transform the stored colour
% \emph{names} from the |dfg/custom| key family into live \cs{colorlet}
% aliases that the rest of the document uses.  Deferring this to
% \cs{AtBeginDocument} means the user's \cs{changeSettings} calls in
% |dfg-customization.tex| are already in force when the bindings run.
%
% The second \cs{AtBeginDocument} block handles |final|-mode side effects:
% it resets all drafting flags (both fast modes, tags, marginalia, skip-pubs)
% to |false|, enables project publications, forces the colour model to |cmyk|,
% and switches the |color@final@white-or-green| alias from green to white so
% that any placeholder boxes are invisible in the submitted PDF.
%
% Packages are loaded in an order that avoids common conflicts:
%  \pkg{xcolor} is loaded first (with the |table| option forwarded
%  beforehand) because almost every other package depends on it.
%  \pkg{tabularray} and its siunitx library are set up before
%  \pkg{hyperref}; reversing this order breaks tblr's PDF bookmark
%  integration.
%  \pkg{hyperref} and \pkg{cleveref} are always loaded last (standard
%  LaTeX best practice).
%
% The page geometry mirrors the DFG layout requirements: A4 paper, 25\,mm
% inner and top margins, 30\,mm outer margin, a 20\,mm footer zone, and a
% 15\,mm note column inside the outer marginal area for the
% \texttt{showmarginalia} running subtotals.  On verso pages, the notes switch
% to the left margin so that they retain the same distance from the paper edge.
% \texttt{includefoot} prevents the footer from overlapping the body text.
%    \begin{macrocode}
\RequirePackage{multicol}
% Defensive definition against lineno/multicol conflict
\AtBeginDocument{%
  \@ifpackageloaded{lineno}{%
  	\providecommand*{\@LN@col}[1]{\relax}%
  }{}%
}
\RequirePackage{babel}
\RequirePackage{geometry}
\geometry{
  a4paper,
  % includefoot,
  top            =30mm,
  bottom         =30mm,
  left           =20mm,
  right          =30mm,
  marginparsep   =5mm,
  marginparwidth =20mm,
  % showframe
}
%    \end{macrocode}
% We provide a color which is used during the writing process.
% Since there are several steps that are calculated on the fly we want to be
% able to see if they match any criteria or if there has been a wrongly inserted
% number.
% The following colors can be overwritten in the \dfgFile{dfg-customization}-file.
% Therefor we load them just before the document starts.
%    \begin{macrocode}
\AtBeginDocument{
  \selectcolormodel{\tl_use:N \l_@@_class_color_model_tl}
  \colorlet{color@item@i}{\l_@@_custom_color_item_i_tl}
  \colorlet{color@tags@font}{\l_@@_custom_colorTagsFont_tl}
  \colorlet{color@tags@line}{\l_@@_custom_colorTagsLine_tl}
  \colorlet{color@font@alternative}{\l_@@_custom_colorfontalternative_tl}
  \colorlet{color@reference@boldAuthor}{\l_@@_custom_referenceBoldAuthor_tl}
  \colorlet{tableHeadingsBG}{\l_@@_custom_tableHeadingsBG_tl}
  \colorlet{tableHeadingsBGalt}{\l_@@_custom_tableHeadingsBGalt_tl}
  \colorlet{tableHeadingsFont}{\l_@@_custom_tableHeadingsFont_tl}
  \colorlet{tableRows}{\l_@@_custom_tableRows_tl}
  \colorlet{tableLines}{\l_@@_custom_tableLines_tl}
  \colorlet{tableOuterLines}{\l_@@_custom_tableOuterLines_tl}
  \colorlet{tableNoValue}{\l_@@_custom_tableNoValue_tl}
  \colorlet{tableFirstColumn}{\l_@@_custom_tableFirstColumn_tl}
  \colorlet{tableLink}{\l_@@_custom_tableLink_tl}
  \colorlet{tableContFootHead}{\l_@@_custom_tableContFootHead_tl}
  \colorlet{tableCaption}{\l_@@_custom_tableCaption_tl}
  \colorlet{thumbIndexBG}{\l_@@_custom_thumbIndexBG_tl}
  \colorlet{thumbIndexFont}{\l_@@_custom_thumbIndexFont_tl}
  % all for the gantt chart 
  \colorlet{color@gantt@default}{\l_@@_custom_gantt_default_tl}
  \colorlet{color@gantt@alternative}{\l_@@_custom_gantt_alternative_tl}
  \colorlet{color@gantt@frame}{\l_@@_custom_gantt_frame_tl}
  \colorlet{color@gantt@crosshatch}{\l_@@_custom_gantt_crosshatch_tl}
  \colorlet{color@gantt@important}{\l_@@_custom_gantt_important_tl}
  \colorlet{color@gantt@stripe-one}{\l_@@_custom_gantt_stripe_one_tl}
  \colorlet{color@gantt@stripe-two}{\l_@@_custom_gantt_stripe_two_tl}

  % NOTE: The aliases below shadow LaTeX/xcolor standard colour names
  % (black, red, green). Any subsequently loaded package relying on the
  % standard red=RGB(255,0,0) will receive bordeaux-100 instead.
  % Consider using dfg-prefixed aliases if you load additional packages.
  \colorlet{black}{black-100}
  \colorlet{blue}{blue-100}
  \colorlet{blueLight}{blue-50}
  \colorlet{green}{green-100}
  \colorlet{greenLight}{green-50}
  \colorlet{red}{bordeaux-100}
  \colorlet{redLight}{bordeaux-50}
  \colorlet{grey}{black-50}
  \colorlet{greyLight}{black-10}

  \colorlet{projectA}{blue}
  \colorlet{projectB}{green}
  \colorlet{projectQ}{grey}
  \colorlet{error}{red}
  \colorlet{referencePI}{color@reference@boldAuthor}
  \colorlet{referenceWP}{color@reference@boldAuthor}
  \colorlet{referenceAim}{color@reference@boldAuthor}
  % Now closing the AtBeginDocument-part:
}
%    \end{macrocode}
% Once you set the flag |final| the color (green) is replaced by white so it is
% ready for submission without indicating the doublechecking aspect. If it stays
% red you should not proceed to submit the proposal.
%    \begin{macrocode}
\AtBeginDocument{
  \bool_if:NTF \l_@@_class_final_bool
  {
  	\colorlet{color@final@white-or-green}{white}
  	\bool_set_false:N \l_@@_class_showmarginalia_bool
  	\bool_set_false:N \l_@@_class_showtags_bool
    \bool_set_false:N \l_@@_class_fastcompile_bool
    \bool_set_false:N \l_@@_class_fastcompile_project_bool
    \bool_set_false:N \l_@@_class_fastcompile_project_show_images_bool
    \bool_set_false:N \l_@@_class_skipTENpublications_bool
    \bool_set_true:N \l_@@_class_fastcompile_project_show_publications_bool
  	\selectcolormodel{cmyk}
  }
  {
  	\colorlet{color@final@white-or-green}{green}
  }
}
%    \end{macrocode}
%    \begin{macrocode}
\RequirePackage{xspace}
\RequirePackage{etoolbox}

\RequirePackage{ragged2e}
\raggedbottom
%    \end{macrocode}
% We are getting rid of having the chapter number added to the figure number,
% same goes for tables.
%    \begin{macrocode}
\counterwithout{figure}{chapter}
\counterwithout{table}{chapter}
%    \end{macrocode}
%    \begin{macrocode}
\RequirePackage{qrcode}
\RequirePackage{graphicx}
\RequirePackage{mwe}% provides the default example-image-a/b logo placeholders
% Set the graphics mode after loading \pkg{graphicx}.  This explicitly clears
% a previously inherited draft setting when project images are requested and
% makes repeated false/true drafting builds deterministic.
\bool_if:NT \l_@@_class_fastcompile_project_bool
{
  \bool_if:NTF \l_@@_class_fastcompile_project_show_images_bool
    { \setkeys{Gin}{draft=false} }
    { \setkeys{Gin}{draft=true} }
}
\graphicspath{
  {figures/}
  {img/}
}
\RequirePackage{fontspec}
\AtBeginDocument{
  \setmainfont{\tl_use:N \l_@@_custom_font_tl}[
  	\tl_use:N \l_@@_custom_fontspec_tl
  ]
  \setsansfont{\tl_use:N \l_@@_custom_sansfont_tl}[
  	\tl_use:N \l_@@_custom_sansfontspec_tl
  ]
}

\RequirePackage{fontawesome5}
\RequirePackage{microtype}
\RequirePackage{enumitem}
% customizing bulletpoints
\newcommand{\dfgArrowHead}{\faCaretRight}
\newcommand{\dfgBulletPoint}{\faCaretRight}
\newcommand{\dfgTargetPoint}{\faBullseye}
\newcommand{\dfgDefaultPoint}{\faCaretRight}
\setlist[enumerate]{nosep}
\setlist[description]{
  %leftmargin=*,
  leftmargin=*
}
\setlist[itemize]{
  nosep,
  label={\textcolor{color@item@i}{\dfgDefaultPoint}},
}
\newlist{contractinformation}{itemize}{2}
\setlist[contractinformation,1]{
  nosep,
  leftmargin=*,
  label={\textcolor{color@item@i}{\dfgBulletPoint}},
}
\setlist[contractinformation,2]{
  nosep,
  leftmargin=*,
  label={\textcolor{color@item@i}{\dfgDefaultPoint}},
}
%    \end{macrocode}
% \subsubsection{Project-body list environments}
%
% \paragraph{workpackages}
% A custom enumitem list with |WP\,\arabic*:| labels at level 1 and
% |WP\,\meta{parent}\alph*:| at level 2.  The |resume| option at level 1
% means the work-package counter continues across multiple projects in the
% same document, giving each WP a globally unique number for cross-references.
% Labels are set via \pkg{cleveref} with the prefix |\bfseries\color{referenceWP}WP|.
%
% \paragraph{aims}
% A special |enumerate| list that automatically wraps its contents in a
% \cs{dfgBoxEnv} frame (the blue highlighted aims box).  The |before| hook
% also temporarily sets all reference colours to the table heading font
% colour so that PI/WP/Aim cross-references inside the aims box are
% visually consistent with the box style.  The |after| hook closes the box.
%    \begin{macrocode}
\newlist{workpackages}{enumerate}{3}
\setlist[workpackages,1]{
  % wide=\parindent,
  leftmargin=0cm,
  labelindent=*,
  % leftmargin=*,
  % labelindent=-3em,
  % font=\normalfont,
  % first=\bfseries,
  topsep=3pt,
  font=\bfseries,
  % nosep,
  label={WP\,\arabic*:},
  ref = {\arabic*},
  resume
}

\setlist[workpackages,2]{
  ref={\theworkpackagesi\alph*},
  %wide=\parindent,
  leftmargin=0cm,
  labelindent=*,
  % font=\normalfont,
  % first=\bfseries,
  topsep=0pt,
  font=\bfseries,
  % nosep,
  label={WP\,\theworkpackagesi\alph*:}
}
%    \end{macrocode}
% \paragraph{bylaws}
% A three-level enumitem list styled for the bylaws section of the CRC
% charter.  Level 1 uses |§\arabic*| paragraph signs; level 2 uses
% |\thebylawsi.\arabic*| for sub-paragraphs.  Both levels are set
% |nosep| to conserve vertical space.
%    \begin{macrocode}

\newlist{bylaws}{enumerate}{3}
\setlist[bylaws]{leftmargin=*}
\setlist[bylaws,1]{
  font=\bfseries,
  first=\bfseries,
  % after=\normalfont,
  label={§\arabic*},
  % itemsep=.5\baselineskip,
  nosep
}
\setlist[bylaws,2]{
  first=\normalfont,
  label={\thebylawsi.\arabic*},
  labelindent=0em,
}
%    \end{macrocode}
% A list for the aims within the projects
%    \begin{macrocode}
\newcommand{\addAim}[1]{\item\label{\l__tmp_current_project_tl-aim-#1}}
\newlist{aims}{enumerate}{1}
\setlist[aims,1]{
  before={\begin{dfgBoxEnv}%
  		[%watermark text={Aims in }
  		]
  		\colorlet{referencePI}{tableHeadingsFont}
  		\colorlet{referenceWP}{tableHeadingsFont}
  		\colorlet{referenceAim}{tableHeadingsFont}},
  after={\end{dfgBoxEnv}},
  wide=\parindent,
  % font=\normalfont,
  % first=\bfseries,
  topsep=3pt,
  font=\bfseries,
  % nosep,
  label={Aim~ \arabic*:},
  ref = {\arabic*},
  %  resume
}
%    \end{macrocode}
% \subsubsection{Page style (headers and footers)}
%
% The page style uses \pkg{scrlayer-scrpage} with a minimal layout:
%  The outer footer shows the page number in bold sans-serif.
%   The inner footer shows the CRC logo (\cs{crcLogo}) at 0.5\,cm
%   height — this places the logo on every page of the proposal for
%   visual identification without cluttering the headers.
%   Both header and footer use \cs{markcase=noupper} so section
%   titles are not forced to uppercase in running heads.
% \cs{footheight} is set explicitly to suppress the \pkg{scrlayer-scrpage}
% warning about an undersized footer layer.
%    \begin{macrocode}
\RequirePackage[
  %headsepline=.5pt,
  markcase=noupper,
  %footsepline,
  autooneside=false, % use left and right marks with a onesided document
  %automark, % set \ leftmark and \ rightmark automatically by \ section and \ subsection
  draft=false,
]{scrlayer-scrpage}
%    \end{macrocode}
% First we clear any presettings so we can apply our own style.
%    \begin{macrocode}
\clearmainofpairofpagestyles
\pagestyle{scrheadings}
\setlength{\footheight}{17.5264pt}
\renewcommand{\chaptermarkformat}{}
\renewcommand{\sectionmarkformat}{}
\ofoot*{\pagemark}%Clear the outer foot
\ifoot*{\crcLogo[height=0.5cm]}%pagemark in the center only on plain pages
\addtokomafont{pagehead}{\normalfont\sffamily}
\addtokomafont{pagefoot}{\bfseries}
% Mark every shipped page of an aggressive project draft without adding a
% package-level watermark dependency.  The native background hook keeps the
% mark behind authored text and is registered only after final-mode precedence
% has been resolved.
\bool_if:NT \l_@@_class_fastcompile_project_bool
{
  \AddToHook{shipout/background}[dfg/fastcompile-project-watermark]
  {
    \put(0.5\paperwidth,-0.5\paperheight)
    {
      \makebox(0,0)
      {
        \rotatebox{45}
        {
          \textcolor{black!7}
          {
            \sffamily\bfseries\fontsize{42}{50}\selectfont
            FAST~COMPILE~-~DRAFT
          }
        }
      }
    }
  }
}
%    \end{macrocode}
% Remodelling the footnotes for more pleasant display
%    \begin{macrocode}
\deffootnote{0em}{0em}{\thefootnotemark\hskip .5em}
\renewcommand{\footnoterule}{%
  % \kern -4.5pt
  % \hrule width \textwidth height 0.5pt
  % \kern 4pt
}
%    \end{macrocode}
% \subsubsection{Heading fonts (KOMA-Script customisation)}
%
% All heading sizes and weights are re-declared here to achieve a compact,
% dense layout that conserves space on the tightly page-budgeted DFG forms:
%  |disposition| is reset to |\normalfont| (KOMA default is bold)
%  so all heading levels start from the same base.
%  Chapter headings (section dividers) are set at 20\,pt bold to
%  stand out without the very large spacing of \cs{Huge}.
%  Section, subsection and subsubsection headings all share
%  12\,pt bold/normal weight, creating a hierarchy that relies on
%  bold vs.\ normal rather than size to distinguish levels.
% The TOC is configured to omit chapter page numbers (they would be
% meaningless given the DFG form structure) and to show section entries
% with a dash-style page separator.  Project TOC entries deliberately use only
% their compact project number, so the fixed number column remains narrow and
% ordinary section titles are not pushed unnecessarily far to the right.
%    \begin{macrocode}
\setkomafont{title}{\Huge\bfseries}
% \setkomafont{disposition}{\normalfont}
\setkomafont{disposition}{\normalfont\sffamily\bfseries}
\setkomafont{descriptionlabel}{\normalfont\bfseries}
%\setkomafont{chapter}{\huge\bfseries}
%\setkomafont{section}{\normalsize\bfseries}
%\setkomafont{subsection}{\normalsize}
%setkomafont{subsubsection}{\normalsize}
\setkomafont{chapter}{\fontsize{20}{10}\selectfont\bfseries}
\setkomafont{section}{\fontsize{12}{10}\selectfont\bfseries}
\setkomafont{subsection}{\fontsize{12}{10}\selectfont}
\setkomafont{subsubsection}{\fontsize{12}{10}\selectfont}
\setkomafont{footnotenumber}{\normalfont\sffamily}
\setkomafont{pageheadfoot}{\normalfont\footnotesize\sffamily}
%    \end{macrocode}
% Adjusting the style for the table of contents.
% First we want to have the normalfont for the chapter entries
%    \begin{macrocode}
\addtokomafont{chapterentry}{\normalfont}
%    \end{macrocode}
%    \begin{macrocode}
\RedeclareSectionCommands[
  font=\usekomafont{subsection},
  % beforeskip=1pt,
  % afterskip=.5pt
]{subsubsection}

\RedeclareSectionCommands[
  tocraggedpagenumber,
  toclinefill=\tocpageseparator,
  tocindent=0em,
  tocnumwidth=4em,
  tocpagenumberbox=\tocpagenumberbox,% <- added
  % tocpagenumberformat=\textsf,
  beforeskip= 0ex,
  afterskip= 0.01ex
]{section,subsection,subsubsection}

\RedeclareSectionCommands[
  tocbeforeskip=2ex,
  tocentryformat=\bfseries\large,
]{section}

\newcommand\tocgobble[1]{}% <- added
\newcommand\tocpageseparator{\normalsize\bfseries\,\mbox{\color{\l_@@_custom_tableLines_tl}---}\,}
\newcommand\tocpagenumberbox[1]{\mbox{#1}}% <- added
% no page number for chapters in TOC
\RedeclareSectionCommands[
  tocraggedpagenumber,
  toclinefill           =\tocgobble,
  tocindent             =0em,
  tocnumwidth           =4em,
  tocpagenumberbox      =\tocgobble,% <- added
  % tocpagenumberformat =\textsf,
  beforeskip            = 0ex,
  afterskip             =0.1ex,
  tocentryformat        =\bfseries\Large\sffamily,
]{chapter}
%    \end{macrocode}
% the depth of chapter is configurable,
% so using this is instead of a absolute
% number is recommended
%    \begin{macrocode}
\setcounter{secnumdepth}{\subsectiontocdepth}
\setcounter{tocdepth}{\subsectiontocdepth}
%    \end{macrocode}
% \subsubsection{ORCiD display commands}
%
% Two commands render ORCiD identifiers:
% \begin{description}
%   \item[\cs{ORCiD}\marg{0000-0000-0000-0000}] Inline use: renders
%         the ORCiD icon followed by the ID as a hyperlink.
%         Intended for manual insertion in text.
%   \item[\cs{getORCiD}\oarg{db}\marg{id}] Database-driven use: looks up
%         the |orcid| field from the |person| database for the given person
%         ID and renders \cs{ORCiD} automatically.  If the field is missing,
%         a |missing-orcid| warning is raised instead of silently omitting
%         the identifier.  The warning is suppressed during the tabularray
%         measuring pass (\cs{lTblrMeasuringBool}) to avoid duplicates.
% \end{description}
% The ORCiD brand green (|orcid| colour) is defined in the colour palette
% section above.  The icon uses the \pkg{academicons} \cs{aiOrcid} glyph.
%    \begin{macrocode}
\RequirePackage{pifont}
\RequirePackage{academicons}
% =============================================================================
% ORCiD-Befehle
% =============================================================================

% Speicher für den per Datenbank gefundenen ORCiD-Wert
\providecommand{\theORCiDValue}{}

% --- Icon ---------------------------------------------------------------------
\NewDocumentCommand{\orcidIcon}{}
{{\sffamily\textcolor{orcid}{\aiOrcid}}}

% --- Reine Wert-Abfrage (ohne Ausgabe) ----------------------------------------
% Holt nur den ORCiD-Wert aus der Datenbank in \theORCiDValue.
% Nützlich, wenn der Wert ohnehin schon per Multi-Fetch geladen wurde
% oder wenn man später formatieren will.
\NewDocumentCommand{\getORCiDvalue}{O{person} m}
{%
  % #1: Datenbank, default ist person
  % #2: id der Person
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  { \cs_set:Npn \theORCiDValue { } }
  { \DTLgetvalueforkey{\theORCiDValue}{orcid}{#1}{id}{#2} }%
}

% --- Formatierung eines bereits geladenen ORCiD-Werts -------------------------
% Erwartet, dass \theORCiDValue gesetzt ist (z.B. via \getORCiDvalue oder
% per \getEntry*[...]{id}{\theORCiDValue=orcid, ...}).
\NewDocumentCommand{\formatORCiD}{O{person} m}
{%
  % #1: Datenbank (für Warnungen / Tag-Overlay)
  % #2: id der Person (für Warnungen / Tag-Overlay)
  \DTLifnullorempty{\theORCiDValue}
  {%
  	\bool_if:NF \lTblrMeasuringBool
  	{ \msg_warning:nnee {dfg}{missing-orcid}{#1}{#2} }%
  	\mbox{~} % if no orcid present
  }
  {%
  	\orcidIcon\,%
  	\dfgShowTag{#2}{orcid}
  	{\href{https://orcid.org/\theORCiDValue}{\theORCiDValue}}[#1]%
  }%
}

% --- Komfort-Befehl: Fetch + Format in einem Aufruf ---------------------------
% Gleiche API wie der ursprüngliche \getORCiD, damit bestehende Aufrufe
% weiterhin funktionieren.
\NewDocumentCommand{\getORCiD}{O{person} m}
{%
  % #1: Datenbank, default ist person
  % #2: id der Person
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  {
    \getORCiDvalue[#1]{#2}%
    \formatORCiD[#1]{#2}%
  }
}

% --- Inline-Variante mit literaler ORCiD --------------------------------------
% Für direkte Angaben ohne Datenbank-Lookup.
\NewDocumentCommand{\ORCiD}{m}
{(\raisebox{-1pt}{\orcidIcon}\,\href{https://orcid.org/#1}{#1})}
%    \end{macrocode}
% \subsubsection{siunitx configuration}
%
% \pkg{siunitx} options must be forwarded with \cs{PassOptionsToPackage}
% \emph{before} the package is implicitly loaded by
% |\UseTblrLibrary{siunitx}|, otherwise they arrive too late.
%
% Key choices:
%  |group-minimum-digits=4|: numbers with 4+ digits get a thousands
%  separator (so |88200| formats as |88,200| EUR).
%  |group-separator={,}|: European style comma separator.
%  |table-auto-round=true|: silently rounds values to fit the
%  |table-format| without requiring \cs{num} wrappers everywhere.
%  |drop-zero-decimal=true|: suppresses redundant decimal zeros in numeric
%  and EUR cells while retaining genuinely fractional values such as explicit
%  animal-housing rates.
%  |mode=match|: inherits the surrounding text font, so numbers
%  in tables match the |\footnotesize| row font automatically.
%  |text-family-to-math=true|, |text-series-to-math=true|: pass
%  the current font family and series into math mode, keeping
%  bold/italic numbers consistent with their surrounding text.
%    \begin{macrocode}
\PassOptionsToPackage{
  mode =  match,
  propagate-math-font = true,
  % reset-math-version  = false,
  % reset-text-family   = false,
  % reset-text-series   = false,
  % reset-text-shape    = false,
  text-family-to-math = true,
  text-series-to-math = true,
  tight-spacing       = true,
  group-minimum-digits  = 4, % --> 1.234 instead of 1234
  group-separator        = {,},% for "12.345" instead of "12 345" %
  table-format = 6,
  table-alignment-mode  = format,
  table-auto-round     = true,
  drop-zero-decimal    = true,
  locale                =UK,
  input-decimal-markers = {.},
  output-decimal-marker = {.},
  input-ignore={,},
  parse-numbers = true
}{siunitx}
%    \end{macrocode}
% This is the package for our tables and we are using quite a bunch of
% additional libraries.
%    \begin{macrocode}
\RequirePackage{tabularray}
\UseTblrLibrary{booktabs}
\UseTblrLibrary{diagbox}
\UseTblrLibrary{siunitx}
\UseTblrLibrary{counter}
\UseTblrLibrary{functional}
%    \end{macrocode}
% \subsubsection{tabularray setup and table themes}
%
% \pkg{tabularray} renders each cell \emph{twice}: once in a hidden
% measuring pass to determine column widths, and once for final output.
% This means every database query, numeric calculation or warning inside
% a cell body would be executed twice.  The global boolean
% \cs{g\_@@\_tblr\_inside\_bool} (toggled via environment hooks) lets code
% detect the measuring pass so it can skip expensive side effects (e.g.\
% the \texttt{missing-key} warning is suppressed when
% \cs{lTblrMeasuringBool} is |true|).
%    \begin{macrocode}
\bool_new:N \g_@@_tblr_inside_bool
% -- Hook into the beginning and ending of the tblr environment ---------------
\AddToHook{env/tblr/begin}{\bool_set_true:N \g_@@_tblr_inside_bool}
\AddToHook{env/tblr/end}{\bool_set_false:N \g_@@_tblr_inside_bool}
%    \end{macrocode}
% \subsubsection{Custom table definition}
% \paragraph{Base Table Theme}
% Defines the shared templates and outer settings used by all table themes.
%    \begin{macrocode}
\SetTblrOuter[tblr]{label=none,entry=none}
% For long tables:
\cs_new_protected:Npn \mytblr_basecode: {
  % Continuous head/footer templates (use ~ for spaces)
  \DeclareTblrTemplate {conthead-text}{default}{%
  	\normalfont\color{tableContFootHead}%
  	\sffamily\footnotesize%
  	\ldots~continuing~from~previous~page.%
  }
  \DeclareTblrTemplate {contfoot-text}{default}{%
  	\normalfont\color{tableContFootHead}%
  	\sffamily\footnotesize%
  	Continue~on~the~following~page~\ldots%
  }
  % Caption continuation uses conthead
  \DeclareTblrTemplate {capcont}{default}{%
  	\UseTblrTemplate{conthead-text}{default}%
  }
  % Left-align tables
  \RenewDocumentCommand \TblrAlignLeft {} {\RaggedRight}%
  % Common outer settings
}
%    \end{macrocode}
% \paragraph{Table themes}
% Three named tblr themes are provided.  All inherit the shared
% \cs{mytblr\_basecode:} helper (continuous head/footer templates, left
% alignment) via a direct call at theme definition time.
%
% \textbf{plain}: minimal two-rule + alternating-row look used for
% simple supplementary tables (e.g.\ the direct-costs breakdown).
%    \begin{macrocode}
\NewTblrTheme{plain}{
  \mytblr_basecode:
  % plain-only inner tweaks:
  \SetTblrInner{
  	rows         = {font=\footnotesize},
    % Keep row metrics independent of descenders such as p, q, f.
    stretch   = 1,
    rowsep    = .667pt,
  	row{even}={bg=tableRows},
  	width=\linewidth,
  	hline{1,Z}={1pt,fg=tableOuterLines},
  }
}
%    \end{macrocode}
% \textbf{main}: the full-featured style used by all DFG data tables.
% Adds a styled first-row header (blue background, bold sans-serif text),
% a midrule below row 1, caption fonts, and row continuation labels for
% long tables that span multiple pages.
%    \begin{macrocode}
\RenewDocumentCommand\TblrAlignLeft{}{\RaggedRight}
\NewTblrTheme{main}{
  \mytblr_basecode:
  % main-only styles & inner grid:
  \SetTblrStyle{caption-tag}{font=\bfseries\footnotesize\sffamily,tableCaption}
  \SetTblrStyle{caption-text}{tableCaption,\footnotesize}
  \SetTblrInner{%
  	row{odd}={bg=tableRows},
  	width=\linewidth,
  	hline{1,Z}={1pt,fg=tableOuterLines},
  	rowhead      = 1,
  	rows         = {font=\footnotesize},
  	width        = \textwidth,
  	hline{1,Z}   = {
  		1pt,
  		fg =tableOuterLines
  	},
  	hline{2} = {1pt, fg=tableOuterLines}, % midrule
    % Keep row metrics independent of descenders such as p, q, f.
    stretch   = .8,
    rowsep    = .500pt,
  	row{1}       = {
  		bg       = tableHeadingsBG,
  		fg       = tableHeadingsFont,
  		font     = \footnotesize\bfseries,
  		halign   = {c},
  		valign   = {t},
  		guard
  	},
  }%
  % \SetTblrInner{
  %   rows={ht=.5\baselineskip},
  %   rowsep       = 0pt,
  % }
}
%    \end{macrocode}
% \textbf{requestedFundingStaff}: caption styling for the staff roster without
% a table-wide row background.  This lets the roster mark individual
% non-applicable cells with the |tableNoValue| background.
%    \begin{macrocode}
\NewTblrTheme{requestedFundingStaff}{
  \mytblr_basecode:
  \SetTblrStyle{caption-tag}{font=\bfseries\footnotesize\sffamily,tableCaption}
  \SetTblrStyle{caption-text}{tableCaption,\footnotesize}
}
%    \end{macrocode}
% a table environment for generic tables
%    \begin{macrocode}
\NewDocumentEnvironment{TableEnv}{ m o m m }
{
  % #1: colspec
  % #2: further options
  % #3: caption
  % #4: label
  \vspace*{-1.5\baselineskip}%
  \DefTblrTemplate{firsthead}{default}%
  {\addtocounter{table}{-1}%
  	\captionof{table}[\InsertTblrText{entry}]%
  	{\InsertTblrText{caption}\vspace*{-2em}}}%
  \begin{tblr}[%
  	%  expand=\tblrbody,
  	theme=main,
  	label  ={#4},
  	caption={#3},
  	long
  ]{%
  	colspec ={#1},
  	row{2-Z}={font=\RaggedRight},
  	rowhead = 1, %<- first row is head
  	#2 %<- in case we need further adjustments
  }
}
{\end{tblr}}
%    \end{macrocode}
% at the final part of projects the costs must be listed more granular.
% this commands provides an easy to use table environment.
%    \begin{macrocode}
\NewDocumentEnvironment{FundingDirectCostsTable}{O{}}
{\textbf{\sffamily#1}\\
  % \nobreak\mbox{~}\\\vspace{-3.25em}\nobreak
  \begin{tblr}[%
  	theme=plain, label=none, entry=none]{
  	rows={font=\footnotesize},
  	colspec={
  			X[t]
  			t{.5cm,halign={right}}
			Q[t,si={table-format=9}]
  		},
  }
}
{\end{tblr}}

%    \end{macrocode}
%    \begin{macrocode}
\RequirePackage{caption}
\captionsetup{%
  % format=llapx,
  hypcap=false,
  format=plain,
  singlelinecheck=off,
  labelsep={colon}, % saving space
  %justification=RaggedRight,
  font={small,sf},
  labelfont={
  		sf,
  		bf, % bold face
  	}
}
\RequirePackage{pgfgantt}
\RequirePackage{placeins}
\RequirePackage{hvfloat} % load after tabularray!!
\hvFloatSet{capPos=bottom,capVPos=top,floatPos=!hb}% this are the default values.
\RequirePackage{marginalia}
\marginaliasetup{
  xsep=0pt,
  width=15mm,
  style=\raggedleft\footnotesize,
  pos=auto,
}
\bool_if:NTF \l_@@_class_cv_bool
  {
    \tl_set_eq:NN \l_@@_custom_biblatexstyle_active_tl
      \l_@@_custom_biblatexstyle_cv_tl
    \tl_set_eq:NN \l_@@_custom_biblatexfeatures_active_tl
      \l_@@_custom_biblatexfeatures_cv_tl
  }
  {
    \tl_set_eq:NN \l_@@_custom_biblatexstyle_active_tl
      \l_@@_custom_biblatexstyle_proposal_tl
    \tl_set_eq:NN \l_@@_custom_biblatexfeatures_active_tl
      \l_@@_custom_biblatexfeatures_proposal_tl
  }
\RequirePackage[
  backend=biber,
  % using the most common style and also saving space.
  % style=ext-numeric, % taken from biblatex-ext
  % just in case we want to switch the style.
  % style=ext-alphabetic,
  %style=ext-authornumber-ecomp,
  style=\l_@@_custom_biblatexstyle_active_tl,
  %introcite=label,
  autocite=inline,
  defernumbers=true, % reset numbered bibliography for each chapter
  giveninits=true, % abbreviate the first names
  maxcitenames=1,
  mincitenames=1,
  maxbibnames=99, % show up to 6 authors of an bib entry (et al. thereafter)
  %nohashothers=true,
  %uniquelist=true,
  %uniquename=allfull,
  %labeldatepartes=true
  \l_@@_custom_biblatexfeatures_active_tl
]{biblatex}
%    \end{macrocode}
% In final documents, \pkg{biblatex-ext-oa} can mark open-access publications
% directly in the bibliography.  Draft documents do not load the package, so
% they avoid DOI API checks and related warnings.  The DOI API backend is useful,
% but \pkg{biblatex-ext-oa-doiapi} and the |doiapi| option can only be used with
% LuaLaTeX.  With LuaTeX binaries from version 1.17.0 onwards, the LuaSocket
% module |socket.http| is exposed only when LuaTeX is started with the
% command-line option |--socket|.  If we always passed |doiapi=true| in final
% mode, a normal final compile without |--socket| would abort while loading
% \pkg{biblatex-ext-oa-doiapi}.
%
% After a user opts in with a contact address, the guard asks LuaTeX whether
% |require("socket.http")| succeeds.  The result is written back into the
% temporary expl3 string |\l_tmpa_str| as the literal text |true| or |false|.
% The Lua code is written without TeX-relevant whitespace, because expl3
% ignores spaces while tokenising this part of the class source; semicolons
% keep the Lua syntax unambiguous after docstrip has generated the |.cls| file.
%
% Automatic lookup is enabled only when LuaSocket is available and the user has
% supplied a non-empty \refKey{doiAPIMail}.  The address is passed to
% \cs{SetDOIAPIMail}; the class never sends a placeholder or maintainer address
% on behalf of its users.  If either prerequisite is missing, the class emits a
% specific warning and loads \pkg{biblatex-ext-oa} with |doiapi=false| so manual
% BibTeX annotations such as |doi+an:default = {=openaccess}| continue to work.
%
% The TikZ symbol package draws the open-access symbols.  The |oanet| symbol is
% the open-access symbol from open-access.net (https://open-access.net/), logo
% by Medien + Design, Center for Digital Systems, Competence Center for
% E-Learning and Multimedia, Freie Universität Berlin, CC BY 4.0
% (https://creativecommons.org/licenses/by/4.0/).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_biblatex_oa_load_without_api:
  {
    \RequirePackage[
      doiapi=false,
      symbolpackage=tikz,
      symbol=oanet]{biblatex-ext-oa}
  }

\bool_if:NT \l_@@_class_final_bool
  {
    \tl_if_blank:VTF \l_@@_custom_doi_api_mail_tl
      {
        \msg_info:nn { dfg } { biblatex-ext-oa-doiapi-email-missing }
        \@@_biblatex_oa_load_without_api:
      }
      {
        \str_set:Nx \l_tmpa_str
          {
            \directlua
              {if(pcall(require,"socket.http"))then;tex.sprint("true");else;tex.sprint("false");end}
          }
        \str_if_eq:VnTF \l_tmpa_str { true }
          {
            \RequirePackage[
              doiapi=true,
              symbolpackage=tikz,
              symbol=oanet]{biblatex-ext-oa}
            \ExecuteBibliographyOptions{openaccess=doiapi}
            \exp_args:NV \SetDOIAPIMail \l_@@_custom_doi_api_mail_tl
          }
          {
            \msg_warning:nn { dfg } { biblatex-ext-oa-doiapi-unavailable }
            \@@_biblatex_oa_load_without_api:
          }
      }
  }
\renewcommand*{\bibfont}{\small}
% A project-text build with publication processing disabled must not require a
% matching biber run merely to keep inline source references readable.  Replace
% the common single-citation commands with quiet key markers; enabling
% |fastcompile-project-show-publications| restores biblatex's normal commands unchanged.
\bool_if:nTF
  {
    \l_@@_class_fastcompile_project_bool
    && ! \l_@@_class_fastcompile_project_show_publications_bool
  }
  {
    % Do not register bibliography data sources or parse a stale full-build
    % .bbl.  Keep biblatex's ordinary initialisation and refsection setup, but
    % replace its data-file stage with the minimum empty-section state.
    \cs_set_protected:Npn \blx@bblfile
      {
        \blx@secinit
        \blx@generate@bbl@mdfivesum@notfound
        \global\togglefalse{blx@bbldone}
        \csnumgdef{blx@labelnumber@\the\c@refsection}{0}
      }
    \NewDocumentCommand{\dfgFastCitation}{m}
      { {\color{black-50}\scriptsize\ttfamily [#1]} }
    \RenewDocumentCommand{\autocite}{s o o m}
      { \dfgFastCitation{#4} }
    \RenewDocumentCommand{\cite}{s o o m}
      { \dfgFastCitation{#4} }
    \RenewDocumentCommand{\parencite}{s o o m}
      { \dfgFastCitation{#4} }
    \RenewDocumentCommand{\textcite}{s o o m}
      { \dfgFastCitation{#4} }
    \RenewDocumentCommand{\footcite}{s o o m}
      { \dfgFastCitation{#4} }
    \RenewDocumentCommand{\smartcite}{s o o m}
      { \dfgFastCitation{#4} }
    \RenewDocumentCommand{\nocite}{m} { }
    % Ignore citation requests restored from auxiliary files produced by a full
    % proposal build.  The fast source commands above do not write replacements.
    \cs_set_protected:Npn \abx@aux@cite   #1#2   { }
    \cs_set_protected:Npn \abx@aux@segm   #1#2#3 { }
    \cs_set_protected:Npn \abx@aux@nocite #1#2   { }
    % This mode deliberately has no bibliography work, so do not advertise a
    % biber rerun in the end-of-document logreq record.
    \AtEndDocument
    {
      \global\let\blx@rerun@biber\relax
      \global\togglefalse{blx@runbiber}
    }
  }
  {
    \addbibresource{bib/dfg-base.bib}
    % The conversion workflow stores bibliography entries that still need
    % review separately.  Load that file when present without requiring it for
    % normal template installations.
    \IfFileExists{bib/conversion-missing.bib}
      {\addbibresource{bib/conversion-missing.bib}}
      {}
    \addbibresource{bib/dfg-strings.bib}
  }
%    \end{macrocode}
% The \cs{AtEveryBibitem} hook strips fields that are irrelevant for a
% funding proposal (URL, month, note, ISSN/ISBN, language) from every
% entry, keeping the reference list compact.  These fields are cleared
% during output only; the |.bib| source files are unchanged.
%    \begin{macrocode}
\AtEveryBibitem{
  \clearfield{url}
  \clearfield{month}
  \clearfield{note}
  \clearfield{issn}
  \clearfield{isbn}
  \clearlist{language}}
%    \end{macrocode}
% \subsubsection{Shared authorship annotations}
%
% The |annote| field in |.bib| entries supports two special values:
% |equal| (for equal-first-author contributions) and |sharedlast| (for
% shared last authorship).  When present, \cs{mkbibnamefamily} appends
% an asterisk |*| after the family name via \cs{addendumasterisk}.
% The asterisk is only printed inside bibliography environments
% (\cs{ifbibliography}), not in inline citations.
%
% Use in |.bib|: add |addendum = equal| or |addendum = sharedlast| (no |{}|) to the affected author's annotation field.
%    \begin{macrocode}
\newcommand{\addendumasterisk}{\ifbibliography{*}{}}
\newcommand{\addendumhashtag}{\ifbibliography{\textsuperscript{\#}{}}}
% There is also the possibility that authors share the last authorship.
% with the bib-string `lastShared` we can get it work.
\renewcommand*{\mkbibnamefamily}[1]{%
  \ifitemannotation{equal} % first check for equal contribution
  {#1\addendumasterisk}% add a * for those authors
  {
  	% Then we check for "shared last authorship"
  	\ifitemannotation{sharedlast}%
  	{#1\addendumhashtag}% adding a symbol
  	{#1}% do nothing for any one else.
  }}
%    \end{macrocode}
%
%  \begin{macrocode}
% \subsubsection{datatool: database backend}
%
% \pkg{datatool} provides the |DTL*| commands that are the actual in-memory
% database engine behind the keyset-based metadata system.  \pkg{csquotes}
% is loaded just before it because \cs{blockcquote} is used in the
% documentation abstract and the class patches \cs{mkccitation} to suppress
% the extra parentheses that csquotes adds around \cs{autocite} results.
\RequirePackage{csquotes}
\renewcommand{\mkccitation}[1]{ (#1)}
\RequirePackage{datatool}
%    \end{macrocode}
% loading |tikz| at least for the thumb index.
%    \begin{macrocode}
\RequirePackage{tikz}
\ExplSyntaxOff
\usetikzlibrary{calc}
\usetikzlibrary{shapes.misc}
\usetikzlibrary{patterns,patterns.meta}
\ExplSyntaxOn
%    \end{macrocode}
% loading these two packages last
%    \begin{macrocode}
\RequirePackage{hyperref}
\RequirePackage{cleveref}
\crefname{workpackagesi}{\bfseries\color{referenceWP}WP}{\bfseries\color{referenceWP}WPs}
\creflabelformat{workpackagesi}{\color{referenceWP}#2\color{referenceWP}\bfseries#1\color{referenceWP}#3}
\crefname{workpackagesii}{\bfseries\color{referenceWP}WP}{\bfseries\color{referenceWP}WPs}
\creflabelformat{workpackagesii}{\color{referenceWP}#2\bfseries\color{referenceWP}#1\color{referenceWP}#3}

\crefname{aimsi}{\bfseries\color{referenceAim}Aim}{\bfseries\color{referenceAim}Aims}
\creflabelformat{aimsi}{\color{referenceAim}#2\color{referenceAim}\bfseries#1\color{referenceAim}#3}



% \subsubsection{Preamble end: global metadata extraction and hyperref}
%
% The \cs{AfterEndPreamble} hook fires after all user preamble code
% (including |dfg-customization.tex| and all \cs{addEntry} calls) but
% before \cs{begin}|{document}|.  This is the earliest point at which
% the |meta| database is guaranteed to be fully populated.
%
% The block extracts the five core CRC fields into named macros
% (\cs{theCRCname}, \cs{theCRCnumber}, \cs{theCRCaffiliation}, etc.)
% that are used in headers, footers, and the hyperref PDF metadata.  It
% treats |meta.ref-affiliation-id| as a comma-separated list: the public
% affiliation macros contain human-readable name and location lists, while
% \cs{theApplicantID} retains the normalized id list for database filters.  It
% also derives \cs{theFundingPeriodNumeralPrevious} by subtracting 1 from
% \cs{theFundingPeriodNumeral}, which is used in the gender equality tables
% to reference the previous funding period.
%
% The \cs{hypersetup} call here (rather than in the preamble) avoids
% needing the user to duplicate CRC metadata in a separate hypersetup block.
\clist_new:N \l_@@_applicant_affiliation_id_clist
\seq_new:N \l_@@_applicant_affiliation_name_seq
\seq_new:N \l_@@_applicant_affiliation_location_seq
\seq_new:N \l_@@_other_applicant_affiliation_name_seq
\tl_new:N \l_@@_applicant_affiliation_name_tl
\tl_new:N \l_@@_applicant_affiliation_location_tl

\cs_new_protected:Npn \@@_set_applicant_affiliation_metadata:
{
  \DTLifnullorempty{\theApplicantID}
    { \clist_clear:N \l_@@_applicant_affiliation_id_clist }
    {
      \clist_set:Nx \l_@@_applicant_affiliation_id_clist
        { \theApplicantID }
      \clist_remove_duplicates:N \l_@@_applicant_affiliation_id_clist
    }
  \tl_set:Nx \l_tmpa_tl
    { \clist_use:Nn \l_@@_applicant_affiliation_id_clist {,} }
  \cs_set:Npx \theApplicantID { \exp_not:V \l_tmpa_tl }
  \cs_set_eq:NN \theAffiliationValue \theApplicantID
  \seq_clear:N \l_@@_applicant_affiliation_name_seq
  \seq_clear:N \l_@@_applicant_affiliation_location_seq
  \clist_map_inline:Nn \l_@@_applicant_affiliation_id_clist
  {
    \DTLifdbexists{affiliation}
    {
      \DTLgetvalueforkey{\l_@@_applicant_affiliation_name_tl}
        {name}{affiliation}{id}{##1}
      \DTLgetvalueforkey{\l_@@_applicant_affiliation_location_tl}
        {location}{affiliation}{id}{##1}
    }
    {
      \tl_set:Nn \l_@@_applicant_affiliation_name_tl {##1}
      \tl_clear:N \l_@@_applicant_affiliation_location_tl
    }
    \DTLifnullorempty{\l_@@_applicant_affiliation_name_tl}
      { \tl_set:Nn \l_@@_applicant_affiliation_name_tl {##1} }
      { }
    \tl_set:Ne \l_tmpb_tl
    {
      \exp_not:N \dfgShowTag{##1}{name}
        {\exp_not:V \l_@@_applicant_affiliation_name_tl}[affiliation]
    }
    \seq_put_right:NV \l_@@_applicant_affiliation_name_seq \l_tmpb_tl
    \DTLifnullorempty{\l_@@_applicant_affiliation_location_tl}
      { }
      {
        \seq_if_in:NVF \l_@@_applicant_affiliation_location_seq
          \l_@@_applicant_affiliation_location_tl
        {
          \tl_set:Ne \l_tmpb_tl
          {
            \exp_not:N \dfgShowTag{##1}{location}
              {\exp_not:V \l_@@_applicant_affiliation_location_tl}
              [affiliation]
          }
          \seq_put_right:NV \l_@@_applicant_affiliation_location_seq
            \l_tmpb_tl
        }
      }
  }
  \cs_set:Npn \theCRCaffiliation
  {
    \seq_use:Nnnn \l_@@_applicant_affiliation_name_seq
      {~and~} {,~} {,~and~}
  }
  \cs_set:Npn \theCRCaffiliationLocation
  {
    \seq_use:Nnnn \l_@@_applicant_affiliation_location_seq
      {~and~} {,~} {,~and~}
  }
  \seq_set_eq:NN \l_@@_other_applicant_affiliation_name_seq
    \l_@@_applicant_affiliation_name_seq
  \seq_pop_left:NNF \l_@@_other_applicant_affiliation_name_seq \l_tmpa_tl
    { \tl_clear:N \l_tmpa_tl }
  \cs_set:Npn \theCRCCoordinatingAffiliation
    { \seq_item:Nn \l_@@_applicant_affiliation_name_seq {1} }
  \cs_set:Npn \theCRCOtherApplicantAffiliations
  {
    \seq_use:Nnnn \l_@@_other_applicant_affiliation_name_seq
      {~and~} {,~} {,~and~}
  }
}

\NewExpandableDocumentCommand{\dfgApplicantAffiliationsTF}{m m}
{
  \int_compare:nNnTF
    { \clist_count:N \l_@@_applicant_affiliation_id_clist } > {1}
    {#2}
    {#1}
}

\NewExpandableDocumentCommand{\dfgOtherApplicantAffiliationsTF}{m m}
{
  \int_compare:nNnTF
    { \clist_count:N \l_@@_applicant_affiliation_id_clist } > {2}
    {#2}
    {#1}
}

\NewDocumentCommand{\dfgCRCName}{}
  { \dfgShowTag{crc}{name}{\theCRCname}[meta] }
\NewDocumentCommand{\dfgCRCNameAddon}{}
  { \dfgShowTag{crc}{nameAddon}{\theCRCnameAddon}[meta] }
\NewDocumentCommand{\dfgCRCNumber}{}
  { \dfgShowTag{crc}{number}{\theCRCnumber}[meta] }
\NewDocumentCommand{\dfgFundingPeriodText}{}
  { \dfgShowTag{crc}{fundingPeriodText}{\theFundingPeriodText}[meta] }
\NewDocumentCommand{\dfgFundingPeriodNumeral}{}
  { \dfgShowTag{crc}{fundingPeriodNumeral}{\theFundingPeriodNumeral}[meta] }
\NewDocumentCommand{\dfgFundingYear}{m}
{
  \dfgShowTag{crc}{fundingYear#1}
  {
    \int_case:nnF {#1}
    {
      {1}{\tmpYearOne}
      {2}{\tmpYearTwo}
      {3}{\tmpYearThree}
      {4}{\tmpYearFour}
      {5}{\tmpYearFive}
    }
    {#1}
  }[meta]
}
\NewDocumentCommand{\dfgFundingYearPrevious}{m}
{
  \dfgShowTag{crc}{fundingYearPrevious#1}
  {
    \int_case:nnF {#1}
    {
      {1}{\tmpYearPreviousOne}
      {2}{\tmpYearPreviousTwo}
      {3}{\tmpYearPreviousThree}
      {4}{\tmpYearPreviousFour}
      {5}{\tmpYearPreviousFive}
    }
    {#1}
  }[meta]
}

\AfterEndPreamble{
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  {
    \clist_clear:N \l_@@_applicant_affiliation_id_clist
    \cs_set:Npn \theApplicantID                  { }
    \cs_set:Npn \theCRCname                      { CRC~project~draft }
    \cs_set:Npn \theCRCnameAddon                 { }
    \cs_set:Npn \theCRCnumber                    { draft }
    \cs_set:Npn \theFundingPeriodNumeral         { 1 }
    \cs_set:Npn \theFundingPeriodText            { draft }
    \cs_set:Npn \theAffiliationValue             { }
    \cs_set:Npn \theCRCaffiliation               { }
    \cs_set:Npn \theCRCaffiliationLocation       { }
    \cs_set:Npn \theCRCCoordinatingAffiliation   { }
    \cs_set:Npn \theCRCOtherApplicantAffiliations{ }
    \cs_set:Npn \tmpYearOne                      { Year~1 }
    \cs_set:Npn \tmpYearTwo                      { Year~2 }
    \cs_set:Npn \tmpYearThree                    { Year~3 }
    \cs_set:Npn \tmpYearFour                     { Year~4 }
    \cs_set:Npn \tmpYearFive                     { Year~5 }
    \cs_set:Npn \tmpYearPreviousOne              { Previous~year~1 }
    \cs_set:Npn \tmpYearPreviousTwo              { Previous~year~2 }
    \cs_set:Npn \tmpYearPreviousThree            { Previous~year~3 }
    \cs_set:Npn \tmpYearPreviousFour             { Previous~year~4 }
    \cs_set:Npn \tmpYearPreviousFive             { Previous~year~5 }
  }
  {
  \DTLgetvalueforkey{\theApplicantID}{ref-affiliation-id}{meta}{id}{crc}
  \DTLgetvalueforkey{\theCRCname}{name}{meta}{id}{crc}% getting Title of CRC
  \DTLgetvalueforkey{\theCRCnameAddon}{nameAddon}{meta}{id}{crc}% getting name addon of CRC
  \DTLgetvalueforkey{\theCRCnumber}{number}{meta}{id}{crc}% getting number of CRC
  \DTLgetvalueforkey{\theFundingPeriodNumeral}{fundingPeriodNumeral}{meta}{id}{crc}% getting period of CRC
  \DTLgetvalueforkey{\theFundingPeriodText}{fundingPeriodText}{meta}{id}{crc}% getting period of CRC
  \@@_set_applicant_affiliation_metadata:
  \DTLgetvalueforkey{\tmpYearOne}  {fundingYear1}{meta}{id}{crc}%
  \DTLgetvalueforkey{\tmpYearTwo}  {fundingYear2}{meta}{id}{crc}%
  \DTLgetvalueforkey{\tmpYearThree}{fundingYear3}{meta}{id}{crc}%
  \DTLgetvalueforkey{\tmpYearFour} {fundingYear4}{meta}{id}{crc}%
  \DTLgetvalueforkey{\tmpYearFive} {fundingYear5}{meta}{id}{crc}%

  \DTLgetvalueforkey{\tmpYearPreviousOne}  {fundingYearPrevious1}{meta}{id}{crc}%
  \DTLgetvalueforkey{\tmpYearPreviousTwo}  {fundingYearPrevious2}{meta}{id}{crc}%
  \DTLgetvalueforkey{\tmpYearPreviousThree}{fundingYearPrevious3}{meta}{id}{crc}%
  \DTLgetvalueforkey{\tmpYearPreviousFour} {fundingYearPrevious4}{meta}{id}{crc}%
  \DTLgetvalueforkey{\tmpYearPreviousFive} {fundingYearPrevious5}{meta}{id}{crc}%
  }


  \providecommand{\thisCRC}
    {CRC\,\texorpdfstring
      {\dfgShowTag{crc}{number}{\theCRCnumber}[meta]}
      {\theCRCnumber}\xspace}
  % Shared implementation for the user-level \CRC and \TRR commands.
  % #1 is the star boolean, #2 the optional title, #3 the printed programme
  % type, and #4 the CRC/TRR number to print and compare with the current CRC.
  % Current CRCs use \thisCRC in the unstarred form; starred current references
  % include the CRC title from the metadata unless an explicit title is given.
  % External CRCs/TRRs always print the requested number and add the optional
  % title when one is supplied.
\cs_new_protected:Npn \@@_crc_print:nnnn #1 #2 #3 #4
  {
    \tl_if_eq:VnTF \theCRCnumber {#4}
      {
        \IfBooleanTF{#1}
          {
            #3\,#4
            \IfValueTF{#2}
              { \ \textit{#2} }
              { \ \textit{\dfgShowTag{crc}{name}{\theCRCname}[meta]} }
          }
          {
            \thisCRC
            \IfValueT{#2}
              { \ \textit{#2} }
          }
      }
      {
        #3\,#4
        \IfValueT{#2}
          { \ \textit{#2} }
      }
  }

  % User-level wrappers around \@@_crc_print:nnnn. They differ only in the
  % printed programme type.
\NewDocumentCommand{\CRC}{s o m}
  {
    \@@_crc_print:nnnn {#1} {#2} {CRC} {#3}
  }

\NewDocumentCommand{\TRR}{s o m}
  {
    \@@_crc_print:nnnn {#1} {#2} {CRC/TRR} {#3}
  }
 %\DTLgetvalueforkey{\theNameSpokespersonPosition}{position}{VIP}{specialRole}{spokesperson}% getting Title of Spokesperson
  %\DTLgetvalueforkey{\theNameSpokespersonName}{name}{VIP}{specialRole}{spokesperson}% getting Title of CRC
  %\DTLgetvalueforkey{\theNameSpokespersonNameFirst}{nameFirst}{VIP}{specialRole}{spokesperson}% getting Title of CRC
  \newcommand{\theFundingPeriodNumeralPrevious}{%
  	\number\numexpr\theFundingPeriodNumeral-1\relax%
  }
  % hyperref options
  \hypersetup{          % setup the hyperref-package options
  	% unicode      = true,
  	pdftitle     = {\theCRCname.\space\theCRCnameAddon},  %   - title (PDF meta)
  	pdfsubject   = {\crc},%   - subject (PDF meta)
  	pdfauthor    = {CRC\,\theCRCnumber~ \theCRCname},  %   - author (PDF meta)
  	%   pdfauthortitle = {\theNameSpokespersonPosition},
  	%   pdfcopyright = {Copyright (c) \thisCRC All rights reserved.},
  	pdfhighlight = /N,
  	pdfdisplaydoctitle = true,
  	pdflang     = {en},
  	%   pdfcaptionwriter = {\theNameSpokespersonNameFirst \theNameSpokespersonName},
  	% pdfencoding = auto,
  	pdfproducer = {LuaLaTeX},
  	% pdflicenseurl = {http://creativecommons.org/licenses/by-nc-nd/4.0/},
  	% plainpages  = false,      %   -
  	colorlinks  = true, % -Colours links instead of ugly boxes
  	urlcolor    = blue, %Colour for external hyperlinks
  	linkcolor   = black,%rwthBlue, %Colour of internal links
  	citecolor   = black, %Colour of citations
  	% linkbordercolor=rwthRed,
  	linktoc     = page,
  	pdfborder   = {0 0 0},      %   -
  	breaklinks  = true,      %   - allow line break inside links
  	bookmarksnumbered  = true,    %
  	bookmarksopenlevel = 1,
  	bookmarksopen      = true,    %
  	bookmarksdepth     = 3,
  	%  final       = true,  % = true, nur bei web-Dokument!! (wichtig!!)
  	%  hypertexnames = false,
  	%  pageanchor=false,
  	%https://tex.stackexchange.com/questions/623377/how-to-increase-the-setting-dest-names-size-using-lualatex-on-tl-2021
  }
}
%    \end{macrocode}
% \subsubsection{\cs{changeSettings}}
%
% \cs{changeSettings}\marg{key=value,...} is the public command used
% to customise the document class beyond its defaults.  It delegates
% directly to \cs{keys\_set:nn}|{dfg/custom}{\meta{key=value,...}}|.
%
% It should be called inside |preamble/dfg-customization.tex| so that all
% customisations are centralised.  Examples:
% \begin{dispListing*}{title={Typical changeSettings call}}
%   \changeSettings{
%     font                        = Arial,
%     crcLogoPath                 = img/logo-crc,
%     affiliationLogoPath         = img/logo-affiliation,
%     doiAPIMail                  = researcher@example.org,
%     projectPIOncePerSection     = true,
%     collaborationAreaColors     = {A=projectA,B=projectB,Q=projectQ},
%     collaborationAreaPalette    = {orange,violet,teal,brown},
%     salary@postDoc              = 90000,
%     animalHousing@mouse         = 0.80,
%     thumbindex                  = false,
%     biblatexstyleCV             = ext-numeric-comp,
%     biblatexstyleFeatureCV      = {sorting=none},
%     biblatexstyleProposal       = ext-authoryear-ecomp,
%     biblatexstyleFeatureProposal= {dashed=false},
%     color@table@rows            = blue-10,
%   }
% \end{dispListing*}
% The command is defined before \pkg{biblatex} is loaded so bibliography
% package options from the customization file take effect in time.
% \subsubsection{Thumb index implementation}
%
% The thumb index is a series of colour tabs printed on the outer margin
% of each page to help readers navigate between chapters or project sections.
% Each tab occupies one slot in a vertical grid that repeats with a period
% equal to \texttt{thumbindex@pattern} (default: 10).
%
% \textbf{Geometry calculation:}
% \cs{thumb\_compute\_height:} calculates the slot height as
% |(\cs{paperheight} - topmargin - bottommargin) / pattern|.
% This is called once at class load time and whenever the customisation
% keys change via \cs{changeSettings}.
%
% \textbf{Placement:}
% \cs{thumb\_place\_node:nnn} draws an absolutely-positioned TikZ node
% on the current page using |remember picture,overlay|.  The anchor is
% placed at |(current page.north west/east) - (0, topmargin + height*(index-1))|.
% The node style |thumb| is a rounded rectangle with the right-side arc
% set to |0pt| (flat edge against the page boundary) and the left side
% fully rounded.
%
% \textbf{Call pattern:}
% \cs{printThumbIndex}\oarg{colour}\marg{label} increments the slot counter,
% wrapping at \texttt{pattern}, then injects the node into both the header
% and footer layers via \cs{lehead}/\cs{lohead} so the tab appears on
% the page regardless of which scrlayer-scrpage style is active.  The
% optional colour argument allows project-specific hues (typically the
% |projectA|, |projectB|, |projectQ| aliases).
%
% \cs{printThumbIndexOff} clears the header/footer layers to suppress the
% tab on pages where no thumb index is desired (e.g.\ the bibliography).
%    \begin{macrocode}
\int_new:N \l_thumb_index_int
\int_zero:N \l_thumb_index_int
%    \end{macrocode}
% the height of the thumb index changes depending on other numbers and is
% hereforth calculated and we have to execute it once.
%    \begin{macrocode}
\dim_new:N \l_thumb_height_dim
\cs_new_protected:Npn \thumb_compute_height:
{
  %   (\paperheight - top - bottom) / pattern
  \dim_set:Nn \l_thumb_height_dim
  {
  	( \paperheight
  	- \l_@@_custom_thumbindex_topmargin_dim
  	- \l_@@_custom_thumbindex_bottommargin_dim )
  	/ \l_@@_custom_thumbindexpattern_int
  }
}
\thumb_compute_height:
%    \end{macrocode}
% defining now the layout of the thumb index. Be aware of the stripped spaces in
% the LaTeX3 environment.
%    \begin{macrocode}
\tikzset
{
  thumb/.style=
  	{
  		fill   = thumbIndexBG ,      % colour may be changed later
  		text   = thumbIndexFont,
  		minimum~ height = \dim_use:N \l_thumb_height_dim,
  		text~ width     = \dim_use:N \l_@@_custom_thumbindex_width_dim,
  		outer~ xsep      = 0em,
  		font            = \tl_use:N \l_@@_custom_thumbindex_font_tl,
  		inner~ xsep     = 2em,
  	}
}
%    \end{macrocode}
% we need a couple of helper commands though.
%   The <even/odd> macros are now tiny wrappers around a single
%   protected function that does the arithmetic in expl3.
%    \begin{macrocode}
\cs_new_protected:Npn \thumb_place_node:nnn #1#2#3
{
  %  #1 = west|east    (anchor direction)
  %  #2 = left|right   (text alignment)
  %  #3 = node contents
  \begin{tikzpicture}[remember~ picture,overlay]
  	\node[
  		thumb,
  		align   =#2,
  		anchor  =#1,
  		rounded~ rectangle,
  		rounded~ rectangle~ #1~ arc=0pt
  	]
  	% ---------------------------------------------------------
  	%   absolute position = (current page.north <west/east>) –
  	%                       (0 , vertical offset)
  	%   The whole thing must be inside $ … $.
  	% ---------------------------------------------------------
  	at
  	($ (current~page.north~ #1)~ -~
  		(0,\dim_eval:n{
  			\l_@@_custom_thumbindex_topmargin_dim
  			+ \l_thumb_height_dim * (\l_thumb_index_int - 1)
  		}) $)
  	{#3};
  \end{tikzpicture}
}

\NewDocumentCommand{\evenpageletterthumb}{m}
{ \thumb_place_node:nnn {west}{left}{#1} }
\NewDocumentCommand{\oddpageletterthumb}{m}
{ \thumb_place_node:nnn {east}{right}{#1} }
%    \end{macrocode}
% Now the key command |\printThumbIndex|.
%    \begin{macrocode}
\NewDocumentCommand{\printThumbIndex}{ O{thumbIndexBG} m }
{
  %   #1 (optional) – colour definition used when no project is given
  %   #2 (mandatory) – the letter (or any material) to be printed

  \bool_if:NT \l_@@_custom_thumbindex_bool
  {
  	\colorlet{thumbIndexBG}{#1}

  	% ---- reset index if we have reached the bottom of the column -----
  	\int_compare:nNnT { \l_thumb_index_int } = { \l_@@_custom_thumbindexpattern_int }
  	{ \int_zero:N \l_thumb_index_int }

  	% ---- step to the *next* position -----------------------------------
  	\int_incr:N \l_thumb_index_int

  	% ---- actually place the thumb on the current page ------------------
  	%   (the same node is put into both the header and the foot, so it
  	%   appears on the page no matter which page‑style you use)
  	\lehead[\evenpageletterthumb{#2}]{\evenpageletterthumb{#2}}
  	\lohead[\oddpageletterthumb{#2}]{\oddpageletterthumb{#2}}
  }
}
\NewDocumentCommand{\printThumbIndexOff}{}
{
  \lehead[]{}
  \lohead[]{}
}
%    \end{macrocode}
% \subsubsection{Bold-author mechanism}
%
% The DFG requires that the names of all CRC project leaders are printed in
% bold in every bibliography list so reviewers can immediately identify the
% investigators' output.  This is technically non-trivial because biblatex
% does not natively support singling out individual author names.
%
% The implementation uses a hash-based approach:
% \begin{enumerate}
%   \item For each PI, \refCom{addboldnames} is called with their name as it
%         appears in the |.bib| file (and all common aliases via
%         \refKey{name-alias}).  Each name is written as a |\@misc|
%         |dataonly| entry to an auxiliary |.bib| file.
%   \item During the |\AfterPreamble| pass, the cite command
%         |\nhblx@getmethehash| processes each entry and extracts its
%         biblatex internal hash (a fingerprint stable across style changes)
%         into the list |\nhblx@boldhashes|.
%   \item The name wrapper |boldifhashinlist| applies
%         \cs{mkboldifhashinlist} to every printed author name; if the
%         author's hash appears in the list, the name is wrapped in
%         \cs{mkbibbold} and coloured with |color@reference@boldAuthor|.
% \end{enumerate}
% The mechanism is only activated when |emphasizeAuthors=true| (the default).
% Fallback no-op definitions of \refCom{addboldnames} and \refCom{resetboldnames}
% are provided via \cs{providecommand} so that content files compile
% correctly even if the feature is disabled.
%
% \refCom{addboldnames} should be called in the preamble of both the proposal
% document and the standalone CV document, typically inside
% |preamble/dfg-customization.tex|.
% For displaying certain authors in bold letters, \refKey{emphasizeAuthors}
% (for the switch) and \refCom{addboldnames} (for the addition of authors).
%    \begin{macrocode}
\int_new:N  \g_@@_boldnames_int
\iow_new:N  \g_@@_boldnames_iow
\prop_new:N \g_@@_boldnames_hashes_prop
\tl_new:N   \l_@@_boldnames_name_tl

\bool_if:NT \l_@@_custom_emphasize_authors_bool
{
  % ---------- Auxiliary .bib file -----------------------------------

  \tl_const:Nn \c_@@_boldnames_bibfile_tl { bib/\jobname-boldAuthors.bib }
  \iow_open:Nn \g_@@_boldnames_iow { \c_@@_boldnames_bibfile_tl }
  \iow_now:Nn  \g_@@_boldnames_iow { @comment{Auto-generated~file} }
  \AtEndDocument { \iow_close:N \g_@@_boldnames_iow }
  \addbibresource{\c_@@_boldnames_bibfile_tl}

  % ---------- Writing a single name ---------------------------------
  %
  % We need:
  %   - the entry KEY  (nhblx@name@<N>)  fully expanded
  %   - the AUTHOR field written verbatim (so \"a etc. survive)
  %
  % \iow_now:Nn  → no expansion
  % \iow_now:Nx  → full expansion (breaks accents in names)
  % \iow_now:Nn + \exp_not:n on the name = best of both via \iow_now:Nx

  \cs_new_protected:Npn \@@_boldnames_write:n #1
  {
  	\int_gincr:N \g_@@_boldnames_int
  	% Stash the name so it survives the x-expansion intact.
  	\tl_set:Nn \l_@@_boldnames_name_tl { #1 }
  	\iow_now:Nx \g_@@_boldnames_iow
  	{
  		@misc{nhblx@name@\int_use:N \g_@@_boldnames_int,
  				author~=~{\exp_not:V \l_@@_boldnames_name_tl},
  				options~=~{dataonly=true},
  			}
  	}
  	% Schedule hash extraction after biblatex has loaded the entry.
  	\exp_args:Nx \AfterPreamble
  	{
  		\exp_not:N \hbox_set:Nn \exp_not:N \l_tmpa_box
  		{ \exp_not:N \nhblx@getmethehash
  			{ nhblx@name@ \int_use:N \g_@@_boldnames_int } }
  	}
  }

  % ---------- User-level commands -----------------------------------

  \NewDocumentCommand \addboldnames { m }
  { \clist_map_function:nN { #1 } \@@_boldnames_write:n }

  \NewDocumentCommand \resetboldnames { }
  { \prop_gclear:N \g_@@_boldnames_hashes_prop }

  % ---------- biblatex glue -----------------------------------------

  \DeclareNameFormat{nhblx@hashextract}
  {
  	\prop_gput:Nen \g_@@_boldnames_hashes_prop { \thefield{hash} } { }
  }

  \DeclareCiteCommand{\nhblx@getmethehash}
  {}{ \printnames[nhblx@hashextract][1-999]{author} }{}{}

  \cs_new_protected:Npn \@@_boldnames_mark:n #1
  {
  	\prop_if_in:NeTF \g_@@_boldnames_hashes_prop { \thefield{hash} }
  	{ \mkbibbold { \textcolor{color@reference@boldAuthor} { #1 } } }
  	{ #1 }
  }

  \cs_set_eq:NN \mkboldifhashinlist \@@_boldnames_mark:n

  \DeclareNameWrapperFormat{boldifhashinlist}
  { \renewcommand*{\mkbibcompletename}{\mkboldifhashinlist} #1 }

  \DeclareNameWrapperAlias{sortname}{default}
  \DeclareNameWrapperAlias{default}{boldifhashinlist}
}

%    \end{macrocode}
% We need the fallback of the commands in case the functionality isnt used at all.
%    \begin{macrocode}
\providecommand { \addboldnames   } [1] { }
\providecommand { \resetboldnames }     { }
%    \end{macrocode}
% \subsubsection{Database infrastructure and key families}
%
% All structured data in the proposal (people, projects, institutions,
% funding entries, \ldots) is stored in \pkg{datatool} databases at
% compile time.  Each database is created lazily: \refCom{addEntry} checks
% whether the named database already exists and creates it if not,
% eliminating the need for explicit initialisation calls.
%
% The central mechanism relies on the L3 variable
% \cs{l\_@@\_database\_name\_tl}, which holds the name of the
% currently-active database while a \cs{keys\_set:nn} call is in
% progress.  Every |.code:n| handler in a keyset calls
% \cs{DTLnewdbentry} with that variable as the database name, so no
% explicit database name is needed inside the keyset definition itself.
%
% The token list is reset in each call to \refCom{addEntry} and is wrapped
% in a |\group_begin:/end:| pair to prevent it from leaking across
% independent \refCom{addEntry} calls.
%
% \paragraph{Input validation strategy}
% Choice-valued keys (e.g.\ \refKey{gender}, \refKey{project-type}) use
% |.choices:nn| with an |unknown .code:n| handler wired to the
% |dfg/invalid-value| message.  Free-text keys accept any input.
% Required keys are marked with |.value\_required:n = true| so that
% omitting them produces an immediate error rather than a silent empty
% database field.
%    \begin{macrocode}
\tl_new:N \l_@@_database_name_tl
%    \end{macrocode}
% \paragraph{Keyset \textbf{meta}}
% The |meta| database holds exactly one row with |id=crc| that describes
% the CRC itself.  Its fields are read in \cs{AfterEndPreamble} to populate
% the global macros used in headers, footers, and PDF metadata
% (\cs{theCRCname}, \cs{theCRCnumber}, \cs{theCRCaffiliation}, etc.).
%
% The \refKey{fundingYears} and \refKey{fundingYearsPrevious} keys accept a
% comma-separated list of calendar years (one per funding year) and expand
% them into individually named fields |fundingYear1| \ldots |fundingYear5|,
% which are used e.g. as column headers in the Gantt chart title row.
%
% \refKey{fundingPeriodNumeral} (1, 2 or 3) drives all period-filtered queries:
% only personnel with a matching |period| entry are included in the project
% leader table and the gender equality analysis.
%    \begin{macrocode}
\keys_define:nn { meta }{
  id              .code:n     =  \DTLnewdbentry{\l_@@_database_name_tl}{id}{#1},
  id              .value_required:n = true,
  name      .code:n  = \DTLnewdbentry{\l_@@_database_name_tl}{name}{#1},
  nameAddon .code:n  = \DTLnewdbentry{\l_@@_database_name_tl}{nameAddon}{#1},
  number    .code:n  = \DTLnewdbentry{\l_@@_database_name_tl}{number}{#1},
  fundingPeriodNumeral .choices:nn = { 1 , 2 , 3 }
  	{
  		% store the numeral itself
  		\DTLnewdbentry{\l_@@_database_name_tl}{fundingPeriodNumeral}{#1}
  		% map numeral → text without a property list
  		\int_case:nnF {#1}
  		{
  			{ 1 } { \DTLnewdbentry{\l_@@_database_name_tl}{fundingPeriodText}{first} }
  			{ 2 } { \DTLnewdbentry{\l_@@_database_name_tl}{fundingPeriodText}{second} }
  			{ 3 } { \DTLnewdbentry{\l_@@_database_name_tl}{fundingPeriodText}{third} }
  		}
  		{
  			% fallback (should not happen because of the .choices clause)
  			\msg_warning:nnnn { staff } { invalid-value }
  			{ #1 } { 1 , 2 , 3 }
  		}
  	} ,
  fundingPeriodNumeral / unknown .code:n =
  	{
  		\msg_warning:nnnn { staff } { invalid-value }
  		{ #1 } { 1 , 2 , 3 }
  	} ,
  fundedSince          .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{fundedSince}{#1},
  fundingYears .code:n =
  	{
  		\seq_set_from_clist:Nn \l_meta_funding_years_seq {#1}
  		%--- create the individual entries -----------------
  		\int_zero_new:N \l_tmpa_int
  		\seq_map_inline:Nn \l_meta_funding_years_seq
  		{
  			\int_incr:N \l_tmpa_int
  			\DTLnewdbentry
  			{\l_@@_database_name_tl}
  			{fundingYear\int_use:N \l_tmpa_int}
  			{##1}
  		}
  	},
  fundingYearsPrevious .code:n =
  	{
  		\seq_set_from_clist:Nn \l_meta_funding_years_previous_seq {#1}

  		%--- create the individual entries -----------------
  		\int_zero_new:N \l_tmpa_int
  		\seq_map_inline:Nn \l_meta_funding_years_previous_seq
  		{
  			\int_incr:N \l_tmpa_int
  			\DTLnewdbentry
  			{\l_@@_database_name_tl}
  			{fundingYearPrevious\int_use:N \l_tmpa_int}
  			{##1}
  		}
  	},
  ref-affiliation-id  .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-affiliation-id}{#1},
}
%    \end{macrocode}
% \paragraph{Keyset \textbf{GenderEquality}}
% This keyset is used to populate the \cs{GenderEqualityStaffTable} and
% \cs{GenderEqualityProjectLeadersTable}.  Each row stores one
% position-level target for the upcoming funding period alongside the
% previous period's objective for comparison.
%
% The live counts (current numbers of female/male/diverse staff per
% position and period) are \emph{computed} at render time from the |person|
% database — they are not entered manually.  Only the
% percentage-female objective values need to be provided here.
%    \begin{macrocode}
\keys_define:nn { GenderEquality }{
  position                             .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{position}{#1},
  previous-objective-percentage-female .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{previous-objective-percentage-female}{#1},
  status-quo-number-female             .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{status-quo-number-female}{#1},
  status-quo-percentage-female         .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{status-quo-percentage-female }{#1},
  future-objective-percentage-female   .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{future-objective-percentage-female}{#1},
}
%    \end{macrocode}
% \paragraph{Multi-value helper: \cs{\_\_dfg\_set\_filtered\_clist:Nnn}}
% Several keys (|role|, |period|) accept comma-separated lists rather than
% a single choice.  The private helper
% \cs{\_\_dfg\_set\_filtered\_clist:Nnn}|{\meta{result}}{\meta{valid}}{\meta{input}}|
% iterates over the input list, drops any item that is not in the valid list
% (and emits an |invalid-value| warning for it), and stores the cleaned
% result in a clist variable.  This is used instead of |.choices:nn| because
% the standard choices handler only accepts a single value.
%    \begin{macrocode}
\clist_new:N \l_@@_person_tmp_period_clist
\clist_new:N \l_@@_person_tmp_role_clist
\clist_new:N \l_@@_keys_tmp_clist
\cs_new_protected:Npn \_@@_set_filtered_clist:Nnn #1#2#3
{
  % #1: clist variable in which valid values are stored
  % #2: clist of valid values
  % #3: clist of given values
  % function assumes none of the values contain braces or `#` tokens
  \clist_set:Nn \l_@@_keys_tmp_clist {#2}
  \clist_clear:N #1
  \clist_map_inline:nn {#3}
  {
  	\clist_if_in:NnTF \l_@@_keys_tmp_clist {##1}
  	{ \clist_put_right:Nn #1 {##1} }
  	{ \msg_warning:nnnn { dfg } { invalid-value } {#3} {#2} }
  }
}
%    \end{macrocode}
%
% \paragraph{Keyset \textbf{project}}
% One row per CRC sub-project.  The \refKey{id} is the short project letter (e.g.\
% |A01|); \refKey{number} is the DFG-assigned project number; \refKey{name} is the full
% project title.  \refKey{project-type} and \refKey{project-status} control how the project
% appears in tables and are choice-validated.
%
% The \refKey{research-area} key is a tick-list of DFG classification codes in
% the form |1.11-01| (see the property list in Section~\ref{sec:research-areas}).
% Multiple codes are passed as a brace-grouped comma list.
%
% The \refKey{ref-person-id} and \refKey{collaborations} values are comma
% lists.  Whitespace surrounding individual IDs is ignored and the canonical,
% space-free list is stored in the database.  Thus
% |{clavel,vonBergen,just}| and |{clavel, vonBergen, just}| are equivalent for
% every later consumer.
% The optional |project-area| key controls the area row in collaboration plots.
% When omitted, the first character of the project ID is used as a fallback.
%
% The \refKey{legal-issues} sub-keyset mirrors the questions from the DFG online
% portal's project-information form (\refKey{L1}--\refKey{L7}).  Nested key-value parsing
% is triggered via a single |legal-issues={...}| block.
%
%    \begin{macrocode}
\cs_new_protected:Npn \@@_new_clist_dbentry:nnn #1#2#3
{
  \clist_set:Nn \l_tmpa_clist {#3}
  \exp_args:NnnV \DTLnewdbentry {#1} {#2} \l_tmpa_clist
}

\bool_new:N \l_@@_project_consider_for_lists_bool
\bool_new:N \l_@@_project_reference_only_bool
\bool_new:N \g_@@_project_count_ready_bool

\keys_define:nn { project }{
  id                       .code:n           =   \DTLnewdbentry{\l_@@_database_name_tl}{id}{#1},
  id                       .value_required:n = true,
  number                   .code:n           = \DTLnewdbentry{\l_@@_database_name_tl}{number}{#1},
  number                   .value_required:n = true,
  name                     .code:n           = \DTLnewdbentry{\l_@@_database_name_tl}{name}{#1},
  project-type             .choices:nn       =  { research,service,mgk,admin} {\DTLnewdbentry{\l_@@_database_name_tl}{project-type}{#1}},
  project-type / unknown   .code:n           = {\msg_warning:nnnn { dfg } { invalid-value }{ #1 }{research,service,mgk,admin}},
  project-type             .value_required:n = true,
  project-status           .choices:nn       =  { N,E,C} {\DTLnewdbentry{\l_@@_database_name_tl}{project-status}{#1}},
  project-status / unknown .code:n           = {\msg_warning:nnnn { dfg } { invalid-value }{ #1 }{N,E,C}},
  project-status           .value_required:n = true,
  consider-for-lists           .choices:nn       = { true,false }
    { \str_if_eq:nnTF {#1} {true}
        { \bool_set_true:N \l_@@_project_consider_for_lists_bool }
        { \bool_set_false:N \l_@@_project_consider_for_lists_bool } },
  consider-for-lists / unknown .code:n           =
    { \msg_warning:nnnn { dfg } { invalid-value } {#1} {true,false} },
  consider-for-lists           .value_required:n = true,
  reference-only           .choices:nn       = { true,false }
    { \str_if_eq:nnTF {#1} {true}
        { \bool_set_true:N \l_@@_project_reference_only_bool }
        { \bool_set_false:N \l_@@_project_reference_only_bool } },
  reference-only / unknown .code:n           =
    { \msg_warning:nnnn { dfg } { invalid-value } {#1} {true,false} },
  reference-only           .value_required:n = true,
  research-area            .code:n           = \DTLnewdbentry{\l_@@_database_name_tl}{research-area}{#1},
  project-area             .code:n           = \DTLnewdbentry{\l_@@_database_name_tl}{project-area}{#1},
  ref-person-id            .code:n           =
  \@@_new_clist_dbentry:nnn {\l_@@_database_name_tl} {ref-person-id} {#1},
  collaborations           .code:n           =
  \@@_new_clist_dbentry:nnn {\l_@@_database_name_tl} {collaborations} {#1},
  legal-issues             .code:n           = { \keys_set:nn { project / legal-issues  } { #1 } }
}
%    \end{macrocode}
% The |legal-issues| key in a |project| entry accepts a sub-keyset that
% maps each legal-issue question to a value.  The questions fall into two
% groups, which are handled differently:
%
% \begin{description}
%   \item[Main questions (\refKey{L1}, \refKey{L2}, \refKey{L3},
%     \refKey{L4}, \refKey{L5}, \refKey{L6}, \refKey{L7})] Each must be
%     answered with exactly \texttt{yes} or \texttt{no}.  Any other
%     value triggers a warning via \cs{person\_questions\_invalid:n}, and
%     no database entry is created.
%
%   \item[Sub-questions (\refKey{L1a}, \refKey{L2a}, \refKey{L5a},
%     \refKey{L7a})] These are conditional follow-ups whose answer only
%     matters when the corresponding main question was answered with
%     \texttt{yes}.  Sub-questions accept \texttt{yes}, \texttt{no},
%     or an empty value.  An empty value records an empty cell in the
%     database, which the typesetting code treats as ``not answered''
%     and consequently does not render in the legal-issues table.
% \end{description}
%
% The asymmetry exists because forcing every sub-question to be answered
% would require authors to fill in irrelevant follow-ups whenever the
% parent question is \texttt{no} -- for example, providing an answer
% to ``has legal authorization been obtained'' for a project that does
% not involve human embryonic stem cells in the first place.  Allowing
% an empty value lets the data file mirror the structure of the
% questionnaire: only the relevant cells need to be filled in.
%
% \medskip
%
% Internally, the main questions use the \refPkg{l3keys} \texttt{.choices:nn}
% property, which natively rejects values outside the allowed set.  The
% sub-questions cannot use \texttt{.choices:nn} directly because that
% property does not accept the empty string as a choice; they instead
% dispatch through the helper \cs{dfg\_legal\_subq:nn}, which inspects
% the supplied value and creates a database entry when the value is
% \texttt{yes}, \texttt{no}, or empty, and warns otherwise.
%
% \medskip
%
% Example of a complete |legal-issues| block in a project entry:
%
% \begin{dispListing*}{title={Example entries for |legal-issues|}}
% legal-issues = {
%   L1  = {yes},
%   L1a = {yes},      % L1 was true, follow-up answered
%   L2  = {no},
%   L2a = {},          % L2 was false, follow-up irrelevant
%   L3  = {yes},
%   L4  = {no},
%   L5  = {no},
%   L5a = {},
%   L6  = {yes},
%   L7  = {yes},
%   L7a = {yes}
% }
% \end{dispListing*}
%
% The empty values for \refKey{L2a} and \refKey{L5a} are valid: they correspond to
% follow-ups whose parent question was answered \texttt{no}, so no
% follow-up information is required or rendered.
%    \begin{macrocode}
\keys_define:nn { project / legal-issues }
{
  % main questions: must be yes/no
  L1  .choices:nn = { yes, no } { \DTLnewdbentry{\l_@@_database_name_tl}{L1} {#1} },
  L2  .choices:nn = { yes, no } { \DTLnewdbentry{\l_@@_database_name_tl}{L2} {#1} },
  L3  .choices:nn = { yes, no } { \DTLnewdbentry{\l_@@_database_name_tl}{L3} {#1} },
  L4  .choices:nn = { yes, no } { \DTLnewdbentry{\l_@@_database_name_tl}{L4} {#1} },
  L5  .choices:nn = { yes, no } { \DTLnewdbentry{\l_@@_database_name_tl}{L5} {#1} },
  L6  .choices:nn = { yes, no } { \DTLnewdbentry{\l_@@_database_name_tl}{L6} {#1} },
  L7  .choices:nn = { yes, no } { \DTLnewdbentry{\l_@@_database_name_tl}{L7} {#1} },
  %
  % sub-questions: yes / no / empty all allowed
  L1a .code:n = { \dfg_legal_subq:nn {L1a} {#1} },
  L2a .code:n = { \dfg_legal_subq:nn {L2a} {#1} },
  L5a .code:n = { \dfg_legal_subq:nn {L5a} {#1} },
  L7a .code:n = { \dfg_legal_subq:nn {L7a} {#1} },
  %
  % unknown handlers (only need them for the binary keys)
  L1  / unknown .code:n = { \person_questions_invalid:n {#1} },
  L2  / unknown .code:n = { \person_questions_invalid:n {#1} },
  L3  / unknown .code:n = { \person_questions_invalid:n {#1} },
  L4  / unknown .code:n = { \person_questions_invalid:n {#1} },
  L5  / unknown .code:n = { \person_questions_invalid:n {#1} },
  L6  / unknown .code:n = { \person_questions_invalid:n {#1} },
  L7  / unknown .code:n = { \person_questions_invalid:n {#1} },
}

% Sub-question handler: accepts yes, no, or empty.
\cs_new_protected:Npn \dfg_legal_subq:nn #1#2
{
  \tl_if_blank:nTF {#2}
  { \DTLnewdbentry{\l_@@_database_name_tl}{#1}{} }
  {
  	\str_case:nnF {#2}
  	{
  		{ yes  } { \DTLnewdbentry{\l_@@_database_name_tl}{#1}{yes}  }
  		{ no } { \DTLnewdbentry{\l_@@_database_name_tl}{#1}{no} }
  	}
  	{ \person_questions_invalid:n {#2} }
  }
}
%    \end{macrocode}
% \paragraph{Keyset \textbf{person}}
% The |person| database is the central personnel registry for the proposal.
% Every PI, manager, steering committee member and early-career researcher
% who appears in any table must have a row here.
%
% \textbf{Key semantics:}
%   \refKey{role}: A filterable comma list of roles.  The supported values
%     (|PI|, |spokesperson|, |manager|, |steering-committee-member|,
%     |rector|) are validated against a fixed list using the multi-value
%     helper so that multiple roles per person are permitted.
%   \refKey{position}: A single choice describing the employment category
%     (|prof-W2|, |prof-W3|, |postDoc|, |PhD|, etc.).  Used in the gender
%     equality and staff cost tables.
%   \refKey{period}: Comma list of funding periods (|1|, |2|, |3|) in which
%     this person is active.  All period-filtered queries
%     (e.g.\ the project-leaders table) use this field.
%   \refKey{name-alias}: Brace-grouped list of name variants as the author
%     name appears in |.bib| files.  These are passed to \cs{addboldnames}
%     so all spelling variants are highlighted consistently.
%   \refKey{contract-information}: Sub-keyset (\refKey{C1}--\refKey{C4a}) for the four
%     employment-contract questions required in the DFG project header.
%     Internally stored as fields |Q1|--|Q4a|.
%    \begin{macrocode}
\keys_define:nn { person }{
  unknown .code:n = { \msg_warning:nnn  { dfg } { unknown-key } {#1}},
  unknown .default:V = \c_novalue_tl,
  id                .code:n =   \DTLnewdbentry{\l_@@_database_name_tl}{id}{#1},
  id                .value_required:n = true,
  firstname        .code:n =	\DTLnewdbentry{\l_@@_database_name_tl}{firstname}{#1},
  firstname .value_required:n = true,
  lastname         .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{lastname}{#1},
  lastname .value_required:n = true,
  academicdegree   .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{academicdegree}{#1},
  gender .choices:nn =  { m , f , d } {\DTLnewdbentry{\l_@@_database_name_tl}{gender}{#1}},
  gender / unknown .code:n = {\msg_warning:nnnn { dfg } { invalid-value }{ #1 }{ m,f,d }},
  gender .value_required:n = true,
  ref-affiliation-id   .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-affiliation-id}{#1},
  ref-institution-id   .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-institution-id}{#1},
  ref-project-id .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-project-id}{#1},
%    \end{macrocode}
% With \refKey{role} we want to differentiate between various people so we easily can
% get the necessary person into the right table. Roles can be e.g. |PI|,
% |service| etc.
%    \begin{macrocode}
  role .code:n = {\_@@_set_filtered_clist:Nnn \l_@@_person_tmp_role_clist {
  			PI,~ spokesperson,~ manager,~ steering-committee-member,~rector
  		} {#1}
  		\exp_args:Nnne \DTLnewdbentry{\l_@@_database_name_tl}{role}
                 { \clist_use:N  \l_@@_person_tmp_role_clist}},
%    \end{macrocode}
% position is also bound to a value list
%    \begin{macrocode}
  position .choices:nn =  {
  		PhD, postDoc, groupLeader, research,
  		nonResearch, student, prof,
  		prof-W2, prof-W3 }
  	{\DTLnewdbentry{\l_@@_database_name_tl}{position}{#1}},
  position / unknown .code:n = {\msg_warning:nnnn { dfg } { invalid-value }{ #1 }{
  			PhD,~ postDoc,~ groupLeader,~ research,~
  			nonResearch,~ student,~ prof,~ prof-W2,~ prof-W3 }},
  positionText .code:n =  \DTLnewdbentry{\l_@@_database_name_tl}{positionText}{#1},
%    \end{macrocode}
% we need to figure out in which funding period the person was active. 
%    \begin{macrocode}
  period .code:n = {
  		\_@@_set_filtered_clist:Nnn \l_@@_person_tmp_period_clist { 1, 2, 3 } {#1}
  		\exp_args:Nnne \DTLnewdbentry{\l_@@_database_name_tl}{period}
                 { \clist_use:N  \l_@@_person_tmp_period_clist }
  	},
%    \end{macrocode}
% The following keys are used for the CV section (additionally |position|).
% We start with |name-alias| which is used to get the author’s name in bold
% letters into the publications list. Write all aliases of the author according
% to their appearence in the |.bib|-file. Encapsulate each with one pair of |{}|.
%    \begin{macrocode}
  name-alias   .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{name-alias}{{#1}},
  orcid        .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{orcid}{#1},
  email        .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{email}{#1},
  phone        .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{phone}{#1},
  url          .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{url}{#1},
  doctorateYear .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{doctorateYear}{#1},
  doctorate    .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{doctorate}{#1},
  degree-programme   .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{degree-programme}{#1},
%    \end{macrocode}
% Following part is for the early career researchers
%    \begin{macrocode}
  financed-by .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{financed-by}{#1},
  topic       .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{topic}{#1},
  category    .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{category}{#1},
  dateDefense .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{dateDefense}{#1},
  periodStart .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{periodStart}{#1},
  periodEnd .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{periodEnd}{#1},
%    \end{macrocode}
% For the PI we need to have information regarding their contract situation.
% Those questions are asked in the Header section of each project.
%    \begin{macrocode}
  contract-information .code:n = { \keys_set:nn { person / contract-information } { #1 } }
}
%    \end{macrocode}
%
% \paragraph{Helper: \cs{person\_questions\_invalid:n}}
% Small private helper used as the |unknown .code:n| handler for every
% boolean choice key in the |contract-information| and
% |project/legal-issues| key families.  It fires |dfg/invalid-value| with
% the allowed set hard-coded to |yes,no|.
%    \begin{macrocode}
\cs_new_protected:Npn \person_questions_invalid:n #1
{ \msg_warning:nnnn { dfg } { invalid-value } {#1} { yes , no } }


\keys_define:nn { person / contract-information }
{
  %--- yes/no questions -----------------------------------------------
  C1 .choices:nn = { yes , no }
  	{ \DTLnewdbentry{\l_@@_database_name_tl}{C1}{#1} },
  C1 / unknown .code:n = { \person_questions_invalid:n {#1} },

  C2 .choices:nn = { yes , no  }
  	{ \DTLnewdbentry{\l_@@_database_name_tl}{C2}{#1} },
  C2 / unknown .code:n = { \person_questions_invalid:n {#1} },

  C3 .choices:nn = { yes , no  }
  	{ \DTLnewdbentry{\l_@@_database_name_tl}{C3}{#1} },
  C3 / unknown .code:n = { \person_questions_invalid:n {#1} },

  C4 .choices:nn = {  yes , no  }
  	{ \DTLnewdbentry{\l_@@_database_name_tl}{C4}{#1} },
  C4 / unknown .code:n = { \person_questions_invalid:n {#1} },

  %--- free-form follow-ups (may be empty) ----------------------------
  C2a .code:n = { \dfg_contract_date:nn {C2a} {#1} },
  C2b .code:n = { \dfg_contract_date:nn {C2b} {#1} },
  C3a .code:n = { \dfg_contract_date:nn {C3a} {#1} },
  C4a .code:n = { \dfg_contract_text:nn {C4a} {#1} },
}

% Date follow-up: allows empty or ISO-8601 (YYYY-MM-DD).
\cs_new_protected:Npn \dfg_contract_date:nn #1#2
{
  \tl_if_blank:nTF {#2}
  { \DTLnewdbentry{\l_@@_database_name_tl}{#1}{} }
  {
  	\dfg_is_iso_date:nTF {#2}
  	{ \DTLnewdbentry{\l_@@_database_name_tl}{#1}{#2} }
  	{
  		\msg_warning:nnnn { dfg } { invalid-date } {#1} {#2}
  		\DTLnewdbentry{\l_@@_database_name_tl}{#1}{#2}
  	}
  }
}

% Plain-text follow-up: allows empty or any string.
\cs_new_protected:Npn \dfg_contract_text:nn #1#2
{
  \DTLnewdbentry{\l_@@_database_name_tl}{#1}{#2}
}

% Format check: YYYY-MM-DD where Y/M/D are digits.
% Doesn't validate calendar correctness (e.g. Feb 30) -- just shape.
\prg_new_protected_conditional:Npnn \dfg_is_iso_date:n #1 { TF , T , F }
{
  \regex_match:nnTF { \A \d{4} - \d{2} - \d{2} \Z } {#1}
  { \prg_return_true: }
  { \prg_return_false: }
}
%    \end{macrocode}
% \paragraph{Keyset \textbf{cv}}
% The |cv| database holds supplementary career information for each PI
% beyond what is already stored in the |person| row.  Multiple entries
% per person are permitted; each entry is identified by |ref-person-id|
% and a \refKey{cv-type} that governs where in the printed CV the item appears.
%
%    \begin{macrocode}
\keys_define:nn { cv }{
  id           .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{id}{#1},
  ref-person-id.code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-person-id}{#1},
  cv-type .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{type}{#1},
  cv-type .choices:nn =  {mandatory, supplement,
  		activities, supervision,
  		distinction, other }
  	{\DTLnewdbentry{\l_@@_database_name_tl}{type}{#1}},
  % Backward-compatibility alias for the former misspelling.
  cv-type / distinction .code:n = {			\DTLnewdbentry{\l_@@_database_name_tl}{type}{distinction}},
  cv-type / unknown .code:n = {\msg_warning:nnnn { dfg } { invalid-value }{ #1 }{
  			mandatory,~ supplement,~
  			activities,~  supervision,~
  			distinction,~ other }},
  positionText .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{positionText}{#1},
  position .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{position}{#1},
  ref-institution-id .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-institution-id}{#1},
  description .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{description}{#1},
  periodStart .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{periodStart}{#1},
  periodEnd .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{periodEnd}{#1},
}
%    \end{macrocode}
% \paragraph{Keysets \textbf{affiliation} and \textbf{institution}}
% The template distinguishes between two levels of organisational unit:
%   affiliation: A \emph{university} or equivalent top-level
%     organisation, described by its full name, abbreviation, and postal
%     address.  Referenced from |person| rows via |ref-affiliation-id|.
%   institution: A \emph{department, institute or centre} within an
%     affiliation (e.g.\ |IT Center RWTH Aachen|).  Referenced from |person|
%     rows via |ref-institution-id| and from |affiliation| via
%     |ref-affiliation-id|.
%
% This two-level model allows the same address block to be reused across
% multiple people without duplicating data, and the same university to
% appear under different institute names for different projects.
%    \begin{macrocode}
\keys_define:nn { affiliation }
{
  id               .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{id}{#1},
  id               .value_required:n = true,
  name             .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{name}{#1},
  abbreviation  .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{abbreviation}{#1},
  addressStreet    .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{addressStreet}{#1},
  addressZIP   .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{addressZIP}{#1},
  location         .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{location}{#1},
  country          .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{country}{#1},
}
%    \end{macrocode}
%    \begin{macrocode}
\keys_define:nn { institution }
{
  id        .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{id}{#1},
  id        .value_required:n = true,
  name      .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{name}{#1},
  abbreviation .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{abbreviation}{#1},
  ref-affiliation-id  .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{ref-affiliation-id}{#1},
}

% Resolve the compact reader-facing institution label once.  Older metadata
% without an abbreviation remains usable by falling back to the full name.
\tl_new:N \l_@@_institution_label_field_tl
\cs_new_protected:Npn \@@_institution_abbreviation_or_name:nN #1#2
{
  \tl_clear:N #2
  \tl_set:Nn \l_@@_institution_label_field_tl { abbreviation }
  \datatool_if_has_key:nnTF { institution } { abbreviation }
  {
    \DTLgetvalueforkey{#2}{abbreviation}{institution}{id}{#1}
  }
  { }
  \DTLifnullorempty{#2}
  {
    \tl_set:Nn \l_@@_institution_label_field_tl { name }
    \DTLgetvalueforkey{#2}{name}{institution}{id}{#1}
  }
  { }
}
%    \end{macrocode}
% \paragraph{Keyset \textbf{funding}}
% One |funding| row represents a single requested-funding line item, such
% as one FTE of PhD salary across five years, or a one-off equipment
% purchase.  The same keyset is also used for\emph{existing} and
% \emph{previous} funding entries in the relevant tables.
%
% \textbf{|funding-type|}:
%   \refKey{staff}: Personnel costs.  Activates the restricted |category|
%     validation (only staff-position names are accepted).
%   \refKey{costs}: Direct project costs (consumables, travel, etc.).
%   \refKey{fellowships}: Stipend payments.
%   \refKey{globalfunds}: Funds requested at the CRC level (coordination).
%   \refKey{instrumentation}: Equipment purchases.
%
% \textbf{\refKey{quantity} and \refKey{sum}}: both accept a |funding/year| sub-keyset
% |{year1={n},year2={n},...}|.  The token-list variable
% \cs{l\_funding\_sum\_quantity\_tl} is set to the key name (|quantity| or
% |sum|) before the sub-parse so the |year\meta{n}| handlers can construct
% the correct database field name (|quantity-year1|, |sum-year2|, etc.)
% without extra parameters.
%    \begin{macrocode}
\str_new:N \l_@@_funding_tmp_type_str
\tl_new:N \l_funding_sum_quantity_tl
\keys_define:nn { funding / year }
{
  year1 .code:n =
  	{\DTLnewdbentry{\l_@@_database_name_tl}{\tl_use:N \l_funding_sum_quantity_tl-year1}{#1}},
  year2 .code:n =
  	{\DTLnewdbentry{\l_@@_database_name_tl}{\tl_use:N \l_funding_sum_quantity_tl-year2}{#1}},
  year3 .code:n =
  	{\DTLnewdbentry{\l_@@_database_name_tl}{\tl_use:N \l_funding_sum_quantity_tl-year3}{#1}},
  year4 .code:n =
  	{\DTLnewdbentry{\l_@@_database_name_tl}{\tl_use:N \l_funding_sum_quantity_tl-year4}{#1}},
  year5 .code:n =
  	{\DTLnewdbentry{\l_@@_database_name_tl}{\tl_use:N \l_funding_sum_quantity_tl-year5}{#1}},
}

\keys_define:nn { funding }
{
  id        .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{id}{#1},
  id        .value_required:n = true,
  ref-project-id .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-project-id}{#1},
  ref-affiliation-id .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{ref-affiliation-id}{#1},
  financed-by .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{financed-by}{#1},
  funding-type .choices:nn =  {
  		staff,~ costs,~ fellowships,~ globalfunds,~ instrumentation }
  	{
  		\str_set:Nn \l_@@_funding_tmp_type_str {#1}
  		\DTLnewdbentry{\l_@@_database_name_tl}{type}{#1}
  	},
  funding-type / unknown .code:n = {\msg_warning:nnnn { dfg } { invalid-value }{ #1 }{
  			staff,~ costs,~ fellowships,~ globalfunds,~ instrumentation }},
  funding-type        .value_required:n = true,
  percentage .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{percentage}{#1},
  quantity .code:n = {
  		\tl_set:Nn \l_funding_sum_quantity_tl {quantity}
  		\keys_set:nn { funding / year  } { #1 }
  	},
  sum .code:n = {
  		\tl_set:Nn \l_funding_sum_quantity_tl {sum}
  		\keys_set:nn { funding / year  } { #1 }
  	},
  category .code:n =
  	{
  		\str_if_eq:VnTF \l_@@_funding_tmp_type_str { staff }
  		{% staff → restricted choices
  			\str_if_in:nnTF {groupLeader, prof , postDoc,medDoc,%
  				PhD,research,nonResearch,student,assistant%
  			}
  			{#1}
  			{
  				\DTLnewdbentry{\l_@@_database_name_tl}{category}{#1}
  			}
  			{
  				\msg_warning:nnnn { dfg } { invalid-value }{ #1 }
  				{%
  					prof,~ groupLeader,~ postDoc,~ medDoc,~
  					PhD,~ research,~ nonResearch,~ student,~ assistant
  				}
  			}
  		}
  		{
  			% non-staff → unrestricted
  			\DTLnewdbentry{\l_@@_database_name_tl}{category}{#1}
  		}
  	},
  % following keys are especially for the previous fundings
  year            .code:n = {\DTLnewdbentry{\l_@@_database_name_tl}{year}{#1}},
  applicant       .code:n = {\DTLnewdbentry{\l_@@_database_name_tl}{applicant}{#1}},
  participant     .code:n = {\DTLnewdbentry{\l_@@_database_name_tl}{participant}{#1}},
  other-funds     .code:n = {\DTLnewdbentry{\l_@@_database_name_tl}{other-funds}{#1}},
  staff           .code:n = {\DTLnewdbentry{\l_@@_database_name_tl}{staff}{#1}},
  costs           .code:n = {\DTLnewdbentry{\l_@@_database_name_tl}{costs}{#1}},
  instrumentation .code:n = {\DTLnewdbentry{\l_@@_database_name_tl}{instrumentation}{#1}},
  fellowships     .code:n = {\DTLnewdbentry{\l_@@_database_name_tl}{fellowships}{#1}},
  globalfunds     .code:n = {\DTLnewdbentry{\l_@@_database_name_tl}{globalfunds}{#1}},
}
%    \end{macrocode}
% A keyset for instrumentation.  The flat |cost| field belongs to the
% informational |existingInstrumentation| list, is expressed in thousands of
% EUR, and is never included in funding totals.  The nested |sum| fields are
% requested-funding amounts expressed in full EUR.
%    \begin{macrocode}
\keys_define:nn { instrumentation }{
  ref-project-id  .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-project-id}{#1},
  quantity        .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{quantity}{#1},
  instrument      .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{instrument}{#1},
  company         .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{company}{#1},
  year            .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{year}{#1},
  cost            .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{cost}{#1},
  financed-by     .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{financed-by}{#1},
  description     .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{description}{#1},
  sum .code:n = {
  		\tl_set:Nn \l_funding_sum_quantity_tl {sum}
  		\keys_set:nn { funding / year  } { #1 }
  	},
}
%    \end{macrocode}
%
% \paragraph{Keyset \textbf{staff}}
% The |staff| key family serves two related personnel data shapes.  Its
% |year1|--|year5| subkeys store the headcount plan per position category for
% \cs{OverviewOfFundsRequestedForStaffTable}.  The flat keys added below store
% the named and unnamed staff roster required by the DFG project template in
% the fixed |RequestedFundingStaff| database.  All keys remain optional at the
% parser level so the older overview declarations continue to work unchanged;
% database-specific validation supplies useful warnings for roster entries.
%
% The \refKey{position} sub-keyset holds named keys for each staff category
% (|postDoc|, |PhD|, |research|, etc.); each key's value is the number of
% FTEs for a specific year.  \cs{l\_staff\_year\_tl} is set to |year1|--|year5|
% before each sub-parse so the handlers can construct the correct field name
% (e.g.\ |postDoc-year2|) without extra parameters.
%    \begin{macrocode}
\tl_new:N \l_staff_year_tl          % will hold “year1”, “year2”, …
\keys_define:nn { staff / position }{
  postDoc      .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{postDoc-\tl_use:N \l_staff_year_tl}{#1},
  PhD          .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{PhD-\tl_use:N \l_staff_year_tl}{#1},
  research     .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{research-\tl_use:N \l_staff_year_tl}{#1},
  nonResearch  .code:n = \DTLnewdbentry{\l_@@_database_name_tl}
  {nonResearch-\tl_use:N \l_staff_year_tl}{#1},
  student      .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{student-\tl_use:N \l_staff_year_tl}{#1},
}

\cs_new_protected:Npn \@@_staff_set_category:n #1
{
  \prop_if_in:NnTF \g_@@_dfg_category_names_prop {#1}
  { \DTLnewdbentry{\l_@@_database_name_tl}{category}{#1} }
  {
    \msg_warning:nnnn { dfg } { invalid-value } {#1}
      { a~key~registered~in~\token_to_str:N \g_@@_dfg_category_names_prop }
  }
}

\keys_define:nn { staff }{
  unknown .code:n = { \msg_warning:nnn { dfg } { unknown-key } {#1} },
  unknown .default:V = \c_novalue_tl,
  ref-project-id .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-project-id}{#1},
  funding-status .choices:nn = { existing, requested }
  { \DTLnewdbentry{\l_@@_database_name_tl}{funding-status}{#1} },
  funding-status / unknown .code:n =
  { \msg_warning:nnnn { dfg } { invalid-value } {#1} { existing,~requested } },
  staff-type .choices:nn = { research, nonResearch }
  { \DTLnewdbentry{\l_@@_database_name_tl}{staff-type}{#1} },
  staff-type / unknown .code:n =
  { \msg_warning:nnnn { dfg } { invalid-value } {#1} { research,~nonResearch } },
  ref-person-id .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{ref-person-id}{#1},
  firstname .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{firstname}{#1},
  lastname .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{lastname}{#1},
  academic-degree .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{academic-degree}{#1},
  positionText .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{positionText}{#1},
  position .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{positionText}{#1},
  field-of-research .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{field-of-research}{#1},
  ref-institution-id .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{ref-institution-id}{#1},
  ref-affiliation-id .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{ref-affiliation-id}{#1},
  department .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{department}{#1},
  commitment .code:n =
  {
    \regex_match:nnTF { \A \d+ (?: \. \d+ )? \Z }
      {#1}
    { \DTLnewdbentry{\l_@@_database_name_tl}{commitment}{#1} }
    { \msg_warning:nnnn { dfg } { invalid-value } {#1}
      { non-negative~integer~or~decimal } }
  },
  category .code:n = \@@_staff_set_category:n {#1},
  funding-source .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{funding-source}{#1},
  description .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{description}{#1},
  year1 .code:n = {
  		\tl_set:Nn \l_staff_year_tl {year1}
  		\keys_set:nn { staff / position  } { #1 }
  	},
  year2 .code:n = {
  		\tl_set:Nn \l_staff_year_tl {year2}
  		\keys_set:nn { staff / position  } { #1 }
  	},
  year3 .code:n = {
  		\tl_set:Nn \l_staff_year_tl {year3}
  		\keys_set:nn { staff / position  } { #1 }
  	},
  year4 .code:n = {
  		\tl_set:Nn \l_staff_year_tl {year4}
  		\keys_set:nn { staff / position  } { #1 }
  	},
  year5 .code:n = {
  		\tl_set:Nn \l_staff_year_tl {year5}
  		\keys_set:nn { staff / position  } { #1 }
  },
}

% Pre-create every roster column once.  Datatool can otherwise report an
% unknown column when an optional key is omitted by every row in the database.
\bool_new:N \g_@@_requested_funding_staff_schema_ready_bool
\cs_new_protected:Npn \@@_requested_funding_staff_ensure_schema:
{
  \bool_if:NF \g_@@_requested_funding_staff_schema_ready_bool
  {
    \clist_map_inline:nn
    {
      ref-project-id, funding-status, staff-type, ref-person-id,
      firstname, lastname, academic-degree, positionText, field-of-research,
      ref-institution-id, ref-affiliation-id, department, commitment, category,
      funding-source, description
    }
    {
      \DTLifhaskey { RequestedFundingStaff } {##1}
      { }
      { \DTLaddcolumn { RequestedFundingStaff } {##1} }
    }
    \bool_gset_true:N \g_@@_requested_funding_staff_schema_ready_bool
  }
}

\tl_new:N \l_@@_requested_funding_staff_validate_project_tl
\tl_new:N \l_@@_requested_funding_staff_validate_status_tl
\tl_new:N \l_@@_requested_funding_staff_validate_type_tl
\tl_new:N \l_@@_requested_funding_staff_validate_person_tl
\tl_new:N \l_@@_requested_funding_staff_validate_lastname_tl
\keys_define:nn { dfg / requested-funding-staff-validation }
{
  ref-project-id .tl_set:N =
    \l_@@_requested_funding_staff_validate_project_tl,
  funding-status .tl_set:N =
    \l_@@_requested_funding_staff_validate_status_tl,
  staff-type .tl_set:N =
    \l_@@_requested_funding_staff_validate_type_tl,
  ref-person-id .tl_set:N =
    \l_@@_requested_funding_staff_validate_person_tl,
  lastname .tl_set:N =
    \l_@@_requested_funding_staff_validate_lastname_tl,
  unknown .code:n = { }
}

\cs_new_protected:Npn \@@_requested_funding_staff_validate:n #1
{
  \tl_clear:N \l_@@_requested_funding_staff_validate_project_tl
  \tl_clear:N \l_@@_requested_funding_staff_validate_status_tl
  \tl_clear:N \l_@@_requested_funding_staff_validate_type_tl
  \tl_clear:N \l_@@_requested_funding_staff_validate_person_tl
  \tl_clear:N \l_@@_requested_funding_staff_validate_lastname_tl
  \keys_set:nn { dfg / requested-funding-staff-validation } {#1}
  \tl_if_blank:VT \l_@@_requested_funding_staff_validate_project_tl
  { \msg_warning:nnn { dfg } { requested-staff-required }
    { ref-project-id } }
  \tl_if_blank:VT \l_@@_requested_funding_staff_validate_status_tl
  { \msg_warning:nnn { dfg } { requested-staff-required }
    { funding-status } }
  \tl_if_blank:VT \l_@@_requested_funding_staff_validate_type_tl
  { \msg_warning:nnn { dfg } { requested-staff-required }
    { staff-type } }
  \bool_lazy_all:nT
  {
    { \tl_if_blank_p:V \l_@@_requested_funding_staff_validate_person_tl }
    { \tl_if_blank_p:V \l_@@_requested_funding_staff_validate_lastname_tl }
  }
  { \msg_warning:nnn { dfg } { requested-staff-required }
    { ref-person-id~or~lastname } }
}
%    \end{macrocode}
% A keyset for the upkeep of laboratory animals.
%    \begin{macrocode}
\keys_define:nn { UpkeepLaboratoryAnimals }{
  ref-project-id .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-project-id}{#1},
  species .choices:nn =  { mouse, mouse-gnotobiotic,rat}
  	{\DTLnewdbentry{\l_@@_database_name_tl}{species}{#1}},
  species / unknown .code:n = {\msg_warning:nnnn { dfg } { invalid-value }{ #1 }{
  			smouse,~ mouse-gnotobiotic,~ rat}},
  species   .value_required:n = true,
  quantity .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{quantity}{#1},
  weeks-kept .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{weeks-kept}{#1},
  purchasing-costs   .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{purchasing-costs}{#1},
  requested-funds   .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{requested-funds}{#1},
  existing-funds .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{existing-funds}{#1},
}
%    \end{macrocode}
% \paragraph{Keyset \textbf{gantt}}
% Each row in a |gantt-\meta{project}| database describes one Gantt bar.
% Bars share their \refKey{id} with the corresponding work-package label, so
% \cs{addWP} automatically creates a matching Gantt entry when called.
%
% \refKey{periodStart} and \refKey{periodEnd} are quarter numbers (1--16 for a standard
% 5-year CRC period).  Setting both to the same value suppresses the bar,
% allowing a work-package item to exist in the list without occupying space
% in the chart.
%
% \refKey{style} selects one of five visual styles for the bar.  Unknown styles
% fall back to |default| with a warning, so the chart always compiles.
%    \begin{macrocode}
\keys_define:nn { gantt }{
  id          .code:n     =  \DTLnewdbentry{\l_@@_database_name_tl}{id}{#1},
  id          .value_required:n = true,
  name        .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{name}{#1},
  description .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{description}{#1},
  periodStart .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{periodStart}{#1},
  periodEnd   .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{periodEnd}{#1},
  style       .choices:nn =  { crosshatch,striped,important,alternative,default }
  	{\DTLnewdbentry{\l_@@_database_name_tl}{style}{#1}},
  style / unknown .code:n = {
  		\msg_warning:nnnn { dfg } { invalid-value }{ #1
  		}{crosshatch,striped,important,alternative,default }
  		\DTLnewdbentry{\l_@@_database_name_tl}{style}{default}
  	},
}
%    \end{macrocode}
% \subsubsection{Core data-access commands}
%
% The following commands form the primary user-facing API for reading
% and writing the datatool databases.  Together with the keyset
% definitions above they provide a strongly-typed, validated interface
% that prevents malformed data from silently entering the proposal.
%
% \paragraph{\cs{dfgShowTag} and \cs{dfgShowCalculatedTag}}
% Direct values use |db:id:field|; aggregates use the concise form
% |calc:command [db]|.  Successive labels alternate between two vertical levels.
% The complete marker has zero width, height, and depth in both prose and tables,
% so annotations cannot change line spacing or table-row height.  When
% \refKey{showtags-tables} is false, the wrapper returns its value unchanged
% while a |tblr| cell is being rendered.  The begin-document specialisation
% keeps the normal |showtags=false| path as cheap as the unannotated output.
%
%    \begin{macrocode}
\NewDocumentCommand{\dfgShowTag}{ m m m o }
{%
  % #1: id
  % #2: field of database
  % #3: value from database field
  % #4: custom field (optional, e.g. database name)
  \bool_if:NTF \l_@@_class_showtags_bool
  { \texorpdfstring{\@@_show_tag_direct:nnnn {#1}{#2}{#3}{#4}}{#3} }
  {#3}%
}

\NewDocumentCommand{\dfgShowCalculatedTag}{ m m +m }
{%
  % #1: calculation command or label
  % #2: contributing database(s)
  % #3: calculated value
  \bool_if:NTF \l_@@_class_showtags_bool
  { \texorpdfstring{\@@_show_tag_value:nn { calc:#1~[#2] } {#3}}{#3} }
  {#3}%
}

\cs_new_protected:Npn \@@_show_tag_direct:nnnn #1#2#3#4
{
  \IfNoValueTF{#4}
    { \@@_show_tag_value:nn { #1:#2 } {#3} }
    { \@@_show_tag_value:nn { #4:#1:#2 } {#3} }
}

\cs_new_protected:Npn \@@_show_tag_value:nn #1#2
{
  \bool_if:nTF
    { \g_@@_tblr_inside_bool && ! \l_@@_class_showtags_tables_bool }
    {#2}
    { \@@_show_tag_overlay:nn {#1}{#2} }
}

\bool_new:N \g_@@_show_tag_upper_bool
\bool_new:N \l_@@_show_tag_leftward_bool
\dim_new:N \l_@@_show_tag_raise_dim

\cs_new_protected:Npn \@@_show_tag_overlay:nn #1#2
{
  % #1: preformatted provenance label
  % #2: displayed value
  \group_begin:
    \bool_if:NTF \g_@@_show_tag_upper_bool
      { \dim_set:Nn \l_@@_show_tag_raise_dim { 1.30em } }
      { \dim_set:Nn \l_@@_show_tag_raise_dim { .9em } }
    \bool_gset_inverse:N \g_@@_show_tag_upper_bool
    \leavevmode
    \smash{%
      \vbox to \z@ {%
			\vss
			\color{color@tags@line}%
      \bool_if:NTF \l_@@_show_tag_leftward_bool
      {%
        \llap{%
          \raise \l_@@_show_tag_raise_dim \hbox{%
            \fontsize{4}{0}\selectfont
            \ttfamily
            #1\,%
          }%
          \vrule
        }%
      }
      {%
        \rlap{%
          \vrule
          \raise \l_@@_show_tag_raise_dim \hbox{%
            \fontsize{4}{0}\selectfont
            \ttfamily
            \,%
            #1%
          }%
        }%
      }%
      }%
    }%
    \textcolor{color@tags@font}{#2}%
  \group_end:
}

% Aggregated monetary tables use full euro amounts.  Guarded tagged cells must
% invoke \cs{TblrNum} explicitly so they still use the current column's
% |table-format| for a common SI field width; outside tables \cs{num} provides
% ordinary inline output.  Marginalia temporarily clear the table-context
% boolean and therefore remain unpadded.  The informational
% existing-instrumentation cost and the animal-housing rate are formatted
% separately because their source units and precision differ from aggregated
% funding values.
\cs_new_protected:Npn \@@_show_table_number:n #1
{
  \bool_if:NTF \g_@@_tblr_inside_bool
    { \TblrNum{#1} }
    { \num{#1} }
}

\cs_new_protected:Npn \@@_show_eur:n #1
{
  \bool_if:NTF \g_@@_tblr_inside_bool
    { \TblrNum{#1} }
    {
      \num[
        round-mode = places,
        round-precision = 0
      ]{#1}
    }
}

% Existing-instrumentation costs are supplied in thousands of EUR and are not
% included in any funding aggregate.  Match the DFG table's one-decimal
% precision while still suppressing a redundant trailing zero.
\cs_new_protected:Npn \@@_show_existing_instrumentation_cost:n #1
{
  \bool_if:NTF \g_@@_tblr_inside_bool
    { \TblrNum{#1} }
    {
      \num[
        round-mode = places,
        round-precision = 1
      ]{#1}
    }
}

\cs_new_protected:Npn \@@_show_calculated_number:nnN #1#2#3
{
  \dfgShowCalculatedTag{#1}{#2}
  { \exp_args:NV \@@_show_eur:n #3 }
}

\AtBeginDocument{%
  \bool_if:NTF \l_@@_class_showtags_bool
  {%
    \RenewDocumentCommand{\dfgShowTag}{ m m m o }
    { \texorpdfstring{\@@_show_tag_direct:nnnn {#1}{#2}{#3}{#4}}{#3} }%
    \RenewDocumentCommand{\dfgShowCalculatedTag}{ m m +m }
    { \texorpdfstring{\@@_show_tag_value:nn { calc:#1~[#2] } {#3}}{#3} }%
  }
  {%
    \RenewDocumentCommand{\dfgShowTag}{ m m m o }
    {#3}%
    \RenewDocumentCommand{\dfgShowCalculatedTag}{ m m +m }
    {#3}%
  }%
}

%    \end{macrocode}
% \begin{macro}{\addEntry}
% \cs{addEntry} \oarg{keys} \marg{database} \marg{key-values}
% Adds a new row to the database named \meta{database}, populated by
% setting the keys defined under the key-path \meta{keys} from
% \meta{key-values}. If \meta{keys} is omitted, it defaults to the
% database name (\meta{database}).
%
% The \texttt{cv} database receives special treatment: entries are only
% recorded when the boolean \cs{l\_dfg\_class\_cv\_bool} is true (i.e.\ when
% a CV is actually being produced). Otherwise the entry is skipped and
% a warning is issued, so that bibliography-style CV entries can be left
% in the source unconditionally without polluting non-CV builds.
%
% The internal helper \cs{\_\_dfg\_add\_entry:nnn} performs the actual
% insertion and is shared between both branches to avoid code
% duplication.
%
% Funding declarations for |RequestedFunding| may occur in project files,
% after the proposal-wide overview tables have already been printed.  Such
% entries are additionally written to the current LaTeX auxiliary file and
% restored on the following run into |RequestedFundingOverview|.  Entries
% encountered before \cs{begin}|{document}| are copied into that overview
% database immediately.  Consequently the declarations remain next to their
% project text, while overview tables have access to the complete data set
% after the usual additional LaTeX run.  A separate database prevents the
% restored rows from duplicating the live rows used by the project tables.
% The same forward-data mechanism copies |RequestedFundingStaff| declarations
% to |RequestedFundingStaffOverview| and
% |RequestedAndExistingFundingDirectCosts| declarations to
% |RequestedAndExistingFundingDirectCostsOverview|.  Chapter 2 can therefore
% aggregate the existing staff and institutional direct-cost support declared
% later in the individual project chapters without a second user-maintained
% database.
%
% \paragraph{Funding aggregate indexes}
% The funding databases remain the authoritative row store.  In addition,
% every funding declaration updates two LaTeX3 property lists: one for
% monetary sums grouped by database, project, funding type, and year field;
% and one for staff quantities grouped by database, project, category, and
% year field.  Each index also stores the corresponding all-project and
% all-type aggregate where applicable.
%
% Both live declarations and rows restored from auxiliary files pass through
% the same registration function.  The indexes therefore remain correct as
% later project files add entries; there is no one-shot cache to invalidate.
% Summary cells perform a property lookup instead of traversing the growing
% database.  Detailed project tables still read their source rows, but collect
% all five funding types in one project-filtered traversal rather than five.
%
% \paragraph{Complete-proposal benchmark}
% The 149-page complete proposal was measured on 2026-07-17 with LuaHBTeX from
% TeX Live 2026.  Times below are for one final LuaLaTeX pass and compare the
% same proposal data before and after the aggregate-index refactor.  Absolute
% values depend on the machine and document contents; the important result is
% that lookup time no longer grows through repeated full database sums.
%
% \begin{center}
% \begin{tabular}{lrrr}
% \hline
% Operation & Before & After & Reduction \\
% \hline
% Staff overview & 135.745\,s & 6.975\,s & 94.9\,\% \\
% Instrumentation overview & 5.239\,s & 0.636\,s & 87.9\,\% \\
% 21 requested-funding tables & 90.444\,s & 28.831\,s & 68.1\,\% \\
% 19 existing-funding tables & 23.277\,s & 6.605\,s & 71.6\,\% \\
% \hline
% Combined & 254.705\,s & 43.047\,s & 83.1\,\% \\
% \hline
% \end{tabular}
% \end{center}
%
% This saves approximately 211.7 seconds per LuaLaTeX pass.  The monitored
% three-pass \texttt{make complete-proposal} release build completed in
% 33 minutes 21 seconds, so the funding changes account for approximately
% 10 minutes 35 seconds of avoided work across that build.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_add_entry:nnn #1#2#3
{
  % #1: keys     #2: database     #3: key-values
  \group_begin:
  \tl_set:Nn \l_@@_database_name_tl {#2}
  \DTLifdbexists {#2}
  { }
  { \DTLaction [ name = \l_@@_database_name_tl ] { new } }
  \bool_lazy_all:nT
  {
    { \str_if_eq_p:nn {#1} { staff } }
    { \str_if_eq_p:nn {#2} { RequestedFundingStaff } }
  }
  {
    \@@_requested_funding_staff_ensure_schema:
    \@@_requested_funding_staff_validate:n {#3}
  }
  \DTLaction [ name = \l_@@_database_name_tl ] { new~row }
  \str_if_eq:nnT {#1} { project }
  {
    \bool_set_true:N  \l_@@_project_consider_for_lists_bool
    \bool_set_false:N \l_@@_project_reference_only_bool
  }
  \exp_args:Ne \keys_set:nn {#1} {#3}
  \str_if_eq:nnT {#1} { project }
  {
    \bool_if:NTF \l_@@_project_consider_for_lists_bool
      { \DTLnewdbentry{\l_@@_database_name_tl}{consider-for-lists}{true} }
      { \DTLnewdbentry{\l_@@_database_name_tl}{consider-for-lists}{false} }
    \bool_if:NTF \l_@@_project_reference_only_bool
      { \DTLnewdbentry{\l_@@_database_name_tl}{reference-only}{true} }
      { \DTLnewdbentry{\l_@@_database_name_tl}{reference-only}{false} }
    \bool_gset_false:N \g_@@_project_count_ready_bool
  }
  \bool_lazy_all:nT
  {
    { \str_if_eq_p:nn {#1} { funding } }
    { \str_if_eq_p:Vn \l_@@_funding_tmp_type_str { staff } }
  }
  { \@@_funding_complete_staff_sums:n {#3} }
  \group_end:
}

% Funding tables repeatedly ask for the same sums, sometimes hundreds of
% times while tabularray measures a table.  Keep the datatool databases as
% the row store, but maintain compact aggregate indexes alongside them.
% The key layout is
%
%   database / project-or-__ALL__ / type-or-__ALL__ / field
%
% for monetary sums and
%
%   database / project-or-__ALL__ / category / quantity-field
%
% for requested staff quantities.  Values are added when an entry is
% declared, so a lookup never has to traverse a datatool database and the
% index cannot become stale when later project files add more rows.
\prop_new:N \g_@@_funding_sum_prop
\prop_new:N \g_@@_funding_staff_quantity_prop
\fp_new:N   \l_@@_funding_cache_fp
\tl_new:N   \l_@@_funding_cache_key_tl
\tl_new:N   \l_@@_funding_cache_value_tl
\tl_new:N   \l_@@_funding_cache_project_tl
\tl_new:N   \l_@@_funding_cache_type_tl
\tl_new:N   \l_@@_funding_cache_category_tl
\tl_new:N   \l_@@_funding_cache_percentage_tl
\tl_new:N   \l_@@_funding_salary_command_tl
\tl_new:N   \l_@@_funding_salary_value_tl
\tl_new:N   \l_@@_funding_cache_sum_one_tl
\tl_new:N   \l_@@_funding_cache_sum_two_tl
\tl_new:N   \l_@@_funding_cache_sum_three_tl
\tl_new:N   \l_@@_funding_cache_sum_four_tl
\tl_new:N   \l_@@_funding_cache_sum_five_tl
\tl_new:N   \l_@@_funding_cache_quantity_one_tl
\tl_new:N   \l_@@_funding_cache_quantity_two_tl
\tl_new:N   \l_@@_funding_cache_quantity_three_tl
\tl_new:N   \l_@@_funding_cache_quantity_four_tl
\tl_new:N   \l_@@_funding_cache_quantity_five_tl
\bool_new:N \l_@@_funding_calculation_store_bool
\bool_new:N \l_@@_funding_calculation_ready_bool
\bool_new:N \l_@@_funding_calculation_needed_bool

\prop_new:N \g_@@_funding_salary_commands_prop
\prop_gset_from_keyval:Nn \g_@@_funding_salary_commands_prop
{
  prof        = dfgSalaryProf,
  groupLeader = dfgSalaryGroupLeader,
  postDoc     = dfgSalaryPostDoc,
  medDoc      = dfgSalaryMedDoc,
  PhD         = dfgSalaryPhD,
  research    = dfgSalaryResearch,
  nonResearch = dfgSalaryNonResearch,
  student     = dfgSalaryStudent,
  assistant   = dfgSalaryAssistant,
  prof-W2     = dfgSalaryProf,
  prof-W3     = dfgSalaryProf
}

\keys_define:nn { dfg / funding-cache / sum }
{
  year1 .tl_set:N = \l_@@_funding_cache_sum_one_tl,
  year2 .tl_set:N = \l_@@_funding_cache_sum_two_tl,
  year3 .tl_set:N = \l_@@_funding_cache_sum_three_tl,
  year4 .tl_set:N = \l_@@_funding_cache_sum_four_tl,
  year5 .tl_set:N = \l_@@_funding_cache_sum_five_tl,
  unknown .code:n = { }
}

\keys_define:nn { dfg / funding-cache / quantity }
{
  year1 .tl_set:N = \l_@@_funding_cache_quantity_one_tl,
  year2 .tl_set:N = \l_@@_funding_cache_quantity_two_tl,
  year3 .tl_set:N = \l_@@_funding_cache_quantity_three_tl,
  year4 .tl_set:N = \l_@@_funding_cache_quantity_four_tl,
  year5 .tl_set:N = \l_@@_funding_cache_quantity_five_tl,
  unknown .code:n = { }
}

\keys_define:nn { dfg / funding-cache }
{
  ref-project-id .tl_set:N = \l_@@_funding_cache_project_tl,
  funding-type   .tl_set:N = \l_@@_funding_cache_type_tl,
  category       .tl_set:N = \l_@@_funding_cache_category_tl,
  percentage     .tl_set:N = \l_@@_funding_cache_percentage_tl,
  sum .code:n =
    { \keys_set:nn { dfg / funding-cache / sum } {#1} },
  quantity .code:n =
    { \keys_set:nn { dfg / funding-cache / quantity } {#1} },
  unknown .code:n = { }
}

\cs_new_protected:Npn \@@_funding_capture:n #1
{
  \tl_clear:N \l_@@_funding_cache_project_tl
  \tl_clear:N \l_@@_funding_cache_type_tl
  \tl_clear:N \l_@@_funding_cache_category_tl
  \tl_clear:N \l_@@_funding_cache_percentage_tl
  \tl_clear:N \l_@@_funding_cache_sum_one_tl
  \tl_clear:N \l_@@_funding_cache_sum_two_tl
  \tl_clear:N \l_@@_funding_cache_sum_three_tl
  \tl_clear:N \l_@@_funding_cache_sum_four_tl
  \tl_clear:N \l_@@_funding_cache_sum_five_tl
  \tl_clear:N \l_@@_funding_cache_quantity_one_tl
  \tl_clear:N \l_@@_funding_cache_quantity_two_tl
  \tl_clear:N \l_@@_funding_cache_quantity_three_tl
  \tl_clear:N \l_@@_funding_cache_quantity_four_tl
  \tl_clear:N \l_@@_funding_cache_quantity_five_tl
  \keys_set:nn { dfg / funding-cache } {#1}
}

\cs_new_protected:Npn \@@_funding_calculation_needed:NN #1#2
{
  \bool_lazy_all:nT
  {
    { \tl_if_blank_p:V #1 }
    { ! \tl_if_blank_p:V #2 }
  }
  { \bool_set_true:N \l_@@_funding_calculation_needed_bool }
}

\cs_new_protected:Npn \@@_funding_calculate_one:NNnn #1#2#3#4
{
  % #1 sum tl, #2 quantity tl, #3 database field, #4 period factor
  \bool_lazy_all:nT
  {
    { \tl_if_blank_p:V #1 }
    { ! \tl_if_blank_p:V #2 }
    { \bool_if_p:N \l_@@_funding_calculation_ready_bool }
  }
  {
    \exp_args:NnV \regex_match:nnTF
      { \A \d+ (?: \. \d+ )? \Z } #2
    {
      \tl_set:Nx #1
      {
        \fp_eval:n
        {
          round(
            \l_@@_funding_salary_value_tl
            * \l_@@_funding_cache_percentage_tl / 100
            * #2
            * #4,
            0
          )
        }
      }
      \bool_if:NT \l_@@_funding_calculation_store_bool
      {
        \exp_args:Nnne \DTLnewdbentry
          {\l_@@_database_name_tl}{#3}{\tl_use:N #1}
      }
    }
    {
      \bool_if:NT \l_@@_funding_calculation_store_bool
      {
        \msg_warning:nne { dfg } { funding-staff-cost-unavailable }
        { project~'\l_@@_funding_cache_project_tl',~#3:~invalid~quantity~'#2' }
      }
    }
  }
}

\cs_new_protected:Npn \@@_funding_calculate_staff_sums:
{
  \str_if_eq:VnT \l_@@_funding_cache_type_tl { staff }
  {
    \bool_set_false:N \l_@@_funding_calculation_needed_bool
    \@@_funding_calculation_needed:NN
      \l_@@_funding_cache_sum_one_tl \l_@@_funding_cache_quantity_one_tl
    \@@_funding_calculation_needed:NN
      \l_@@_funding_cache_sum_two_tl \l_@@_funding_cache_quantity_two_tl
    \@@_funding_calculation_needed:NN
      \l_@@_funding_cache_sum_three_tl \l_@@_funding_cache_quantity_three_tl
    \@@_funding_calculation_needed:NN
      \l_@@_funding_cache_sum_four_tl \l_@@_funding_cache_quantity_four_tl
    \@@_funding_calculation_needed:NN
      \l_@@_funding_cache_sum_five_tl \l_@@_funding_cache_quantity_five_tl
    \bool_if:NT \l_@@_funding_calculation_needed_bool
    {
      \bool_set_true:N \l_@@_funding_calculation_ready_bool
      \prop_get:NVNTF \g_@@_funding_salary_commands_prop
        \l_@@_funding_cache_category_tl \l_@@_funding_salary_command_tl
      {
        \cs_if_exist:cTF { \l_@@_funding_salary_command_tl }
        { \tl_set:Nx \l_@@_funding_salary_value_tl
          { \use:c { \l_@@_funding_salary_command_tl } } }
        { \bool_set_false:N \l_@@_funding_calculation_ready_bool }
      }
      { \bool_set_false:N \l_@@_funding_calculation_ready_bool }
      \exp_args:NnV \regex_match:nnF
        { \A \d+ (?: \. \d+ )? \Z }
        \l_@@_funding_cache_percentage_tl
      { \bool_set_false:N \l_@@_funding_calculation_ready_bool }
      \exp_args:NnV \regex_match:nnF
        { \A \d+ (?: \. \d+ )? \Z }
        \l_@@_funding_salary_value_tl
      { \bool_set_false:N \l_@@_funding_calculation_ready_bool }
      \bool_lazy_all:nT
      {
        { \bool_if_p:N \l_@@_funding_calculation_store_bool }
        { ! \bool_if_p:N \l_@@_funding_calculation_ready_bool }
      }
      {
        \msg_warning:nne { dfg } { funding-staff-cost-unavailable }
        {
          project~'\l_@@_funding_cache_project_tl',~category~
          '\l_@@_funding_cache_category_tl',~percentage~
          '\l_@@_funding_cache_percentage_tl'
        }
      }
      \@@_funding_calculate_one:NNnn
        \l_@@_funding_cache_sum_one_tl
        \l_@@_funding_cache_quantity_one_tl { sum-year1 } { 0.5 }
      \@@_funding_calculate_one:NNnn
        \l_@@_funding_cache_sum_two_tl
        \l_@@_funding_cache_quantity_two_tl { sum-year2 } { 1 }
      \@@_funding_calculate_one:NNnn
        \l_@@_funding_cache_sum_three_tl
        \l_@@_funding_cache_quantity_three_tl { sum-year3 } { 1 }
      \@@_funding_calculate_one:NNnn
        \l_@@_funding_cache_sum_four_tl
        \l_@@_funding_cache_quantity_four_tl { sum-year4 } { 1 }
      \@@_funding_calculate_one:NNnn
        \l_@@_funding_cache_sum_five_tl
        \l_@@_funding_cache_quantity_five_tl { sum-year5 } { 0.5 }
    }
  }
}

\cs_new_protected:Npn \@@_funding_complete_staff_sums:n #1
{
  \bool_set_true:N \l_@@_funding_calculation_store_bool
  \@@_funding_capture:n {#1}
  \@@_funding_calculate_staff_sums:
}

\cs_new_protected:Npn \@@_funding_cache_add:Nnn #1#2#3
{
  \tl_set:Nx \l_@@_funding_cache_key_tl {#2}
  \tl_set:Nx \l_@@_funding_cache_value_tl {#3}
  \tl_if_blank:VF \l_@@_funding_cache_value_tl
  {
    \prop_get:NVNTF #1
      \l_@@_funding_cache_key_tl \l_@@_funding_cache_value_tl
    {
      \fp_set:Nn \l_@@_funding_cache_fp
        { \l_@@_funding_cache_value_tl + (#3) }
    }
    { \fp_set:Nn \l_@@_funding_cache_fp {#3} }
    \prop_gput:NVx #1 \l_@@_funding_cache_key_tl
      { \fp_to_decimal:N \l_@@_funding_cache_fp }
  }
}

\cs_new_protected:Npn \@@_funding_cache_sum_year:nnn #1#2#3
{
  % #1 database, #2 field, #3 value
  \tl_if_blank:VF \l_@@_funding_cache_type_tl
  {
    \@@_funding_cache_add:Nnn \g_@@_funding_sum_prop
      {#1/\l_@@_funding_cache_project_tl/
       \l_@@_funding_cache_type_tl/#2} {#3}
    \@@_funding_cache_add:Nnn \g_@@_funding_sum_prop
      {#1/__ALL__/\l_@@_funding_cache_type_tl/#2} {#3}
  }
  \@@_funding_cache_add:Nnn \g_@@_funding_sum_prop
    {#1/\l_@@_funding_cache_project_tl/__ALL__/#2} {#3}
  \@@_funding_cache_add:Nnn \g_@@_funding_sum_prop
    {#1/__ALL__/__ALL__/#2} {#3}
}

\cs_new_protected:Npn \@@_funding_cache_quantity_year:nnn #1#2#3
{
  % #1 database, #2 field, #3 value
  \@@_funding_cache_add:Nnn \g_@@_funding_staff_quantity_prop
    {#1/\l_@@_funding_cache_project_tl/
     \l_@@_funding_cache_category_tl/#2} {#3}
  \@@_funding_cache_add:Nnn \g_@@_funding_staff_quantity_prop
    {#1/__ALL__/\l_@@_funding_cache_category_tl/#2} {#3}
}

\cs_new_protected:Npn \@@_funding_cache_entry:nn #1#2
{
  \group_begin:
  \bool_set_false:N \l_@@_funding_calculation_store_bool
  \@@_funding_capture:n {#2}
  \@@_funding_calculate_staff_sums:
  \tl_if_blank:VF \l_@@_funding_cache_project_tl
  {
    \@@_funding_cache_sum_year:nnn {#1} {sum-year1}
      {\l_@@_funding_cache_sum_one_tl}
    \@@_funding_cache_sum_year:nnn {#1} {sum-year2}
      {\l_@@_funding_cache_sum_two_tl}
    \@@_funding_cache_sum_year:nnn {#1} {sum-year3}
      {\l_@@_funding_cache_sum_three_tl}
    \@@_funding_cache_sum_year:nnn {#1} {sum-year4}
      {\l_@@_funding_cache_sum_four_tl}
    \@@_funding_cache_sum_year:nnn {#1} {sum-year5}
      {\l_@@_funding_cache_sum_five_tl}
    \str_if_eq:VnT \l_@@_funding_cache_type_tl {staff}
    {
      \tl_if_blank:VF \l_@@_funding_cache_category_tl
      {
        \@@_funding_cache_quantity_year:nnn {#1} {quantity-year1}
          {\l_@@_funding_cache_quantity_one_tl}
        \@@_funding_cache_quantity_year:nnn {#1} {quantity-year2}
          {\l_@@_funding_cache_quantity_two_tl}
        \@@_funding_cache_quantity_year:nnn {#1} {quantity-year3}
          {\l_@@_funding_cache_quantity_three_tl}
        \@@_funding_cache_quantity_year:nnn {#1} {quantity-year4}
          {\l_@@_funding_cache_quantity_four_tl}
        \@@_funding_cache_quantity_year:nnn {#1} {quantity-year5}
          {\l_@@_funding_cache_quantity_five_tl}
      }
    }
  }
  \group_end:
}

\cs_new_protected:Npn \@@_funding_sum_set:Nnnnn #1#2#3#4#5
{
  % #1 result, #2 database, #3 project, #4 type, #5 field list
  \fp_zero:N \l_@@_funding_cache_fp
  \clist_map_inline:nn {#5}
  {
    \tl_set:Nx \l_@@_funding_cache_key_tl {#2/#3/#4/##1}
    \prop_get:NVNT \g_@@_funding_sum_prop
      \l_@@_funding_cache_key_tl \l_@@_funding_cache_value_tl
    {
      \fp_add:Nn \l_@@_funding_cache_fp
        { \l_@@_funding_cache_value_tl }
    }
  }
  \tl_set:Nx #1 { \fp_to_decimal:N \l_@@_funding_cache_fp }
}

\bool_new:N \g_@@_document_started_bool

\AtBeginDocument
  { \bool_gset_true:N \g_@@_document_started_bool }

% This command is deliberately public and free of expl3 punctuation because
% it is written to, and subsequently read from, LaTeX .aux files.
\NewDocumentCommand \dfgRestoreRequestedFunding { +m }
{
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  {
    \@@_add_entry:nnn { funding } { RequestedFundingOverview } {#1}
    \@@_funding_cache_entry:nn { RequestedFundingOverview } {#1}
  }
}

% This public command is written to the auxiliary file.  Keep its name free of
% expl3 punctuation so LaTeX can read it before the document body starts.
\cs_new_protected:Npn \@@_requested_funding_staff_overview_ensure_schema:
{
  \DTLifdbexists { RequestedFundingStaffOverview }
  { }
  { \DTLaction [ name = RequestedFundingStaffOverview ] { new } }
  \clist_map_inline:nn
  {
    ref-project-id, funding-status, staff-type, ref-person-id,
    firstname, lastname, academic-degree, positionText, field-of-research,
    ref-institution-id, ref-affiliation-id, department, commitment, category,
    funding-source, description
  }
  {
    \DTLifhaskey { RequestedFundingStaffOverview } {##1}
    { }
    { \DTLaddcolumn { RequestedFundingStaffOverview } {##1} }
  }
}

\NewDocumentCommand \dfgRestoreRequestedFundingStaff { +m }
{
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  {
    \@@_requested_funding_staff_overview_ensure_schema:
    \@@_add_entry:nnn { staff } { RequestedFundingStaffOverview } {#1}
  }
}

\bool_if:NF \l_@@_class_fastcompile_project_bool
{ \@@_requested_funding_staff_overview_ensure_schema: }

% Existing direct-cost rows are normally declared in the individual project
% descriptions, after section 2.1.1 has already been typeset.  Mirror them to
% a dedicated overview database so that the project table keeps using its live
% rows without counting the restored rows twice.
\cs_new_protected:Npn
  \@@_requested_and_existing_direct_costs_overview_ensure_schema:
{
  \DTLifdbexists { RequestedAndExistingFundingDirectCostsOverview }
  { }
  { \DTLaction [ name = RequestedAndExistingFundingDirectCostsOverview ] { new } }
  \clist_map_inline:nn
  {
    ref-project-id, ref-affiliation-id, financed-by,
    sum-year1, sum-year2, sum-year3, sum-year4, sum-year5
  }
  {
    \DTLifhaskey { RequestedAndExistingFundingDirectCostsOverview } {##1}
    { }
    { \DTLaddcolumn { RequestedAndExistingFundingDirectCostsOverview } {##1} }
  }
}

% This public command is written to the auxiliary file.  Its name deliberately
% contains no expl3 punctuation so that LaTeX can read it at the start of the
% following run.
\NewDocumentCommand \dfgRestoreRequestedAndExistingFundingDirectCosts { +m }
{
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  {
    \@@_requested_and_existing_direct_costs_overview_ensure_schema:
    \@@_add_entry:nnn { funding }
      { RequestedAndExistingFundingDirectCostsOverview } {#1}
  }
}

\bool_if:NF \l_@@_class_fastcompile_project_bool
{ \@@_requested_and_existing_direct_costs_overview_ensure_schema: }

% Keep the overview tables usable on the first run, before any project-local
% entries have reached the auxiliary files.  A newly created database has no
% columns, so establish the RequestedFunding schema explicitly: otherwise
% sorting or filtering an empty overview raises ``No sort columns'' and
% ``Unknown column key'' errors.  No placeholder row is required.
\bool_if:NF \l_@@_class_fastcompile_project_bool
{
  \DTLifdbexists { RequestedFundingOverview }
    { }
    {
      \DTLaction [ name = RequestedFundingOverview ] { new }
      \DTLaddcolumn { RequestedFundingOverview } { ref-project-id }
      \DTLaddcolumn { RequestedFundingOverview } { type }
      \DTLaddcolumn { RequestedFundingOverview } { category }
      \DTLaddcolumn { RequestedFundingOverview } { percentage }
      \DTLaddcolumn { RequestedFundingOverview } { quantity-year1 }
      \DTLaddcolumn { RequestedFundingOverview } { quantity-year2 }
      \DTLaddcolumn { RequestedFundingOverview } { quantity-year3 }
      \DTLaddcolumn { RequestedFundingOverview } { quantity-year4 }
      \DTLaddcolumn { RequestedFundingOverview } { quantity-year5 }
      \DTLaddcolumn { RequestedFundingOverview } { sum-year1 }
      \DTLaddcolumn { RequestedFundingOverview } { sum-year2 }
      \DTLaddcolumn { RequestedFundingOverview } { sum-year3 }
      \DTLaddcolumn { RequestedFundingOverview } { sum-year4 }
      \DTLaddcolumn { RequestedFundingOverview } { sum-year5 }
    }
}

\cs_new_protected:Npn \@@_cache_requested_funding:n #1
{
  \bool_if:NTF \g_@@_document_started_bool
  {
    \iow_now:Nx \@auxout
      {
        \token_to_str:N \dfgRestoreRequestedFunding
        { \exp_not:n {#1} }
      }
  }
  { \dfgRestoreRequestedFunding{#1} }
}

\cs_new_protected:Npn \@@_cache_requested_funding_staff:n #1
{
  \bool_if:NTF \g_@@_document_started_bool
  {
    \iow_now:Nx \@auxout
    {
      \token_to_str:N \dfgRestoreRequestedFundingStaff
      { \exp_not:n {#1} }
    }
  }
  { \dfgRestoreRequestedFundingStaff{#1} }
}

\cs_new_protected:Npn
  \@@_cache_requested_and_existing_direct_costs:n #1
{
  \bool_if:NTF \g_@@_document_started_bool
  {
    \iow_now:Nx \@auxout
    {
      \token_to_str:N \dfgRestoreRequestedAndExistingFundingDirectCosts
      { \exp_not:n {#1} }
    }
  }
  { \dfgRestoreRequestedAndExistingFundingDirectCosts{#1} }
}

\NewDocumentCommand \addEntry { O{} m m }
{
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  {
  \tl_if_eq:nnTF {#1} { cv }
  { \bool_if:NTF \l_@@_class_cv_bool
	{ \@@_add_entry:nnn {#1} {#2} {#3} }
  	{ \msg_warning:nnn { dfg } { cv-entry-omitted } {#2} } }
  {% default behaviour: use #2 as family if #1 is empty
   \tl_if_empty:nTF {#1}
   { \@@_add_entry:nnn {#2} {#2} {#3} }
   {
      \@@_add_entry:nnn {#1} {#2} {#3}
      \str_if_eq:nnT {#1} { funding }
        { \@@_funding_cache_entry:nn {#2} {#3} }
      \bool_lazy_all:nT
        {
          { \str_if_eq_p:nn {#1} { funding } }
          { \str_if_eq_p:nn {#2} { RequestedFunding } }
        }
        { \@@_cache_requested_funding:n {#3} }
      \bool_lazy_all:nT
        {
          { \str_if_eq_p:nn {#1} { staff } }
          { \str_if_eq_p:nn {#2} { RequestedFundingStaff } }
        }
        { \@@_cache_requested_funding_staff:n {#3} }
      \bool_lazy_all:nT
        {
          { \str_if_eq_p:nn {#1} { funding } }
          { \str_if_eq_p:nn {#2} { RequestedAndExistingFundingDirectCosts } }
        }
        { \@@_cache_requested_and_existing_direct_costs:n {#3} }
    }
  }
  }
}
%    \end{macrocode}
% \end{macro}
%
% \begin{message}{cv-entry-omitted}
% Issued by \cs{addEntry} when an entry is targeted at the \texttt{cv}
% database but no CV is being produced (\cs{l\_dfg\_class\_cv\_bool} is
% false). The omitted entry's key-value data is included in the message
% to aid debugging.
%    \begin{macrocode}
\msg_new:nnn { dfg } { cv-entry-omitted }
{
  CV~entry~omitted:~no~CV~is~being~created.^^J
  Entry~data:~'#1'.
}
%    \end{macrocode}
% \end{message}
% There is a shortcut to define a database for e.g. a whole command to avoid all
% the time to write something like
% \cs{getEntry}\oarg{person}\marg{MM}\marg{lastname}.
% So you can define \cs{tmpLocalDB} with the database name.
%    \begin{macrocode}
\str_set:Nn \tmpLocalDB {}
%    \end{macrocode}
% \paragraph{\refCom{getEntry}}
% The primary read command: \cs{getEntry}\oarg{db}\marg{id-value}\marg{field}\oarg{id-field}.
% \begin{enumerate}
%   \item |#1|: Database name (default: \cs{tmpLocalDB}).
%   \item |#2|: The value to look up in the |id-field| column.
%   \item |#3|: The field whose value is to be returned.
%   \item |#4|: The name of the ID column (default: |id|); change this to
%         look up rows by a field other than the primary key.
% \end{enumerate}
% The guard logic runs in order:
%   If \refKey{fastcompile-project}|=true|, replace the output with a literal
%   identifier placeholder to skip the query entirely.
%   If |#1| is empty (\cs{tmpLocalDB} not set), warn and abort.
%   If the database does not exist, warn and abort.
%   Retrieve the value; if null/empty, warn (but only outside the
%   tabularray measuring pass to avoid duplicate messages).
%   Output via \cs{dfgShowTag} so that \refKey{showtags} annotations
%         are applied automatically.
%
% \textbf{PDF-bookmark note (FIXME):} When |#3| contains LaTeX commands,
% the value may produce garbage in PDF bookmarks.  Wrapping the output
% in \cs{texorpdfstring} would fix this but requires knowing at definition
% time what the field contains, which is not possible.  A workaround is
% to use \cs{texorpdfstring} at the call site for fields that appear in
% section headings.
%    \begin{macrocode}
%\getEntry [<DB>]{<id-value>}{<field>}                 [<id-column>]
%   single field, prints with \dfgShowTag wrapping
%
%\getEntry*[<DB>]{<id-value>}{<assignments>}            [<id-column>]
%   multi-field, assigns to macros, no printing
\NewDocumentCommand \dfgFastReference { m }
{ { \color{black-50}\ttfamily #1 } }

\cs_new_protected:Npn \@@_fast_clear_assignment:w #1 = #2 \q_stop
{ \cs_set:Npn #1 { } }

\cs_new_protected:Npn \@@_fast_clear_assignments:n #1
{
  \clist_map_inline:nn {#1}
  { \@@_fast_clear_assignment:w ##1 \q_stop }
}

\NewDocumentCommand{\getEntry}{s O{\tmpLocalDB} m m O{id}}
{%
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  {
    \IfBooleanTF{#1}
    { \@@_fast_clear_assignments:n {#4} }
    { \dfgFastReference{#3} }
  }
  {
    \IfBooleanTF{#1}
    { \@@_get_entry_multi:nnnn  {#2}{#3}{#4}{#5} }
    { \@@_get_entry_single:nnnn {#2}{#3}{#4}{#5} }%
  }
}

% --- single-field (your existing behaviour, lightly cleaned) ----------------
\cs_new_protected:Nn \@@_get_entry_single:nnnn
{
  % #1 db, #2 id-value, #3 field, #4 id-column
  \tl_if_blank:nTF {#1}
  { \msg_warning:nne {dfg}{database-name-not-given}{#2-/-#3} }
  {%
  	\DTLifdbexists{#1}
  	{%
  		\DTLgetvalueforkey{\thevalue}{#3}{#1}{#4}{#2}%
  		\DTLifnullorempty{\thevalue}
  		{%
  			\bool_if:NF \lTblrMeasuringBool
  			{ \msg_warning:nneee {dfg}{missing-key}{#1}{#2}{#3} }%
  		}
  		{ \dfgShowTag{#2}{#3}{\thevalue}[#1] }%
  	}
  	{ \msg_warning:nne {dfg}{database-not-found}{#1} }%
  }%
}

% --- multi-field: hoists checks out of per-field loop -----------------------
\cs_new_protected:Nn \@@_get_entry_multi:nnnn
{
  \tl_if_blank:nTF {#1}
  { \msg_warning:nne {dfg}{database-name-not-given}{#2-/-multi} }
  {%
  	\tl_set:Nx \l_tmpa_tl {#1}%
  	\tl_set:Nx \l_tmpb_tl {#2}%
  	\DTLifdbexists{\l_tmpa_tl}
  	{%
  		% \typeout{DEBUG:~about~to~assign~from~\l_tmpa_tl~for~id~\l_tmpb_tl}%
  		\use:x
  		{
  			\exp_not:N \DTLassignfirstmatch
  			{ \exp_not:V \l_tmpa_tl }
  			{ \exp_not:n {#4} }
  			{ \exp_not:V \l_tmpb_tl }
  			{ \exp_not:n {#3} }
  		}%
  		% \typeout{DEBUG:~done.~theLastName~=~\theLastName}%
  	}
  	{ \msg_warning:nne {dfg}{database-not-found}{\l_tmpa_tl} }%
  }%
}

\cs_new_protected:Npn \@@_check_empty:w #1 = #2 \q_stop #3#4
{
  % #1: target macro tokens, #2: field name, #3: db, #4: id
  \exp_args:NV \DTLifnullorempty #1
  { \msg_warning:nneee {dfg}{missing-key}{#3}{#4}{#2} }
  { }%
}

\cs_new_protected:Nn \@@_check_empty:nnn
{
  % #1 db, #2 id, #3 single "\macro = field" pair
  \@@_check_empty:w #3 \q_stop {#1}{#2}%
}

%    \end{macrocode}
% Sometimes you need to get the last name of a person in the text.
% Here is how to do it, \refCom{getName}.
%    \begin{macrocode}
\NewDocumentCommand{\getName}{m}{\getEntry[person]{#1}{lastname}}
%    \end{macrocode}
% Sometimes you need to get the full name of a person in the text.
% Here is how to do it, \refCom{getFullName}.
%    \begin{macrocode}
\NewDocumentCommand{\getFullName}{s m}
{%
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  { \dfgFastReference{#2} }
  {
  % #1: starred -> include academic degree
  % #2: person id
  \getEntry*[person]{#2}{
  	\theAcademicDegree = academicdegree,
  	\theFirstName      = firstname,
  	\theLastName       = lastname
  }%
  \IfBooleanT{#1}
  {
    \DTLifnullorempty{\theAcademicDegree}{}
      {\dfgShowTag{#2}{academicdegree}{\theAcademicDegree}[person]\space}
  }%
  \dfgShowTag{#2}{firstname}{\theFirstName}[person]\space
  \dfgShowTag{#2}{lastname}{\theLastName}[person]
  }
}
%    \end{macrocode}
% \paragraph{\refCom{compareEntry}}
% \refCom{compareEntry}\oarg{db}\marg{id}\marg{field}\marg{value}\marg{true}\marg{false}
% reads \meta{field} from the row with the given \meta{id} and executes
% \meta{yes} if it matches \meta{value}, otherwise \meta{no}.  It is
% used throughout the tables to branch on e.g.\ project type or status
% without repeating the full \cs{DTLgetvalueforkey}/|\if| pattern.
%
% The internal implementation \cs{dfg\_compare\_entry:nnnnnn} runs the same
% three guard checks as \refCom{getEntry} (empty DB name, non-existent DB),
% then uses \cs{exp\_args:Nx} to fully expand \cs{thevalue} before the
% \cs{tl\_if\_eq:nnTF} test, ensuring that stored macro values are resolved
% correctly.
%    \begin{macrocode}
\cs_new_protected:Npn \dfg_compare_entry:nnnnnn #1#2#3#4#5#6
{
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  {#6}
  {
  \tl_if_blank:nTF {#1}
  { \msg_warning:nnn { dfg } { database-name-not-given } {#1} }
  {
  	\DTLifdbexists{#1}
  	{
  		\DTLgetvalueforkey{\thevalue}{#3}{#1}{id}{#2}%
  		\str_if_eq:eeTF { \thevalue } {#4}
  		{#5}
  		{#6}
  	}
  	{ \msg_warning:nnn { dfg } { database-not-found } {#1} }
  }
  }
}

\NewDocumentCommand \compareEntry { O{\tmpLocalDB} m m m m m }
{
  \dfg_compare_entry:nnnnnn {#1}{#2}{#3}{#4}{#5}{#6}
}
%    \end{macrocode}
% \subsubsection{Table and list dispatch (\cs{printTable}, \cs{printList})}
%
% Rather than requiring the user to call \cs{ProjectLeadersTable},
% \cs{OverviewOfFundsRequestedForStaffTable}, etc.\ directly, two thin
% dispatchers are provided: \cs{printTable}\oarg{opts}\marg{name} and
% \cs{printList}\oarg{opts}\marg{name}.
%
% They synthesise the command name by appending |Table| or |List| to the
% \meta{name} argument (using \cs{cs:w}\ldots\cs{cs\_end:}), then pass
% the optional argument through if present.  This pattern means new tables
% can be added to the class without any change to user-facing call sites.
%
% Both commands check |fastcompile| first and emit a \cs{dfgItemSkipped}
% placeholder instead of running the real command when compilation speed
% is prioritised.  During real rendering they also establish the compact
% former-project context: reference-only projects receive an asterisk, and a
% local legend is added only if at least one such project was encountered.  A
% \cs{rowNumber} counter is reset before each table for use in zebra-stripe
% logic inside individual table implementations.
%    \begin{macrocode}

\tl_new:N \l_tblr_body_tl                % token list that will hold the rows

\bool_new:N \l_@@_former_project_compact_bool
\bool_new:N \g_@@_former_project_seen_bool

\cs_new_protected:Npn \@@_former_project_note:
{
  \par\smallskip
  \noindent
  {\normalfont\normalcolor\footnotesize
    \textsuperscript{*}\,Former~project}\par
}

\cs_new_protected:Npn \@@_former_project_context:n #1
{
  \bool_set_true:N \l_@@_former_project_compact_bool
  % Table cells and list implementations introduce their own groups, so the
  % occurrence flag must be latched globally for the duration of this context.
  \bool_gset_false:N \g_@@_former_project_seen_bool
  #1
  \bool_if:NT \g_@@_former_project_seen_bool
    { \@@_former_project_note: }
  \bool_set_false:N \l_@@_former_project_compact_bool
  \bool_gset_false:N \g_@@_former_project_seen_bool
}

\cs_new_protected:Npn \@@_print_thing:nnnn #1#2#3#4 {
  \bool_if:NTF \l_@@_class_fastcompile_bool
  { \@@_print_thing_skipped:nn {#1} {#3} }
  {%
    \@@_former_project_context:n
    {
      #4%
      \StartTimer
      \@@_print_thing_call:nnn {#1} {#2} {#3}%
      \StopTimer { \@@_print_thing_label:n {#3} }%
    }
  }
}

\cs_new_protected:Npn \@@_print_thing_call:nnn #1#2#3 {
  \tl_if_head_is_group:nTF {#3}
  { \@@_print_thing_split:nnw {#1} {#2} #3 \empty \q_stop }
  { \cs:w #3 #1 \cs_end: #2 }
}

\cs_new_protected:Npn \@@_print_thing_split:nnw #1#2#3#4 \q_stop {
  \cs:w #3 #1 \cs_end: #2 #4
}

\cs_new:Npn \@@_print_thing_label:n #1 {
  \tl_if_head_is_group:nTF {#1}
  { \@@_print_thing_label_aux:w #1 \empty \q_stop }
  { #1 }
}

\cs_new:Npn \@@_print_thing_label_aux:w #1#2 \q_stop {
  #1 \tl_if_blank:nF {#2} { - \@@_print_thing_label_tail:n {#2} }
}

\cs_new:Npn \@@_print_thing_label_tail:n #1 {
  \tl_if_head_eq_charcode:nNTF {#1} [
    { \@@_print_thing_label_skip_optional:w #1 \q_stop }
    { \tl_head:n {#1} }
}

\cs_new:Npn \@@_print_thing_label_skip_optional:w [#1]#2 \q_stop {
  \tl_head:n {#2}
}

\cs_new_protected:Npn \@@_print_thing_skipped:nn #1#2 {
  \dfgItemSkipped { \@@_print_thing_label:n {#2} #1 }
}

\NewDocumentCommand{\printTable}{ o +m }{%
  \IfNoValueTF {#1}
  { \@@_print_thing:nnnn { Table } { } {#2} { \setcounter{rowNumber}{0} } }
  { \@@_print_thing:nnnn { Table } { [#1] } {#2} { \setcounter{rowNumber}{0} } }%
}

\NewDocumentCommand{\printList}{ o +m }{%
  \IfNoValueTF {#1}
  { \@@_print_thing:nnnn { List } { } {#2} { } }
  { \@@_print_thing:nnnn { List } { [#1] } {#2} { } }%
}

\NewDocumentCommand{\printPlot}{ o +m }{%
  \IfNoValueTF {#1}
  { \@@_print_thing:nnnn { Plot } { } {#2} { } }
  { \@@_print_thing:nnnn { Plot } { [#1] } {#2} { } }%
}

\newcounter{rowNumber}
%    \end{macrocode}
% \subsubsection{Data tables}
%
% All tables follow the same three-phase pattern:
%   \textbf{Body accumulation:} A \cs{DTLforeach*} loop iterates
%   over the relevant database (filtered and sorted as required) and
%   appends one tblr row to the token list \cs{l\_tblr\_body\_tl}
%   via \cs{tl\_gput\_right:Nx}.  Using a global token list and
%   \texttt{:Nx} (full expansion) ensures that database values are
%   resolved at loop time rather than at tblr rendering time.
%   \textbf{Table opening:} \cs{begin}|{tblr}| with the |main| theme,
%   |expand=|\cs{l\_tblr\_body\_tl}, |long| (for page-breaking), and a
%   column spec tailored to the specific table.
%   \textbf{Header row + body:} A literal first row provides column
%         headings; \cs{l\_tblr\_body\_tl} follows as the data rows.
%
% \paragraph{ProjectLeadersTable}
% Lists all PIs who are active in the current funding period
% (\cs{theFundingPeriodNumeral}), sorted by last name.  The filter
% applies two conditions simultaneously: \refKey{period} must contain the current
% numeral and \refKey{role} must contain |PI|.  The first cell of every row
% defines the hyperlink destination |pi:<id>| used by \cs{getPI}.
%    \begin{macrocode}

% Use the same institution formatter as the CV section.  The public
% \dfgInstitutionList macro maps institution ids through \_@@_one_institution:n
% and uses \par\medskip between multiple institutions in the standard layout.
\NewDocumentCommand{\dfgPLInstitutionList}{m}{%
  \dfgInstitutionList{#1}[abbreviation]%
}

\int_new:N \l_@@_pl_iter_int

% Keep the hyperref command protected while tabularray expands the assembled
% table body.  It is executed only when the corresponding name cell is typeset.
\cs_new_protected:Npn \@@_pi_target:n #1
  { \hypertarget{pi:#1}{} }

\NewDocumentCommand{\ProjectLeadersTable}{}{%
  \def\tblrbody{}%

  \StartTimer
  \DTLsort*{lastname}{person}%
  \StopTimer{ProjectLeaderTable-sort}

  \int_zero:N \l_@@_pl_iter_int

  \StartTimer
  \DTLforeach*[
  	\DTLisinlist{\theFundingPeriodNumeral}{\period}
  	\and
  	\DTLisinlist{PI}{\role}
  ]{person}{
  	\id              = id,
  	\role            = role,
  	\lastname        = lastname,
  	\firstname       = firstname,
  	\academicdegree  = academicdegree,
  	\period          = period,
  	\refProjectId    = ref-project-id,
  	\refInstitutionId = ref-institution-id,
  	\doctorateYear   = doctorateYear,
  	\gender          = gender
  }{%
  	\int_incr:N \l_@@_pl_iter_int
  	\protected@edef\tblrbody{\tblrbody
		{\noexpand\@@_pi_target:n{\id}%
		 {\noexpand{\color{referencePI}\bfseries
        \noexpand\dfgShowTag{\id}{lastname}{\lastname}[person]},~
        \noexpand\dfgShowTag{\id}{firstname}{\firstname}[person]}
        \noexpand\\
        \noexpand\dfgShowTag{\id}{academicdegree}{\academicdegree}[person]}
      \noexpand& \noexpand\dfgShowTag{\id}{gender}{\gender}[person]
      \noexpand& \noexpand\dfgShowTag{\id}{doctorateYear}{\doctorateYear}[person]
  		\noexpand& {\noexpand\dfgPLInstitutionList{\id}}
  		\noexpand& \noexpand\getProject{\refProjectId}
  		\noexpand\\
  	}%
  }
  \StopTimer{PL-loop}
  \iow_term:x { PL-iterations:~ \int_use:N \l_@@_pl_iter_int }

  \StartTimer
  \begin{tblr}[
  		theme  = main,
  		expand = \tblrbody,
  		long
  	]{
  		colspec   = {t{3.5cm}t{1cm}t{1.6cm}X[t]t{1.3cm}},
  		column{1} = { fg = referencePI, halign = l },
  		column{2} = { halign = c },
  		column{3} = { halign = c },
  		column{4} = { halign = l },
  		column{5} = { halign = c },
  		rowhead   = 1,
  		row{1}    = {
  			            bg     = tableHeadingsBG,
  			            fg     = tableHeadingsFont,
  			            font   = \footnotesize\bfseries,
  			            halign = c,
  			            valign = t,
  			            guard
  		            },
  	}
  	Project~ leader
  	 & Gender
  	 & {Doctorate          \\ obtained~ in}
  	 & {Home~ institution, \\ location}
  	 & Project(s)                           \\
  	\tblrbody
  \end{tblr}
  \StopTimer{PL-render}
}
%    \end{macrocode}
% After the list of the PIs we need to have an aggregated list of the
% participating institutions.
%    \begin{macrocode}
\prop_new:N \l_@@_inst_to_aff_prop
\prop_new:N \l_@@_inst_name_prop
\prop_new:N \l_@@_inst_seen_prop
\prop_new:N \l_@@_aff_seen_prop
\prop_new:N \l_@@_aff_to_insts_prop  % values are seq names (tl)
\prop_new:N \l_@@_aff_name_prop
\seq_new:N  \l_@@_affiliations_seq
\seq_new:N  \l_@@_aff_sort_seq
\seq_new:N  \l_@@_inst_sort_seq
\tl_new:N   \l_@@_output_tl
\tl_new:N   \l_@@_aff_label_tl
\int_new:N  \l_@@_seq_counter_int
\cs_generate_variant:Nn \seq_set_from_clist:Nn { Ne , NV }

% Append an institution name to the per-affiliation seq.
% Lazily creates the seq on first use and stores its name in the prop.
\cs_new_protected:Npn \@@_append_inst:nn #1#2 {
  \prop_get:NnNTF \l_@@_aff_to_insts_prop {#1} \l_tmpd_tl
  {%
  	% \l_tmpd_tl now holds the seq's csname; append to it
  	\seq_put_right:cn { \l_tmpd_tl } {#2}%
  }
  {%
  	\int_incr:N \l_@@_seq_counter_int
  	\tl_set:Nx \l_tmpd_tl
  	{ l_@@_inst_seq_ \int_use:N \l_@@_seq_counter_int _seq }%
  	\seq_new:c { \l_tmpd_tl }%
  	\seq_put_right:cn { \l_tmpd_tl } {#2}%
  	\prop_put:NnV \l_@@_aff_to_insts_prop {#1} \l_tmpd_tl
  }
}
\cs_generate_variant:Nn \@@_append_inst:nn { VV }

\cs_new_protected:Npn \@@_collect_pi_institution:n #1
{
  \tl_if_blank:nF {#1}
  {
  	\prop_if_in:NnF \l_@@_inst_seen_prop {#1}
  	{%
  		\prop_put:Nnn \l_@@_inst_seen_prop {#1} {1}%
  		\prop_get:NnNT \l_@@_inst_to_aff_prop {#1} \l_tmpb_tl
  		{%
  			\prop_get:NnNT \l_@@_inst_name_prop {#1} \l_tmpc_tl
        {
          \tl_set:Ne \l_tmpe_tl
          {
            \exp_not:N \dfgShowTag {#1}{name}
              {\exp_not:V \l_tmpc_tl}[institution]
          }
          \@@_append_inst:VV \l_tmpb_tl \l_tmpe_tl
        }%
  			\prop_if_in:NVF \l_@@_aff_seen_prop \l_tmpb_tl
  			{%
  				\prop_put:NVn \l_@@_aff_seen_prop \l_tmpb_tl {1}%
  				\seq_put_right:NV \l_@@_affiliations_seq \l_tmpb_tl
  			}%
  		}%
  	}%
  }
}

\NewDocumentCommand{\ParticipatingInstitutionsList}{ O{count} }
{%
  % #1: alpha: affiliations are ordered alphabetically 
  % #1: count: by count 
  \prop_clear:N \l_@@_inst_to_aff_prop
  \prop_clear:N \l_@@_inst_name_prop
  \prop_clear:N \l_@@_inst_seen_prop
  \prop_clear:N \l_@@_aff_seen_prop
  \prop_clear:N \l_@@_aff_to_insts_prop
  \seq_clear:N  \l_@@_affiliations_seq
  \tl_clear:N   \l_@@_output_tl
  \int_zero:N   \l_@@_seq_counter_int

  % --- 1. One pass over institution: id -> aff-id, id -> name ---------
  \DTLforeach*{institution}{
  	\l_tmpa_tl = id,
  	\l_tmpb_tl = ref-affiliation-id,
  	\l_tmpc_tl = name
  }{%
  	\prop_put:NVV \l_@@_inst_to_aff_prop \l_tmpa_tl \l_tmpb_tl
  	\prop_put:NVV \l_@@_inst_name_prop   \l_tmpa_tl \l_tmpc_tl
  }

  % --- 2. One pass over person: collect active PI institutions --------
  \DTLforeach*[
  	\DTLisinlist{\theFundingPeriodNumeral}{\pPeriod} \and
  	\DTLisinlist{PI}{\pRole}
  ]{person}{ \l_tmpa_tl = ref-institution-id ,\pPeriod=period,\pRole=role}{%
  	\seq_set_from_clist:NV \l_tmpa_seq \l_tmpa_tl
  	\seq_map_inline:Nn \l_tmpa_seq
  	{ \@@_collect_pi_institution:n {##1} }%
  }

  % --- 3a. Precompute affiliation display names ----------------------
  \prop_clear:N \l_@@_aff_name_prop
  \seq_map_inline:Nn \l_@@_affiliations_seq {%
  	\getEntry*[affiliation]{##1}{ \l_tmpa_tl = name }%
  	\prop_put:NnV \l_@@_aff_name_prop {##1} \l_tmpa_tl
  }

  % --- 3b. Sort affiliations according to requested order ------------
  \str_case:nnF {#1}
  {
  	{ alpha }
  	{%
  		\seq_sort:Nn \l_@@_affiliations_seq
  		{%
  			\prop_get:NnN \l_@@_aff_name_prop {##1} \l_tmpa_tl
  			\prop_get:NnN \l_@@_aff_name_prop {##2} \l_tmpb_tl
  			\str_compare:eNeTF { \l_tmpa_tl } < { \l_tmpb_tl }
  				{ \sort_return_same: }
  				{ \sort_return_swapped: }%
  		}%
  	}
  	{ count }
  	{%
  		\seq_sort:Nn \l_@@_affiliations_seq
  		{%
  			\prop_get:NnN \l_@@_aff_to_insts_prop {##1} \l_tmpc_tl
  			\prop_get:NnN \l_@@_aff_to_insts_prop {##2} \l_tmpd_tl
  			\int_compare:nNnTF
  			{ \seq_count:c { \l_tmpc_tl } } > { \seq_count:c { \l_tmpd_tl } }
  				{ \sort_return_same: }
  				{%
  					\int_compare:nNnTF
  					{ \seq_count:c { \l_tmpc_tl } } < { \seq_count:c { \l_tmpd_tl } }
  						{ \sort_return_swapped: }
  						{%
  							% equal counts → alphabetical tiebreak
  							\prop_get:NnN \l_@@_aff_name_prop {##1} \l_tmpa_tl
  							\prop_get:NnN \l_@@_aff_name_prop {##2} \l_tmpb_tl
  							\str_compare:eNeTF { \l_tmpa_tl } < { \l_tmpb_tl }
  								{ \sort_return_same: }
  								{ \sort_return_swapped: }%
  						}%
  				}%
  		}%
  	}
  }
  {%
  	\msg_warning:nnn { @@ } { unknown-order }
  	{ Unknown~order~'#1';~using~'alpha'. }%
  	\seq_sort:Nn \l_@@_affiliations_seq
  	{%
  		\prop_get:NnN \l_@@_aff_name_prop {##1} \l_tmpa_tl
  		\prop_get:NnN \l_@@_aff_name_prop {##2} \l_tmpb_tl
  		\str_compare:eNeTF { \l_tmpa_tl } < { \l_tmpb_tl }
  			{ \sort_return_same: }
  			{ \sort_return_swapped: }%
  	}%
  }

  % --- 4. Emit output -------------------------------------------------
  \bool_set_true:N \l_tmpa_bool
  \seq_map_inline:Nn \l_@@_affiliations_seq {%
  	\bool_if:NTF \l_tmpa_bool
  	{ \bool_set_false:N \l_tmpa_bool }
  	{ \tl_put_right:Nn \l_@@_output_tl {\par} }%
  	\getEntry*[affiliation]{##1}{
  		\theAffName     = name,
  		\theAffLocation = location
  	}%
  	\prop_get:NnN \l_@@_aff_to_insts_prop {##1} \l_tmpd_tl
  	\seq_set_eq:Nc \l_@@_inst_sort_seq { \l_tmpd_tl }%
  	\seq_sort:Nn \l_@@_inst_sort_seq
  	{%
  		\str_compare:nNnTF {####1} < {####2}
  			{ \sort_return_same: }
  			{ \sort_return_swapped: }%
  	}%
  	\tl_set:Nx \l_@@_aff_label_tl { \seq_use:Nn \l_@@_inst_sort_seq {\\} }%
  	\tl_put_right:Nx \l_@@_output_tl {%
  		{ \exp_not:N \usekomafont{subsubsection}
        \exp_not:N \dfgShowTag {##1}{name}
          {\exp_not:V \theAffName}[affiliation]
        \exp_not:n {\space(}
        \exp_not:N \dfgShowTag {##1}{location}
          {\exp_not:V \theAffLocation}[affiliation]
        \exp_not:n {)\\} }%
  		\exp_not:V \l_@@_aff_label_tl \exp_not:n {\\}%
  	}%
  }
  \tl_use:N \l_@@_output_tl
}

%    \end{macrocode}
% Very similar to the table for the PIs we need one table for the projects.
% First we start with a helper command to get for each referenced person the
% required data.
%    \begin{macrocode}
\NewDocumentCommand{\getPersonInformation}{O{person} m}
{%
  % #1: database
  % #2: comma-separated list of person ids
  \def\tmpLocalDB{#1}%
  \seq_clear:N \l_tmpa_seq
  \seq_set_from_clist:Ne \l_tmpa_seq {#2}%
  \bool_if:NTF \l_@@_project_one_PI_bool
  {%
  	% Single-PI mode: no boxing, just emit each entry inline
  	\bool_set_true:N \l_tmpa_bool
  	\seq_map_inline:Nn \l_tmpa_seq
  	{%
  		\bool_if:NTF \l_tmpa_bool
  		{ \bool_set_false:N \l_tmpa_bool }
  		{ ~ }%
  		\__getperson_one:n {##1}%
  	}%
  }
  {%
  	% Multi-PI mode: lay out as a 2-column raster
  	\begin{tcbraster}[
  			raster~ columns=2,
  			raster~ equal~ height=rows,
  			raster~ column~ skip=4pt,
  			raster~ row~ skip=10pt,
  			PIbox
  		]
  		\seq_map_inline:Nn \l_tmpa_seq
  		{%
  			\__getperson_one:n {##1}%
  		}%
  	\end{tcbraster}
  }%
}

\cs_new_protected:Npn \__getperson_one:n #1
{%
  \getEntry*[\tmpLocalDB]{#1}{
  	\theFirstName      = firstname,
  	\theLastName       = lastname,
  	\theAcademicDegree = academicdegree,
  	\thePhone          = phone,
  	\theEmail          = email,
    \theInstitution    = ref-institution-id,
  	\theORCiD         = orcid
  }%
  \begin{tcolorbox}[PIbox,title={
          \dfgShowTag{#1}{firstname}{\theFirstName}[\tmpLocalDB]\space
  				\color{referencePI}\bfseries
          \dfgShowTag{#1}{lastname}{\theLastName}[\tmpLocalDB]
  				\normalfont\normalcolor,\newline
          \dfgShowTag{#1}{academicdegree}{\theAcademicDegree}[\tmpLocalDB]}]
  	\ifdefempty{\theORCiD}{\mbox{~}\\[.75\baselineskip]}{\getORCiD{#1}\\}
  	\ifdefempty{\theInstitution}{}{\dfgInstitutionList{#1}\newline}
    \ifdefempty{\thePhone}{}
      {\faPhone\space\dfgShowTag{#1}{phone}{\thePhone}[\tmpLocalDB]\\}
    \ifdefempty{\theEmail}{}
      {\faEnvelope\space\dfgShowTag{#1}{email}{\theEmail}[\tmpLocalDB]}
  \end{tcolorbox}
}

% ============================================================
%  Vorberechnung: kompakte Projects-Table-Daten pro Person
% ============================================================

% --- Allokationen, ausserhalb jeder Funktion ---------------------
\prop_new:N \g_@@_proj_pi_prop
\bool_new:N \g_@@_proj_pi_built_bool
\prop_new:N \g_@@_aff_narrow_prop
\prop_new:N \g_@@_inst_narrow_prop


% Helper für die Render-Zeit-Formatierung
\NewDocumentCommand{\dfgPIformat}{mmm}{%
  % #1 = person id, #2 = firstname, #3 = lastname
  \dfgShowTag{#1}{firstname}{#2}[person]\space
  {\color{referencePI}\bfseries
    \dfgShowTag{#1}{lastname}{#3}[person],}\space
}

% Vorberechnung: speichere nur die Tokens, NICHT \color & \bfseries direkt
\cs_new_protected:Npn \@@_proj_pi_build: {
  \bool_if:NF \g_@@_proj_pi_built_bool {
  	\bool_gset_true:N \g_@@_proj_pi_built_bool

  	% Pass 1+2: Institution-Strings vorberechnen (wie vorher)
  	\prop_new:N \l_@@_aff_narrow_prop
  	\DTLforeach*{affiliation}{
  		\l_tmpa_tl = id,
  		\l_tmpb_tl = name
  	}{%
  		\prop_put:NVV \l_@@_aff_narrow_prop \l_tmpa_tl \l_tmpb_tl
  	}

  \prop_new:N \l_@@_inst_narrow_prop
  \DTLforeach*{institution}{
  		\l_tmpa_tl = id,
  		\l_tmpb_tl = name,
  		\l_tmpc_tl = ref-affiliation-id
  	}{%
		\@@_institution_abbreviation_or_name:nN
		  { \l_tmpa_tl } \l_tmpf_tl
  		\prop_get:NVNT \l_@@_aff_narrow_prop \l_tmpc_tl \l_tmpd_tl {%
  			\tl_set:Nx \l_tmpe_tl
			{
          \exp_not:N \dfgShowTag
            {\exp_not:V \l_tmpa_tl}
            {\exp_not:V \l_@@_institution_label_field_tl}
            {\exp_not:V \l_tmpf_tl}[institution]
          ,~
          \exp_not:N \dfgShowTag
            {\exp_not:V \l_tmpc_tl}{name}
            {\exp_not:V \l_tmpd_tl}[affiliation]
        }
  			\prop_put:NVV \l_@@_inst_narrow_prop \l_tmpa_tl \l_tmpe_tl
  		}
  	}

  	% Pass 3: per Person die ganze Zelle vorberechnen, mit \dfgPIformat
  	\DTLforeach*{person}{
  		\l_tmpa_tl = id,
  		\l_tmpb_tl = firstname,
  		\l_tmpc_tl = lastname,
  		\l_tmpd_tl = ref-institution-id
  	}{%
  		\tl_clear:N \l_tmpe_tl
  		\tl_put_right:Nx \l_tmpe_tl {%
  			\exp_not:N \dfgPIformat
        { \exp_not:V \l_tmpa_tl }
  			{ \exp_not:V \l_tmpb_tl }
  			{ \exp_not:V \l_tmpc_tl }%
  		}%
  		% Institutions, separator ";~"
  		\seq_set_from_clist:NV \l_tmpa_seq \l_tmpd_tl
  		\bool_set_true:N \l_tmpa_bool
  		\seq_map_inline:Nn \l_tmpa_seq {%
  			\bool_if:NTF \l_tmpa_bool
  			{ \bool_set_false:N \l_tmpa_bool }
  			{ \tl_put_right:Nn \l_tmpe_tl { ;~ } }%
  			\prop_get:NnNT \l_@@_inst_narrow_prop {##1} \l_tmpf_tl
  			{ \tl_put_right:NV \l_tmpe_tl \l_tmpf_tl }%
  		}
  		\prop_gput:NVV \g_@@_proj_pi_prop \l_tmpa_tl \l_tmpe_tl
  	}
  }
}

% Schneller Drop-in
\NewDocumentCommand{\dfgFastPIinProjectsTable}{m}{%
  \@@_proj_pi_build:
  \seq_set_from_clist:Nn \l_tmpa_seq {#1}%
  \bool_set_true:N \l_tmpa_bool
  \seq_map_inline:Nn \l_tmpa_seq {%
  	\bool_if:NTF \l_tmpa_bool
  	{ \bool_set_false:N \l_tmpa_bool }
  	{ \newline }%
  	\prop_get:NnNT \g_@@_proj_pi_prop {##1} \l_tmpb_tl
  	{ \tl_use:N \l_tmpb_tl }%
  }
}

\NewDocumentCommand{\dfgPIinProjectsTable}{O{person} m}
{%
  % #1: database
  % #2: comma-separated list of person ids
  \def\tmpLocalDB{#1}%
  \seq_clear:N \l_tmpa_seq
  \seq_set_from_clist:Nn \l_tmpa_seq {#2}%
  \bool_set_true:N \l_tmpa_bool
  \seq_map_inline:Nn \l_tmpa_seq
  {%
  	\bool_if:NTF \l_tmpa_bool
  	{ \bool_set_false:N \l_tmpa_bool }
  	{ \newline }%
  	\__pi_in_projects_one:n {##1}%
  }%
}

\cs_new_protected:Npn \__pi_in_projects_one:n #1
{%
  \getEntry*[\tmpLocalDB]{#1}{
  	\theAcademicDegree = academicdegree,
  	\theFirstName = firstname,
  	\theLastName  = lastname
  }%
  \group_begin:
  %%\theAcademicDegree\space%
  \dfgShowTag{#1}{firstname}{\theFirstName}[\tmpLocalDB]\space
  \color{referencePI}\bfseries
  \dfgShowTag{#1}{lastname}{\theLastName}[\tmpLocalDB],\space
  \normalfont\normalcolor
  \dfgInstitutionList{#1}[abbreviation,noaddress,nolocation,nozip,narrow]%
  \group_end:
}
\NewDocumentCommand{\ProjectsTable}{mm}
{%
  \def\tblrbody{}%
  \clist_clear:N \l_@@_research_area_clist
  \tl_clear:N    \l_tmpa_tl
  \clist_clear:N \l_tmpa_clist
  \seq_clear:N   \l_tmpb_seq
  \seq_clear:N   \l_tmpa_seq

  \StartTimer
  \DTLsort{number}{project}%
  \StopTimer{Proj-#1-sort}

  \int_zero:N \l_tmpa_int

  \StartTimer
  \DTLforeach*[
  	\DTLisPrefix{\pNumber}{#1}
    \and
    \not\DTLiseq{\pConsiderForLists}{false}
  ]{project}{
  	\pID          = id,
  	\pNumber      = number,
  	\pName        = name,
  	\pStatus      = project-status,
  	\pType        = project-type,
    \pConsiderForLists = consider-for-lists,
  	\l_tmpa_clist = research-area,
  	\pRefPersonId = ref-person-id
  }{%
  	\int_incr:N \l_tmpa_int
  	% --- reset ALL flags each iteration ---------------------------------
  	\bool_set_false:N \l_@@_project_type_research_bool
  	\bool_set_false:N \l_@@_project_type_service_bool
  	\bool_set_false:N \l_@@_project_type_mgk_bool
  	\bool_set_false:N \l_@@_project_type_admin_bool

  	\bool_set_false:N \l_@@_project_status_N_bool
  	\bool_set_false:N \l_@@_project_status_E_bool
  	\bool_set_false:N \l_@@_project_status_C_bool


  	\str_case:Vn {\pStatus}
  	{
  		{N}{ \bool_set_true:N \l_@@_project_status_N_bool }
  		{E}{ \bool_set_true:N \l_@@_project_status_E_bool }
  		{C}{ \bool_set_true:N \l_@@_project_status_C_bool }
  	}

  	\str_case:Vn {\pType}{
  		{research}{ \bool_set_true:N \l_@@_project_type_research_bool }
  		{service} { \bool_set_true:N \l_@@_project_type_service_bool  }
  		{mgk}     { \bool_set_true:N \l_@@_project_type_mgk_bool      }
  		{admin}   { \bool_set_true:N \l_@@_project_type_admin_bool    }
  	}

  	\bool_if:nT
  	{ \l_@@_project_type_research_bool && ! \l_@@_project_status_E_bool }
  	{%
  		\clist_sort:Nn \l_tmpa_clist
  		{ \fp_compare:nTF {##1 < ##2} {\sort_return_swapped:} {\sort_return_same:} }%
  		\seq_set_from_clist:NN \l_tmpa_seq \l_tmpa_clist
  		\seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq
  		{%
  			\prop_if_in:NnTF \g_@@_dfg_research_areas_prop {##1}
  			{ ##1 }
  			{ \textcolor{error}{\textbf{##1}} }%
  		}%
  	}

  	\protected@edef\tblrbody{\tblrbody
      \noexpand\getProject{\pID}
      & {\noexpand\dfgShowTag{\pID}{project-status}{\pStatus}[project]}
      & \noexpand\dfgShowTag{\pID}{name}{\pName}[project]
  		&
  		\bool_if:nT
  		{ \l_@@_project_type_research_bool && ! \l_@@_project_status_E_bool }
      {{\noexpand\dfgShowTag{\pID}{research-area}
          {\seq_use:Nn \l_tmpb_seq {\\}}[project]}}
  		& \dfgFastPIinProjectsTable{\pRefPersonId}
  		\\
  	}%
  }
  \StopTimer{Proj-#1-loop}
  \iow_term:x { Proj-#1-iterations:~ \int_use:N \l_tmpa_int }

  \StartTimer
  \begin{tblr}[
  		theme   = main,
  		expand  = \tblrbody,
  		caption = {Project~area~#1~--~#2},
  		long
  	]{
  		colspec     = {t{1.1cm}t{0.7cm}X[t]t{1.2cm}X[t]},
  		rowhead     = 1,
  		column{2,4} = {halign=c},
  		column{1}   = {font=\Large\bfseries, fg=tableFirstColumn},
  		column{3,5} = {font=\footnotesize\raggedright},
  		row{1}      = {
  			              bg     = tableHeadingsBG,
  			              fg     = tableHeadingsFont,
  			              font   = \footnotesize\bfseries,
  			              halign = c,
  			              valign = t,
  			              guard
  		              },
  	}
  	Project
  	 & {Status}
  	 & Title
  	 & {\mbox{Research}                                               \\area}
  	 & Project\space leader(s),\space institute(s),\space location(s)         \\
  	\tblrbody
  \end{tblr}
  \StopTimer{Proj-#1-render}
}
%    \end{macrocode}
% \paragraph{Project overview table}
% \cs{projectOverviewTable} produces the compact project list used on the
% proposal's final page.  Current and new projects remain in project-number
% order; ending projects (status |E|) are moved to the end.  The status marker
% is omitted for current projects and printed after the project number for all
% other statuses.
%
% Project-leader names are resolved while the table body is assembled.  This
% avoids repeating database lookups during tabularray's measuring and rendering
% passes.  All three headings use the canonical dark blue at a larger size;
% the cell-specific rule ensures that the first heading (``Project'') is not
% overridden by the first-column styling.  The final-page source can therefore
% remain deliberately small:
% |\pagestyle{empty}| followed by |\printTable{projectOverview}|.
%    \begin{macrocode}
\tl_new:N  \l_@@_project_overview_body_tl
\tl_new:N  \l_@@_project_overview_ending_body_tl
\tl_new:N  \l_@@_project_overview_id_tl
\tl_new:N  \l_@@_project_overview_number_tl
\tl_new:N  \l_@@_project_overview_name_tl
\tl_new:N  \l_@@_project_overview_status_tl
\tl_new:N  \l_@@_project_overview_consider_for_lists_tl
\tl_new:N  \l_@@_project_overview_person_ids_tl
\tl_new:N  \l_@@_project_overview_leaders_tl
\tl_new:N  \l_@@_project_overview_project_cell_tl
\seq_new:N \l_@@_project_overview_person_seq

\cs_new_protected:Npn \@@_project_overview_set_leaders:n #1
{
  \tl_clear:N \l_@@_project_overview_leaders_tl
  \seq_set_from_clist:Nn \l_@@_project_overview_person_seq {#1}
  \seq_map_indexed_inline:Nn \l_@@_project_overview_person_seq
  {
    \DTLgetvalueforkey{\l_tmpa_tl}{firstname}{person}{id}{##2}
    \DTLgetvalueforkey{\l_tmpb_tl}{lastname}{person}{id}{##2}
    \int_compare:nNnT {##1} > {1}
      { \tl_put_right:Nn \l_@@_project_overview_leaders_tl { \newline } }
    \tl_if_blank:VF \l_tmpa_tl
    {
      \tl_put_right:Ne \l_@@_project_overview_leaders_tl
      {
        \exp_not:N \dfgShowTag {##2}{firstname}
          {\exp_not:V \l_tmpa_tl}[person]
        \exp_not:N \space
      }
    }
    \tl_put_right:Ne \l_@@_project_overview_leaders_tl
    {
      \exp_not:N \hyperlink { pi:\exp_not:n {##2} }
      {
        \exp_not:N \textbf
        {
          \exp_not:N \color { referencePI }
          \exp_not:N \dfgShowTag {##2}{lastname}
            {\exp_not:V \l_tmpb_tl}[person]
        }
      }
    }
  }
}

\cs_new_protected:Npn \@@_project_overview_append_row:N #1
{
  \exp_args:NV \@@_project_overview_set_leaders:n
    \l_@@_project_overview_person_ids_tl
  \tl_set:Ne \l_@@_project_overview_project_cell_tl
  {
    \exp_not:N \getProject
      { \exp_not:V \l_@@_project_overview_id_tl }
  }
  \str_if_eq:VnF \l_@@_project_overview_status_tl { C }
  {
    \tl_if_blank:VF \l_@@_project_overview_status_tl
    {
      \tl_put_right:Ne \l_@@_project_overview_project_cell_tl
      {
        \exp_not:N \,
        \exp_not:N \dfgShowTag
          {\exp_not:V \l_@@_project_overview_id_tl}{project-status}
          {\exp_not:V \l_@@_project_overview_status_tl}[project]
      }
    }
  }
  \tl_put_right:Ne #1
  {
    { \exp_not:V \l_@@_project_overview_project_cell_tl }
    & {
      \exp_not:N \dfgShowTag
        {\exp_not:V \l_@@_project_overview_id_tl}{name}
        {\exp_not:V \l_@@_project_overview_name_tl}[project]
    }
    & { \exp_not:V \l_@@_project_overview_leaders_tl }
    \exp_not:N \\
  }
}

\cs_new_protected:Npn \@@_project_overview_collect:
{
  \DTLsort{number}{project}
  \DTLforeach*{project}
  {
    \l_@@_project_overview_id_tl         = id,
    \l_@@_project_overview_number_tl     = number,
    \l_@@_project_overview_name_tl       = name,
    \l_@@_project_overview_status_tl     = project-status,
    \l_@@_project_overview_consider_for_lists_tl = consider-for-lists,
    \l_@@_project_overview_person_ids_tl = ref-person-id
  }
  {
    \str_if_eq:VnF \l_@@_project_overview_consider_for_lists_tl { false }
    {
      \str_if_eq:VnTF \l_@@_project_overview_status_tl { E }
        { \@@_project_overview_append_row:N \l_@@_project_overview_ending_body_tl }
        { \@@_project_overview_append_row:N \l_@@_project_overview_body_tl }
    }
  }
  \tl_put_right:NV \l_@@_project_overview_body_tl
    \l_@@_project_overview_ending_body_tl
}

\cs_new_protected:Npn \@@_project_overview_typeset:
{
  \par\vspace*{-5\baselineskip}
  \begin{center}
    \crcLogo[height=1cm]
  \end{center}
  \enlargethispage{3\baselineskip}
  \begin{tblr}[
    theme  = main,
    expand = \l_@@_project_overview_body_tl
  ]{
    vspan       = even,
    rowsep      = 1pt,
    rows        = {ht=2\baselineskip,valign=m},
    colspec     = {m{1.5cm}X[m]m{4cm}},
    rowhead     = 1,
	column{1}   = {font=\Large\bfseries, fg=tableFirstColumn},
    column{2,3} = {font=\raggedright},
    row{1} = {font=\large\bfseries,fg=tableHeadingsFont},
  }
    Project
    & Title
    & Project\space leader(s) \\
    \l_@@_project_overview_body_tl
  \end{tblr}
}

\NewDocumentCommand{\projectOverviewTable}{}
{
  \group_begin:
  \DTLifdbexists{project}
  {
    \tl_clear:N \l_@@_project_overview_body_tl
    \tl_clear:N \l_@@_project_overview_ending_body_tl
    \@@_project_overview_collect:
    \@@_project_overview_typeset:
  }
  { \msg_warning:nnn { dfg } { database-not-found } { project } }
  \group_end:
}
%    \end{macrocode}
% We turn now to the part to get the research areas aggregated.
%    \begin{macrocode}
\clist_new:N \l_@@_research_area_clist   % new clist name
\clist_new:N \l_@@_research_area_final_clist   % new clist name
\NewDocumentCommand{\ResearchAreasFromProjectsList}{o}{
  % #1: IDs of project to be excluded
  \clist_clear:N \l_@@_research_area_clist
  \tl_clear:N \l_tmpa_tl

  \DTLforeach[
  	% exclude mentioned projects (for whatsoever reason)
  	\not\DTLisinlist{\pNumber}{#1}% 1st condition
    \and
    \not\DTLiseq{\pConsiderForLists}{false}
  ]
  {project}{%
  	\pNumber       =number,
  	\pType         =project-type,
    \pConsiderForLists=consider-for-lists,
  	\l_tmpa_tl     =research-area%
  }{%
  	% Quite heavy but it works to skip the research area for non-research projects
  	\bool_set_false:N \l_@@_project_type_research_bool
  	\bool_set_false:N \l_@@_project_type_service_bool
  	\bool_set_false:N \l_@@_project_type_mgk_bool
  	\bool_set_false:N \l_@@_project_type_admin_bool

  	\str_case:Vn {\pType}{
  		{research}{ \bool_set_true:N \l_@@_project_type_research_bool }
  		{service} { \bool_set_true:N \l_@@_project_type_service_bool  }
  		{mgk}     { \bool_set_true:N \l_@@_project_type_mgk_bool      }
  		{admin}   { \bool_set_true:N \l_@@_project_type_admin_bool    }
  	}
  	\bool_lazy_any:nT {{ \l_@@_project_type_research_bool}}
  	{\clist_put_right:NV \l_@@_research_area_clist { \l_tmpa_tl }}%
  }
  \clist_remove_duplicates:N \l_@@_research_area_clist
  % sorting and faking that the numbers are floats.... HACK
  \clist_sort:Nn \l_@@_research_area_clist
  { \fp_compare:nTF { ##1 < ##2 } { \sort_return_swapped: } { \sort_return_same: } }

  \clist_map_inline:Nn \l_@@_research_area_clist {
  	\clist_put_right:NV \l_@@_research_area_final_clist { \dfgResearchAreasList{##1}}
  }

  \dfgShowCalculatedTag{ResearchAreasFromProjectsList}{project}
  {
    \clist_use:Nnnn \l_@@_research_area_final_clist {,~}{,~}{,~and~}%
    .%final dot.
  }
}
% \subsubsection{DFG research area classification}
% \label{sec:research-areas}
% The DFG publishes an official hierarchical subject classification list;
% a project must declare which areas its work belongs to.  The global
% property list \cs{g\_@@\_dfg\_research\_areas\_prop} maps every
% classification code (e.g.\ |2.11-01|) to its English label.
%
% Usage: supply one or more codes as a comma-separated value in the
% |research-area| key of an \refCom{addEntry}|{project}| block.
% \cs{printResearchAreas} then looks up and formats them as a
% natural-language list.
%
% \textbf{Sorting note:} the codes are numeric strings with a hyphen
% (|2.11-01|), which cannot be compared as plain integers.  The sort
% in \cs{printResearchAreas} uses \cs{fp\_compare:nTF} after stripping
% the hyphen suffix — a known workaround for the absence of a
% lexicographic sort in expl3 for this mixed format.
\prop_new:N \g_@@_dfg_research_areas_prop
\prop_gset_from_keyval:Nn \g_@@_dfg_research_areas_prop
{
  1.11-01 = {Prehistory~and~World~Archaeology},
  1.11-02 = {Greek~and~Latin~Philology},
  1.11-03 = {Ancient~History},
  1.11-04 = {Classical,~Roman,~Christian~and~Islamic~Archaeology},
  1.11-05 = {Egyptology~and~Ancient~Near~Eastern~Studies},

  1.12-01 = {Medieval~History},
  1.12-02 = {Early~Modern~History},
  1.12-03 = {Modern~and~Contemporary~History},
  1.12-04 = {History~of~Science},

  1.13-01 = {Art~History},
  1.13-02 = {Musicology},
  1.13-03 = {Theatre~and~Media~Studies},

  1.14-01 = {General~and~Comparative~Linguistics,~Experimental~Linguistics,~Typology,~Non-European~Languages},
  1.14-02 = {Individual~Linguistics,~Historical~Linguistics},
  1.14-03 = {Applied~Linguistics,~Computational~Linguistics},

  1.15-01 = {German~Medieval~Studies~(Medieval~German~Literature)},
  1.15-02 = {German~Literary~and~Cultural~Studies~(Modern~German~Literature)},
  1.15-03 = {European~and~American~Literary~and~Cultural~Studies},
  1.15-04 = {General~and~Comparative~Literary~Studies;~Cultural~Studies},

  1.16-01 = {Social~and~Cultural~Anthropology~and~Ethnology},
  1.16-02 = {Asian~Studies},
  1.16-03 = {African,~American~and~Oceania~Studies},
  1.16-04 = {Islamic~Studies,~Arabian~Studies,~Semitic~Studies},
  1.16-05 = {Religious~Studies~and~Jewish~Studies},

  1.17-01 = {Protestant~Theology},
  1.17-02 = {Roman~Catholic~Theology},

  1.18-01 = {History~of~Philosophy},
  1.18-02 = {Theoretical~Philosophy},
  1.18-03 = {Practical~Philosophy},

  1.21-01 = {General~Education~and~History~of~Education},
  1.21-02 = {General~and~Domain-Specific~Teaching~and~Learning},
  1.21-03 = {Education~Systems~and~Educational~Institutions},
  1.21-04 = {Educational~Research~on~Socialisation,~Welfare~and~Professionalism},

  1.22-01 = {General,~Cognitive~and~Mathematical~Psychology},
  1.22-02 = {Biological~Psychology~and~Cognitive~Neuroscience},
  1.22-03 = {Developmental~and~Educational~Psychology},
  1.22-04 = {Social~Psychology,~Industrial~and~Organisational~Psychology},
  1.22-05 = {Personality~Psychology,~Clinical~and~Medical~Psychology,~Methodology},

  1.23-01 = {Sociological~Theory},
  1.23-02 = {Empirical~Social~Research},
  1.23-03 = {Communication~Sciences},
  1.23-04 = {Political~Science},

  1.24-01 = {Economic~Theory},
  1.24-02 = {Economic~Policy,~Applied~Economics},
  1.24-03 = {Accounting~and~Finance},
  1.24-04 = {Management~and~Marketing},
  1.24-05 = {Operations~Management~and~Computer~Science~for~Business~Administration},
  1.24-06 = {Statistics~and~Econometrics},
  1.24-07 = {Economic~and~Social~History},

  1.25-01 = {Principles~of~Law~and~Jurisprudence},
  1.25-02 = {Private~Law},
  1.25-03 = {Public~Law},
  1.25-04 = {Criminal~Law},
  1.25-05 = {Criminology},

  2.11-01 = {Biochemistry},
  2.11-02 = {Biophysics},
  2.11-03 = {Cell~Biology},
  2.11-04 = {Structural~Biology},
  2.11-05 = {General~Genetics~and~Functional~Genome~Biology},
  2.11-06 = {Developmental~Biology},
  2.11-07 = {Bioinformatics~and~Theoretical~Biology},

  2.12-01 = {Evolution~and~Systematics~of~Plants~and~Fungi},
  2.12-02 = {Ecology~and~Biodiversity~of~Plants~and~Ecosystems},
  2.12-03 = {Organismic~Interactions,~Chemical~Ecology~and~Microbiomes~of~Plant~Systems},
  2.12-04 = {Plant~Physiology},
  2.12-05 = {Plant~Biochemistry~and~Biophysics},
  2.12-06 = {Plant~Cell~and~Developmental~Biology},
  2.12-07 = {Plant~Genetics~and~Genomics},

  2.13-01 = {Systematics~and~Morphology~(Zoology)},
  2.13-02 = {Evolution,~Anthropology},
  2.13-03 = {Ecology~and~Biodiversity~of~Animals~and~Ecosystems,~Organismic~Interactions},
  2.13-04 = {Sensory~and~Behavioural~Biology},
  2.13-05 = {Animal~Physiology~and~Biochemistry},
  2.13-06 = {Evolutionary~Cell~and~Developmental~Biology~(Zoology)},

  2.21-01 = {Metabolism,~Biochemistry~and~Genetics~of~Microorganisms},
  2.21-02 = {Microbial~Ecology~and~Applied~Microbiology},
  2.21-03 = {Medical~Microbiology~and~Mycology,~Hygiene,~Molecular~Infection~Biology},
  2.21-04 = {Virology},
  2.21-05 = {Immunology},
  2.21-06 = {Parasitology~and~Biology~of~Tropical~Infectious~Disease~Pathogens},

  2.22-01 = {Epidemiology~and~Medical~Biometry~/~Statistics},
  2.22-02 = {Public~Health,~Healthcare~Research,~Social~and~Occupational~Medicine},
  2.22-03 = {Human~Genetics},
  2.22-04 = {Anatomy~and~Physiology},
  2.22-05 = {Nutritional~Sciences},
  2.22-06 = {Pathology},
  2.22-07 = {Medical~Informatics~and~Medical~Bioinformatics},
  2.22-08 = {Pharmacy},
  2.22-09 = {Pharmacology},
  2.22-10 = {Toxicology,~Laboratory~Medicine},
  2.22-11 = {Anaesthesiology},
  2.22-12 = {Cardiology,~Angiology},
  2.22-13 = {Pneumology,~Thoracic~Surgery},
  2.22-14 = {Hematology,~Oncology},
  2.22-15 = {Gastroenterology},
  2.22-16 = {Nephrology},
  2.22-17 = {Endocrinology,~Diabetology,~Metabolism},
  2.22-18 = {Rheumatology},
  2.22-19 = {Dermatology},
  2.22-20 = {Pediatric~and~Adolescent~Medicine},
  2.22-21 = {Gynaecology~and~Obstetrics},
  2.22-22 = {Clinical~Immunology~and~Allergology},
  2.22-23 = {Reproductive~Medicine,~Urology},
  2.22-24 = {Biogerontology~and~Geriatric~Medicine},
  2.22-25 = {General~and~Visceral~Surgery},
  2.22-26 = {Cardiac~and~Vascular~Surgery},
  2.22-27 = {Orthopaedics,~Traumatology,~Reconstructive~Surgery},
  2.22-28 = {Dentistry,~Oral~Surgery},
  2.22-29 = {Otolaryngology,~Phoniatrics~and~Audiology},
  2.22-30 = {Radiology},
  2.22-31 = {Clinical~Infectiology~and~Tropical~Medicine},
  2.22-32 = {Medical~Physics,~Biomedical~Technology},
  2.22-33 = {Nuclear~Medicine,~Radiotherapy,~Radiobiology},

  2.23-01 = {Developmental~Neurobiology},
  2.23-02 = {Molecular~Biology~and~Physiology~of~Neurons~and~Glial~Cells},
  2.23-03 = {Experimental~and~Theoretical~Network~Neuroscience},
  2.23-04 = {Cognitive,~Systems~and~Behavioural~Neurobiology},
  2.23-05 = {Experimental~Models~for~the~Understanding~of~Nervous~System~Diseases},
  2.23-06 = {Molecular~and~Cellular~Neurology~and~Neuropathology},
  2.23-07 = {Clinical~Neurology;~Neurosurgery~and~Neuroradiology},
  2.23-08 = {Human~Cognitive~and~Systems~Neuroscience},
  2.23-09 = {Biological~Psychiatry},
  2.23-10 = {Clinical~Psychiatry,~Psychotherapy,~Child~and~Adolescent~Psychiatry},
  2.23-11 = {Ophthalmology},

  2.31-01 = {Soil~Sciences},
  2.31-02 = {Plant~Breeding~and~Plant~Pathology},
  2.31-03 = {Plant~Cultivation,~Plant~Nutrition,~Agricultural~Technology},
  2.31-04 = {Ecology~of~Land~Use},
  2.31-05 = {Agricultural~Economics,~Agricultural~Policy,~Agricultural~Sociology},
  2.31-06 = {Forestry},
  2.31-07 = {Animal~Breeding,~Animal~Nutrition,~Animal~Husbandry},

  3.11-01 = {Inorganic~Molecular~Chemistry~-~Synthesis~and~Characterisation},
  3.11-02 = {Organic~Molecular~Chemistry~-~Synthesis~and~Characterisation},

  3.12-01 = {Solid~State~and~Surface~Chemistry,~Material~Synthesis},
  3.12-02 = {Physical~Chemistry~of~Solids~and~Surfaces,~Material~Characterisation},

  3.13-01 = {Physical~Chemistry~of~Molecules,~Liquids~and~Interfaces,~Biophysical~Chemistry},

  3.14-01 = {Analytical~Chemistry},

  3.15-01 = {Biological~and~Biomimetic~Chemistry},
  3.15-02 = {Food~Chemistry},

  3.16-01 = {Preparatory~and~Physical~Chemistry~of~Polymers},
  3.16-02 = {Experimental~and~Theoretical~Physics~of~Polymers},
  3.16-03 = {Polymer~Materials},

  3.17-01 = {Theoretical~Chemistry:~Electron~Structure,~Dynamics,~Simulation},
  3.17-02 = {Theoretical~Chemistry:~Molecules,~Materials,~Surfaces},

  3.21-01 = {Experimental~Condensed~Matter~Physics},
  3.21-02 = {Theoretical~Condensed~Matter~Physics},

  3.22-01 = {Statistical~Physics,~Nonlinear~Dynamics,~Complex~Systems,~Soft~and~Fluid~Matter,~Biological~Physics},

  3.23-01 = {Optics,~Quantum~Optics~and~Physics~of~Atoms,~Molecules~and~Plasmas},

  3.24-01 = {Nuclear~and~Elementary~Particle~Physics,~Quantum~Mechanics,~Relativity,~Fields},

  3.25-01 = {Astrophysics~and~Astronomy},

  3.31-01 = {Mathematics},

  3.41-01 = {Atmospheric~Science},
  3.41-02 = {Oceanography},

  3.42-01 = {Geology},
  3.42-02 = {Palaeontology},

  3.43-01 = {Geophysics},
  3.43-02 = {Geodesy,~Photogrammetry,~Remote~Sensing,~Geoinformatics,~Cartography},

  3.44-01 = {Mineralogy,~Petrology~and~Geochemistry},

  3.45-01 = {Physical~Geography},
  3.45-02 = {Human~Geography},

  3.46-01 = {Hydrogeology,~Hydrology,~Limnology,~Urban~Water~Management,~Water~Chemistry,~Integrated~Water~Resources~Management},

  4.11-01 = {Metal-Cutting~and~Abrasive~Manufacturing~Engineering},
  4.11-02 = {Primary~Shaping~and~Reshaping~Technology,~Additive~Manufacturing},
  4.11-03 = {Joining~and~Separation~Technology},
  4.11-04 = {Plastics~Engineering},
  4.11-05 = {Production~Systems,~Operations~Management,~Quality~Management~and~Factory~Planning},
  4.11-06 = {Production~Automation~and~Assembly~Technology},

  4.12-01 = {Engineering~Design,~Machine~Elements,~Product~Development},
  4.12-02 = {Mechanics},
  4.12-03 = {Lightweight~Construction,~Textile~Technology},
  4.12-04 = {Acoustics},

  4.21-01 = {Chemical~and~Thermal~Process~Engineering},
  4.21-02 = {Technical~Chemistry},
  4.21-03 = {Mechanical~Process~Engineering},
  4.21-04 = {Biological~Process~Engineering},
  4.21-05 = {Systems~Process~Engineering},

  4.22-01 = {Energy~Process~Engineering},
  4.22-02 = {Technical~Thermodynamics},
  4.22-03 = {Fluid~Mechanics},
  4.22-04 = {Hydraulic~and~Turbo~Engines~and~Piston~Engines},

  4.31-01 = {Metallurgical,~Thermal~and~Thermomechanical~Treatment~of~Materials},
  4.31-02 = {Materials~in~Sintering~Processes~and~Generative~Manufacturing~Processes},
  4.31-03 = {Coating~and~Surface~Technology},
  4.31-04 = {Mechanical~Properties~of~Metallic~Materials~and~their~Microstructural~Origins},
  4.31-05 = {Glass,~Ceramics~and~Derived~Composites},
  4.31-06 = {Polymeric~and~Biogenic~Materials~and~Derived~Composites},

  4.32-01 = {Synthesis~and~Properties~of~Functional~Materials},
  4.32-02 = {Biomaterials},
  4.32-03 = {Thermodynamics~and~Kinetics~as~well~as~Properties~of~Phases~and~Microstructure~of~Materials},
  4.32-04 = {Computer-Aided~Design~of~Materials~and~Simulation~of~Materials~Behaviour~from~Atomic~to~Microscopic~Scale},

  4.41-01 = {Automation,~Mechatronics,~Control~Systems,~Intelligent~Technical~Systems,~Robotics},
  4.41-02 = {Measurement~Systems},
  4.41-03 = {Microsystems},
  4.41-04 = {Traffic~and~Transport~Systems,~Intelligent~and~Automated~Traffic},
  4.41-05 = {Human~Factors,~Ergonomics,~Human-Machine~Systems},
  4.41-06 = {Biomedical~Systems~Technology},

  4.42-01 = {Electronic~Semiconductors,~Components~and~Circuits,~Integrated~Systems,~Sensor~Technology,~Theoretical~Electrical~Engineering},
  4.42-02 = {Communication~Technology~and~Networks,~High-Frequency~Technology~and~Photonic~Systems,~Signal~Processing~and~Machine~Learning~for~Information~Technology},
  4.42-03 = {Electrical~Energy~Systems,~Power~Management,~Power~Electronics,~Electrical~Machines~and~Drives},
  4.42-04 = {Hardware~Systems~and~Architectures~for~Information~Technology~and~Artificial~Intelligence,~Quantum~Engineering~Systems},

  4.43-01 = {Theoretical~Computer~Science},
  4.43-02 = {Software~Engineering~and~Programming~Languages},
  4.43-03 = {Security~and~Dependability,~Operating,~Communication~and~Distributed~Systems},
  4.43-04 = {Artificial~Intelligence~and~Machine~Learning~Methods},
  4.43-05 = {Image~and~Language~Processing,~Computer~Graphics~and~Visualisation,~Human~Computer~Interaction,~Ubiquitous~and~Wearable~Computing},
  4.43-06 = {Data~Management,~Data-Intensive~Systems,~Computer~Science~Methods~in~Business~Informatics},
  4.43-07 = {Computer~Architecture,~Embedded~and~Massively~Parallel~Systems},

  4.51-01 = {Architecture,~Building~and~Construction~History,~Construction~Research,~Sustainable~Building~Technology},
  4.51-02 = {Urbanism,~Spatial~Planning,~Transportation~and~Infrastructure~Planning,~Landscape~Planning},
  4.51-03 = {Construction~Material~Sciences,~Chemistry,~Building~Physics},
  4.51-04 = {Structural~Engineering,~Building~Informatics~and~Construction~Operation},
  4.51-05 = {Applied~Mechanics,~Statics~and~Dynamics},
  4.51-06 = {Geotechnics,~Hydraulic~Engineering},

}

\NewDocumentCommand{\dfgResearchAreasList}{m}{
  % #1: area-list
  \prop_if_in:NnTF \g_@@_dfg_research_areas_prop {#1}
  {
  	% key exists → fetch the description and typeset it
  	\prop_get:NnN \g_@@_dfg_research_areas_prop {#1} \l_tmpa_tl
  	\textbf{#1}:~\l_tmpa_tl
  }
  {
  	% key missing → same fallback as your original macro
  	\textcolor{error}{\textbf{#1}:~ research~ area~ not~ found}
  	\msg_warning:nne { dfg } { research-area-not-found }{#1}
  }
}
%    \end{macrocode}
% We turn to the early career phases
%    \begin{macrocode}
\str_new:N \l_@@_row_color_str
\NewDocumentCommand{\EarlyCareerResearchersTable}{ O{EarlyCareerResearcher} }{%
  \def\dfgLocalDB{#1}
  \DTLifdbexists{\dfgLocalDB}{%
  	\DTLsort*{ref-project-id,lastname}{\dfgLocalDB}%
  	\def\tblrbody{}%
  	\DTLforeach*{\dfgLocalDB}{%
  		\pRefProjectID=ref-project-id,%
  		\pLastname=lastname,%
  		\pFirstname=firstname,%
  		\pFinancedBy=financed-by,%
  		\pTopic=topic,%
  		\pCategory=category,%
  		\pPeriodStart=periodStart,%
  		\pPeriodEnd=periodEnd%
  	}{
  		\str_case:en {\pCategory}{
  			{MD}{\str_set:Nn \l_@@_row_color_str {green!10} }
  			{PhD}{\str_set:Nn \l_@@_row_color_str {blue!10} }
  		}
  		\DTLgetvalueforkey{\theProjectNumber}{number}{project}{id}{\pRefProjectID}
  		\protected@edef\tblrbody{\tblrbody
  			\SetRow{\l_@@_row_color_str}
  	       	\datatool_if_null:NTF {\theProjectNumber}{\pRefProjectID}{\getProject{\pRefProjectID}}
      & \noexpand\dfgShowTag{\pRefProjectID/\pLastname}{lastname}
          {\pLastname}[\dfgLocalDB],~
        \noexpand\dfgShowTag{\pRefProjectID/\pLastname}{firstname}
          {\pFirstname}[\dfgLocalDB]
      & \noexpand\dfgShowTag{\pRefProjectID/\pLastname}{financed-by}
          {\pFinancedBy}[\dfgLocalDB]
      & \noexpand\dfgShowTag{\pRefProjectID/\pLastname}{topic}
          {\pTopic}[\dfgLocalDB]
  			&
  			{
  				\ifdefempty{\pPeriodEnd}{since~}{}
          \noexpand\dfgShowTag{\pRefProjectID/\pLastname}{periodStart}
            {\pPeriodStart}[\dfgLocalDB]
          \ifdefempty{\pPeriodEnd}{}{--\\
            \noexpand\dfgShowTag{\pRefProjectID/\pLastname}{periodEnd}
              {\pPeriodEnd}[\dfgLocalDB]}}
  			\\
  		}}%
  	\begin{tblr}[%
  			theme=main,
  			expand=\tblrbody,
  			remark{Note}={Row~colours~indicate~category~of~doctoral~candidates:~
  				             \textcolor{blue}{Dr.\,rer.\,nat.},~
  				             \textcolor{green}{Dr.\,med.}.~
  				             \textbf{RS}~=~Rising~Star.~
  				             Doctoral~candidates~with~highlighted~names~have~obtained~the~doctoral~degree.~
  				             MD~denotes~medical~students~supported~by~DFG~stipends~for~up~to~6~months.
  			             },
  			long
  		]{
  			colspec = {t{.8cm}t{3cm}t{1.2cm}X[t]t{1.8cm}},
  			rowhead = 1,
  			column{1} = {
  				            font={\bfseries},
  				            fg = {tableFirstColumn}
  			            },
  			% row{even}={bg=tableRows},
  			column{4} = {font={\footnotesize\itshape}},
  			row{1}       = {
  				               bg       = tableHeadingsBG,
  				               fg       = tableHeadingsFont,
  				               font     = \footnotesize\bfseries,
  				               halign   = {c},
  				               valign   = {t},
  				               guard
  			               },
  		}
  		Project %
  		 & Surname,~ first~ name             %
  		 & {Type~ of~            \\ funding} %
  		 & Topic                             %
  		 & Duration                          \\
  		\tblrbody
  	\end{tblr}}
  {
  	Database~ \texttt{#1}~ missing.
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
}
%    \end{macrocode}
% Following now the section about diversity and equity.
% Before that there is a command to get proper position names based on a
% property list.
%    \begin{macrocode}

\prop_new:N \g_@@_dfg_position_names_prop
\prop_gset_from_keyval:Nn \g_@@_dfg_position_names_prop
{
  PhD         = {Doctoral~researchers},
  postDoc     = {Postdoctoral~researchers},
  groupLeader = {Research~ group~ leaders,~
  		junior~ research~ group~ leaders,~
  		junior~ professors},
  research    = {Other~ research~ staff},
  nonResearch = {Non-research~ staff},
  student     = {Student~ and~ graduate~ assistants},
  prof        = {Professors},
  prof-W2     = {Professors~ W2/C3},
  prof-W3     = {Professors~ W3/C4}
}
\prop_new:N \g_@@_dfg_category_names_prop
\prop_gset_from_keyval:Nn \g_@@_dfg_category_names_prop
{
  PhD         = {Doctoral~researcher},
  postDoc     = {Postdoctoral~researcher},
  medDoc      = {Medical~doctoral~researcher},
  groupLeader = {(Jr.)~ Research~ group~ leader},
  research    = {Other~ research~ staff},
  nonResearch = {Non-research~ staff},
  student     = {Student/graduate~ assistant},
  assistant   = {Research~assistant},
  prof        = {Professor},
  prof-W2     = {Professor~ (W2/C3)},
  prof-W3     = {Professor~ (W3/C4)},
}
\cs_generate_variant:Nn \prop_if_in:NnTF { NeTF }

\NewDocumentCommand{\dfgPositionName}{m}{%
  \prop_if_in:NeTF \g_@@_dfg_position_names_prop {#1}
  {
  	\prop_get:NeN \g_@@_dfg_position_names_prop {#1} \l_tmpa_tl
  	\l_tmpa_tl
  }
  {
  	\textcolor{error}{mismatch:~#1}
  	\msg_warning:nne { dfg } { item-not-matched }{ #1 }
  }
}
\NewDocumentCommand{\dfgCategoryName}{m}{
  \prop_if_in:NeTF \g_@@_dfg_category_names_prop {#1}
  {
  	\prop_get:NeN \g_@@_dfg_category_names_prop {#1} \l_tmpa_tl
  	\l_tmpa_tl
  }
  {
  	\textcolor{error}{mismatch:~#1}
  	\msg_warning:nne { dfg } { item-not-matched }{ #1 }
  }
}
%    \end{macrocode}
%    \begin{macrocode}
\NewDocumentCommand{\GenderEqualityStaffTable}{ O{GenderEqualityStaff} }{%
  \def\dfgLocalDB{#1}
  \DTLifdbexists{\dfgLocalDB}{%
  	\tl_clear:N \l_tblr_body_tl
  	\DTLforeach*[
  		\DTLiseq{PhD}{\pPosition}
  		\OR
  		\DTLiseq{postDoc}{\pPosition}
  	]{\dfgLocalDB}{%
  		\pPosition=position,%
  		\pPrevObjPctFemale=previous-objective-percentage-female,%
  		\pStatusQuoNumFemale=status-quo-number-female,%
  		\pStatusQuoPctFemale=status-quo-percentage-female,%
  		\pFutureObjPctFemale=future-objective-percentage-female%
  	}{
  		\tl_gput_right:Nx \l_tblr_body_tl
  		{
      \dfgShowTag{\pPosition}{position}
        {\dfgPositionName{\pPosition}}[\dfgLocalDB] &
      \dfgShowTag{\pPosition}{previous-objective-percentage-female}
        {\pPrevObjPctFemale}[\dfgLocalDB] &
      \dfgShowTag{\pPosition}{status-quo-number-female}
        {\pStatusQuoNumFemale}[\dfgLocalDB] &
      \dfgShowTag{\pPosition}{status-quo-percentage-female}
        {\pStatusQuoPctFemale}[\dfgLocalDB] &
      \dfgShowTag{\pPosition}{future-objective-percentage-female}
        {\pFutureObjPctFemale}[\dfgLocalDB] \\
  		}
  	}
  	\begin{tblr}[%
  			theme=main,
			note{a}={Reference~ date:~ proposal~ for~ \dfgFundingPeriodText\space~ funding~ period},
  			expand=\l_tblr_body_tl,
  			long
  		]{
  			vspan=even,
  			%row{Z}= {font={\footnotesize\bfseries}},
  			colspec = {
  					X[m] % position
  					m{2cm} % proportion
  					m{2cm} % number
  					m{2cm} % female
  					m{3cm}
  				},
  			hspan=minimal, % !!!!! https://tex.stackexchange.com/a/637391/98739
  			vline{3} = {3-3}{1pt,solid,fg={tableLines}},
  			vline{5} = {1-3}{1pt,solid,fg={tableLines}},
  			hline{4} = {1pt,solid,fg={tableLines}},
  			% hline{Y} = {1pt,solid,fg={tableOuterLines}},
  			hline{2} = {wd=0pt},
  			rowhead = 3,
  			column{2-5}={halign={c}},
  			%  column{1} = {font={\bfseries},
  			%    fg = {rwthBlue}},
  			row{2-3} ={
  				          guard,
  				          valign={t},
  				          font={\footnotesize\bfseries},
  				          fg={tableHeadingsFont},
  				          bg={white}},
  		}
  		\SetCell[r=3]{c} % empty
  		 & \SetCell[c=3]{c} Second~ funding~ period  %
  		 &                                           %
  		 &                                           %
  		 & Third~ funding~ period                    \\
  		% empty
  		 & {Objective~ [\unit{\percent}]}
  		 & \SetCell[c=2]{c}{Status~ Quo\TblrNote{a}}
  		 &
  		 & {Objective~ [\unit{\percent}]}            \\
  		% empty
  		 &                                           % empty
  		 & Number
  		 & [\unit{\percent}]
  		 & f                                         \\
  		\tl_use:N \l_tblr_body_tl
  		% Total
  		%  &                                           % objective
  		%  &                                           % number
  		%  &                                           % percentage
  		%  &                                           % objective \\
  	\end{tblr}}
  {
  	Database~ \texttt{#1}~ missing.
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
}
%    \end{macrocode}
%    \begin{macrocode}
\int_new:N \l_@@_count_int
\int_new:N \l_@@_total_int
\int_new:N \l_@@_tmp_int
\int_new:N \l_@@_tmp_total_int
\int_new:N \l_@@_tmp_position_int
\int_new:N \l_@@_tmp_gender_int
\int_new:N \l_@@_percent_int
%    \end{macrocode}
% Cached counting infrastructure:
% A single pass over the |person| database fills a property list with one
% count per (position, gender, phase) triple.  All user-facing commands then
% read from this prop list in O(1) instead of doing a fresh full-table scan
% per call.  This replaces ~100 full database walks per gender table with 1.
%    \begin{macrocode}
\prop_new:N \g_@@_counts_prop
\tl_new:N   \l_@@_count_key_tl
\tl_new:N   \l_@@_count_phase_tl
\tl_new:N   \l_@@_count_db_tl
%    \end{macrocode}
% Compute counts for ALL (position, gender) combinations in one pass.
% Stores them in |\g_@@_counts_prop| with key "<position>/<gender>".
% |\dfg_compute_counts:nn {<db>} {<phase>}|.
%    \begin{macrocode}
\cs_new_protected:Npn \dfg_compute_counts:nn #1#2
{
  % Skip if already computed for this (db, phase).
  \tl_set:Nx \l_tmpa_tl { #1 | #2 }
  \tl_if_eq:NNF \l_tmpa_tl \l_@@_count_phase_tl
  {
  	\tl_set:Nx \l_@@_count_phase_tl { #1 | #2 }
  	\prop_gclear:N \g_@@_counts_prop
  	\DTLforeach*[
  		\DTLisinlist{#2}{\pPeriod}
  		\and
  		\DTLisinlist{PI}{\pRole}
  	]{#1}{
  		\pPosition = position,
  		\pGender   = gender,
  		\pPeriod   = period,
  		\pRole     = role
  	}{
  		\tl_set:Nx \l_@@_count_key_tl { \pPosition | \pGender }
  		\prop_get:NVNTF \g_@@_counts_prop \l_@@_count_key_tl \l_tmpb_tl
  		{
  			\int_set:Nn \l_@@_count_int { \l_tmpb_tl + 1 }
  			\prop_gput:NVx \g_@@_counts_prop \l_@@_count_key_tl
  			{ \int_use:N \l_@@_count_int }
  		}
  		{
  			\prop_gput:NVn \g_@@_counts_prop \l_@@_count_key_tl { 1 }
  		}
  	}
  }
}
% O(1) lookup. Returns 0 for unknown keys.
% \dfg_count_lookup:nn {<position>} {<gender>}  -> integer literal
\cs_new:Npn \dfg_count_lookup:nn #1#2
{
  \prop_if_in:NnTF \g_@@_counts_prop { #1 | #2 }
  { \prop_item:Nn \g_@@_counts_prop { #1 | #2 } }
  { 0 }
}

% Set <int> to count for (position, gender) — uses cache.
% \dfg_count_position_set:Nnnnn <int> {<db>} {<position>} {<gender>} {<phase>}
\cs_new_protected:Npn \dfg_count_position_set:Nnnnn #1#2#3#4#5
{
  \prop_if_in:NnTF \g_@@_dfg_position_names_prop {#3}
  {
  	\dfg_compute_counts:nn {#2} {#5}
  	\int_set:Nn #1 { \dfg_count_lookup:nn {#3} {#4} }
  }
  {
  	\textcolor{error}{mismatch:~#3}
  	\msg_warning:nne { dfg } { item-not-matched }{ #3 }
  }
}

% Sum across all genders for one position.
% \dfg_total_position_set:Nnnn <int> {<db>} {<position>} {<phase>}
\cs_new_protected:Npn \dfg_total_position_set:Nnnn #1#2#3#4
{
  \dfg_compute_counts:nn {#2} {#4}
  \int_set:Nn #1
  {
  	\dfg_count_lookup:nn {#3} {f}
  	+ \dfg_count_lookup:nn {#3} {m}
  	+ \dfg_count_lookup:nn {#3} {d}
  }
}

% Sum across all positions for one gender.
% \dfg_total_gender_set:Nnnn <int> {<db>} {<gender>} {<phase>}
\cs_new_protected:Npn \dfg_total_gender_set:Nnnn #1#2#3#4
{
  \dfg_compute_counts:nn {#2} {#4}
  \int_set:Nn #1
  {
  	\dfg_count_lookup:nn {postDoc}     {#3}
  	+ \dfg_count_lookup:nn {groupLeader} {#3}
  	+ \dfg_count_lookup:nn {prof-W2}    {#3}
  	+ \dfg_count_lookup:nn {prof-W3}    {#3}
  }
}

% Grand total across all positions and genders.
% \dfg_total_position_gender_set:Nnn <int> {<db>} {<phase>}
\cs_new_protected:Npn \dfg_total_position_gender_set:Nnn #1#2#3
{
  \dfg_compute_counts:nn {#2} {#3}
  \int_zero:N #1
  \clist_map_inline:nn {postDoc, groupLeader, prof-W2, prof-W3}
  {
  	\clist_map_inline:nn { f , m , d }
  	{
  		\int_add:Nn #1 { \dfg_count_lookup:nn {##1} {####1} }
  	}
  }
}
%    \end{macrocode}
% You can get the count of PIs of a certain position, gender and funding phase. 
%    \begin{macrocode}
\NewDocumentCommand{\getPositionGenderPhaseAmount}{ O{person} m m m }
{
  % #1: database
  % #2: position
  % #3: gender
  % #4: phase
  \dfg_count_position_set:Nnnnn \l_@@_tmp_int {#1} {#2} {#3} {#4}
  \dfgShowCalculatedTag{getPositionGenderPhaseAmount}{#1}
    { \int_use:N \l_@@_tmp_int }
}
%    \end{macrocode}
% This command sums up a certain gender column based on a funding phase. 
%    \begin{macrocode}
\NewDocumentCommand{\getPositionPhaseTotal}{ O{person} m m }
{
  % #1: database
  % #2: position
  % #3: phase

  \dfg_total_position_set:Nnnn \l_@@_total_int {#1} {#2} {#3}

  % no macro supplied → print the total
  \dfgShowCalculatedTag{getPositionPhaseTotal}{#1}
    { \int_use:N \l_@@_total_int }
}
%    \end{macrocode}
% This command sums up a certain gender column based on a funding phase. 
%    \begin{macrocode}
\NewDocumentCommand{\getGenderPhaseTotal}{ O{person} m m  }
{
  % #1: database
  % #2: gender
  % #3: phase
  \dfg_total_gender_set:Nnnn \l_@@_total_int {#1} {#2} {#3}

  % % no macro supplied → print the total
  \dfgShowCalculatedTag{getGenderPhaseTotal}{#1}
    { \int_use:N \l_@@_total_int }
}
%    \end{macrocode}
% This will get you the percentage of a certain position, gender and phase.
% Mainly for the table below, but can be used anywhere.
%    \begin{macrocode}
\NewDocumentCommand{\getPositionGenderPhasePercentage}{ O{person} m m m}
{
  % #1: database
  % #2: position
  % #3: gender
  % #4: phase

  \dfg_total_position_set:Nnnn \l_@@_total_int {#1} {#2} {#4}

  % --- number of the requested gender ---------------------------
  \dfg_count_position_set:Nnnnn \l_@@_tmp_int {#1}{#2}{#3}{#4}

  % --- avoid division by zero ----------------------------------
  \dfgShowCalculatedTag{getPositionGenderPhasePercentage}{#1}
  {
    \int_compare:nNnTF { \l_@@_total_int } = { 0 }
    { 0 }
    {
      % --- integer percentage (rounded) ------------------------
      \int_set:Nn \l_@@_percent_int
      { \fp_eval:n { round( 100 * \l_@@_tmp_int / \l_@@_total_int ) } }

      % print the integer together with the percent sign
      \int_use:N \l_@@_percent_int
    }
  }
}
%    \end{macrocode}
% The following command is meant to get the overall percentage of a certain
% gender.
% It goes into the final total row of the table, but it also can be used
% elsewhere with any funding phase you want.
%    \begin{macrocode}
\NewDocumentCommand{\getGenderPhasePercentage}{ O{person} m m  }
{
  % #1: database
  % #2: gender
  % #3: phase

  \int_zero:N \l_@@_percent_int
  \int_zero:N \l_@@_tmp_int
  \int_zero:N \l_@@_tmp_total_int

  \dfg_total_position_gender_set:Nnn \l_@@_tmp_total_int {#1} {#3}


  % % --- number of the requested gender ---------------------------
  \dfg_total_gender_set:Nnnn \l_@@_tmp_gender_int {#1}{#2}{#3}

  % --- avoid division by zero ----------------------------------
  \dfgShowCalculatedTag{getGenderPhasePercentage}{#1}
  {
    \int_compare:nNnTF { \l_@@_tmp_total_int } = { 0 }
    { 0 }
    {
      % --- integer percentage (rounded) ------------------------
      \int_set:Nn \l_@@_percent_int
      { \fp_eval:n { round( 100 * \l_@@_tmp_gender_int / \l_@@_tmp_total_int ) } }

      % print the integer together with the percent sign
      \int_use:N \l_@@_percent_int
    }
  }
  % \par Gender: #2--
  % Phase: #3--
  % Count: \int_use:N \l_@@_tmp_gender_int --
  % Count Total:\int_use:N \l_@@_tmp_total_int\par------------
}
%    \end{macrocode}
% Finally the table which is mostly calculated automatically based on the person-database.
%    \begin{macrocode}
\NewDocumentCommand{\GenderEqualityProjectLeadersTable}{ O{GenderEqualityProjectLeaders} }{%
  \def\dfgLocalDB{#1}
  \DTLifdbexists{\dfgLocalDB}{%
  	% --- prime the count cache once for this table's phase ----------
  	\dfg_compute_counts:nn {person} {\theFundingPeriodNumeralPrevious}%
  	\tl_clear:N \l_tblr_body_tl
  	\DTLforeach*[
  		% just making absolutely sure we only have the data sets we need.
  		\DTLiseq{postDoc}{\pPosition}
  		\OR
  		\DTLiseq{groupLeader}{\pPosition}
  		\OR
  		\DTLiseq{prof-W2}{\pPosition}
  		\OR
  		\DTLiseq{prof-W3}{\pPosition}
  	]{\dfgLocalDB}{%
  		\pPosition=position,%
  		\pPrevObjPctFemale=previous-objective-percentage-female,%
  		\pFutureObjPctFemale=future-objective-percentage-female%
  	}{

  		\tl_gput_right:Nx \l_tblr_body_tl
  		{
      \dfgShowTag{\pPosition}{position}
        {\dfgPositionName{\pPosition}}[\dfgLocalDB] % position
      & \dfgShowTag{\pPosition}{previous-objective-percentage-female}
          {\pPrevObjPctFemale}[\dfgLocalDB] % objective
  			& \getPositionGenderPhaseAmount{\pPosition}{f}{\theFundingPeriodNumeralPrevious} % f number
  			& \getPositionGenderPhaseAmount{\pPosition}{m}{\theFundingPeriodNumeralPrevious} % m number
  			& \getPositionGenderPhaseAmount{\pPosition}{d}{\theFundingPeriodNumeralPrevious}% d number
  			&  \getPositionGenderPhasePercentage{\pPosition}{f}{\theFundingPeriodNumeralPrevious}% f percentage
  			&  \getPositionGenderPhasePercentage{\pPosition}{m}{\theFundingPeriodNumeralPrevious}% m percentage
  			&  \getPositionGenderPhasePercentage{\pPosition}{d}{\theFundingPeriodNumeralPrevious}% d percentage
      & \dfgShowTag{\pPosition}{future-objective-percentage-female}
          {\pFutureObjPctFemale}[\dfgLocalDB] % f objective
  			\\
  		}
  	}
  	\begin{tblr}[%
  			theme=main,
  			note{a}={Reference~ date:~ proposal~ for~ third~ funding~ period},
  			expand=\l_tblr_body_tl,
  			long
  		]{
  			vline{3} = {3-4}{1pt,solid,tableLines},
  			vline{6} = {4-4}{1pt,solid,tableLines},
  			vline{9} = {1-4}{1pt,solid,tableLines},
  			vspan=even,
  			colspec = {
  					X[m] % position
  					m{2cm} % objective
  					m{0.4cm} % f
  					m{0.4cm} % m
  					m{0.4cm} % d
  					m{0.4cm} % f
  					m{0.4cm} % m
  					m{0.4cm} % d
  					m{3cm} % objective
  				},
  			hspan=minimal, % !!!!! https://tex.stackexchange.com/a/637391/98739
  			row{Z}= {font={\footnotesize\bfseries}},
  			hline{5} = {1pt,solid,tableLines},
  			hline{Y} = {1pt,solid,fg={tableOuterLines}},
  			hline{2} = {wd=0pt},
  			row{odd}={bg=white},
  			row{even}={bg=tableRows},
  			row{1-4}={bg=tableHeadingsBG},
  			rowhead = 3,
  			column{2-9}={halign={c}},
  			%  column{1} = {font={\bfseries},
  			%    fg = {rwthBlue}},
  			row{2-4} ={
  				          guard,
  				          valign={t},
  				          font={\footnotesize\bfseries},
  				          fg={tableHeadingsFont},
  				          bg={white}},
  		}
  		\SetCell[r=4]{c} % empty
  		 & \SetCell[c=6]{c} Second~ funding~ period                       %
  		 &                                                                %
  		 &                                                                %
  		 &                                                                %
  		 &                                                                %
  		 &                                                                %
  		 &                                                                %
  		 & Third~ funding~ period                                         \\
  		% empty
  		 & {Objective~ [\unit{\percent}]}
  		 & \SetCell[c=6]{c}Status~ Quo\TblrNote{a}
  		 &
  		 &
  		 &
  		 &
  		 &
  		 & {Objective~ [\unit{\percent}]}                                 \\
  		% empty
  		 &                                                                % empty
  		 & \SetCell[c=3]{c}Number
  		 &
  		 &
  		 & \SetCell[c=3]{c} [\unit{\percent}]
  		 &
  		 &
  		 &                                                                \\
  		% empty
  		 &                                                                % empty
  		 & f
  		 & m
  		 & d
  		 & f
  		 & m
  		 & d
  		 & f                                                              \\
  		% \tl_use:N
  		\l_tblr_body_tl
  		Total\printMarginalia{
  			     Total~ no.:~
  			     \dfg_total_position_gender_set:Nnn \l_@@_tmp_total_int
  			     {person} % database
  			     {\theFundingPeriodNumeralPrevious} % phase
             \num{\int_use:N \l_@@_tmp_total_int}

  		     }
  		 &                                                                % objective
  		 & \getGenderPhaseTotal{f}{\theFundingPeriodNumeralPrevious}      % number f
  		 & \getGenderPhaseTotal{m}{\theFundingPeriodNumeralPrevious}      % number m
  		 & \getGenderPhaseTotal{d}{\theFundingPeriodNumeralPrevious}      % number d
  		 & \getGenderPhasePercentage{f}{\theFundingPeriodNumeralPrevious} % percentage f
  		 & \getGenderPhasePercentage{m}{\theFundingPeriodNumeralPrevious} % percentage m
  		 & \getGenderPhasePercentage{d}{\theFundingPeriodNumeralPrevious} % percentage d
  		 &                                                                \\
  	\end{tblr}}
  {
  	Database~ \texttt{#1}~ missing.
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
}
%    \end{macrocode}
% We continue with the list of existing instrumentation
%    \begin{macrocode}
\NewDocumentCommand{\ExistingInstrumentationTable}{ O{existingInstrumentation} }{%
  \def\dfgLocalDB{#1}
  \def\tblrbody{}
  \DTLifdbexists{\dfgLocalDB}{%
  	\DTLforeach*{\dfgLocalDB}{%
  		\instProject=ref-project-id,%
  		\instInstrument=instrument,%
  		\instCompany=company,%
  		\instQuantity=quantity,%
  		\instYear=year,%
  		\instCost=cost,%
  		\instSource=financed-by%
  	}{%
		\protected@edef\tblrbody{\tblrbody
  			\getProject{\instProject}
      & \ifdefempty{\instQuantity}{}{
          \noexpand\dfgShowTag{\instProject/\instInstrument}{quantity}
            {\instQuantity}[\dfgLocalDB]\,\times\,}
        \noexpand\dfgShowTag{\instProject/\instInstrument}{instrument}
          {\instInstrument}[\dfgLocalDB]
      \ifdefempty{\instCompany}{}{\space(
        \noexpand\dfgShowTag{\instProject/\instInstrument}{company}
          {\instCompany}[\dfgLocalDB])}
      & \noexpand\dfgShowTag{\instProject/\instInstrument}{year}
          {\instYear}[\dfgLocalDB]
      & \noexpand\dfgShowTag{\instProject/\instInstrument}{cost}
          {\noexpand\@@_show_existing_instrumentation_cost:n{\instCost}}[\dfgLocalDB]
      & \noexpand\dfgShowTag{\instProject/\instInstrument}{financed-by}
          {\instSource}[\dfgLocalDB]
  			\\
  		}}%
  	\begin{tblr}[%
  			theme=main,
  			expand=\tblrbody,
  			long,
			note{a}={Figures~ in~ thousands},
  		]{%
  			%rowsep=1pt,
  			vspan=even,
			colspec = {X[-.8,m]X[4.5,m]X[m]X[-1,c,si={table-format=4.1}]X[1.7,m]},
  			rowhead = 1,
  			column{3}={halign={c}},
			column{4}={halign={r},guard},
  			column{5}={halign={l}},
  			% cell{1}{4}={valign={m}},
  			cell{1}{1-5} = {cmd={\hypersetup{linkcolor=tableLink}}},
  			row{1}={valign=t, halign={c},guard},
  			% row{1} = {font={\bfseries},fg={white}}
  		}
  		Project %
  		 & Description~ of~ instrumentation                           %
  		 & {Year~ of~                       \\ purchase}
  		 & \SetCell{c}{{{Cost~ of~          \\purchase}}}\TblrNote{a}
  		 & {Source~ of~                     \\ funding}               \\
  		\tblrbody
  	\end{tblr}
  }
  {
  	Database~ \texttt{#1}~ missing.
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  	a	}
}
%    \end{macrocode}
% We turn to the laboratory animals
%    \begin{macrocode}
\NewDocumentCommand{\UpkeepLaboratoryAnimalsTable}{ O{UpkeepLaboratoryAnimals} }{%
  \def\tmpLocalDB{#1}%
  \DTLifdbexists{\tmpLocalDB}{%
  	\DTLsort{ref-project-id}{\tmpLocalDB}%
  	\DTLsumcolumn{\tmpLocalDB}{quantity}{\totalQuantity}%
  	\DTLsumcolumn{\tmpLocalDB}{requested-funds}{\totalRequestedFunds}%
  	\DTLsumcolumn{\tmpLocalDB}{existing-funds}{\totalExistingFunds}%
  	\DTLconverttodecimal{\totalRequestedFunds}{\totalRequestedFunds}%
  	\DTLconverttodecimal{\totalExistingFunds}{\totalExistingFunds}%
  	\def\tblrbody{}%
  	\def\totalMouseQuantity{}%
  	\def\totalRatQuantity{}%
  	\DTLforeach*{\tmpLocalDB}{%
  		\pProject=ref-project-id,%
  		\pSpecies=species,%
  		\pQuantity=quantity,
  		\pWeeksKept=weeks-kept,%
  		\pPurchasingCosts=purchasing-costs,%
  		\pRequestedFunds=requested-funds,%
  		\pExistingFunds=existing-funds%
  	}{
  		\str_case:en {\pSpecies}{

  			{mouse}{%
  				\protected@edef\crcSpecies{Mouse}%
  				\protected@edef\crcHousingCosts{\dfgMouseHousing}%
  				\DTLgadd{\totalMouseQuantity}{\totalMouseQuantity}{\pQuantity}}%
  			{mouse-gnotobiotic}{%
  				\protected@edef\crcSpecies{Mouse~ {\footnotesize(gnotobiotic)}}%
  				\protected@edef\crcHousingCosts{\dfgMouseHousingGnotobiotic}%
  				\DTLgadd{\totalMouseQuantity}{\totalMouseQuantity}{\pQuantity}}%
  			{rat}{%
  				\protected@edef\crcSpecies{Rat}%
  				\protected@edef\crcHousingCosts{\dfgRatHousing}%
  				\DTLgadd{\totalRatQuantity}{\totalRatQuantity}{\pQuantity}}
  		}
  		\protected@edef\tblrbody{\tblrbody
  			\getProject{\pProject}
      & \noexpand\dfgShowTag{\pProject/\pSpecies}{species}
          {\crcSpecies}[\tmpLocalDB]
      & \noexpand\dfgShowTag{\pProject/\pSpecies}{quantity}
          {\noexpand\@@_show_table_number:n{\pQuantity}}[\tmpLocalDB]
      & \noexpand\dfgShowTag{\pProject/\pSpecies}{weeks-kept}
          {\noexpand\@@_show_table_number:n{\pWeeksKept}}[\tmpLocalDB]
      & \noexpand\dfgShowCalculatedTag{animalHousingRate}
          {settings,\tmpLocalDB}
          {\noexpand\@@_show_table_number:n{\crcHousingCosts}}
      & \noexpand\dfgShowTag{\pProject/\pSpecies}{purchasing-costs}
          {\noexpand\@@_show_eur:n{\pPurchasingCosts}}[\tmpLocalDB]
      & \noexpand\dfgShowTag{\pProject/\pSpecies}{requested-funds}
          {\noexpand\@@_show_eur:n{\pRequestedFunds}}[\tmpLocalDB]
      & \noexpand\dfgShowTag{\pProject/\pSpecies}{existing-funds}
          {\noexpand\@@_show_eur:n{\pExistingFunds}}[\tmpLocalDB] \\
  		}   % \DTLconverttodecimal{\totalMouseQuantity}{\totalMouseQuantity}%
  	}%
  	\begin{tblr}[%
  			theme=main,
  			expand=\tblrbody,
  			long,
			note{a}={Figures~ in~ EUR},
  		]{%
  			vspan=even,
      colspec ={*{1}{Q[l]}
        *{1}{X[2,l]}
        *{2}{X[1.3,c,si={table-format=3}]}
        *{1}{X[-1,c,si={table-format=2.2,table-auto-round=false}]}
        *{1}{X[-1,c,si={table-format=5}]}
        *{2}{X[-1,c,si={table-format=6}]}
      },
  			rowhead={1},
			column{3-8}={guard},
  			%rowfoot = 1,
  			hline{Y}={%
  				         wd=1pt,
  				         tableLines},
  			row{Z}={%
  				       bg=white,
  				       fg=black,
  				       font=\footnotesize\bfseries,
  				       halign={c},
  				       valign={t}},
  			% cell{Y}{3}={halign={l}},
  			row{1}={%
  				       guard,
  				       halign={c},
  				       cmd={\hypersetup{linkcolor=tableLink}},
  			       },
  		}
  		Project
  		 & Species
  		 & Quantity
  		 & {Average~                                                                     \\number~ of~\\weeks~ kept}
  		 & {Housing~ costs~                                                              \\per~ animal~\\per~ week\TblrNote{a}}
  		 & {Purchasing~                                                                  \\costs~ \\per~ animal\TblrNote{a}}
  		 & {Requested~                                                                   \\funds\TblrNote{a}}
  		 & {Existing~                                                                    \\funds\TblrNote{a}}                   \\
  		\tblrbody
  		Total
  		 &
       & \SetCell{halign={l},font={\bfseries\footnotesize}}
        {Mice:~\dfgShowCalculatedTag{UpkeepLaboratoryAnimalsTable}{\tmpLocalDB}
            {\totalMouseQuantity}
         \\Rats:~\dfgShowCalculatedTag{UpkeepLaboratoryAnimalsTable}{\tmpLocalDB}
            {\totalRatQuantity}}
  		 & \SetCell{tableNoValue}
  		 & \SetCell{tableNoValue}
  		 & \SetCell{tableNoValue}
       & \dfgShowCalculatedTag{UpkeepLaboratoryAnimalsTable}{\tmpLocalDB}
          {\@@_show_eur:n{\totalRequestedFunds}}
       & \dfgShowCalculatedTag{UpkeepLaboratoryAnimalsTable}{\tmpLocalDB}
          {\@@_show_eur:n{\totalExistingFunds}}
  	\end{tblr}}
  {
  	Database~ \texttt{#1}~ missing.
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
}
%    \end{macrocode}
%
%    \begin{macrocode}
\newcommand{\dfgRotate}[1]{\rotatebox{90}{\dfgPositionName{#1}}}
%    \end{macrocode}
%
% \paragraph{\refCom{getCountRequestedStaff} with aggregate indexing}
% Funding declarations update a property-list index when they are read.
% Consequently this command only performs one property lookup; it never
% traverses a datatool database.  This matters especially for
% \pkg{tabularray}, which evaluates table cells more than once while measuring
% and typesetting them.  Missing tuples and explicit zero values both print
% the faded multiplication sign used elsewhere in funding tables, preserving
% the display of the former database sum.
%
% \begin{docCommand}{getCountRequestedStaff}{\oarg{project}\marg{year}\marg{category}}
%   Sum of the requested staff |quantity-year|\meta{year} values in
%   the currently selected requested-funding database, normally
%   |RequestedFunding|, filtered by \meta{category} and (when
%   \meta{project} is given) by \meta{project}.  Display follows the
%   usual table conventions: an absent or zero sum prints a faded
%   \cs{texttimes}, and any other value prints verbatim.
% \end{docCommand}
%    \begin{macrocode}
\tl_new:N \l_@@_requested_staff_database_tl
\tl_set:Nn \l_@@_requested_staff_database_tl { RequestedFunding }

\NewDocumentCommand{\getCountRequestedStaff}{omm}{%
  \tl_set:Nx \l_@@_funding_cache_key_tl
  {
    \IfNoValueTF{#1}
      {\tl_use:N \l_@@_requested_staff_database_tl/
       __ALL__/#3/quantity-year#2}
      {\tl_use:N \l_@@_requested_staff_database_tl/
       #1/#3/quantity-year#2}
  }
  \dfgShowCalculatedTag{getCountRequestedStaff}
    {\l_@@_requested_staff_database_tl}
  {
    \prop_get:NVNTF \g_@@_funding_staff_quantity_prop
      \l_@@_funding_cache_key_tl \l_@@_funding_cache_value_tl
    {
      \fp_compare:nNnTF {\l_@@_funding_cache_value_tl} = {0}
        {\textcolor{tableNoValue!60!black}{\texttimes}}
        {\l_@@_funding_cache_value_tl}
    }
    {\textcolor{tableNoValue!60!black}{\texttimes}}
  }
}
%    \end{macrocode}
%
% \paragraph{\refCom{OverviewExistingStaffTable}}
% The chapter-2 overview reuses the project-level staff roster instead of
% maintaining a second set of totals.  Only records with
% |funding-status=existing| are counted.  Each record contributes one person
% to every distinct parent affiliation reached through its
% |ref-institution-id| list; when that field is absent, both organisation and
% category are inherited through |ref-person-id| from the central |person|
% row.  Multiple institutions at the same affiliation are counted once.  The
% comma-separated applicant affiliations come from |meta|
% and occupy the first numeric columns.  The heading is singular for one
% applicant affiliation and plural for several.  Other affiliations are added
% in first-use order.
%
% Because project declarations normally occur after chapter 2, the default
% database is |RequestedFundingStaffOverview|, restored from the preceding
% LaTeX run's auxiliary file.  Passing |RequestedFundingStaff| explicitly is
% useful in focused tests or documents that load all rows before the table.
%
% The DFG overview has seven fixed category rows.  The more detailed roster
% categories |medDoc| and |assistant| are folded into enquote{Other research
% staff} and enquote{Student and graduate assistants}, respectively.
%
% \begin{docCommand}{OverviewExistingStaffTable}{\oarg{database}}
%   Print the DFG enquote{Overview of existing staff}.  The optional database
%   defaults to |RequestedFundingStaffOverview|.  Use the public call
%   \refCom{printTable}|{OverviewExistingStaff}| in chapter 2.  Direct calls
%   also emit the standard skipped-item notice instead of querying unavailable
%   metadata when either fast-compilation mode is active.
% \end{docCommand}
%    \begin{macrocode}
\seq_new:N  \l_@@_oes_affiliation_seq
\prop_new:N \l_@@_oes_affiliation_name_prop
\prop_new:N \l_@@_oes_affiliation_abbreviation_prop
\prop_new:N \l_@@_oes_count_prop
\prop_new:N \l_@@_oes_row_affiliation_seen_prop
\tl_new:N   \l_@@_oes_applicant_affiliation_tl
\tl_new:N   \l_@@_oes_person_tl
\tl_new:N   \l_@@_oes_category_tl
\tl_new:N   \l_@@_oes_institutions_tl
\tl_new:N   \l_@@_oes_affiliation_tl
\tl_new:N   \l_@@_oes_candidate_affiliation_tl
\tl_new:N   \l_@@_oes_registered_affiliation_tl
\tl_new:N   \l_@@_oes_affiliation_name_tl
\tl_new:N   \l_@@_oes_affiliation_abbreviation_tl
\tl_new:N   \l_@@_oes_lookup_key_tl
\tl_new:N   \l_@@_oes_database_tl
\tl_new:N   \l_@@_oes_table_body_tl
\tl_new:N   \l_@@_oes_colspec_tl
\int_new:N  \l_@@_oes_affiliation_count_int
\int_new:N  \l_@@_oes_applicant_affiliation_count_int
\int_new:N  \l_@@_oes_other_affiliation_count_int
\int_new:N  \l_@@_oes_record_count_int
\clist_new:N \l_@@_oes_applicant_affiliation_clist

\cs_new_protected:Npn \@@_oes_resolve_person_fallbacks:
{
  \tl_if_blank:VF \l_@@_oes_person_tl
  {
    \DTLifdbexists{person}
    {
      \DTLgetvalueforkey{\l_tmpa_tl}{id}{person}{id}
        {\l_@@_oes_person_tl}
      \DTLifnullorempty{\l_tmpa_tl}
      {
        \msg_warning:nnee { dfg } { requested-staff-unresolved-person }
          { \pOESProject } { \l_@@_oes_person_tl }
      }
      {
        \tl_if_blank:VT \l_@@_oes_category_tl
        {
          \DTLgetvalueforkey{\l_tmpa_tl}{position}{person}{id}
            {\l_@@_oes_person_tl}
          \DTLifnullorempty{\l_tmpa_tl}
            { }
            { \tl_set:NV \l_@@_oes_category_tl \l_tmpa_tl }
        }
        \bool_lazy_all:nT
        {
          { \tl_if_blank_p:V \l_@@_oes_institutions_tl }
          { \tl_if_blank_p:V \l_@@_oes_affiliation_tl }
        }
        {
          \DTLgetvalueforkey{\l_tmpa_tl}{ref-institution-id}{person}{id}
            {\l_@@_oes_person_tl}
          \DTLifnullorempty{\l_tmpa_tl}
            { }
            { \tl_set:NV \l_@@_oes_institutions_tl \l_tmpa_tl }
          \tl_if_blank:VT \l_@@_oes_institutions_tl
          {
            \DTLgetvalueforkey{\l_tmpa_tl}{ref-affiliation-id}{person}{id}
              {\l_@@_oes_person_tl}
            \DTLifnullorempty{\l_tmpa_tl}
              { }
              { \tl_set:NV \l_@@_oes_affiliation_tl \l_tmpa_tl }
          }
        }
      }
    }
    {
      \msg_warning:nnee { dfg } { requested-staff-unresolved-person }
        { \pOESProject } { \l_@@_oes_person_tl }
    }
  }
}

\cs_new_protected:Npn \@@_oes_register_affiliation:n #1
{
  \tl_set:Ne \l_@@_oes_registered_affiliation_tl {#1}
  \tl_trim_spaces:N \l_@@_oes_registered_affiliation_tl
  \tl_if_blank:VF \l_@@_oes_registered_affiliation_tl
  {
    \seq_if_in:NVF \l_@@_oes_affiliation_seq
      \l_@@_oes_registered_affiliation_tl
    {
      \tl_clear:N \l_@@_oes_affiliation_name_tl
      \tl_clear:N \l_@@_oes_affiliation_abbreviation_tl
      \DTLifdbexists{affiliation}
      {
        \DTLgetvalueforkey{\l_@@_oes_affiliation_name_tl}
          {name}{affiliation}{id}{\l_@@_oes_registered_affiliation_tl}
        \DTLifnullorempty{\l_@@_oes_affiliation_name_tl}
        {
          \msg_warning:nnee { dfg } { requested-staff-unresolved-affiliation }
            { OverviewExistingStaff }
            { \l_@@_oes_registered_affiliation_tl }
          \tl_set:NV \l_@@_oes_affiliation_name_tl
            \l_@@_oes_registered_affiliation_tl
          \tl_set:NV \l_@@_oes_affiliation_abbreviation_tl
            \l_@@_oes_registered_affiliation_tl
        }
        {
          \DTLgetvalueforkey{\l_@@_oes_affiliation_abbreviation_tl}
            {abbreviation}{affiliation}{id}
            {\l_@@_oes_registered_affiliation_tl}
          \DTLifnullorempty{\l_@@_oes_affiliation_abbreviation_tl}
          {
            \msg_warning:nne { dfg } { requested-staff-missing-abbreviation }
              { \l_@@_oes_registered_affiliation_tl }
            \tl_set:NV \l_@@_oes_affiliation_abbreviation_tl
              \l_@@_oes_affiliation_name_tl
          }
          { }
        }
      }
      {
        \msg_warning:nnee { dfg } { requested-staff-unresolved-affiliation }
          { OverviewExistingStaff }
          { \l_@@_oes_registered_affiliation_tl }
        \tl_set:NV \l_@@_oes_affiliation_name_tl
          \l_@@_oes_registered_affiliation_tl
        \tl_set:NV \l_@@_oes_affiliation_abbreviation_tl
          \l_@@_oes_registered_affiliation_tl
      }
      \seq_put_right:NV \l_@@_oes_affiliation_seq
        \l_@@_oes_registered_affiliation_tl
      \prop_put:NVV \l_@@_oes_affiliation_name_prop
        \l_@@_oes_registered_affiliation_tl \l_@@_oes_affiliation_name_tl
      \prop_put:NVV \l_@@_oes_affiliation_abbreviation_prop
        \l_@@_oes_registered_affiliation_tl
        \l_@@_oes_affiliation_abbreviation_tl
    }
  }
}

\cs_new_protected:Npn \@@_oes_count_affiliation:n #1
{
  \tl_set:Ne \l_@@_oes_candidate_affiliation_tl {#1}
  \tl_trim_spaces:N \l_@@_oes_candidate_affiliation_tl
  \tl_if_blank:VF \l_@@_oes_candidate_affiliation_tl
  {
    \prop_if_in:NVF \l_@@_oes_row_affiliation_seen_prop
      \l_@@_oes_candidate_affiliation_tl
    {
      \prop_put:NVn \l_@@_oes_row_affiliation_seen_prop
        \l_@@_oes_candidate_affiliation_tl {1}
      \@@_oes_register_affiliation:n
        { \l_@@_oes_candidate_affiliation_tl }
      \tl_set:Nx \l_tmpb_tl
        { \l_@@_oes_category_tl / \l_@@_oes_candidate_affiliation_tl }
      \prop_get:NVNTF \l_@@_oes_count_prop \l_tmpb_tl \l_tmpc_tl
      { \int_set:Nn \l_tmpa_int { \l_tmpc_tl + 1 } }
      { \int_set:Nn \l_tmpa_int { 1 } }
      \prop_put:NVx \l_@@_oes_count_prop \l_tmpb_tl
        { \int_use:N \l_tmpa_int }
    }
  }
}

\cs_new_protected:Npn \@@_oes_collect_current:
{
  \DTLifnullorempty{\pOESPerson}
    { \tl_clear:N \l_@@_oes_person_tl }
    { \tl_set:Ne \l_@@_oes_person_tl {\pOESPerson} }
  \DTLifnullorempty{\pOESCategory}
    { \tl_clear:N \l_@@_oes_category_tl }
    { \tl_set:Ne \l_@@_oes_category_tl {\pOESCategory} }
  \DTLifnullorempty{\pOESInstitutions}
    { \tl_clear:N \l_@@_oes_institutions_tl }
    { \tl_set:Ne \l_@@_oes_institutions_tl {\pOESInstitutions} }
  \DTLifnullorempty{\pOESAffiliation}
    { \tl_clear:N \l_@@_oes_affiliation_tl }
    { \tl_set:Ne \l_@@_oes_affiliation_tl {\pOESAffiliation} }
  \@@_oes_resolve_person_fallbacks:
  \str_case:VnF \l_@@_oes_category_tl
  {
    { prof }        { \tl_set:Nn \l_@@_oes_category_tl { prof } }
    { prof-W2 }     { \tl_set:Nn \l_@@_oes_category_tl { prof } }
    { prof-W3 }     { \tl_set:Nn \l_@@_oes_category_tl { prof } }
    { groupLeader } { \tl_set:Nn \l_@@_oes_category_tl { groupLeader } }
    { postDoc }     { \tl_set:Nn \l_@@_oes_category_tl { postDoc } }
    { PhD }         { \tl_set:Nn \l_@@_oes_category_tl { PhD } }
    { medDoc }      { \tl_set:Nn \l_@@_oes_category_tl { research } }
    { research }    { \tl_set:Nn \l_@@_oes_category_tl { research } }
    { nonResearch } { \tl_set:Nn \l_@@_oes_category_tl { nonResearch } }
    { student }     { \tl_set:Nn \l_@@_oes_category_tl { student } }
    { assistant }   { \tl_set:Nn \l_@@_oes_category_tl { student } }
  }
  { \tl_clear:N \l_@@_oes_category_tl }
  \tl_if_blank:VF \l_@@_oes_category_tl
  {
    \int_incr:N \l_@@_oes_record_count_int
    \prop_clear:N \l_@@_oes_row_affiliation_seen_prop
    \tl_if_blank:VTF \l_@@_oes_institutions_tl
    {
      \tl_if_blank:VTF \l_@@_oes_affiliation_tl
      {
        \msg_warning:nne { dfg } { existing-staff-no-organisation }
          { \pOESProject / \pOESLastname }
      }
      { \@@_oes_count_affiliation:n { \l_@@_oes_affiliation_tl } }
    }
    {
      \clist_set:NV \l_tmpa_clist \l_@@_oes_institutions_tl
      \clist_map_inline:Nn \l_tmpa_clist
      {
        \tl_clear:N \l_tmpa_tl
        \DTLifdbexists{institution}
        {
          \DTLgetvalueforkey{\l_tmpa_tl}
            {ref-affiliation-id}{institution}{id}{##1}
        }
        { }
        \DTLifnullorempty{\l_tmpa_tl}
        {
          \msg_warning:nnee { dfg } { requested-staff-unresolved-institution }
            { OverviewExistingStaff } {##1}
        }
        { \@@_oes_count_affiliation:n { \l_tmpa_tl } }
      }
    }
  }
}

\cs_new_protected:Npn \@@_oes_append_empty_cells:n #1
{
  \int_step_inline:nn {#1}
    { \tl_put_right:Nn \l_@@_oes_table_body_tl { & } }
}

\cs_new_protected:Npn \@@_oes_append_category:nn #1#2
{
  \tl_put_right:Nn \l_@@_oes_table_body_tl {#2}
  \seq_map_inline:Nn \l_@@_oes_affiliation_seq
  {
    \tl_set:Ne \l_@@_oes_lookup_key_tl { #1 / ##1 }
    \prop_get:NVNTF \l_@@_oes_count_prop
      \l_@@_oes_lookup_key_tl \l_tmpc_tl
    {
      \tl_put_right:Ne \l_@@_oes_table_body_tl
      {
        & \exp_not:N \dfgShowCalculatedTag{OverviewExistingStaffTable}
          {\exp_not:V \l_@@_oes_database_tl,person,institution,affiliation}
          {\exp_not:V \l_tmpc_tl}
      }
    }
    {
      \tl_put_right:Ne \l_@@_oes_table_body_tl
      {
        & \exp_not:N \dfgShowCalculatedTag{OverviewExistingStaffTable}
          {\exp_not:V \l_@@_oes_database_tl,person,institution,affiliation}{0}
      }
    }
  }
  \tl_put_right:Nn \l_@@_oes_table_body_tl { \\ }
}

\cs_new_protected:Npn \@@_oes_build_table_body:
{
  \int_set:Nn \l_@@_oes_affiliation_count_int
    { \seq_count:N \l_@@_oes_affiliation_seq }
  \int_set:Nn \l_@@_oes_other_affiliation_count_int
    {
      \l_@@_oes_affiliation_count_int
      - \l_@@_oes_applicant_affiliation_count_int
    }
  \tl_set:Nx \l_@@_oes_colspec_tl
    {
      X[4,l]~*{\int_use:N \l_@@_oes_affiliation_count_int}{X[1,c]}
    }
  \tl_clear:N \l_@@_oes_table_body_tl
  \tl_put_right:Nx \l_@@_oes_table_body_tl
  {
    \exp_not:N \SetCell [r=3] {c,m} Category
    & \exp_not:N \SetCell
      [c=\int_use:N \l_@@_oes_affiliation_count_int] {c,m}
      {Number~of~persons}
  }
  \@@_oes_append_empty_cells:n
    { \l_@@_oes_affiliation_count_int - 1 }
  \tl_put_right:Nn \l_@@_oes_table_body_tl { \\ & }
  \int_compare:nNnTF
    { \l_@@_oes_applicant_affiliation_count_int } = {1}
  {
    \tl_put_right:Nn \l_@@_oes_table_body_tl
      { \SetCell{c,m} {at~the~applicant\\university} }
  }
  {
    \tl_put_right:Nx \l_@@_oes_table_body_tl
    {
      \exp_not:N \SetCell
        [c=\int_use:N \l_@@_oes_applicant_affiliation_count_int] {c,m}
        {at~the~applicant\\universities}
    }
    \@@_oes_append_empty_cells:n
      { \l_@@_oes_applicant_affiliation_count_int - 1 }
  }
  \int_compare:nNnT { \l_@@_oes_other_affiliation_count_int } > {0}
  {
    \tl_put_right:Nx \l_@@_oes_table_body_tl
    {
      & \exp_not:N \SetCell
        [c=\int_use:N \l_@@_oes_other_affiliation_count_int] {c,m}
        {at~other~participating\\institutions}
    }
    \@@_oes_append_empty_cells:n
      { \l_@@_oes_other_affiliation_count_int - 1 }
  }
  \tl_put_right:Nn \l_@@_oes_table_body_tl { \\ }
  \tl_put_right:Nn \l_@@_oes_table_body_tl { & }
  \seq_map_indexed_inline:Nn \l_@@_oes_affiliation_seq
  {
    \int_compare:nNnF {##1} = {1}
      { \tl_put_right:Nn \l_@@_oes_table_body_tl { & } }
    \tl_set:Nn \l_tmpa_tl {##2}
    \prop_get:NVN \l_@@_oes_affiliation_abbreviation_prop
      \l_tmpa_tl \l_tmpb_tl
    \tl_put_right:Ne \l_@@_oes_table_body_tl
    {
      \exp_not:N \dfgShowCalculatedTag{affiliationLabel}{affiliation}
        {\exp_not:V \l_tmpb_tl}
    }
  }
  \tl_put_right:Nn \l_@@_oes_table_body_tl { \\ }
  \@@_oes_append_category:nn { prof } { Professors }
  \@@_oes_append_category:nn { groupLeader }
    { Junior~research~group~leaders }
  \@@_oes_append_category:nn { postDoc } { Postdoctoral~researchers }
  \@@_oes_append_category:nn { PhD } { Doctoral~researchers }
  \@@_oes_append_category:nn { research } { Other~research~staff }
  \@@_oes_append_category:nn { nonResearch } { Non-research~staff }
  \@@_oes_append_category:nn { student }
    { Student~and~graduate~assistants }
}

\cs_new_protected:Npn \@@_oes_print_legend:
{
  \vspace*{-1.5\baselineskip}%
  %\par\noindent
  \group_begin:
  \footnotesize\textbf{Affiliations:}\space
  \seq_map_indexed_inline:Nn \l_@@_oes_affiliation_seq
  {
    \int_compare:nNnF {##1} = {1} {;\space}
    \tl_set:Nn \l_tmpa_tl {##2}
    \prop_get:NVN \l_@@_oes_affiliation_abbreviation_prop
      \l_tmpa_tl \l_tmpb_tl
    \prop_get:NVN \l_@@_oes_affiliation_name_prop
      \l_tmpa_tl \l_tmpc_tl
    \textbf{\dfgShowCalculatedTag{affiliationLabel}{affiliation}
      {\l_tmpb_tl}}:~
    \dfgShowTag{##2}{name}{\l_tmpc_tl}[affiliation]
  }
  .\par
  \group_end:
}

\cs_new_protected:Npn \@@_oes_typeset:n #1
{
  \begin{tblr}[
    theme=main,
    long,
    expand=\l_@@_oes_table_body_tl
  ]{
    colspec={#1},
    rowhead=3,
    rows={valign=m},
    column{2-Z}={halign=c},
    row{1-3}={font=\footnotesize\bfseries,
      fg=tableHeadingsFont,bg=tableHeadingsBG},
    hline{4}={wd=1pt,tableLines},
    vline{2}={wd=.75pt,tableLines}
  }
    \l_@@_oes_table_body_tl
  \end{tblr}
}

\cs_new_protected:Npn \@@_overview_existing_staff:n #1
{
  \group_begin:
  \tl_set:Nn \l_@@_oes_database_tl {#1}
  \seq_clear:N \l_@@_oes_affiliation_seq
  \prop_clear:N \l_@@_oes_affiliation_name_prop
  \prop_clear:N \l_@@_oes_affiliation_abbreviation_prop
  \prop_clear:N \l_@@_oes_count_prop
  \int_zero:N \l_@@_oes_record_count_int
  \tl_clear:N \l_@@_oes_applicant_affiliation_tl
  \DTLifdbexists{meta}
  {
    \DTLgetvalueforkey{\l_@@_oes_applicant_affiliation_tl}
      {ref-affiliation-id}{meta}{id}{crc}
  }
  { }
  \DTLifnullorempty{\l_@@_oes_applicant_affiliation_tl}
    { \tl_set:Nn \l_@@_oes_applicant_affiliation_tl { applicant } }
    { }
  \clist_set:NV \l_@@_oes_applicant_affiliation_clist
    \l_@@_oes_applicant_affiliation_tl
  \clist_map_inline:Nn \l_@@_oes_applicant_affiliation_clist
    { \@@_oes_register_affiliation:n {##1} }
  \int_set:Nn \l_@@_oes_applicant_affiliation_count_int
    { \seq_count:N \l_@@_oes_affiliation_seq }
  \DTLifdbexists{#1}
  {
    \DTLforeach*{#1}
    {
      \pOESProject=ref-project-id,
      \pOESStatus=funding-status,
      \pOESLastname=lastname,
      \pOESPerson=ref-person-id,
      \pOESCategory=category,
      \pOESInstitutions=ref-institution-id,
      \pOESAffiliation=ref-affiliation-id
    }
    {
      \DTLifnullorempty{\pOESStatus}
      { }
      {
        \tl_set:Ne \l_tmpa_tl { \pOESStatus }
        \str_if_eq:VnT \l_tmpa_tl { existing }
          { \@@_oes_collect_current: }
      }
    }
  }
  { \msg_warning:nnn { dfg } { database-not-found } {#1} }
  \int_compare:nNnT { \l_@@_oes_record_count_int } = {0}
    { \msg_warning:nnn { dfg } { existing-staff-no-data } {#1} }
  \@@_oes_build_table_body:
  \exp_args:NV \@@_oes_typeset:n \l_@@_oes_colspec_tl
  \@@_oes_print_legend:
  \group_end:
}

\NewDocumentCommand{\OverviewExistingStaffTable}
  { O{RequestedFundingStaffOverview} }
{
  \bool_if:NTF \l_@@_class_fastcompile_bool
    { \dfgItemSkipped{OverviewExistingStaffTable} }
    { \@@_overview_existing_staff:n {#1} }
}
%    \end{macrocode}
%
% \paragraph{\refCom{OverviewOfFundsRequestedForStaffTable}}
% Each body row is assembled by \cs{tl\_put\_right:Nx} into
% \cs{l\_tblr\_body\_tl} and contains twenty-five
% \refCom{getCountRequestedStaff} calls (five years $\times$ five
% categories) plus the leading \cs{getProject}\marg{project}; the
% foot row issues another twenty-five calls for the column totals.
%
% No indexing logic appears here: \refCom{addEntry} maintains the aggregate
% property list and \refCom{getCountRequestedStaff} encapsulates its lookup.
% The speed-up therefore applies transparently to every other consumer of the
% macro as well (marginalia, individual project tables, etc.).
%
% \begin{docCommand}{OverviewOfFundsRequestedForStaffTable}{\oarg{database}}
%   Emit the overview of requested staff funding.  \meta{database}
%   defaults to |RequestedFundingOverview|, which combines funding declared
%   before the document with project-local declarations restored from the
%   preceding run's auxiliary files.  The table contains five year
%   bands of five category columns (|postDoc|, |PhD|, |research|,
%   |nonResearch|, |student|), one body row per project, and a
%   \enquote{Total} foot row.
% \end{docCommand}
%    \begin{macrocode}
\NewDocumentCommand{\OverviewOfFundsRequestedForStaffTable}{ O{RequestedFundingOverview} }{%
 \def\tmpLocalDB{#1}
  \tl_set:Nn \l_@@_requested_staff_database_tl {#1}
  \DTLifdbexists{\tmpLocalDB}{%
	\tl_clear:N \l_tblr_body_tl
	\DTLsort{number}{project}
    \DTLforeach*[
      \not\DTLiseq{\tmpProjectStatus}{E}
      \and
      \not\DTLiseq{\tmpProjectConsiderForLists}{false}
    ]{project}{%
		\pProject               = number,
	    \tmpProjectStatus       = project-status,
	    \tmpProjectType         = project-type,
      \tmpProjectConsiderForLists = consider-for-lists,
	}{%
	\tl_put_right:Nx \l_tblr_body_tl
		{
			\getProject{\pProject}
			& \getCountRequestedStaff[\pProject]{1}{postDoc}
			& \getCountRequestedStaff[\pProject]{1}{PhD}
			& \getCountRequestedStaff[\pProject]{1}{research}
			& \getCountRequestedStaff[\pProject]{1}{nonResearch}
			& \getCountRequestedStaff[\pProject]{1}{student}

			& \getCountRequestedStaff[\pProject]{2}{postDoc}
			& \getCountRequestedStaff[\pProject]{2}{PhD}
			& \getCountRequestedStaff[\pProject]{2}{research}
			& \getCountRequestedStaff[\pProject]{2}{nonResearch}
			& \getCountRequestedStaff[\pProject]{2}{student}

			& \getCountRequestedStaff[\pProject]{3}{postDoc}
			& \getCountRequestedStaff[\pProject]{3}{PhD}
			& \getCountRequestedStaff[\pProject]{3}{research}
			& \getCountRequestedStaff[\pProject]{3}{nonResearch}
			& \getCountRequestedStaff[\pProject]{3}{student}

			& \getCountRequestedStaff[\pProject]{4}{postDoc}
			& \getCountRequestedStaff[\pProject]{4}{PhD}
			& \getCountRequestedStaff[\pProject]{4}{research}
			& \getCountRequestedStaff[\pProject]{4}{nonResearch}
			& \getCountRequestedStaff[\pProject]{4}{student}

			& \getCountRequestedStaff[\pProject]{5}{postDoc}
			& \getCountRequestedStaff[\pProject]{5}{PhD}
			& \getCountRequestedStaff[\pProject]{5}{research}
			& \getCountRequestedStaff[\pProject]{5}{nonResearch}
			& \getCountRequestedStaff[\pProject]{5}{student} \\
		}
     }

	\begin{tblr}[%
			theme=main,
			expand=\l_tblr_body_tl,
			long,
		]{%
			vspan=even,
			colspec = {*{1}{X[2,m]}
						*{24}{Q[c]}
				},
			rowhead = 2,
			colsep=4.5pt,
			vline{2,7,12,17,22}={tableLines,solid,wd=.75pt},
			vline{2,7,12,17,22}={3-Z}{tableLines,solid,wd=.75pt},
			hline{2}={wd=0pt},
			hline{3}={wd=1pt,tableLines},
			hline{Y}={wd=1pt,tableOuterLines},
			row{2} = {
				         fg={tableHeadingsFont},
				         bg={tableHeadingsBG},
				         halign={c}
			         },
			row{Z}= {font={\footnotesize\bfseries}}
		}
		 &
		\SetCell[c=5]{c} \dfgFundingYear{1}
		 & & & & &
		\SetCell[c=5]{c} \dfgFundingYear{2}
		 & & & & &
		\SetCell[c=5]{c} \dfgFundingYear{3}
		 & & & & &
		\SetCell[c=5]{c} \dfgFundingYear{4}
		 & & & & &
		\SetCell[c=5]{c} \dfgFundingYear{5}
		 & & & &
		\\
		\rotatebox{90}{Project} %
		 & \dfgRotate{postDoc}
		 & \dfgRotate{PhD}
		 & \dfgRotate{research}
		 & \dfgRotate{nonResearch}
		 & \dfgRotate{student}
		 & \dfgRotate{postDoc}
		 & \dfgRotate{PhD}
		 & \dfgRotate{research}
		 & \dfgRotate{nonResearch}
		 & \dfgRotate{student}
		 & \dfgRotate{postDoc}
		 & \dfgRotate{PhD}
		 & \dfgRotate{research}
		 & \dfgRotate{nonResearch}
		 & \dfgRotate{student}
		 & \dfgRotate{postDoc}
		 & \dfgRotate{PhD}
		 & \dfgRotate{research}
		 & \dfgRotate{nonResearch}
		 & \dfgRotate{student}
		 & \dfgRotate{postDoc}
		 & \dfgRotate{PhD}
		 & \dfgRotate{research}
		 & \dfgRotate{nonResearch}
		 & \dfgRotate{student}
		\\
		\l_tblr_body_tl
		Total
		 & \getCountRequestedStaff{1}{postDoc}
		 & \getCountRequestedStaff{1}{PhD}
		 & \getCountRequestedStaff{1}{research}
		 & \getCountRequestedStaff{1}{nonResearch}
		 & \getCountRequestedStaff{1}{student}
		 & \getCountRequestedStaff{2}{postDoc}
		 & \getCountRequestedStaff{2}{PhD}
		 & \getCountRequestedStaff{2}{research}
		 & \getCountRequestedStaff{2}{nonResearch}
		 & \getCountRequestedStaff{2}{student}
		 & \getCountRequestedStaff{3}{postDoc}
		 & \getCountRequestedStaff{3}{PhD}
		 & \getCountRequestedStaff{3}{research}
		 & \getCountRequestedStaff{3}{nonResearch}
		 & \getCountRequestedStaff{3}{student}
		 & \getCountRequestedStaff{4}{postDoc}
		 & \getCountRequestedStaff{4}{PhD}
		 & \getCountRequestedStaff{4}{research}
		 & \getCountRequestedStaff{4}{nonResearch}
		 & \getCountRequestedStaff{4}{student}
		 & \getCountRequestedStaff{5}{postDoc}
		 & \getCountRequestedStaff{5}{PhD}
		 & \getCountRequestedStaff{5}{research}
		 & \getCountRequestedStaff{5}{nonResearch}
		 & \getCountRequestedStaff{5}{student}
	\end{tblr}

}
  {
	Database~ \texttt{#1}~ missing.
	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
  \tl_set:Nn \l_@@_requested_staff_database_tl { RequestedFunding }
}
%    \end{macrocode}
%    \begin{macrocode}
\NewDocumentCommand{\getSumRequestedFundsInstrumentation}{som}{
  % #2: project
  % #3: year
  \IfNoValueTF{#2}
    { \@@_funding_sum_set:Nnnnn \SumFundsRequestedInstrumentation
        {RequestedFundingOverview}{__ALL__}{instrumentation}{#3} }
    { \@@_funding_sum_set:Nnnnn \SumFundsRequestedInstrumentation
        {RequestedFundingOverview}{#2}{instrumentation}{#3} }
  \@@_show_calculated_number:nnN
    {getSumRequestedFundsInstrumentation}
    {RequestedFundingOverview}
    \SumFundsRequestedInstrumentation
}
%    \end{macrocode}
% \paragraph{Requested instrumentation overview}
% The overview filters its database for |funding-type=instrumentation|.  When
% the filter yields no rows, the table is suppressed and a sentence names the
% proposed funding-period number instead.  This also covers a freshly created
% overview database on the first compilation pass.
%
% \begin{docCommand}{OverviewFundsRequestedInstrumentationTable}
%   {\oarg{database}}
%   Print the requested-instrumentation overview from \meta{database}, or state
%   that no instrumentation funds are requested for the current funding
%   period.  The database defaults to |RequestedFundingOverview|.
% \end{docCommand}
%    \begin{macrocode}
\NewDocumentCommand{\OverviewFundsRequestedInstrumentationTable} { O{RequestedFundingOverview} }{%
\def\tmpLocalDB{#1}
  \DTLifdbexists{\tmpLocalDB}{%
	\tl_clear:N \l_tblr_body_tl
	\DTLsort{ref-project-id}{\tmpLocalDB}
	\DTLforeach*[\DTLiseq{\pFundingType}{instrumentation}]{\tmpLocalDB}{%
		\pProject=ref-project-id,
        \pFundingType=type,
		\pDescription=category,
		\pSumYearOne=sum-year1,
		\pSumYearTwo=sum-year2,
		\pSumYearThree=sum-year3,
		\pSumYearFour=sum-year4,
		\pSumYearFive=sum-year5
	}{%
	\tl_put_right:Nx \l_tblr_body_tl
		{
			\getProject{\pProject}
			\printMarginalia{
				\getSumRequestedFundsInstrumentation[\pProject]{%
					sum-year1,
					sum-year2,
					sum-year3,
					sum-year4,
					sum-year5
				}
			}
      & \dfgShowTag{\pProject}{category}{\pDescription}[\tmpLocalDB]
      & \dfgShowTag{\pProject}{sum-year1}
          {\exp_not:N \@@_show_eur:n {\pSumYearOne}}[\tmpLocalDB]
      & \dfgShowTag{\pProject}{sum-year2}
          {\exp_not:N \@@_show_eur:n {\pSumYearTwo}}[\tmpLocalDB]
      & \dfgShowTag{\pProject}{sum-year3}
          {\exp_not:N \@@_show_eur:n {\pSumYearThree}}[\tmpLocalDB]
      & \dfgShowTag{\pProject}{sum-year4}
          {\exp_not:N \@@_show_eur:n {\pSumYearFour}}[\tmpLocalDB]
      & \dfgShowTag{\pProject}{sum-year5}
          {\exp_not:N \@@_show_eur:n {\pSumYearFive}}[\tmpLocalDB] \\
		}
     }
\tl_if_empty:VTF \l_tblr_body_tl
{
	\par\noindent
	No~funds~for~instrumentation~are~requested~for~funding~period~
	\dfgFundingPeriodNumeral.
	\par
}
{
\begin{tblr}[%
			theme=main,
			expand=\l_tblr_body_tl,
			long,
			remark{Note} = {Figures~ in~ EUR}
		]{%
			vspan=even,
			row{Z} = {guard,font={\footnotesize\bfseries}},
			colspec = {
					*{1}{X[-1,t]}
						*{1}{X[2,t]}
						*{5}{X[-1,c,si={table-format=8}]}
				},
			rowhead = 2,
			column{3-7}={guard},
			%colsep=4.5pt,
			hline{2}={wd=0pt},
			hline{3}={wd=1pt,tableOuterLines},
			hline{Y}={wd=1pt,tableOuterLines},
			row{2} = {
				         fg={tableHeadingsFont},
				         bg={tableHeadingsBG},
				         halign={c},
				         guard,
			         },
		}
		Project
		 & {Description~of                                 \\ instrumentation}
		 & \SetCell[c=5]{c,guard} Funds~ requested~ for
		 &                                                                     % year 2
		 &                                                                     % year 3
		 &                                                                     % year 4
		 &                                                                     % year 5
		\\
		 &
		 & \dfgFundingYear{1}
		 & \dfgFundingYear{2}
		 & \dfgFundingYear{3}
		 & \dfgFundingYear{4}
		 & \dfgFundingYear{5}   \\

		\l_tblr_body_tl
		\SetCell[c=2]{l}Total
		\printMarginalia{
			\getSumRequestedFundsInstrumentation{%
				sum-year1,
				sum-year2,
				sum-year3,
				sum-year4,
				sum-year5
			}
		}
		 &
		 & \getSumRequestedFundsInstrumentation{sum-year1}
		 & \getSumRequestedFundsInstrumentation{sum-year2}
		 & \getSumRequestedFundsInstrumentation{sum-year3}
		 & \getSumRequestedFundsInstrumentation{sum-year4}
		 & \getSumRequestedFundsInstrumentation{sum-year5}   \\
	\end{tblr}
}
}
  {
	Database~ \texttt{#1}~ missing.
	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
}

%    \end{macrocode}
%  Generic memoized \cs{DTLsumforkeys}
%    \begin{macrocode}
\prop_new:N \g_@@_dtlsum_cache_prop
%    \end{macrocode}
% Memoized form WITH filter:
%   |\@@_dtlsum_filtered:nnnnN {db}{filter-key}{filter-value}{cols}{result-cs}|
% This computes |\DTLsumforkeys[\DTLiseq{\pTmp}{value}][\pTmp=key]{db}{cols}{result}|
%    \begin{macrocode}

\cs_new_protected:Npn \@@_dtlsum_filtered:nnnnN #1#2#3#4#5 {
  \tl_set:Nx \l_tmpa_tl
  { #1 || \tl_to_str:n {#2} || \tl_to_str:n {#3} || \tl_to_str:n {#4} }
  \prop_get:NVNTF \g_@@_dtlsum_cache_prop \l_tmpa_tl \l_tmpb_tl
  { \cs_set_eq:NN #5 \l_tmpb_tl }
  {%
  	\DTLsumforkeys[\DTLiseq{\pCacheKey}{#3}][\pCacheKey=#2]{#1}{#4}{#5}%
  	\prop_gput:NVV \g_@@_dtlsum_cache_prop \l_tmpa_tl #5
  }
}

% Memoized form WITHOUT filter:
%   \@@_dtlsum_all:nnN {db}{cols}{result-cs}
\cs_new_protected:Npn \@@_dtlsum_all:nnN #1#2#3 {
  \tl_set:Nx \l_tmpa_tl
  { #1 || NOFILTER || \tl_to_str:n {#2} }
  \prop_get:NVNTF \g_@@_dtlsum_cache_prop \l_tmpa_tl \l_tmpb_tl
  { \cs_set_eq:NN #3 \l_tmpb_tl }
  {%
  	\DTLsumforkeys{#1}{#2}{#3}%
  	\prop_gput:NVV \g_@@_dtlsum_cache_prop \l_tmpa_tl #3
  }
}

% ============================================================
%  Drop-in replacements
% ============================================================

\providecommand{\SumPreviousRequestedFunding}{0}
\providecommand{\SumRequestedFunding}{0}

\NewDocumentCommand{\getSumPreviousRequestedFunding}{O{PreviousRequestedFunding}mm}{%
  \DTLifdbexists{#1}{%
  	\str_if_eq:nnTF {#2} {all}
  	{ \@@_dtlsum_all:nnN {#1} {#3} \SumPreviousRequestedFunding }
  	{ \@@_dtlsum_filtered:nnnnN {#1} {year} {#2} {#3} \SumPreviousRequestedFunding }%
    \@@_show_calculated_number:nnN
      {getSumPreviousRequestedFunding}{#1}
      \SumPreviousRequestedFunding
  }{%
  	\texttt{\color{error}XXX}%
  	\msg_warning:nne { dfg } { database-not-found } { #1 }%
  }%
}

\NewDocumentCommand{\getSumRequestedFunding}{O{RequestedFundingOverview}mm}{%
  \DTLifdbexists{#1}{%
  	\str_if_eq:nnTF {#2} {all}
    { \@@_funding_sum_set:Nnnnn \SumRequestedFunding {#1}
      {__ALL__}{#3}{sum-year1,sum-year2,sum-year3,sum-year4,sum-year5} }
    { \@@_funding_sum_set:Nnnnn \SumRequestedFunding {#1}
      {__ALL__}{#3}{sum-year#2} }%
    \@@_show_calculated_number:nnN
      {getSumRequestedFunding}{#1}
      \SumRequestedFunding
  }{%
  	\texttt{\color{error}XXX}%
  	\msg_warning:nne { dfg } { database-not-found } { #1 }%
  }%
}

\NewDocumentCommand{\getTotalSumRequestedFunding}{O{RequestedFundingOverview}mm}{%
  \DTLifdbexists{#1}{%
    \tl_set:Nn \l_tmpa_tl {#3}
    \str_if_eq:nnT {#3} {all} { \tl_set:Nn \l_tmpa_tl {__ALL__} }
    \str_if_eq:nnTF {#2} {all}
      { \@@_funding_sum_set:Nnnnn \SumRequestedFunding {#1}
          {__ALL__}{\l_tmpa_tl}
          {sum-year1,sum-year2,sum-year3,sum-year4,sum-year5} }
      { \@@_funding_sum_set:Nnnnn \SumRequestedFunding {#1}
          {__ALL__}{\l_tmpa_tl}{sum-year#2} }%
    \@@_show_calculated_number:nnN
      {getTotalSumRequestedFunding}{#1}
      \SumRequestedFunding
  }{%
  	\texttt{\color{error}XXX}%
  	\msg_warning:nne { dfg } { database-not-found } { #1 }%
  }%
}

\NewDocumentCommand{\PreviousAndCurrentRequestedFundingTable}{O{PreviousRequestedFunding}}
{
  \def\tmpLocalDB{#1}
  \begin{tblr}[%
  		theme=main,
  		expand=\l_tblr_body_tl,
  		long,
		remark{Note} = {Figures~ in~ EUR}
  	]{%
  		row{8,Z} = {guard,font={\footnotesize\bfseries}},
  		colspec = {
        *{1}{t{3.5cm}}@{}
        *{6}{X[-1,c,si={table-format=8}]}
      },
  		rowhead = 2,
		column{2-7}={guard},
  		%colsep=4.5pt,
  		hline{2}={wd=0pt},
  		hline{3}={wd=1pt,tableOuterLines},
  		% hline{Y}={wd=1pt,tableOuterLines},
  		row{1,2} = {
  			           fg={tableHeadingsFont},
  			           bg={tableHeadingsBG},
  			           halign={c},
  			           guard,
  		           },
  	}
  	\SetCell[r=2]{b}{Financial~year/                         \\funding~period}
  	 & \SetCell[c=5]{c} Funding~ for                         % staff
  	 &                                                       % costs
  	 &                                                       % instrumentation
  	 &                                                       % fellowships
  	 &                                                       % globalfunds
  	 & \SetCell[r=2]{b} Total                                \\
  	 &
  	Staff
  	 & Direct~ costs
  	 & Instrumentation
  	 & Fellowships
  	 & Globalfunds
  	 &                                                       \\
	\dfgFundingYearPrevious{1}
    \printMarginalia{%
      \getSumPreviousRequestedFunding{1}{%
        staff,costs,instrumentation,fellowships,globalfunds}%
    }
  	 & \getSumPreviousRequestedFunding{1}{staff}             % staff
  	 & \getSumPreviousRequestedFunding{1}{costs}             % costs
  	 & \getSumPreviousRequestedFunding{1}{instrumentation}   % instrumentation
  	 & \getSumPreviousRequestedFunding{1}{fellowships}       % fellowships
  	 & \getSumPreviousRequestedFunding{1}{globalfunds}       % globalfunds
  	 &
  	\getSumPreviousRequestedFunding{1}{staff,costs,instrumentation,
  		fellowships,globalfunds}
  	\\ % Total

	\dfgFundingYearPrevious{2}
    \printMarginalia{%
      \getSumPreviousRequestedFunding{2}{%
        staff,costs,instrumentation,fellowships,globalfunds}%
    }
  	 & \getSumPreviousRequestedFunding{2}{staff}             % staff
  	 & \getSumPreviousRequestedFunding{2}{costs}             % costs
  	 & \getSumPreviousRequestedFunding{2}{instrumentation}   % instrumentation
  	 & \getSumPreviousRequestedFunding{2}{fellowships}       % fellowships
  	 & \getSumPreviousRequestedFunding{2}{globalfunds}       % globalfunds
  	 &
  	\getSumPreviousRequestedFunding{2}{staff,costs,instrumentation,
  		fellowships,globalfunds}
  	\\ % Total
	\dfgFundingYearPrevious{3}
    \printMarginalia{%
      \getSumPreviousRequestedFunding{3}{%
        staff,costs,instrumentation,fellowships,globalfunds}%
    }
  	 & \getSumPreviousRequestedFunding{3}{staff}             % staff
  	 & \getSumPreviousRequestedFunding{3}{costs}             % costs
  	 & \getSumPreviousRequestedFunding{3}{instrumentation}   % instrumentation
  	 & \getSumPreviousRequestedFunding{3}{fellowships}       % fellowships
  	 & \getSumPreviousRequestedFunding{3}{globalfunds}       % globalfunds
  	 &
  	\getSumPreviousRequestedFunding{3}{staff,costs,instrumentation,
  		fellowships,globalfunds}
  	\\ % Total

	\dfgFundingYearPrevious{4}
    \printMarginalia{%
      \getSumPreviousRequestedFunding{4}{%
        staff,costs,instrumentation,fellowships,globalfunds}%
    }
  	 & \getSumPreviousRequestedFunding{4}{staff}             % staff
  	 & \getSumPreviousRequestedFunding{4}{costs}             % costs
  	 & \getSumPreviousRequestedFunding{4}{instrumentation}   % instrumentation
  	 & \getSumPreviousRequestedFunding{4}{fellowships}       % fellowships
  	 & \getSumPreviousRequestedFunding{4}{globalfunds}       % globalfunds
  	 &
  	\getSumPreviousRequestedFunding{4}{staff,costs,instrumentation,
  		fellowships,globalfunds}
  	\\ % Total

	\dfgFundingYearPrevious{5}
    \printMarginalia{%
      \getSumPreviousRequestedFunding{5}{%
        staff,costs,instrumentation,fellowships,globalfunds}%
    }
  	 & \getSumPreviousRequestedFunding{5}{staff}             % staff
  	 & \getSumPreviousRequestedFunding{5}{costs}             % costs
  	 & \getSumPreviousRequestedFunding{5}{instrumentation}   % instrumentation
  	 & \getSumPreviousRequestedFunding{5}{fellowships}       % fellowships
  	 & \getSumPreviousRequestedFunding{5}{globalfunds}       % globalfunds
  	 &
  	\getSumPreviousRequestedFunding{5}{staff,costs,instrumentation,
  		fellowships,globalfunds}
  	\\ % Total
  	\SetHline{-}{tableOuterLines,0.5pt}
  	\SetRow{belowsep=5pt}
    Ending~Funding~period
    \printMarginalia{%
      \getSumPreviousRequestedFunding{all}{%
        staff,costs,instrumentation,fellowships,globalfunds}%
    }
  	 & \getSumPreviousRequestedFunding{all}{staff}           % staff
  	 & \getSumPreviousRequestedFunding{all}{costs}           % costs
  	 & \getSumPreviousRequestedFunding{all}{instrumentation} % instrumentation
  	 & \getSumPreviousRequestedFunding{all}{fellowships}     % fellowships
  	 & \getSumPreviousRequestedFunding{all}{globalfunds}     % globalfunds
  	 &
  	\getSumPreviousRequestedFunding{all}{staff,costs,instrumentation,
  		fellowships,globalfunds}
  	\\ % Total

  	\SetHline{-}{tableOuterLines,1pt}
	\dfgFundingYear{1}
    \printMarginalia{\getTotalSumRequestedFunding{1}{all}}
  	 & \getSumRequestedFunding{1}{staff}
  	 & \getSumRequestedFunding{1}{costs}
  	 & \getSumRequestedFunding{1}{instrumentation}
  	 & \getSumRequestedFunding{1}{fellowships}
  	 & \getSumRequestedFunding{1}{globalfunds}
  	 & \getTotalSumRequestedFunding{1}{all}
  	\\
	\dfgFundingYear{2}
    \printMarginalia{\getTotalSumRequestedFunding{2}{all}}
  	 & \getSumRequestedFunding{2}{staff}
  	 & \getSumRequestedFunding{2}{costs}
  	 & \getSumRequestedFunding{2}{instrumentation}
  	 & \getSumRequestedFunding{2}{fellowships}
  	 & \getSumRequestedFunding{2}{globalfunds}
  	 & \getTotalSumRequestedFunding{2}{all}
  	\\

	\dfgFundingYear{3}
    \printMarginalia{\getTotalSumRequestedFunding{3}{all}}
  	 & \getSumRequestedFunding{3}{staff}
  	 & \getSumRequestedFunding{3}{costs}
  	 & \getSumRequestedFunding{3}{instrumentation}
  	 & \getSumRequestedFunding{3}{fellowships}
  	 & \getSumRequestedFunding{3}{globalfunds}
  	 & \getTotalSumRequestedFunding{3}{all}
  	\\
	\dfgFundingYear{4}
    \printMarginalia{\getTotalSumRequestedFunding{4}{all}}
  	 & \getSumRequestedFunding{4}{staff}
  	 & \getSumRequestedFunding{4}{costs}
  	 & \getSumRequestedFunding{4}{instrumentation}
  	 & \getSumRequestedFunding{4}{fellowships}
  	 & \getSumRequestedFunding{4}{globalfunds}
  	 & \getTotalSumRequestedFunding{4}{all}
  	\\
	\dfgFundingYear{5}
    \printMarginalia{\getTotalSumRequestedFunding{5}{all}}
  	 & \getSumRequestedFunding{5}{staff}
  	 & \getSumRequestedFunding{5}{costs}
  	 & \getSumRequestedFunding{5}{instrumentation}
  	 & \getSumRequestedFunding{5}{fellowships}
  	 & \getSumRequestedFunding{5}{globalfunds}
  	 & \getTotalSumRequestedFunding{5}{all}
  	\\

  	\SetHline{-}{tableOuterLines,0.5pt}
  	New~ Funding~period
    \printMarginalia{\getTotalSumRequestedFunding{all}{all}}
  	 & \getTotalSumRequestedFunding{all}{staff}              % staff
  	 & \getTotalSumRequestedFunding{all}{costs}              % costs
  	 & \getTotalSumRequestedFunding{all}{instrumentation}    % instrumentation
  	 & \getTotalSumRequestedFunding{all}{fellowships}        % fellowships
  	 & \getTotalSumRequestedFunding{all}{globalfunds}        % globalfunds
  	 &
  	\getTotalSumRequestedFunding{all}{all}
  	\\ % Total
  \end{tblr}
}
%    \end{macrocode}
%
% Section 2.1.1 reuses the project-level existing-funds declarations.  Both the
% stored values and the overview display use full euros.  The shared euro
% formatter adds thousands separators and rounds display values to whole euros
% (for example, |5000| is printed as |5,000|).
%
% |ref-affiliation-id| determines the column: every id listed in
% |meta/crc.ref-affiliation-id| is applicant core support, the sentinel
% |other-funds| selects other funding sources, and every other affiliation id
% is treated as another participating institution.  The descriptive
% |financed-by| value does not perform this classification.
%    \begin{macrocode}
\cs_new_protected:Npn
  \@@_get_sum_previous_requested_funding_eur:nnn #1#2#3
{
  \DTLifdbexists{#1}
  {
    \str_if_eq:nnTF {#2} {all}
      { \@@_dtlsum_all:nnN {#1} {#3} \SumPreviousRequestedFunding }
      { \@@_dtlsum_filtered:nnnnN
          {#1} {year} {#2} {#3} \SumPreviousRequestedFunding }
    \@@_show_calculated_number:nnN
      {getSumPreviousRequestedFunding}{#1}
      \SumPreviousRequestedFunding
  }
  {
    \texttt{\color{error}XXX}
    \msg_warning:nne { dfg } { database-not-found } {#1}
  }
}

\NewDocumentCommand{\getSumRequestedFundingDirectCosts}{
  O{RequestedAndExistingFundingDirectCostsOverview}
  m m }
{
  % #1: database
  % #2: year
  % #3: affiliation

  \str_if_eq:nnTF {#2}{all}
  {
  	\str_case:nn {#3}
  	{
		{applicant} {\DTLsumforkeys[\DTLisinlist{\pAffiliation}{\theApplicantID}]
  			[\pAffiliation=ref-affiliation-id]{#1}
  			{sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
  			{\SumRequestedFundingDirectCosts}}

  		{participant}{
  			\DTLsumforkeys[
				\not\DTLisinlist{\pAffiliation}{\theApplicantID}
  				\and
  				\not\DTLiseq{\pAffiliation}{other-funds}
  			]
  			[\pAffiliation=ref-affiliation-id]{#1}
  			{sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
  			{\SumRequestedFundingDirectCosts}}

  		{other-funds}{\DTLsumforkeys[\DTLiseq{\pAffiliation}{other-funds}]
  			[\pAffiliation=ref-affiliation-id]{#1}
  			{sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
  			{\SumRequestedFundingDirectCosts}}

  		{all}{\DTLsumforkeys{#1}
  			{sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
  			{\SumRequestedFundingDirectCosts}}
  	}}
  {
  	\str_case:nn {#3}
  	{
		{applicant} {\DTLsumforkeys[\DTLisinlist{\pAffiliation}{\theApplicantID}]
  			[\pAffiliation=ref-affiliation-id]{#1}
  			{sum-year#2}
  			{\SumRequestedFundingDirectCosts}}

  		{participant}{
  			\DTLsumforkeys[
				\not\DTLisinlist{\pAffiliation}{\theApplicantID}
  				\and
  				\not\DTLiseq{\pAffiliation}{other-funds}
  			]
  			[\pAffiliation=ref-affiliation-id]{#1}
  			{sum-year#2}
  			{\SumRequestedFundingDirectCosts}}

  		{other-funds}{\DTLsumforkeys[\DTLiseq{\pAffiliation}{other-funds}]
  			[\pAffiliation=ref-affiliation-id]{#1}
  			{sum-year#2}
  			{\SumRequestedFundingDirectCosts}}

  		{all}{\DTLsumforkeys{#1}
  			{sum-year#2}
  			{\SumRequestedFundingDirectCosts}}
  	}}


  \@@_show_calculated_number:nnN
    {getSumRequestedFundingDirectCosts}{#1}
    \SumRequestedFundingDirectCosts
}

\NewDocumentCommand{\ExistingFundsDirectCostsTable}
  {O{RequestedAndExistingFundingDirectCostsOverview}}
{
  \DTLifdbexists{#1}{
  	\begin{tblr}[%
  			theme=main,
  			% expand=\l_tblr_body_tl,
  			long,
			remark{Note} = {Figures~ in~ EUR}
  		]{%
  			row{7,Z} = {guard,font={\footnotesize\bfseries}},
			colspec = {
        *{1}{t{3.5cm}}
        *{4}{X[-1,c,si={table-format=9}]}
      },
  			% rowhead = 1,
			column{2-5}={guard},
  			%colsep=4.5pt,
  			% hline{3}={wd=1pt,tableOuterLines},
  			% hline{Y}={wd=1pt,tableOuterLines},
  			row{1} = {
  				         fg={tableHeadingsFont},
  				         bg={tableHeadingsBG},
  				         halign={c},
  				         guard,
  			         },
  		}
		 {Financial~year/                                                                         \\funding~period}
		 & {Core~ support~ provided~                                                             \\by~ applicant~
		   \dfgApplicantAffiliationsTF{university}{universities}}

  		 & {Core~ support~ provided~                                                             \\by~
  			   other~ participating~ institutions}
  		 & Other~ funds
  		 & Total                                                                                                              \\

		\dfgFundingYearPrevious{1}
      \printMarginalia{%
        \@@_get_sum_previous_requested_funding_eur:nnn
          {PreviousExistingFundsDirectCosts}{1}{%
          applicant,participant,other-funds}%
      }
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{1}{applicant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{1}{participant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{1}{other-funds}}
		 &
		{\@@_get_sum_previous_requested_funding_eur:nnn
		    {PreviousExistingFundsDirectCosts}{1}{
				applicant,
				participant,
				other-funds}}                                                \\

		\dfgFundingYearPrevious{2}
      \printMarginalia{%
        \@@_get_sum_previous_requested_funding_eur:nnn
          {PreviousExistingFundsDirectCosts}{2}{%
          applicant,participant,other-funds}%
      }
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{2}{applicant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{2}{participant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{2}{other-funds}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{2}{
				   applicant,
				   participant,
				   other-funds}}                                             \\

		\dfgFundingYearPrevious{3}
      \printMarginalia{%
        \@@_get_sum_previous_requested_funding_eur:nnn
          {PreviousExistingFundsDirectCosts}{3}{%
          applicant,participant,other-funds}%
      }
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{3}{applicant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{3}{participant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{3}{other-funds}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{3}{
				   applicant,
				   participant,
				   other-funds}}                                             \\

		\dfgFundingYearPrevious{4}
      \printMarginalia{%
        \@@_get_sum_previous_requested_funding_eur:nnn
          {PreviousExistingFundsDirectCosts}{4}{%
          applicant,participant,other-funds}%
      }
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{4}{applicant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{4}{participant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{4}{other-funds}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{4}{
				   applicant,
				   participant,
				   other-funds}}                                             \\

		\dfgFundingYearPrevious{5}
      \printMarginalia{%
        \@@_get_sum_previous_requested_funding_eur:nnn
          {PreviousExistingFundsDirectCosts}{5}{%
          applicant,participant,other-funds}%
      }
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{5}{applicant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{5}{participant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{5}{other-funds}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{5}{
				   applicant,
				   participant,
				   other-funds}}                                             \\

  		\SetHline{-}{tableOuterLines,0.5pt}
  		\SetRow{belowsep=5pt}
      Ending~Funding~period
      \printMarginalia{%
        \@@_get_sum_previous_requested_funding_eur:nnn
          {PreviousExistingFundsDirectCosts}{all}{%
          applicant,participant,other-funds}%
      }
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{all}{applicant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{all}{participant}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{all}{other-funds}}
		 & {\@@_get_sum_previous_requested_funding_eur:nnn
		      {PreviousExistingFundsDirectCosts}{all}{
				   applicant,
				   participant,
				   other-funds}}                                           \\

  		\SetHline{-}{tableOuterLines,1pt}
		\dfgFundingYear{1}
      \printMarginalia{\getSumRequestedFundingDirectCosts[#1]{1}{all}}
		 & \getSumRequestedFundingDirectCosts[#1]{1}{applicant}
		 & \getSumRequestedFundingDirectCosts[#1]{1}{participant}
		 & \getSumRequestedFundingDirectCosts[#1]{1}{other-funds}
		 & \getSumRequestedFundingDirectCosts[#1]{1}{all}                                                                         \\
		\dfgFundingYear{2}
      \printMarginalia{\getSumRequestedFundingDirectCosts[#1]{2}{all}}
		 & \getSumRequestedFundingDirectCosts[#1]{2}{applicant}
		 & \getSumRequestedFundingDirectCosts[#1]{2}{participant}
		 & \getSumRequestedFundingDirectCosts[#1]{2}{other-funds}
		 & \getSumRequestedFundingDirectCosts[#1]{2}{all}                                                                         \\
		\dfgFundingYear{3}
      \printMarginalia{\getSumRequestedFundingDirectCosts[#1]{3}{all}}
		 & \getSumRequestedFundingDirectCosts[#1]{3}{applicant}
		 & \getSumRequestedFundingDirectCosts[#1]{3}{participant}
		 & \getSumRequestedFundingDirectCosts[#1]{3}{other-funds}
		 & \getSumRequestedFundingDirectCosts[#1]{3}{all}                                                                         \\
		\dfgFundingYear{4}
      \printMarginalia{\getSumRequestedFundingDirectCosts[#1]{4}{all}}
		 & \getSumRequestedFundingDirectCosts[#1]{4}{applicant}
		 & \getSumRequestedFundingDirectCosts[#1]{4}{participant}
		 & \getSumRequestedFundingDirectCosts[#1]{4}{other-funds}
		 & \getSumRequestedFundingDirectCosts[#1]{4}{all}                                                                         \\
		\dfgFundingYear{5}
      \printMarginalia{\getSumRequestedFundingDirectCosts[#1]{5}{all}}
		 & \getSumRequestedFundingDirectCosts[#1]{5}{applicant}
		 & \getSumRequestedFundingDirectCosts[#1]{5}{participant}
		 & \getSumRequestedFundingDirectCosts[#1]{5}{other-funds}
		 & \getSumRequestedFundingDirectCosts[#1]{5}{all}                                                                         \\


  		\SetHline{-}{tableOuterLines,0.5pt}
		New~ Funding~period
      \printMarginalia{\getSumRequestedFundingDirectCosts[#1]{all}{all}}
		 & \getSumRequestedFundingDirectCosts[#1]{all}{applicant}
		 & \getSumRequestedFundingDirectCosts[#1]{all}{participant}
		 & \getSumRequestedFundingDirectCosts[#1]{all}{other-funds}
		 & \getSumRequestedFundingDirectCosts[#1]{all}{all}                                                                       \\
  	\end{tblr}
  }{
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
}
%    \end{macrocode}
% The core part is definitely all about the projects.
%    \begin{macrocode}
\clist_new:N \l_tmp_research_area_clist
\bool_new:N  \l_@@_project_one_PI_bool
\bool_new:N  \g_@@_fast_project_started_bool

\NewDocumentCommand{\printProjectHead}{m}
{%
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  {
    \bool_if:NF \g_@@_fast_project_started_bool
    {
      \setcounter{page}{1}% Ignore page checkpoints restored by excluded files.
      \bool_gset_true:N \g_@@_fast_project_started_bool
    }
    \def\tmpLocalDB{project}%
    \setcounter{section}{0}%
    \setcounter{figure}{0}%
    \setcounter{table}{0}%
    \setcounter{secnumdepth}{2}%
    \restartlist{workpackages}%
    \tl_set:Nn \l__tmp_current_project_tl {#1}%
    \cs_set:Npn \tmpProjectNumber       {#1}%
    \cs_set:Npn \tmpProjectTitle        { }%
    \cs_set:Npn \tmpProjectStatus       { }%
    \cs_set:Npn \tmpProjectType         { }%
    \cs_set:Npn \tmpProjectResearchArea { }%
    \cs_set:Npn \tmpProjectPIids        { }%
    \bool_set_true:N \l_@@_project_one_PI_bool
    \renewcommand*{\thesection}      {\arabic{section}}%
    \renewcommand*{\thesubsection}   {\thesection.\arabic{subsection}}%
    \renewcommand*{\thesubsubsection}{\thesubsection.\arabic{subsubsection}}%
    \renewcommand*{\thefigure}       {\arabic{figure}}%
    \renewcommand*{\thetable}        {\arabic{table}}%
    \renewcommand*{\theHpart}        {\thepart.#1}%
    \renewcommand*{\theHchapter}     {\thechapter.#1}%
    \renewcommand*{\theHsection}     {\thesection.#1}%
    \renewcommand*{\theHsubsection}  {\thesubsection.#1}%
    \renewcommand*{\theHsubsubsection}{\thesubsubsection.#1}%
    \renewcommand*{\theHfigure}      {\thefigure.#1}%
    \renewcommand*{\theHtable}       {\thetable.#1}%
    \renewcommand*{\theHfootnote}    {\thefootnote.#1}%
    \chead*{\textbf{Project~#1}\enspace|\enspace FAST~COMPILE~-~DRAFT}%
    \printThumbIndexOff
    \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
    {
      \@@_project_results_prepare:n {#1}%
      \citereset
      \begin{refsection}
    }
  }
  {
  % #1: project id
  \cleardoublepage
\phantomsection
  \def\tmpLocalDB{project}%
  \setcounter{section}{0}%
  \setcounter{figure}{0}%
  \setcounter{table}{0}%
  \setcounter{tocdepth}{0}%
  \restartlist{workpackages}%
  \tl_set:Nn \l__tmp_current_project_tl {#1}%
  \@@_project_results_prepare:n {#1}%

  \renewcommand*{\theHpart}        {\thepart.#1}%
  \renewcommand*{\theHchapter}     {\thechapter.#1}%
  \renewcommand*{\theHsection}     {\thesection.#1}%
  \renewcommand*{\theHsubsection}  {\thesubsection.#1}%
  \renewcommand*{\theHsubsubsection}{\thesubsubsection.#1}%
  \renewcommand*{\theHfigure}      {\thefigure.#1}%
  \renewcommand*{\theHtable}       {\thetable.#1}%
  \renewcommand*{\theHfootnote}    {\thefootnote.#1}%

  % --- single row scan for all project columns we need --------------------
  \getEntry*[\tmpLocalDB]{#1}{
  	\tmpProjectNumber       = number,
  	\tmpProjectTitle        = name,
  	\tmpProjectStatus       = project-status,
  	\tmpProjectType         = project-type,
  	\tmpProjectResearchArea = research-area,
  	\tmpProjectPIids        = ref-person-id
  }%

	% Register the bibliography aliases of every PI assigned to this project.
	% The mapping parameter is doubled because this loop occurs inside the
	% definition of \printProjectHead.
	\datatool_if_has_key:nnT { person } { name-alias }
	{
		\clist_map_inline:Nn \tmpProjectPIids
		{
			\DTLgetvalueforkey { \theAliases } { name-alias } { person } { id } { ##1 }
			\DTLifnullorempty { \theAliases }
			{ }
			{ \exp_args:No \addboldnames { \theAliases } }
		}
  	}

  % --- precompute the few derived booleans we actually use ----------------
  \int_compare:nNnTF { \clist_count:N \tmpProjectPIids } > {1}
  	{ \bool_set_false:N \l_@@_project_one_PI_bool }
  	{ \bool_set_true:N  \l_@@_project_one_PI_bool }%

  \citereset
  \hypertarget{project:#1}{}%

  \use:x
  {
  	\exp_not:N \printThumbIndex
  	[ project \tl_head:n {#1} ]
  	{ \exp_not:n {#1} }
  }%

  \chead{\getPIofProject{#1}[\space\cdot\space]%
    \space|\space
    \dfgShowTag{#1}{name}{\tmpProjectTitle}[project]}%

 

 % --- toc entry ----------------------------------------------------------
  \addtocentrydefault{section}{
    \texorpdfstring
      { \dfgShowTag{#1}{number}{\tmpProjectNumber}[project] }
      { \tmpProjectNumber }
    \str_if_eq:eeF {\tmpProjectStatus} {C}
      {
        \space
        \texorpdfstring
          {\dfgShowTag{#1}{project-status}{\tmpProjectStatus}[project]}
          {\tmpProjectStatus}
      }%
  }
  {
    \texorpdfstring{\dfgShowTag{#1}{name}{\tmpProjectTitle}[project]}{}%
  }% 
  \setcounter{secnumdepth}{2}%
  \addtocontents{toc}{\protect\setcounter{tocdepth}{0}}%
  \hypersetup{bookmarksdepth=0}%
  \begin{refsection}

  \section{%
    General~information~about~Project~%
    \texorpdfstring
    {
      \getProject{#1}%
      \str_if_eq:eeF {\tmpProjectStatus} {C}
        { \c_space_tl
          \dfgShowTag{#1}{project-status}{\tmpProjectStatus}[project] }%
    }
    {\tmpProjectNumber}%
   }
 \subsection{Project~title:~
   \texorpdfstring
     {\dfgShowTag{#1}{name}{\tmpProjectTitle}[project]}
     {\tmpProjectTitle}}

  % --- research areas (for active research and service projects) ----------
  \str_if_eq:eeF {\tmpProjectStatus} {E}
  {
   \bool_lazy_or:nnT
   { \str_if_eq_p:ee {\tmpProjectType} {research} }
   { \str_if_eq_p:ee {\tmpProjectType} {service}  }
   {%
  	\clist_clear:N \l_tmp_research_area_clist
  	\clist_sort:Nn \tmpProjectResearchArea
  	{ \fp_compare:nTF {##1 < ##2} {\sort_return_swapped:} {\sort_return_same:} }%
  	\clist_map_inline:Nn \tmpProjectResearchArea
  	{ \clist_put_right:Nn \l_tmp_research_area_clist { \dfgResearchAreasList{##1} } }%
    \subsection{Research~area
      \int_compare:nNnT { \clist_count:N \tmpProjectResearchArea } > {1}
        {s}
      :~
      \texorpdfstring
        {\dfgShowTag{#1}{research-area}
          {\clist_use:Nn \l_tmp_research_area_clist {,~}}[project]}
        {\clist_use:Nn \l_tmp_research_area_clist {,~}}}%
   }
  }

  \bool_if:NTF \l_@@_project_one_PI_bool
  { \subsection{Project~leader}  }
  { \subsection{Project~leaders} }

  \getPersonInformation{\tmpProjectPIids}\par
  \vspace*{2em}

  % --- contract information (skip for admin / ending) ---------------------
  \bool_lazy_or:nnF
  { \str_if_eq_p:ee {\tmpProjectType}   {admin} }
  { \str_if_eq_p:ee {\tmpProjectStatus} {E}     }
  {%
  	\begin{contractinformation}
  		\clist_map_inline:nn {C1,C2,C3,C4}
  		{ \dfgPIcontractInformation{##1} }%
  	\end{contractinformation}
  }

  % --- legal issues (skip for admin / mgk / ending) -----------------------
  \bool_lazy_any:nF
  {
  	{ \str_if_eq_p:ee {\tmpProjectType}   {admin} }
  	{ \str_if_eq_p:ee {\tmpProjectType}   {mgk}   }
  	{ \str_if_eq_p:ee {\tmpProjectStatus} {E}     }
  }
  {%
  	\subsection{Legal~issues}%
  	\def\tmpLocalDB{project}%
  	This~project~includes\\

  	\tl_clear:N \l_mytblr_body_tl
  	\tl_put_right:Ne \l_mytblr_body_tl
	{ 1. & research~requiring~compliance~with~discipline-specific~research~ethics~guidelines. & \checkYesNo{L1} \\ }%
  	\compareEntry{#1}{L1}{yes}
  	{
  		\tl_put_right:Ne \l_mytblr_body_tl
	{ & A~statement~from~the~responsible~ethics~committee~is~required~and~will~be~obtained~before~funding~starts. & \checkYesNo{L1a} \\ }%
  	}
  	{}%
  	\tl_put_right:Ne \l_mytblr_body_tl
  	{ 2. & clinical~trials & \checkYesNo{L2} \\ }%
  	\compareEntry{#1}{L2}{yes}
  	{
  		\tl_put_right:Ne \l_mytblr_body_tl
  		{ & A~copy~of~the~studies'~registration~is~included~with~the~proposal. & \checkYesNo{L2a} \\ }%
  	}
  	{}%
  	\tl_put_right:Ne \l_mytblr_body_tl
  	{
  		3. & experiments~involving~vertebrates. & \checkYesNo{L3} \\
  		4. & experiments~involving~recombinant~DNA. & \checkYesNo{L4} \\
  		5. & research~involving~human~embryonic~stem~cells. & \checkYesNo{L5} \\
  	}
  	\compareEntry{#1}{L5}{yes}
  	{
  		\tl_put_right:Ne \l_mytblr_body_tl
  		{ & Legal~authorization~has~been~obtained. & \checkYesNo{L5a} \\ }%
  	}
  	{}%
  	\tl_put_right:Ne \l_mytblr_body_tl
  	{
		6. & research~concerning~the~Convention~on~Biological~Diversity. & \checkYesNo{L6} \\
  		7. & investigations~involving~dual~use~research~of~concern. & \checkYesNo{L7} \\
  	}
  	\compareEntry{#1}{L7}{yes}
  	{
  		\tl_put_right:Ne \l_mytblr_body_tl
  		{ & A~copy~of~the~statement~by~the~institution's~research~ethics~committee~is~included~with~the~proposal. & \checkYesNo{L7a} \\ }%
  	}
  	{}%
  	\begin{tblr}[
  			theme  = plain,
  			expand = \l_mytblr_body_tl,
  		]{
  			rowhead   = 0,
			rowsep    = 0pt,
  			hline{2}  = {0pt},
  			rows      = {bg=white, halign=l, font=\footnotesize},
  			column{1} = {halign=r},
  			colspec   = {t{.25cm}X[t]t{.75cm}}
  		}
  		\tl_use:N \l_mytblr_body_tl
  	\end{tblr}%
  }
  }
}
%    \end{macrocode}
%    \begin{macrocode}
\NewDocumentCommand{\checkYesNo}{O{\tmpProjectNumber} m}
{%
  \compareEntry{#1}%        current project ID
  {#2}%                   which cell
  {yes}%                 if cell value is 'yes'
  {\dfgShowTag{#1}{#2}{{\bfseries\color{green}\faCheck}\,yes}[project]}%
  {\dfgShowTag{#1}{#2}{{\bfseries\color{red}\faTimes}\space no}[project]}%
}
%    \end{macrocode}
% Another helper command to retrieve the information about a PI and
% his/her/their involvement within the project.
%    \begin{macrocode}
% --------------------------------------------------------------------------
% PI contract information
% --------------------------------------------------------------------------

\seq_new:N   \l_@@_contract_pi_ids_seq
\seq_new:N   \l_@@_contract_true_pi_ids_seq
\seq_new:N   \l_@@_contract_false_pi_ids_seq
\clist_new:N \l_@@_contract_answers_clist
\tl_new:N    \l_@@_contract_answer_tl
\tl_new:N    \l_@@_contract_field_list_tl

\NewDocumentCommand{\dfgPIcontractInformation}{ o m }
 {
  % #1: optional comma-separated PI ids
  %     If omitted, use the current value of \tmpProjectPIids.
  % #2: question id, e.g. C1 / C2 / C3 / C4
  \IfNoValueTF {#1}
   {
    \@@_pi_contract_information:Vn \tmpProjectPIids {#2}
   }
   {
    \@@_pi_contract_information:nn {#1} {#2}
   }
 }

\cs_new_protected:Npn \@@_pi_contract_information:nn #1#2
 {
  % #1: comma-separated PI ids
  % #2: question id, e.g. C1 / C2 / C3 / C4

  \def\tmpLocalDB{person}%
  \seq_set_from_clist:Nn \l_@@_contract_pi_ids_seq {#1}

  \str_case:nn {#2}
   {
    {C1}
     {
      \item
      Is~the~employment~of~the~
      \bool_if:NTF \l_@@_project_one_PI_bool
       { project~leader~at~the~institution~ }
       { project~leaders~at~the~institutions~ }%
      indicated~contractually~secured~for~the~duration~of~
      the~proposed~funding~period?\space
      \@@_pi_contract_yes_no:n {#2}%
     }

    {C2}
     {
      \item
      \bool_if:NTF \l_@@_project_one_PI_bool
       { Does~the~above~mentioned~person~hold~a~fixed-term~position? }
       { Do~any~of~the~above~mentioned~persons~hold~fixed-term~positions? }%
      \space
      \@@_pi_contract_yes_no:n {#2}%

      \clist_if_in:NnT \l_@@_contract_answers_clist {yes}
       {
        \begin{contractinformation}
          \item End~date~of~fixed-term~contract:\space
          \@@_pi_contract_field_list:nN {C2a} \l_@@_contract_true_pi_ids_seq

          \item Further~employment~is~planned~until:\space
          \@@_pi_contract_field_list:nN {C2b} \l_@@_contract_true_pi_ids_seq
        \end{contractinformation}
       }
     }

    {C3}
     {
      \item
      \bool_if:NTF \l_@@_project_one_PI_bool
       { Will~the~above~mentioned~person~ }
       { Will~one~or~more~of~the~above-mentioned~persons~ }%
      retire~during~the~proposed~funding~period?\space
      \@@_pi_contract_yes_no:n {#2}%

      \clist_if_in:NnT \l_@@_contract_answers_clist {yes}
       {
        \begin{contractinformation}
          \item Anticipated~retirement~date:\space
          \@@_pi_contract_field_list:nN {C3a} \l_@@_contract_true_pi_ids_seq
        \end{contractinformation}
       }
     }

    {C4}
     {
      \item
      Funding~for~the~position~of~the~
      \bool_if:NTF \l_@@_project_one_PI_bool
       { project~leader~at~the~institution~ }
       { project~leaders~at~the~institutions~ }%
      indicated~is~covered~by~core~support~(state~funds~or~similar):\space
      \@@_pi_contract_yes_no:n {#2}%

      \clist_if_in:NnT \l_@@_contract_answers_clist {no}
       {
        \begin{contractinformation}
          \item Type~and~source~of~funding:\space
          \@@_pi_contract_field_list:nN {C4a} \l_@@_contract_false_pi_ids_seq
        \end{contractinformation}
       }
     }
   }
 }

\cs_generate_variant:Nn \@@_pi_contract_information:nn { Vn }


\cs_new_protected:Npn \@@_pi_contract_yes_no:n #1
 {
  % #1: question id, e.g. C1 / C2 / C3 / C4

  \clist_clear:N \l_@@_contract_answers_clist
  \seq_clear:N   \l_@@_contract_true_pi_ids_seq
  \seq_clear:N   \l_@@_contract_false_pi_ids_seq
  \tl_clear:N    \l_@@_contract_answer_tl

  \bool_set_true:N \l_tmpa_bool

  \seq_map_inline:Nn \l_@@_contract_pi_ids_seq
   {
    \bool_if:NTF \l_tmpa_bool
     { \bool_set_false:N \l_tmpa_bool }
     { \tl_put_right:Nn \l_@@_contract_answer_tl {,~} }%

    \DTLgetvalueforkey{\theLastName}{lastname}{person}{id}{##1}%

    \compareEntry{##1}{#1}{yes}
     {
      \tl_put_right:Nn \l_@@_contract_answer_tl
        { \dfgShowTag{##1}{#1}{\textbf{yes}}[person] }%
      \clist_put_right:Nn \l_@@_contract_answers_clist {true}%
      \seq_put_right:Nn   \l_@@_contract_true_pi_ids_seq {##1}%
     }
     {
      \tl_put_right:Nn \l_@@_contract_answer_tl
        { \dfgShowTag{##1}{#1}{\textbf{no}}[person] }%
      \clist_put_right:Nn \l_@@_contract_answers_clist {false}%
      \seq_put_right:Nn   \l_@@_contract_false_pi_ids_seq {##1}%
     }

    \bool_if:NF \l_@@_project_one_PI_bool
     {
      \tl_put_right:Nx \l_@@_contract_answer_tl
       {
        \exp_not:n {~(}
        \exp_not:N \dfgShowTag{##1}{lastname}
          {\exp_not:V \theLastName}[person]
        \exp_not:n {)}
       }%
     }
   }

  \tl_use:N \l_@@_contract_answer_tl
 }


\cs_new_protected:Npn \@@_pi_contract_field_list:nN #1#2
 {
  % #1: field id, e.g. C2a / C2b / C3a / C4a
  % #2: sequence variable containing the PI ids for which the field is relevant

  \tl_clear:N \l_@@_contract_field_list_tl
  \bool_set_true:N \l_tmpa_bool

  \seq_map_inline:Nn #2
   {
    \bool_if:NTF \l_tmpa_bool
     { \bool_set_false:N \l_tmpa_bool }
     { \tl_put_right:Nn \l_@@_contract_field_list_tl {,~} }%

    \getEntry*[person]{##1}
     {
      \theFieldValue = #1,
      \theLastName   = lastname
     }%

    \tl_put_right:Nx \l_@@_contract_field_list_tl
     {
      \exp_not:N \textbf
      {
        \exp_not:N \dfgShowTag{##1}{#1}
          {\exp_not:V \theFieldValue}[person]
      }
      \int_compare:nNnT { \seq_count:N #2 } > {1}
       {
        \exp_not:n {~(}
        \exp_not:N \dfgShowTag{##1}{lastname}
          {\exp_not:V \theLastName}[person]
        \exp_not:n {)}
       }
     }%
   }

  \tl_use:N \l_@@_contract_field_list_tl
 }


\cs_new_protected:Npn \__pi_question_field_list:nn #1#2
{%
  \tl_clear:N \l_tmpa_tl
  \bool_set_true:N \l_tmpa_bool   % first-iteration flag
  \seq_map_inline:Nn #2
  {%
  	\bool_if:NTF \l_tmpa_bool
  	{ \bool_set_false:N \l_tmpa_bool }
  	{ \tl_put_right:Nn \l_tmpa_tl {,~} }%
  	\getEntry*[person]{##1}{
  		\theFieldValue = #1,
  		\theLastName   = lastname
  	}%
  	\tl_put_right:Nx \l_tmpa_tl
  	{
		\exp_not:N \textbf
    {
      \exp_not:N \dfgShowTag{##1}{#1}
        {\exp_not:V \theFieldValue}[person]
    }
  		\int_compare:nNnT { \seq_count:N #2 } > {1}
      {
        \exp_not:n {\space(}
        \exp_not:N \dfgShowTag{##1}{lastname}
          {\exp_not:V \theLastName}[person]
        \exp_not:n {)}
      }
  	}%
  }%
  \tl_use:N \l_tmpa_tl
}

\tl_new:N \l_@@_yes_names_tl
\tl_new:N \l_@@_no_names_tl

\cs_new_protected:Npn \tmp_person_question_yes_no:n #1
{%
  \clist_clear:N \l_tmpc_clist
  \seq_clear:N   \l_tmpd_seq
  \seq_clear:N   \l_tmpe_seq
  \tl_clear:N    \l_tmpa_tl
  \bool_set_true:N \l_tmpa_bool   % first-iteration flag
  \seq_map_inline:Nn \l_tmpa_seq
  {%
  	\bool_if:NTF \l_tmpa_bool
  	{ \bool_set_false:N \l_tmpa_bool }
  	{ \tl_put_right:Nn \l_tmpa_tl {,~} }%
  	\DTLgetvalueforkey{\theLastName}{lastname}{person}{id}{##1}%
  	\compareEntry{##1}{#1}{yes}
  	{%
    \tl_put_right:Nn \l_tmpa_tl
      { \dfgShowTag{##1}{#1}{\textbf{yes}}[person] }%
  		\clist_put_right:Nn \l_tmpc_clist {yes}%
  		\seq_put_right:Nn   \l_tmpd_seq   {##1}%
  	}
  	{%
    \tl_put_right:Nn \l_tmpa_tl
      { \dfgShowTag{##1}{#1}{\textbf{no}}[person] }%
  		\clist_put_right:Nn \l_tmpc_clist {false}%
  		\seq_put_right:Nn   \l_tmpe_seq   {##1}%
  	}%
  	\bool_if:NF \l_@@_project_one_PI_bool
  	{%
    \tl_put_right:Nx \l_tmpa_tl
    {
      \exp_not:n {\space(}
      \exp_not:N \dfgShowTag{##1}{lastname}
        {\exp_not:V \theLastName}[person]
      \exp_not:n {)}
    }%
  	}%
  }%
  \tl_use:N \l_tmpa_tl
}
%    \end{macrocode}
% Ending projects report three distinct kinds of published results.  Each
% populated list is cited in its own reference segment.  The combined list is
% persisted in the auxiliary file so a preceding project-report bibliography
% can omit entries that are printed again in the result lists.
%    \begin{macrocode}
\clist_new:N \l_@@_project_results_quality_assured_clist
\clist_new:N \l_@@_project_results_other_clist
\clist_new:N \l_@@_project_results_patents_clist
\clist_new:N \l_@@_project_results_all_clist
\clist_new:N \l_@@_project_results_excluded_clist
\prop_new:N  \g_@@_project_results_aux_prop

\NewDocumentCommand{\dfgProjectResultsAux}{mm}
{
  \prop_gput:Nnn \g_@@_project_results_aux_prop {#1} {#2}
}

\cs_new_protected:Npn \@@_project_results_prepare:n #1
{
  \clist_clear:N \l_@@_project_results_excluded_clist
  \prop_get:NnNT \g_@@_project_results_aux_prop {#1} \l_tmpa_tl
  {
    \clist_set:NV \l_@@_project_results_excluded_clist \l_tmpa_tl
  }
}

\cs_new_protected:Npn \@@_project_results_collect:N #1
{
  \clist_map_inline:Nn #1
  {
    \str_if_eq:nnF {##1} {none}
    { \clist_put_right:Nn \l_@@_project_results_all_clist {##1} }
  }
}

\cs_new_protected:Npn \@@_project_results_register:
{
  \clist_clear:N \l_@@_project_results_all_clist
  \@@_project_results_collect:N \l_@@_project_results_quality_assured_clist
  \@@_project_results_collect:N \l_@@_project_results_other_clist
  \@@_project_results_collect:N \l_@@_project_results_patents_clist
  \clist_remove_duplicates:N \l_@@_project_results_all_clist
  \clist_set_eq:NN
    \l_@@_project_results_excluded_clist
    \l_@@_project_results_all_clist
  \iow_now:Ne \@auxout
  {
    \exp_not:N \dfgProjectResultsAux
    { \exp_not:V \l__tmp_current_project_tl }
    { \exp_not:V \l_@@_project_results_all_clist }
  }
}

\cs_new_protected:Npn \@@_project_results_skip_if_listed:
{
  \clist_map_inline:Nn \l_@@_project_results_excluded_clist
  {
    \str_if_eq:eeT {##1} { \strfield{entrykey} }
    {
      \skipentry
      \clist_map_break:
    }
  }
}

\defbibcheck{dfg-project-report}
{ \@@_project_results_skip_if_listed: }

\defbibheading{dfg-project-report-references}
{ \subsubsection{References} }

\NewDocumentCommand{\projectPublicationsHeading}{}
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
  { \subsection{Project-~and~subject-related~list~of~publications} }
}

\NewDocumentCommand{\projectNocite}{m}
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
  { \nocite{#1} }
}

\NewDocumentCommand{\printProjectBibliography}{o}
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
  {
    \IfNoValueTF{#1}
    { \printbibliography }
    { \printbibliography[#1] }
  }
}

\NewDocumentEnvironment{projectReport}{}
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
  { \begin{refsegment} }
}
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
  {
    \printbibliography[
      segment = \therefsegment,
      check   = dfg-project-report,
      heading = dfg-project-report-references
    ]
    \end{refsegment}
  }
}

\keys_define:nn { dfg / project-results }
{
  quality-assured .clist_set:N = \l_@@_project_results_quality_assured_clist,
  quality-assured .value_required:n = true,
  other .clist_set:N = \l_@@_project_results_other_clist,
  other .value_required:n = true,
  patents .clist_set:N = \l_@@_project_results_patents_clist,
  patents .value_required:n = true,
  unknown .code:n = { \msg_warning:nnn { dfg } { unknown-key } {#1} }
}

\cs_new_protected:Npn \@@_project_results_print:Nn #1#2
{
  \clist_if_empty:NTF #1
  {#2}
  {
    \str_if_eq:eeTF { \clist_use:Nn #1 {,} } { none }
    { None. }
    {
      \begin{refsegment}
        \exp_args:Ne \nocite { \clist_use:Nn #1 {,} }
        \printbibliography[segment=\therefsegment, heading=none]
      \end{refsegment}
    }
  }
}

\NewDocumentCommand{\printProjectResults}{m}
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
  {
  \FloatBarrier
  \group_begin:
    \clist_clear:N \l_@@_project_results_quality_assured_clist
    \clist_clear:N \l_@@_project_results_other_clist
    \clist_clear:N \l_@@_project_results_patents_clist
    \keys_set:nn { dfg / project-results } {#1}
    \@@_project_results_register:
    \setbibpreamble{}

    \subsubsection{Publications~with~scientific~quality~assurance}
    \@@_project_results_print:Nn
      \l_@@_project_results_quality_assured_clist
      { List~publications~with~scientific~quality~assurance. }

    \subsubsection{Other~publications~and~published~results}
    \@@_project_results_print:Nn
      \l_@@_project_results_other_clist
      { List~datasets,~software,~preprints,~protocols,~or~other~relevant~
        published~results~that~are~not~included~above. }

    \subsubsection{Patents}
    \@@_project_results_print:Nn
      \l_@@_project_results_patents_clist
      { List~patents~and~patent~applications,~or~state~that~none~resulted~
        from~the~project. }
  \group_end:
  }
}
%    \end{macrocode}
%    \begin{macrocode}
\NewDocumentCommand{\printProjectTail}{}{
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  {
    \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
    {
      \end{refsection}
      \resetboldnames
    }
  }
  {
    \end{refsection}
    \resetboldnames%
    \clearpage
    \addtocontents{toc}{\protect\setcounter{tocdepth}{1}}%
    \hypersetup{bookmarksdepth = 3}
    \colorlet{thumbIndexBG}{\l_@@_custom_thumbIndexBG_tl}
  }
}
%    \end{macrocode}
% To get the interim sum printed in the margin area we use a custom command.
% Table rows are denser than the package's default collision distance, so these
% notes use fixed placement with no collision padding. This keeps every total
% on its row anchor instead of accumulating a downward displacement.  The
% leader is placed before the value in the right margin and after the value in
% the left margin, keeping it adjacent to the table on both page sides. You can
% switch the notes off using the customization section.
%    \begin{macrocode}
\NewDocumentCommand{\printMarginalia}{O{\hrulefill}m}
{
  \bool_if:NT \l_@@_class_showmarginalia_bool
  {\bool_set_false:N \g_@@_tblr_inside_bool
	\bool_set_true:N \l_@@_show_tag_leftward_bool
    \marginalia[type=fixed,ysep=0pt]
    {
      \int_if_odd:nTF { \marginaliapage }
        { #1#2 }
        { #2#1 }
    }
	\bool_set_false:N \l_@@_show_tag_leftward_bool
  	\bool_set_true:N \g_@@_tblr_inside_bool
  }
}
%    \end{macrocode}
%
%    \begin{macrocode}
\tl_new:N \l__tmp_body_staff_tl
\tl_new:N \l__tmp_body_costs_tl
\tl_new:N \l__tmp_body_fellowships_tl
\tl_new:N \l__tmp_body_globalfunds_tl
\tl_new:N \l__tmp_body_instrumentation_tl
\cs_new_protected:Npn \@@_requested_funding_append_nonstaff:N #1
{
  \DTLaddall{\tmpHorizontalSum}{
    \pSumYearOne,
    \pSumYearTwo,
    \pSumYearThree,
    \pSumYearFour,
    \pSumYearFive
  }
  \tl_put_right:Ne #1
  {
    \dfgShowTag{\pProject/\pCategory}{category}{\pCategory}[\tmpLocalDB]
    \printMarginalia{\dfgShowCalculatedTag{RequestedFundingTable}{\tmpLocalDB}
      {\@@_show_eur:n{\tmpHorizontalSum}}}
    & & \dfgShowTag{\pProject/\pCategory}{sum-year1}
          {\@@_show_eur:n{\pSumYearOne}}[\tmpLocalDB]
    & & \dfgShowTag{\pProject/\pCategory}{sum-year2}
          {\@@_show_eur:n{\pSumYearTwo}}[\tmpLocalDB]
    & & \dfgShowTag{\pProject/\pCategory}{sum-year3}
          {\@@_show_eur:n{\pSumYearThree}}[\tmpLocalDB]
    & & \dfgShowTag{\pProject/\pCategory}{sum-year4}
          {\@@_show_eur:n{\pSumYearFour}}[\tmpLocalDB]
    & & \dfgShowTag{\pProject/\pCategory}{sum-year5}
          {\@@_show_eur:n{\pSumYearFive}}[\tmpLocalDB] \\
  }
}
\NewDocumentCommand{\RequestedFundingTable}{m}
{
  \group_begin:
  \sisetup{drop-zero-decimal=true}
  % #1: project
  \def\tmpLocalDB{RequestedFunding}%
  \DTLifdbexists{\tmpLocalDB}{%
  	\tl_clear:N \l__tmp_body_staff_tl
  	\tl_clear:N \l__tmp_body_costs_tl
  	\tl_clear:N \l__tmp_body_fellowships_tl
  	\tl_clear:N \l__tmp_body_globalfunds_tl
  	\tl_clear:N \l__tmp_body_instrumentation_tl
  	\tl_put_right:Nn \l__tmp_body_staff_tl {

  		\SetRow{tableHeadingsBGalt}
  		\SetCell{font=\footnotesize\bfseries,halign=l}
  		Staff
  		& Qty & Sum
  		& Qty & Sum
  		& Qty & Sum
  		& Qty & Sum
  		& Qty & Sum \\
  	}

  	\tl_put_right:Nn \l__tmp_body_costs_tl {
  		\SetHline{-}{tableOuterLines,0.5pt}
  		\SetRow{tableHeadingsBGalt}
  		\SetCell{font=\footnotesize\bfseries,halign=l}
  		Direct~ Costs
  		& & Sum
  		& & Sum
  		& & Sum
  		& & Sum
  		& & Sum  \\
  	}
  	\tl_put_right:Nn \l__tmp_body_fellowships_tl {
  		\SetHline{-}{tableOuterLines,0.5pt}
  		\SetRow{tableHeadingsBGalt}
  		\SetCell{font=\footnotesize\bfseries,halign=l}
  		Fellowships
  		& & Sum
  		& & Sum
  		& & Sum
  		& & Sum
  		& & Sum \\
  	}
  	\tl_put_right:Nn \l__tmp_body_globalfunds_tl {
  		\SetHline{-}{tableOuterLines,0.5pt}
  		\SetRow{tableHeadingsBGalt}
  		\SetCell{font=\footnotesize\bfseries,halign=l}
  		Globalfunds
  		& & Sum
  		& & Sum
  		& & Sum
  		& & Sum
  		& & Sum  \\
  	}
  	\tl_put_right:Nn \l__tmp_body_instrumentation_tl {
  		\SetHline{-}{tableOuterLines,0.5pt}
  		\SetRow{tableHeadingsBGalt}
  		\SetCell{font=\footnotesize\bfseries,halign=l}
  		Instrumentation
  		& & Sum
  		& & Sum
  		& & Sum
  		& & Sum
  		& & Sum  \\
  	}


	% One filtered traversal is enough: dispatch each matching row to the
	% token list for its funding type.  The previous implementation traversed
	% the complete, growing database once for every type.
	\DTLforeach[\DTLiseq{#1}{\pProject}]{\tmpLocalDB}{
  			\pProject           =ref-project-id,
  			\pType              =type,
  			\pCategory          =category,
  			\pPercentage        =percentage,
  			\pQuantityYearOne   =quantity-year1,
  			\pQuantityYearTwo   =quantity-year2,
  			\pQuantityYearThree =quantity-year3,
  			\pQuantityYearFour  =quantity-year4,
  			\pQuantityYearFive  =quantity-year5,
  			\pSumYearOne        =sum-year1,
  			\pSumYearTwo        =sum-year2,
  			\pSumYearThree      =sum-year3,
  			\pSumYearFour       =sum-year4,
  			\pSumYearFive       =sum-year5
  		}{

  			\str_case:enF {\pType}
  			{
  				{staff} {
  					\DTLaddall{\tmpHorizontalSum}{
  						\pSumYearOne,
  						\pSumYearTwo,
  						\pSumYearThree,
  						\pSumYearFour,
  						\pSumYearFive
  					}
  					\tl_put_right:Ne \l__tmp_body_staff_tl
  					{

						\dfgShowTag{\pProject/\pCategory}{category}
              {\dfgCategoryName{\pCategory}}[\tmpLocalDB],~
            \dfgShowTag{\pProject/\pCategory}{percentage}
              {\qty{\pPercentage}{\percent}}[\tmpLocalDB]
						\printMarginalia{\dfgShowCalculatedTag{RequestedFundingTable}
              {\tmpLocalDB}{\@@_show_eur:n{\tmpHorizontalSum}}}
						& \dfgShowTag{\pProject/\pCategory}{quantity-year1}
                {\@@_show_table_number:n{\pQuantityYearOne}}[\tmpLocalDB]
						& \dfgShowTag{\pProject/\pCategory}{sum-year1}
                {\@@_show_eur:n{\pSumYearOne}}[\tmpLocalDB]
						& \dfgShowTag{\pProject/\pCategory}{quantity-year2}
                {\@@_show_table_number:n{\pQuantityYearTwo}}[\tmpLocalDB] % year2
						& \dfgShowTag{\pProject/\pCategory}{sum-year2}
                {\@@_show_eur:n{\pSumYearTwo}}[\tmpLocalDB]
						& \dfgShowTag{\pProject/\pCategory}{quantity-year3}
                {\@@_show_table_number:n{\pQuantityYearThree}}[\tmpLocalDB] % year3
						& \dfgShowTag{\pProject/\pCategory}{sum-year3}
                {\@@_show_eur:n{\pSumYearThree}}[\tmpLocalDB]
						& \dfgShowTag{\pProject/\pCategory}{quantity-year4}
                {\@@_show_table_number:n{\pQuantityYearFour}}[\tmpLocalDB] % year4
						& \dfgShowTag{\pProject/\pCategory}{sum-year4}
                {\@@_show_eur:n{\pSumYearFour}}[\tmpLocalDB]
						& \dfgShowTag{\pProject/\pCategory}{quantity-year5}
                {\@@_show_table_number:n{\pQuantityYearFive}}[\tmpLocalDB] % year5
						& \dfgShowTag{\pProject/\pCategory}{sum-year5}
                {\@@_show_eur:n{\pSumYearFive}}[\tmpLocalDB]
  						\\
  					}
				}
        {costs}
          {\@@_requested_funding_append_nonstaff:N \l__tmp_body_costs_tl}
        {fellowships}
          {\@@_requested_funding_append_nonstaff:N \l__tmp_body_fellowships_tl}
        {globalfunds}
          {\@@_requested_funding_append_nonstaff:N \l__tmp_body_globalfunds_tl}
        {instrumentation}
          {\@@_requested_funding_append_nonstaff:N \l__tmp_body_instrumentation_tl}
			}
      { }
	}
  	\tl_put_right:Ne \l__tmp_body_staff_tl
  	{
  		\SetRow{belowsep=5pt}
  		\SetHline{-}{tableOuterLines,0.5pt}
  		Total~
  		\printMarginalia{%
  			\getSumRequestedFunds{#1}{staff}
  			{sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
  		}
  		& \SetCell{bg=tableNoValue}
  		& \getSumRequestedFunds{#1}{staff}{sum-year1}
  		& \SetCell{bg=tableNoValue}
  		& \getSumRequestedFunds{#1}{staff}{sum-year2}
  		& \SetCell{bg=tableNoValue}
  		& \getSumRequestedFunds{#1}{staff}{sum-year3}
  		& \SetCell{bg=tableNoValue}
  		& \getSumRequestedFunds{#1}{staff}{sum-year4}
  		& \SetCell{bg=tableNoValue}
  		& \getSumRequestedFunds{#1}{staff}{sum-year5}
  		\\
  	}

  	\clist_map_inline:nn {
  		costs,fellowships,globalfunds,instrumentation
  	}{

  		\tl_put_right:ce { l__tmp_body_##1_tl }
  		{
  			\SetRow{belowsep=5pt}
  			\SetHline{-}{tableLines,0.5pt}
  			Total
  			\printMarginalia{%
  				\getSumRequestedFunds{#1}{##1}
  				{sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
  			}
  			& &
  			\getSumRequestedFunds{#1}{##1}{sum-year1}
  			& &
  			\getSumRequestedFunds{#1}{##1}{sum-year2}
  			& &
  			\getSumRequestedFunds{#1}{##1}{sum-year3}
  			& &
  			\getSumRequestedFunds{#1}{##1}{sum-year4}
  			& &
  			\getSumRequestedFunds{#1}{##1}{sum-year5}
  			\\
  		}}

  	% delete when zero
  	\dfgCheckIfZeroShowCategory{#1}{staff}
  	\dfgCheckIfZeroShowCategory{#1}{costs}
  	\dfgCheckIfZeroShowCategory{#1}{fellowships}
  	\dfgCheckIfZeroShowCategory{#1}{globalfunds}
  	\dfgCheckIfZeroShowCategory{#1}{instrumentation}

  	\begin{tblr}[
  			theme=main,
  			long,
  			expand=
  			\l__tmp_body_staff_tl
  			\l__tmp_body_costs_tl
  			\l__tmp_body_fellowships_tl
  			\l__tmp_body_globalfunds_tl
  			\l__tmp_body_instrumentation_tl,
			remark{Note}={Figures~ in~ EUR},
  		]{
  			colsep=3pt,
			colspec = {
					*{1}{X[3.1,t]}
					*{5}{
						@{}X[0.75,c,si={table-format=1}]
						@{}X[r,si={table-format=7}]
					}
  					% *{1}{X[2,t]}
  					% *{10}{@{}X[c, si={table-format=4}]}
  				},
  			rows = {bg=white},
			column{2-Z}={guard},
  			row{1}= {bg=tableHeadingsBG},
  			row{1,2}= {guard},
  		}
		Funding~for
		 & \SetCell[c=2]{c} \dfgFundingYear{1}
  		 &
		 & \SetCell[c=2]{c} \dfgFundingYear{2}
  		 &
		 & \SetCell[c=2]{c} \dfgFundingYear{3}
  		 &
		 & \SetCell[c=2]{c} \dfgFundingYear{4}
  		 &
		 & \SetCell[c=2]{c} \dfgFundingYear{5}
  		 &                                           \\

  		\l__tmp_body_staff_tl
  		\l__tmp_body_costs_tl
  		\l__tmp_body_fellowships_tl
  		\l__tmp_body_globalfunds_tl
  		\l__tmp_body_instrumentation_tl

  		\SetHline{-}{tableOuterLines,.75pt}
  		\SetCell{font=\bfseries\footnotesize}
  		Total
  		\printMarginalia{%
  			\getTotalSumRequestedFunds{#1}
  			{sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
  		}
  		 &
  		 & \getTotalSumRequestedFunds{#1}{sum-year1}
  		 &
  		 & \getTotalSumRequestedFunds{#1}{sum-year2}
  		 &
  		 & \getTotalSumRequestedFunds{#1}{sum-year3}
  		 &
  		 & \getTotalSumRequestedFunds{#1}{sum-year4}
  		 &
  		 & \getTotalSumRequestedFunds{#1}{sum-year5} \\
  	\end{tblr}
  }{
  	Database~ \texttt{#1}~ missing.
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
  \group_end:
}
%    \end{macrocode}

% \paragraph{\refCom{RequestedFundingStaffTable}}
% The DFG staff roster uses one database and one project-filtered traversal.
% Rows are first dispatched, in declaration order, to four sequences.  The
% sequences are then rendered in the official order (existing research,
% existing non-research, requested research, requested non-research), which
% also assigns the continuous sequence numbers used by the descriptions.
% When both staff types occur within a funding-status block, a horizontal rule
% separates the research and non-research groups without repeating their
% row-spanning labels.  Category values and the emphasized job-description
% headings are left aligned for easier scanning.
% Person, institution, and affiliation references are resolved during this
% assembly phase,
% before tabularray measures any cells.  Thus neither measuring passes nor page
% breaks repeat Datatool queries.
%
% \begin{docCommand}{RequestedFundingStaffTable}{\marg{project}}
%   Print the official DFG requested-funding staff roster, the institution and
%   parent-affiliation legend, and both applicable job-description blocks for
%   \meta{project}.  The data source is always |RequestedFundingStaff|.  For
%   an ending project (|project-status=E|), rows declared with
%   |funding-status=requested| are automatically labelled as staff funded with
%   approved grant money; this matches the terminology of the ending-project
%   report while retaining the same two-value data model.
% \end{docCommand}
%    \begin{macrocode}
\seq_new:N \l_@@_rfs_existing_research_seq
\seq_new:N \l_@@_rfs_existing_nonresearch_seq
\seq_new:N \l_@@_rfs_requested_research_seq
\seq_new:N \l_@@_rfs_requested_nonresearch_seq
\seq_new:N \l_@@_rfs_institution_seq
\seq_new:N \l_@@_rfs_affiliation_seq
\prop_new:N \l_@@_rfs_duplicate_prop
\prop_new:N \l_@@_rfs_institution_name_prop
\prop_new:N \l_@@_rfs_institution_abbreviation_prop
\prop_new:N \l_@@_rfs_institution_affiliation_abbreviation_prop
\prop_new:N \l_@@_rfs_affiliation_abbreviation_prop
\prop_new:N \l_@@_rfs_affiliation_name_prop
\tl_new:N \l_@@_rfs_table_body_tl
\tl_new:N \l_@@_rfs_existing_descriptions_tl
\tl_new:N \l_@@_rfs_requested_descriptions_tl
\tl_new:N \l_@@_rfs_project_tl
\tl_new:N \l_@@_rfs_project_status_tl
\tl_new:N \l_@@_rfs_existing_group_label_tl
\tl_new:N \l_@@_rfs_requested_group_label_tl
\tl_new:N \l_@@_rfs_existing_description_heading_tl
\tl_new:N \l_@@_rfs_requested_description_heading_tl
\tl_new:N \l_@@_rfs_ref_person_tl
\tl_new:N \l_@@_rfs_firstname_tl
\tl_new:N \l_@@_rfs_lastname_tl
\tl_new:N \l_@@_rfs_degree_tl
\tl_new:N \l_@@_rfs_position_tl
\tl_new:N \l_@@_rfs_field_tl
\tl_new:N \l_@@_rfs_ref_institution_tl
\tl_new:N \l_@@_rfs_ref_affiliation_tl
\tl_new:N \l_@@_rfs_department_tl
\tl_new:N \l_@@_rfs_funding_status_tl
\tl_new:N \l_@@_rfs_commitment_tl
\tl_new:N \l_@@_rfs_category_tl
\tl_new:N \l_@@_rfs_funding_source_tl
\tl_new:N \l_@@_rfs_description_tl
\tl_new:N \l_@@_rfs_name_cell_tl
\tl_new:N \l_@@_rfs_plain_name_tl
\tl_new:N \l_@@_rfs_description_name_tl
\tl_new:N \l_@@_rfs_field_cell_tl
\tl_new:N \l_@@_rfs_department_cell_tl
\tl_new:N \l_@@_rfs_commitment_cell_tl
\tl_new:N \l_@@_rfs_category_cell_tl
\tl_new:N \l_@@_rfs_funding_source_cell_tl
\tl_new:N \l_@@_rfs_group_cell_tl
\tl_new:N \l_@@_rfs_institution_name_tl
\tl_new:N \l_@@_rfs_institution_abbreviation_tl
\tl_new:N \l_@@_rfs_institution_affiliation_tl
\tl_new:N \l_@@_rfs_affiliation_name_tl
\tl_new:N \l_@@_rfs_affiliation_abbreviation_tl
\int_new:N \l_@@_rfs_display_number_int
\int_new:N \l_@@_rfs_record_count_int
\bool_new:N \l_@@_rfs_person_resolved_bool
\bool_new:N \l_@@_rfs_name_incomplete_bool

\keys_define:nn { dfg / requested-funding-staff-row }
{
  ref-person-id .tl_set:N = \l_@@_rfs_ref_person_tl,
  firstname .tl_set:N = \l_@@_rfs_firstname_tl,
  lastname .tl_set:N = \l_@@_rfs_lastname_tl,
  academic-degree .tl_set:N = \l_@@_rfs_degree_tl,
  positionText .tl_set:N = \l_@@_rfs_position_tl,
  position .tl_set:N = \l_@@_rfs_position_tl,
  field-of-research .tl_set:N = \l_@@_rfs_field_tl,
  ref-institution-id .tl_set:N = \l_@@_rfs_ref_institution_tl,
  ref-affiliation-id .tl_set:N = \l_@@_rfs_ref_affiliation_tl,
  department .tl_set:N = \l_@@_rfs_department_tl,
  funding-status .tl_set:N = \l_@@_rfs_funding_status_tl,
  commitment .tl_set:N = \l_@@_rfs_commitment_tl,
  category .tl_set:N = \l_@@_rfs_category_tl,
  funding-source .tl_set:N = \l_@@_rfs_funding_source_tl,
  description .tl_set:N = \l_@@_rfs_description_tl,
  unknown .code:n = { }
}

\cs_new:Npn \@@_rfs_missing_text:
{ \textcolor{tableNoValue!55!black}{\emph{not~provided}} }

\cs_new:Npn \@@_rfs_error_text:n #1
{ \textcolor{error}{\texttt{<?#1?>}} }

\cs_new_protected:Npn \@@_rfs_warn_missing:n #1
{
  \msg_warning:nnee { dfg } { requested-staff-missing-field }
    { \l_@@_rfs_project_tl }
    { no.~\int_use:N \l_@@_rfs_display_number_int \c_colon_str\space #1 }
}

\cs_new_protected:Npn \@@_rfs_row_clear:
{
  \tl_clear:N \l_@@_rfs_ref_person_tl
  \tl_clear:N \l_@@_rfs_firstname_tl
  \tl_clear:N \l_@@_rfs_lastname_tl
  \tl_clear:N \l_@@_rfs_degree_tl
  \tl_clear:N \l_@@_rfs_position_tl
  \tl_clear:N \l_@@_rfs_field_tl
  \tl_clear:N \l_@@_rfs_ref_institution_tl
  \tl_clear:N \l_@@_rfs_ref_affiliation_tl
  \tl_clear:N \l_@@_rfs_department_tl
  \tl_clear:N \l_@@_rfs_funding_status_tl
  \tl_clear:N \l_@@_rfs_commitment_tl
  \tl_clear:N \l_@@_rfs_category_tl
  \tl_clear:N \l_@@_rfs_funding_source_tl
  \tl_clear:N \l_@@_rfs_description_tl
}

\cs_new_protected:Npn \@@_rfs_store:N #1
{
  \seq_put_right:Ne #1
  {
    ref-person-id = { \exp_not:V \pRFSRefPerson },
    firstname = { \exp_not:V \pRFSFirstname },
    lastname = { \exp_not:V \pRFSLastname },
    academic-degree = { \exp_not:V \pRFSDegree },
    positionText = { \exp_not:V \pRFSPosition },
    field-of-research = { \exp_not:V \pRFSField },
    ref-institution-id = { \exp_not:V \pRFSRefInstitution },
    ref-affiliation-id = { \exp_not:V \pRFSRefAffiliation },
    department = { \exp_not:V \pRFSDepartment },
    funding-status = { \exp_not:V \pRFSFundingStatus },
    commitment = { \exp_not:V \pRFSCommitment },
    category = { \exp_not:V \pRFSCategory },
    funding-source = { \exp_not:V \pRFSFundingSource },
    description = { \exp_not:V \pRFSDescription }
  }
}

\cs_new_protected:Npn \@@_rfs_collect_current:
{
  \clist_map_inline:nn
  {
    \pRFSRefPerson, \pRFSFirstname, \pRFSLastname, \pRFSDegree,
    \pRFSPosition, \pRFSField, \pRFSRefInstitution,
    \pRFSRefAffiliation, \pRFSDepartment, \pRFSCommitment,
    \pRFSCategory, \pRFSFundingSource, \pRFSDescription
  }
  { \DTLifnullorempty{##1}{\cs_set:Npn ##1 {}}{} }
  \tl_if_blank:VTF \pRFSRefPerson
  {
    \str_if_eq:VnTF \pRFSLastname { TBA }
    {
      \tl_set:Ne \l_tmpa_tl
      {
        \exp_not:V \pRFSProject / \exp_not:V \pRFSFundingStatus /
        \exp_not:V \pRFSStaffType / vacancy /
        \exp_not:V \pRFSCategory / \exp_not:V \pRFSPosition /
        \exp_not:V \pRFSField / \exp_not:V \pRFSRefInstitution /
        \exp_not:V \pRFSDepartment
      }
    }
    {
      \tl_set:Ne \l_tmpa_tl
      {
        \exp_not:V \pRFSProject / \exp_not:V \pRFSFundingStatus /
        \exp_not:V \pRFSStaffType / name /
        \exp_not:V \pRFSLastname / \exp_not:V \pRFSFirstname
      }
    }
  }
  {
    \tl_set:Ne \l_tmpa_tl
    {
      \exp_not:V \pRFSProject / \exp_not:V \pRFSFundingStatus /
      \exp_not:V \pRFSStaffType / person / \exp_not:V \pRFSRefPerson
    }
  }
  \prop_get:NVNTF \l_@@_rfs_duplicate_prop \l_tmpa_tl \l_tmpb_tl
  { \msg_warning:nne { dfg } { requested-staff-duplicate } { \l_tmpa_tl } }
  { \prop_put:NVn \l_@@_rfs_duplicate_prop \l_tmpa_tl { 1 } }
  \tl_set:Ne \l_tmpa_tl
    { \pRFSFundingStatus / \pRFSStaffType }
  \str_case:VnF \l_tmpa_tl
  {
    { existing/research }
      { \@@_rfs_store:N \l_@@_rfs_existing_research_seq }
    { existing/nonResearch }
      { \@@_rfs_store:N \l_@@_rfs_existing_nonresearch_seq }
    { requested/research }
      { \@@_rfs_store:N \l_@@_rfs_requested_research_seq }
    { requested/nonResearch }
      { \@@_rfs_store:N \l_@@_rfs_requested_nonresearch_seq }
  }
  { }
}

\cs_new_protected:Npn \@@_rfs_use_fallback:NN #1#2
{
  \tl_if_blank:VT #1
  { \DTLifnullorempty{#2}{ }{ \tl_set:NV #1 #2 } }
}

\cs_new_protected:Npn \@@_rfs_resolve_person:
{
  \bool_set_false:N \l_@@_rfs_person_resolved_bool
  \tl_if_blank:VF \l_@@_rfs_ref_person_tl
  {
    \DTLifdbexists{person}
    {
      \DTLgetvalueforkey{\l_tmpa_tl}{lastname}{person}{id}
        {\l_@@_rfs_ref_person_tl}
      \DTLifnullorempty{\l_tmpa_tl}
      {
        \msg_warning:nnee { dfg } { requested-staff-unresolved-person }
          { \l_@@_rfs_project_tl } { \l_@@_rfs_ref_person_tl }
      }
      {
        \bool_set_true:N \l_@@_rfs_person_resolved_bool
        \@@_rfs_use_fallback:NN \l_@@_rfs_lastname_tl \l_tmpa_tl
        \DTLgetvalueforkey{\l_tmpa_tl}{firstname}{person}{id}
          {\l_@@_rfs_ref_person_tl}
        \@@_rfs_use_fallback:NN \l_@@_rfs_firstname_tl \l_tmpa_tl
        \DTLgetvalueforkey{\l_tmpa_tl}{academicdegree}{person}{id}
          {\l_@@_rfs_ref_person_tl}
        \@@_rfs_use_fallback:NN \l_@@_rfs_degree_tl \l_tmpa_tl
        \DTLgetvalueforkey{\l_tmpa_tl}{positionText}{person}{id}
          {\l_@@_rfs_ref_person_tl}
        \@@_rfs_use_fallback:NN \l_@@_rfs_position_tl \l_tmpa_tl
        \DTLgetvalueforkey{\l_tmpa_tl}{position}{person}{id}
          {\l_@@_rfs_ref_person_tl}
        \@@_rfs_use_fallback:NN \l_@@_rfs_category_tl \l_tmpa_tl
        \bool_lazy_all:nT
        {
          { \tl_if_blank_p:V \l_@@_rfs_department_tl }
          { \tl_if_blank_p:V \l_@@_rfs_ref_institution_tl }
          { \tl_if_blank_p:V \l_@@_rfs_ref_affiliation_tl }
        }
        {
          \DTLgetvalueforkey{\l_tmpa_tl}{ref-institution-id}{person}{id}
            {\l_@@_rfs_ref_person_tl}
          \@@_rfs_use_fallback:NN \l_@@_rfs_ref_institution_tl \l_tmpa_tl
          \tl_if_blank:VT \l_@@_rfs_ref_institution_tl
          {
            \DTLgetvalueforkey{\l_tmpa_tl}{ref-affiliation-id}{person}{id}
              {\l_@@_rfs_ref_person_tl}
            \@@_rfs_use_fallback:NN \l_@@_rfs_ref_affiliation_tl \l_tmpa_tl
          }
        }
      }
    }
    {
      \msg_warning:nnee { dfg } { requested-staff-unresolved-person }
        { \l_@@_rfs_project_tl } { \l_@@_rfs_ref_person_tl }
    }
  }
}

\cs_new_protected:Npn \@@_rfs_register_affiliation:n #1
{
  \tl_set:Ne \l_tmpa_tl {#1}
  \tl_clear:N \l_@@_rfs_affiliation_name_tl
  \tl_clear:N \l_@@_rfs_affiliation_abbreviation_tl
  \DTLifdbexists{affiliation}
  {
    \DTLgetvalueforkey{\l_@@_rfs_affiliation_name_tl}
      {name}{affiliation}{id}{\l_tmpa_tl}
    \DTLifnullorempty{\l_@@_rfs_affiliation_name_tl}
    {
      \msg_warning:nnee { dfg } { requested-staff-unresolved-affiliation }
        { \l_@@_rfs_project_tl } { \l_tmpa_tl }
      \tl_clear:N \l_@@_rfs_affiliation_name_tl
    }
    {
      \DTLgetvalueforkey{\l_@@_rfs_affiliation_abbreviation_tl}
        {abbreviation}{affiliation}{id}{\l_tmpa_tl}
      \DTLifnullorempty{\l_@@_rfs_affiliation_abbreviation_tl}
      {
        \msg_warning:nne { dfg } { requested-staff-missing-abbreviation }
          { \l_tmpa_tl }
        \tl_set:NV \l_@@_rfs_affiliation_abbreviation_tl
          \l_@@_rfs_affiliation_name_tl
      }
      { }
      \seq_if_in:NVF \l_@@_rfs_affiliation_seq \l_tmpa_tl
      {
        \seq_put_right:NV \l_@@_rfs_affiliation_seq \l_tmpa_tl
        \prop_put:NVV \l_@@_rfs_affiliation_abbreviation_prop
          \l_tmpa_tl \l_@@_rfs_affiliation_abbreviation_tl
        \prop_put:NVV \l_@@_rfs_affiliation_name_prop
          \l_tmpa_tl \l_@@_rfs_affiliation_name_tl
      }
    }
  }
  {
    \msg_warning:nnee { dfg } { requested-staff-unresolved-affiliation }
      { \l_@@_rfs_project_tl } { \l_tmpa_tl }
  }
}

\cs_new_protected:Npn \@@_rfs_resolve_organisation:
{
  \tl_if_blank:VT \l_@@_rfs_department_tl
  {
    \tl_if_blank:VTF \l_@@_rfs_ref_institution_tl
    {
      % Compatibility fallback for roster declarations written before the
      % institution-level key was introduced.
      \tl_if_blank:VTF \l_@@_rfs_ref_affiliation_tl
      {
        \@@_rfs_warn_missing:n { department~or~ref-institution-id }
        \tl_set:Nn \l_@@_rfs_department_tl
          { \SetCell{bg=tableNoValue}\@@_rfs_missing_text: }
      }
      {
        \@@_rfs_register_affiliation:n { \l_@@_rfs_ref_affiliation_tl }
        \tl_if_blank:VTF \l_@@_rfs_affiliation_name_tl
        {
          \tl_set:Ne \l_@@_rfs_department_tl
          {
            \exp_not:N \SetCell { bg=tableNoValue }
            \exp_not:N \@@_rfs_error_text:n
              { \exp_not:V \l_@@_rfs_ref_affiliation_tl }
          }
        }
        {
          \tl_set:NV \l_@@_rfs_department_tl
            \l_@@_rfs_affiliation_abbreviation_tl
        }
      }
    }
    {
      \tl_clear:N \l_@@_rfs_department_tl
      \DTLifdbexists{institution}
      {
        \clist_set:NV \l_tmpa_clist \l_@@_rfs_ref_institution_tl
        \bool_set_true:N \l_tmpa_bool
        \clist_map_inline:Nn \l_tmpa_clist
        {
          \bool_if:NTF \l_tmpa_bool
            { \bool_set_false:N \l_tmpa_bool }
            { \tl_put_right:Nn \l_@@_rfs_department_tl {,~} }
          \DTLgetvalueforkey{\l_@@_rfs_institution_affiliation_tl}
            {ref-affiliation-id}{institution}{id}{##1}
          \DTLifnullorempty{\l_@@_rfs_institution_affiliation_tl}
          {
            \msg_warning:nnee { dfg } { requested-staff-unresolved-institution }
              { \l_@@_rfs_project_tl } {##1}
            \tl_put_right:Ne \l_@@_rfs_department_tl
              { \exp_not:N \@@_rfs_error_text:n { \exp_not:n {##1} } }
          }
          {
            \DTLgetvalueforkey{\l_@@_rfs_institution_name_tl}
              {name}{institution}{id}{##1}
            \@@_institution_abbreviation_or_name:nN
              {##1} \l_@@_rfs_institution_abbreviation_tl
            \@@_rfs_register_affiliation:n
              { \l_@@_rfs_institution_affiliation_tl }
            \DTLifnullorempty{\l_@@_rfs_institution_name_tl}
            {
              \tl_set:NV \l_@@_rfs_institution_name_tl
                \l_@@_rfs_affiliation_name_tl
            }
            { }
            \DTLifnullorempty{\l_@@_rfs_institution_abbreviation_tl}
            {
              \tl_set:NV \l_@@_rfs_institution_abbreviation_tl
                \l_@@_rfs_affiliation_abbreviation_tl
            }
            { }
            \tl_put_right:NV \l_@@_rfs_department_tl
              \l_@@_rfs_institution_abbreviation_tl
            \tl_set:Nn \l_tmpa_tl {##1}
            \seq_if_in:NVF \l_@@_rfs_institution_seq \l_tmpa_tl
            {
              \seq_put_right:NV \l_@@_rfs_institution_seq \l_tmpa_tl
              \prop_put:NVV \l_@@_rfs_institution_name_prop
                \l_tmpa_tl \l_@@_rfs_institution_name_tl
              \prop_put:NVV \l_@@_rfs_institution_abbreviation_prop
                \l_tmpa_tl \l_@@_rfs_institution_abbreviation_tl
              \prop_put:NVV
                \l_@@_rfs_institution_affiliation_abbreviation_prop
                \l_tmpa_tl \l_@@_rfs_affiliation_abbreviation_tl
            }
          }
        }
      }
      {
        \msg_warning:nnee { dfg } { requested-staff-unresolved-institution }
          { \l_@@_rfs_project_tl } { \l_@@_rfs_ref_institution_tl }
        \tl_set:Ne \l_@@_rfs_department_tl
        {
          \exp_not:N \SetCell { bg=tableNoValue }
          \exp_not:N \@@_rfs_error_text:n
            { \exp_not:V \l_@@_rfs_ref_institution_tl }
        }
      }
    }
  }
}

\cs_new_protected:Npn \@@_rfs_make_cell:NnN #1#2#3
{
  \tl_if_blank:VTF #1
  {
    \@@_rfs_warn_missing:n {#2}
    \tl_set:Nn #3 { \SetCell{bg=tableNoValue}\@@_rfs_missing_text: }
  }
  { \tl_set:NV #3 #1 }
}

\cs_new_protected:Npn \@@_rfs_make_name_cell:
{
  \bool_set_false:N \l_@@_rfs_name_incomplete_bool
  \str_if_eq:VnTF \l_@@_rfs_lastname_tl { TBA }
  {
    \tl_if_blank:VT \l_@@_rfs_position_tl
    {
      \@@_rfs_warn_missing:n { position }
      \tl_set:Nn \l_@@_rfs_position_tl { \@@_rfs_missing_text: }
      \bool_set_true:N \l_@@_rfs_name_incomplete_bool
    }
    \tl_set:Nn \l_@@_rfs_plain_name_tl { TBA }
    \tl_set:Nn \l_@@_rfs_description_name_tl { TBA }
    \tl_set:Ne \l_tmpa_tl
      {
        TBA
        \exp_not:N \newline
        (\exp_not:V \l_@@_rfs_position_tl)
      }
  }
  {
    \tl_if_blank:VT \l_@@_rfs_lastname_tl
    {
      \@@_rfs_warn_missing:n { lastname~or~resolvable~ref-person-id }
      \tl_set:Nn \l_@@_rfs_lastname_tl { \@@_rfs_error_text:n {name} }
      \bool_set_true:N \l_@@_rfs_name_incomplete_bool
    }
    \tl_if_blank:VT \l_@@_rfs_firstname_tl
    {
      \@@_rfs_warn_missing:n { firstname }
      \tl_set:Nn \l_@@_rfs_firstname_tl { \@@_rfs_missing_text: }
      \bool_set_true:N \l_@@_rfs_name_incomplete_bool
    }
    \tl_if_blank:VT \l_@@_rfs_position_tl
    {
      \@@_rfs_warn_missing:n { position }
      \tl_set:Nn \l_@@_rfs_position_tl { \@@_rfs_missing_text: }
      \bool_set_true:N \l_@@_rfs_name_incomplete_bool
    }
    \tl_set:Ne \l_@@_rfs_plain_name_tl
      {
        \exp_not:V \l_@@_rfs_lastname_tl,\exp_not:N \space
        \exp_not:V \l_@@_rfs_firstname_tl
      }
    \tl_clear:N \l_@@_rfs_description_name_tl
    \tl_if_blank:VF \l_@@_rfs_degree_tl
      {
        \tl_put_right:Ne \l_@@_rfs_description_name_tl
          { \exp_not:V \l_@@_rfs_degree_tl \exp_not:N \space }
      }
    \tl_put_right:Ne \l_@@_rfs_description_name_tl
    {
      \exp_not:V \l_@@_rfs_firstname_tl \exp_not:N \space
      \exp_not:V \l_@@_rfs_lastname_tl
    }
    \tl_set:NV \l_tmpa_tl \l_@@_rfs_plain_name_tl
    \tl_if_blank:VF \l_@@_rfs_degree_tl
    {
      \tl_put_right:Ne \l_tmpa_tl
        { ,\exp_not:N \space \exp_not:V \l_@@_rfs_degree_tl }
    }
    \tl_put_right:Ne \l_tmpa_tl
    {
      \exp_not:N \newline
      (\exp_not:V \l_@@_rfs_position_tl)
    }
    \bool_if:NT \l_@@_rfs_person_resolved_bool
    {
      \str_if_eq:VnT \l_@@_rfs_funding_status_tl { existing }
      {
        \tl_set:Ne \l_tmpa_tl
        {
          \exp_not:N \textbf { \exp_not:V \l_@@_rfs_lastname_tl },
          \exp_not:N \space \exp_not:V \l_@@_rfs_firstname_tl
        }
        \tl_if_blank:VF \l_@@_rfs_degree_tl
        {
          \tl_put_right:Ne \l_tmpa_tl
            { ,\exp_not:N \space \exp_not:V \l_@@_rfs_degree_tl }
        }
        \tl_put_right:Ne \l_tmpa_tl
        {
          \exp_not:N \newline
          (\exp_not:V \l_@@_rfs_position_tl)
        }
      }
    }
  }
  \bool_if:NF \l_@@_rfs_person_resolved_bool
  {
    \tl_if_blank:VF \l_@@_rfs_ref_person_tl
    {
      \bool_set_true:N \l_@@_rfs_name_incomplete_bool
      \tl_put_right:Ne \l_tmpa_tl
      {
        \exp_not:N \space
        \exp_not:N \@@_rfs_error_text:n
          { \exp_not:V \l_@@_rfs_ref_person_tl }
      }
    }
  }
  \tl_clear:N \l_@@_rfs_name_cell_tl
  \bool_if:NT \l_@@_rfs_name_incomplete_bool
  { \tl_put_right:Nn \l_@@_rfs_name_cell_tl { \SetCell{bg=tableNoValue} } }
  \bool_if:NTF \l_@@_rfs_person_resolved_bool
  {
    \tl_put_right:Ne \l_@@_rfs_name_cell_tl
    {
      \exp_not:N \hyperlink { pi:\exp_not:V \l_@@_rfs_ref_person_tl }
      {
        \exp_not:N \textcolor { referencePI }
        {
          \exp_not:N \dfgShowCalculatedTag{RequestedFundingStaffTable}
            {RequestedFundingStaff,person}
            {\exp_not:V \l_tmpa_tl}
        }
      }
    }
  }
  {
    \tl_put_right:Ne \l_@@_rfs_name_cell_tl
    {
      \exp_not:N \dfgShowCalculatedTag{RequestedFundingStaffTable}
        {RequestedFundingStaff,person}
        {\exp_not:V \l_tmpa_tl}
    }
  }
}

\cs_new_protected:Npn \@@_rfs_render_row:nnnN #1#2#3#4
{
  \int_incr:N \l_@@_rfs_display_number_int
  \@@_rfs_resolve_person:
  \@@_rfs_resolve_organisation:
  \@@_rfs_make_name_cell:
  \@@_rfs_make_cell:NnN \l_@@_rfs_field_tl
    { field-of-research } \l_@@_rfs_field_cell_tl
  \tl_if_blank:VF \l_@@_rfs_field_tl
  {
    \tl_set:Ne \l_@@_rfs_field_cell_tl
    {
      \exp_not:N \dfgShowTag
        {\exp_not:V \l_@@_rfs_project_tl/
         \int_use:N \l_@@_rfs_display_number_int}
        {field-of-research}{\exp_not:V \l_@@_rfs_field_cell_tl}
        [RequestedFundingStaff]
    }
  }
  \tl_set:NV \l_@@_rfs_department_cell_tl \l_@@_rfs_department_tl
  \tl_if_in:VnF \l_@@_rfs_department_cell_tl { \SetCell }
  {
    \tl_set:Ne \l_@@_rfs_department_cell_tl
    {
      \exp_not:N \dfgShowCalculatedTag{RequestedFundingStaffTable}
        {RequestedFundingStaff,person,institution,affiliation}
        {\exp_not:V \l_@@_rfs_department_cell_tl}
    }
  }
  \str_if_eq:VnTF \l_@@_rfs_funding_status_tl { requested }
  {
    \tl_set:Nn \l_@@_rfs_commitment_cell_tl
      { \SetCell{bg=tableNoValue} }
    \tl_set:Nn \l_@@_rfs_funding_source_cell_tl
      { \SetCell{bg=tableNoValue} }
  }
  {
    \@@_rfs_make_cell:NnN \l_@@_rfs_commitment_tl
      { commitment } \l_@@_rfs_commitment_cell_tl
    \@@_rfs_make_cell:NnN \l_@@_rfs_funding_source_tl
      { funding-source } \l_@@_rfs_funding_source_cell_tl
    \tl_if_blank:VF \l_@@_rfs_commitment_tl
    {
      \tl_set:Ne \l_@@_rfs_commitment_cell_tl
      {
        \exp_not:N \dfgShowTag
          {\exp_not:V \l_@@_rfs_project_tl/
           \int_use:N \l_@@_rfs_display_number_int}
          {commitment}{\exp_not:V \l_@@_rfs_commitment_cell_tl}
          [RequestedFundingStaff]
      }
    }
    \tl_if_blank:VF \l_@@_rfs_funding_source_tl
    {
      \tl_set:Ne \l_@@_rfs_funding_source_cell_tl
      {
        \exp_not:N \dfgShowTag
          {\exp_not:V \l_@@_rfs_project_tl/
           \int_use:N \l_@@_rfs_display_number_int}
          {funding-source}{\exp_not:V \l_@@_rfs_funding_source_cell_tl}
          [RequestedFundingStaff]
      }
    }
  }
  \str_if_eq:VnTF \l_@@_rfs_funding_status_tl { existing }
  {
    \tl_set:Nn \l_@@_rfs_category_cell_tl
      { \SetCell{bg=tableNoValue} }
  }
  {
    \tl_if_blank:VTF \l_@@_rfs_category_tl
    {
      \@@_rfs_warn_missing:n { category }
      \tl_set:Nn \l_@@_rfs_category_cell_tl
        { \SetCell{bg=tableNoValue}\@@_rfs_missing_text: }
    }
    {
      \prop_get:NVNTF \g_@@_dfg_category_names_prop
        \l_@@_rfs_category_tl \l_@@_rfs_category_cell_tl
      { }
      {
        \tl_set:Ne \l_@@_rfs_category_cell_tl
          { \exp_not:N \@@_rfs_error_text:n { \exp_not:V \l_@@_rfs_category_tl } }
      }
    }
  }
  \tl_if_in:VnF \l_@@_rfs_category_cell_tl { \SetCell }
  {
    \tl_set:Ne \l_@@_rfs_category_cell_tl
    {
      \exp_not:N \dfgShowCalculatedTag{RequestedFundingStaffTable}
        {RequestedFundingStaff,person}
        {\exp_not:V \l_@@_rfs_category_cell_tl}
    }
  }
  \int_compare:nNnTF {#1} = {1}
  {
    \tl_set:Ne \l_@@_rfs_group_cell_tl
    {
      \exp_not:N \SetCell [ r=#2 ] { l }
      { \exp_not:n {#3} } &
    }
  }
  { \tl_set:Nn \l_@@_rfs_group_cell_tl { & } }
  \tl_put_right:Ne \l_@@_rfs_table_body_tl
  {
    \exp_not:V \l_@@_rfs_group_cell_tl
    \int_use:N \l_@@_rfs_display_number_int
    & \exp_not:V \l_@@_rfs_name_cell_tl
    & \exp_not:V \l_@@_rfs_field_cell_tl
    & \exp_not:V \l_@@_rfs_department_cell_tl
    & \exp_not:V \l_@@_rfs_commitment_cell_tl
    & \exp_not:V \l_@@_rfs_category_cell_tl
    & \exp_not:V \l_@@_rfs_funding_source_cell_tl
    \\
  }
  \tl_if_blank:VT \l_@@_rfs_description_tl
  {
    \@@_rfs_warn_missing:n { description }
    \tl_set:Nn \l_@@_rfs_description_tl
      { \textcolor{error}{Description~not~provided.} }
  }
  \tl_put_right:Ne #4
  {
    \par\noindent
    \exp_not:N \textbf
      { \int_use:N \l_@@_rfs_display_number_int.\space
        \exp_not:N \dfgShowCalculatedTag{RequestedFundingStaffTable}
          {RequestedFundingStaff,person}
          {\exp_not:V \l_@@_rfs_description_name_tl} }
    \quad
    \exp_not:N \dfgShowTag
      {\exp_not:V \l_@@_rfs_project_tl/
       \int_use:N \l_@@_rfs_display_number_int}
      {description}{\exp_not:V \l_@@_rfs_description_tl}
      [RequestedFundingStaff]
    \par
  }
}

\cs_new_protected:Npn \@@_rfs_render_group:NnN #1#2#3
{
  \seq_map_indexed_inline:Nn #1
  {
    \@@_rfs_row_clear:
    \keys_set:nn { dfg / requested-funding-staff-row } {##2}
    \@@_rfs_render_row:nnnN {##1} { \seq_count:N #1 } {#2} #3
  }
}

\cs_new_protected:Npn \@@_rfs_render_status:NNnN #1#2#3#4
{
  \int_compare:nNnT { \seq_count:N #1 + \seq_count:N #2 } > {0}
  {
    \tl_put_right:Nn \l_@@_rfs_table_body_tl
    {
      \SetRow{bg=tableHeadingsBGalt,font=\footnotesize\bfseries}
      \SetCell[c=8]{l} #3 & & & & & & & \\*
    }
    \@@_rfs_render_group:NnN #1 { Research~staff } #4
    \seq_if_empty:NF #1
    {
      \seq_if_empty:NF #2
      {
        \tl_put_right:Nn \l_@@_rfs_table_body_tl
          { \SetHline{-}{tableOuterLines,0.5pt} }
      }
    }
    \@@_rfs_render_group:NnN #2 { Non-research~staff } #4
  }
}

\cs_new_protected:Npn \@@_rfs_print_legend:
{
  \bool_lazy_or:nnT
    { ! \seq_if_empty_p:N \l_@@_rfs_institution_seq }
    { ! \seq_if_empty_p:N \l_@@_rfs_affiliation_seq }
  {
    \par\smallskip\noindent
    \group_begin:
    \footnotesize
    \seq_if_empty:NF \l_@@_rfs_institution_seq
    {
      \textbf{Institutions:}\space
      \seq_map_indexed_inline:Nn \l_@@_rfs_institution_seq
      {
        \int_compare:nNnF {##1} = {1} {;\space}
        \tl_set:Nn \l_tmpa_tl {##2}
        \prop_get:NVN \l_@@_rfs_institution_name_prop
          \l_tmpa_tl \l_tmpb_tl
        \prop_get:NVN \l_@@_rfs_institution_abbreviation_prop
          \l_tmpa_tl \l_tmpd_tl
        \prop_get:NVN \l_@@_rfs_institution_affiliation_abbreviation_prop
          \l_tmpa_tl \l_tmpc_tl
        \textbf{\dfgShowCalculatedTag{institutionLabel}{institution}
          {\l_tmpd_tl}}:~
        \dfgShowTag{##2}{name}{\l_tmpb_tl}[institution]\space
        (\dfgShowCalculatedTag{affiliationLabel}{affiliation}
          {\l_tmpc_tl})
      }
      .\space
    }
    \seq_if_empty:NF \l_@@_rfs_affiliation_seq
    {
      \textbf{Affiliations:}\space
      \seq_map_indexed_inline:Nn \l_@@_rfs_affiliation_seq
      {
        \int_compare:nNnF {##1} = {1} {;\space}
        \tl_set:Nn \l_tmpa_tl {##2}
        \prop_get:NVN \l_@@_rfs_affiliation_abbreviation_prop
          \l_tmpa_tl \l_tmpb_tl
        \prop_get:NVN \l_@@_rfs_affiliation_name_prop
          \l_tmpa_tl \l_tmpc_tl
        \textbf{\dfgShowCalculatedTag{affiliationLabel}{affiliation}
          {\l_tmpb_tl}}:~
        \dfgShowTag{##2}{name}{\l_tmpc_tl}[affiliation]
      }
      .
    }
    \par
    \group_end:
  }
}

\cs_new_protected:Npn \@@_rfs_no_data:n #1
{
  \msg_warning:nnn { dfg } { requested-staff-no-data } {#1}
  \par\noindent
  \textcolor{tableNoValue!55!black}
    {No~staff~data~have~been~provided~for~this~project.}
  \par
}

\NewDocumentCommand{\RequestedFundingStaffTable}{m}
{
  \group_begin:
  \tl_set:Nn \l_@@_rfs_project_tl {#1}
  \tl_clear:N \l_@@_rfs_project_status_tl
  \DTLifdbexists{project}
  {
    \DTLgetvalueforkey{\l_@@_rfs_project_status_tl}
      {project-status}{project}{id}{#1}
  }
  { }
  \str_if_eq:VnTF \l_@@_rfs_project_status_tl { E }
  {
    \tl_set:Nn \l_@@_rfs_existing_group_label_tl {Existing~staff}
    \tl_set:Nn \l_@@_rfs_requested_group_label_tl
      {Staff~funded~with~approved~grant~money}
    \tl_set:Nn \l_@@_rfs_existing_description_heading_tl
      {Job~descriptions~of~staff~(supported~through~existing~funds):}
    \tl_set:Nn \l_@@_rfs_requested_description_heading_tl
      {Job~descriptions~of~staff~(funded~with~approved~grant~money):}
  }
  {
    \tl_set:Nn \l_@@_rfs_existing_group_label_tl {Existing~staff}
    \tl_set:Nn \l_@@_rfs_requested_group_label_tl {Requested~staff}
    \tl_set:Nn \l_@@_rfs_existing_description_heading_tl
      {Job~descriptions~of~staff~for~the~proposed~funding~period~
        (supported~through~existing~funds):}
    \tl_set:Nn \l_@@_rfs_requested_description_heading_tl
      {Job~descriptions~of~staff~for~the~proposed~funding~period~
        (requested~funds):}
  }
  \seq_clear:N \l_@@_rfs_existing_research_seq
  \seq_clear:N \l_@@_rfs_existing_nonresearch_seq
  \seq_clear:N \l_@@_rfs_requested_research_seq
  \seq_clear:N \l_@@_rfs_requested_nonresearch_seq
  \seq_clear:N \l_@@_rfs_institution_seq
  \seq_clear:N \l_@@_rfs_affiliation_seq
  \prop_clear:N \l_@@_rfs_duplicate_prop
  \prop_clear:N \l_@@_rfs_institution_name_prop
  \prop_clear:N \l_@@_rfs_institution_abbreviation_prop
  \prop_clear:N \l_@@_rfs_institution_affiliation_abbreviation_prop
  \prop_clear:N \l_@@_rfs_affiliation_abbreviation_prop
  \prop_clear:N \l_@@_rfs_affiliation_name_prop
  \tl_clear:N \l_@@_rfs_table_body_tl
  \tl_clear:N \l_@@_rfs_existing_descriptions_tl
  \tl_clear:N \l_@@_rfs_requested_descriptions_tl
  \DTLifdbexists{RequestedFundingStaff}
  {
    \DTLforeach[\DTLiseq{#1}{\pRFSProject}]
      {RequestedFundingStaff}
    {
      \pRFSProject=ref-project-id,
      \pRFSFundingStatus=funding-status,
      \pRFSStaffType=staff-type,
      \pRFSRefPerson=ref-person-id,
      \pRFSFirstname=firstname,
      \pRFSLastname=lastname,
      \pRFSDegree=academic-degree,
      \pRFSPosition=positionText,
      \pRFSField=field-of-research,
      \pRFSRefInstitution=ref-institution-id,
      \pRFSRefAffiliation=ref-affiliation-id,
      \pRFSDepartment=department,
      \pRFSCommitment=commitment,
      \pRFSCategory=category,
      \pRFSFundingSource=funding-source,
      \pRFSDescription=description
    }
    { \@@_rfs_collect_current: }
    \int_set:Nn \l_@@_rfs_record_count_int
    {
      \seq_count:N \l_@@_rfs_existing_research_seq
      + \seq_count:N \l_@@_rfs_existing_nonresearch_seq
      + \seq_count:N \l_@@_rfs_requested_research_seq
      + \seq_count:N \l_@@_rfs_requested_nonresearch_seq
    }
    \int_compare:nNnTF { \l_@@_rfs_record_count_int } = {0}
    { \@@_rfs_no_data:n {#1} }
    {
      \int_zero:N \l_@@_rfs_display_number_int
      \@@_rfs_render_status:NNnN
        \l_@@_rfs_existing_research_seq
        \l_@@_rfs_existing_nonresearch_seq
        {\tl_use:N \l_@@_rfs_existing_group_label_tl}
        \l_@@_rfs_existing_descriptions_tl
      \@@_rfs_render_status:NNnN
        \l_@@_rfs_requested_research_seq
        \l_@@_rfs_requested_nonresearch_seq
        {\tl_use:N \l_@@_rfs_requested_group_label_tl}
        \l_@@_rfs_requested_descriptions_tl
      \begin{tblr}[
        theme=requestedFundingStaff,
        long,
        postsep=0pt,
        expand=\l_@@_rfs_table_body_tl
      ]{
        colsep=2pt,
        width=\textwidth,
        hline{1,Z}={1pt,fg=tableOuterLines},
        hline{2}={1pt,fg=tableOuterLines},
        stretch=.8,
        rowsep=.500pt,
        colspec={X[1.1,l]
                 X[.42,c] % no
                 X[2.18,l] % Name
                 X[1.4,l] % field
                 X[1.5,c] % department
                 X[1.05,c] % proj com.
                 X[1.1,c] % category
                 X[.95,c] % funding
                 },
        column{1}={font=\footnotesize\bfseries,valign=m},
        column{2}={halign=c},
        rows={font=\footnotesize,valign=t},
        rowhead=1,
        row{1}={bg=tableHeadingsBG,fg=tableHeadingsFont,
          font=\scriptsize\bfseries,guard},
        cell{1}{1-8}={halign=c,valign=m}
      }
        & {No.}
        & {Name,~academic\\degree,~position}
        & {Field~of\\research}
        & {Departm.~of\\(non-)univers.\\institution}
        & {Project\\commitm.~(h/wk)}
        & Category
        & {Funding\\source} \\
        \l_@@_rfs_table_body_tl
      \end{tblr}
      \@@_rfs_print_legend:
      \tl_if_empty:NF \l_@@_rfs_existing_descriptions_tl
      {
        \par\medskip\noindent
        {\tl_use:N \l_@@_rfs_existing_description_heading_tl}\par\nobreak
        {\normalfont\normalsize\setlength{\parskip}{0pt}
          \tl_use:N \l_@@_rfs_existing_descriptions_tl}
      }
      \tl_if_empty:NF \l_@@_rfs_requested_descriptions_tl
      {
        \par\medskip\noindent
        {\tl_use:N \l_@@_rfs_requested_description_heading_tl}\par\nobreak
        {\normalfont\normalsize\setlength{\parskip}{0pt}
          \tl_use:N \l_@@_rfs_requested_descriptions_tl}
      }
    }
  }
  { \@@_rfs_no_data:n {#1} }
  \group_end:
}
%    \end{macrocode}
%    \begin{macrocode}

\NewDocumentCommand{\getTotalSumRequestedFunds}{O{RequestedFunding}mm}{
  % #1: database
  % #2: project
  % #3: year
  \def\tmpLocalDB{#1}%
  \DTLifdbexists{\tmpLocalDB}{%
    \@@_funding_sum_set:Nnnnn \TotalSumRequestedFunds
      {#1}{#2}{__ALL__}{#3}
    \@@_show_calculated_number:nnN
      {getTotalSumRequestedFunds}{#1}
      \TotalSumRequestedFunds
  }{
  	\texttt{\color{error}XXX}
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
}


\NewDocumentCommand{\getSumExistingFunds}{O{RequestedAndExistingFundingDirectCosts}mm}{
  % #1: database
  % #2: project
  % #3: year
  \def\tmpLocalDB{#1}%
  \DTLifdbexists{\tmpLocalDB}{
    \@@_funding_sum_set:Nnnnn \SumExistingFunds
      {#1}{#2}{__ALL__}{#3}

    \@@_show_calculated_number:nnN
      {getSumExistingFunds}{#1}
      \SumExistingFunds
  }{
  	\texttt{\color{error}XXX}
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
}


\providecommand{\SumRequestedFunds}{0}

\NewDocumentCommand{\getSumRequestedFunds}{ O{RequestedFunding} m m m }{%
  \DTLifdbexists{#1}{%
    \@@_funding_sum_set:Nnnnn \SumRequestedFunds {#1}{#2}{#3}{#4}%
    \@@_show_calculated_number:nnN
      {getSumRequestedFunds}{#1}
      \SumRequestedFunds
  }{%
  	\texttt{\color{error}XXX}%
  	\msg_warning:nne { dfg } { database-not-found } { #1 }%
  }%
}
\NewDocumentCommand{\dfgCheckIfZeroShowCategory}{ O{RequestedFunding} m m }
{
  % #1: database
  % #2: project
  % #3: category/type
  \def\tmpLocalDB{#1}
  \DTLifdbexists{\tmpLocalDB}{
    \@@_funding_sum_set:Nnnnn \SumRequestedFunds {#1}{#2}{#3}
      {sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
  	\fp_compare:nNnT { \SumRequestedFunds } = {0}
  	{ \tl_clear:c {l__tmp_body_#3_tl }}
  }
  {
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
}
%    \end{macrocode}
% This is for |Requested funding for direct costs fo the new funding period| and
% is partially data from new key-values and partially it has to be reused.
%    \begin{macrocode}
\NewDocumentCommand{\RequestedAndExistingFundingDirectCostsTable}{m}
{
  % #1: project
  \def\tmpLocalDB{RequestedAndExistingFundingDirectCosts}%
  \DTLifdbexists{\tmpLocalDB}{%
  	\tl_clear:N \l__tmp_body_costs_tl
  	\DTLforeach[\DTLiseq{\pProject}{#1}]{\tmpLocalDB}{
  		\pProject=ref-project-id,
  		\pAffiliation=ref-affiliation-id,
  		\pFinancedBy=financed-by,
  		\pSumYearOne=sum-year1,
  		\pSumYearTwo=sum-year2,
  		\pSumYearThree=sum-year3,
  		\pSumYearFour=sum-year4,
  		\pSumYearFive=sum-year5
  	}{
		\DTLaddall{\tmpHorizontalSum}{
  			\pSumYearOne,
  			\pSumYearTwo,
  			\pSumYearThree,
  			\pSumYearFour,
  			\pSumYearFive
  		}

  		\tl_put_right:Ne \l__tmp_body_costs_tl
  		{
  			\str_if_eq:VnTF { \pAffiliation }  { other-funds }
  			{ Other }
      { \getEntry[affiliation]{\pAffiliation}{name} : } ~
      existing~ funds~ from~
      % Freeze the database value without expanding commands such as \RWTH,
      % whose trailing \xspace must only run when the completed cell is typeset.
      \dfgShowTag{\pProject/\pAffiliation}{financed-by}
        {\exp_not:V \pFinancedBy}[\tmpLocalDB]
      \printMarginalia{\dfgShowCalculatedTag
        {RequestedAndExistingFundingDirectCostsTable}{\tmpLocalDB}
        {\@@_show_eur:n{\tmpHorizontalSum}}}
      & \dfgShowTag{\pProject/\pAffiliation}{sum-year1}
          {\@@_show_eur:n{\pSumYearOne}}[\tmpLocalDB]
      & \dfgShowTag{\pProject/\pAffiliation}{sum-year2}
          {\@@_show_eur:n{\pSumYearTwo}}[\tmpLocalDB]
      & \dfgShowTag{\pProject/\pAffiliation}{sum-year3}
          {\@@_show_eur:n{\pSumYearThree}}[\tmpLocalDB]
      & \dfgShowTag{\pProject/\pAffiliation}{sum-year4}
          {\@@_show_eur:n{\pSumYearFour}}[\tmpLocalDB]
      & \dfgShowTag{\pProject/\pAffiliation}{sum-year5}
          {\@@_show_eur:n{\pSumYearFive}}[\tmpLocalDB] \\
  		}
  	}
  	\tl_put_right:Ne \l__tmp_body_costs_tl
  	{
  		\SetHline{-}{tableOuterLines,0.5pt}
  		\SetRow{belowsep=5pt}
  		Sum~ of~ existing~ funds
  		\printMarginalia{%
  			\getSumExistingFunds{#1}
  			{sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
  		}
  		& \getSumExistingFunds{#1}{sum-year1}
  		& \getSumExistingFunds{#1}{sum-year2}
  		& \getSumExistingFunds{#1}{sum-year3}
  		& \getSumExistingFunds{#1}{sum-year4}
  		& \getSumExistingFunds{#1}{sum-year5} \\
  	}

  	\begin{tblr}[
  			theme=main,
  			long,
  			expand=
  			\l__tmp_body_costs_tl,
			remark{Note}={Figures~ in~ EUR},
  		]{
  			% colsep=3pt,
  			colspec = {
  					*{1}{X[4,t]}
  						*{5}{
							@{}X[c,si={table-format=8}]
  						}},
  			rows = {bg=white},
			column{2-6}={guard},
  			row{1}= {guard,bg=tableHeadingsBG},
  			row{Y,Z}= {
  				          %bg=tableHeadingsBGalt,
  				          font={\footnotesize\bfseries}},
  		}

		 & \dfgFundingYear{1}
		 & \dfgFundingYear{2}
		 & \dfgFundingYear{3}
		 & \dfgFundingYear{4}
		 & \dfgFundingYear{5}                                \\

  		\l__tmp_body_costs_tl

  		\SetHline{-}{tableOuterLines,.75pt}
  		%\SetCell{font=\bfseries\footnotesize}
  		Sum~ of~ requested~ funds
  		\printMarginalia{%
  			\getSumRequestedFunds{#1}{costs}
  			{sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
  		}
  		 & \getSumRequestedFunds{#1}{costs}{sum-year1}
  		 & \getSumRequestedFunds{#1}{costs}{sum-year2}
  		 & \getSumRequestedFunds{#1}{costs}{sum-year3}
  		 & \getSumRequestedFunds{#1}{costs}{sum-year4}
  		 & \getSumRequestedFunds{#1}{costs}{sum-year5} \\
  	\end{tblr}
  }{
  	Database~ \texttt{#1}~ missing.
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
}
%    \end{macrocode}
% \subsubsection{Boxes}
%    \begin{macrocode}
\RequirePackage[breakable,fitting,skins,most]{tcolorbox}

\tcbset{
  PIbox/.style={
  		%enhanced, breakable,
  		colback=white, colframe=white,
  		coltitle=black,
  		boxrule=0pt, %arc=2pt,
  		before~ skip=0pt, after~ skip=7pt,
  		before~ upper=\RaggedRight\small,
  		boxsep=0pt,
  		left=0pt, right=0pt, top=7pt, bottom=0pt,
  	},
}

\bool_if:NTF \l_@@_class_final_bool
{\newcommand{\dfgcomment}[2][]{}}
{\NewTotalTColorBox{\dfgcomment}{ O{} m }
  {%
  	nobeforeafter,
  	colupper=black!50!white,
  	coltitle=black!75!white,
  	fonttitle=\fontsize{7}{9}\selectfont\bfseries,
  	colback=black!5!white,
  	colframe=black!15!white,
  	width=\linewidth,
  	%  text height=4cm,
  	breakable,
  	enhanced,
  	left=0pt,right=0pt,
  	top=0pt,bottom=0pt,
  	% text width=\linewidth,
  	fontupper=\fontsize{7}{9}\selectfont,
  	title={Anmerkung~der~DFG},
  	#1
  }{#2}}
%    \end{macrocode}
% defining standard for boxes
%    \begin{macrocode}
\tcbset{
  dfgStyle/.style={%
  		enhanced~ jigsaw,
  		colback       =white,
  		colbacktitle  =tableHeadingsBG,
  		coltitle      =tableHeadingsFont,
  		colframe      =tableOuterLines,
  		%colupper      =tableHeadingsFont,
  		fontupper     =\sffamily,
  		fonttitle     =\bfseries,
  		% after skip   =1em,
  		before        ={\pagebreak[0]},
  		after         ={\nopagebreak},
  		% fonttitle    =\bfseries,
  		%boxrule      =0.5pt,
  		sharp~ corners,
  		toprule      =1pt,
  		rightrule    =0mm,
  		leftrule     =0mm,
  		% drop shadow =rwthGrey,
  		%drop large lifted shadow,
  		width         =\linewidth,
  		bottomrule    =1pt,
  		% draft,
  		left          =2mm,
  		bottom        =0mm,
  		top           =0mm,
  		capture       =minipage,
  	}}
%    \end{macrocode}
%
%    \begin{macrocode}
\NewTotalTColorBox{\dfgBox}{ O{} m }
{%
  dfgStyle,
  nobeforeafter,
  left=0pt,right=0pt,
  top=0pt,bottom=0pt,
  #1
}{#2}
%    \end{macrocode}
% A handy box to aggregate important points, \refEnv{dfgSummaryBox}.
%    \begin{macrocode}
\newtcolorbox{dfgSummaryBox}[1][]{
  dfgStyle,
  top=1mm,
  left=1mm,
  bottom=1mm,
  before={\par},
  after={\par},
  before~ upper={\begin{itemize}[leftmargin=.5cm]%
  		\renewcommand{\labelitemi}{\dfgTargetPoint}%
  		\hypersetup{linkcolor=tableHeadingsFont}%
  		\colorlet{referencePI}{tableHeadingsFont}
  		\colorlet{referenceWP}{tableHeadingsFont}
  		\colorlet{referenceAim}{tableHeadingsFont}
  	},
  after~ upper={\end{itemize}},
  %  height=2.5cm,
  fontupper=\rmfamily,
  % ------ title below.
  width=\linewidth,
  rounded~ corners,
  toprule=1pt,
  rightrule=1pt,
  leftrule=1pt,
  bottomrule=1pt,
  % attach boxed title to bottom center,
  boxed~ title~ style={empty,boxrule=1pt},
  varwidth~ boxed~ title=0.5\linewidth,
  #1
}
%    \end{macrocode}
% Box for anything like the aims section.
%    \begin{macrocode}
\newtcolorbox{dfgBoxEnv}[1][]{
  dfgStyle,
  % top=-1.5mm,
  % left=1mm,
  before={\par},
  #1
}
%    \end{macrocode}
% \subsubsection{New Commands}
% Providing further commands that can and will be used throughout the document
%    \begin{macrocode}
\providecommand{\crc}{Collaborative~ Research~ Centre\xspace}
\providecommand{\dfgLocation}{<Location>\xspace}
\providecommand{\dfgDate}{2026-06-11\xspace} % date when proposal will be turned in
\providecommand{\dfgTitle}{\enquote{\get[meta]{crc}{name}}\xspace}
\providecommand{\InfoTeX}{LuaLaTeX~ (via~ Overleaf).}

% getting the main logo of the CRC
% the filename needs to be adjusted or make this more generic.
\providecommand{\crcLogoPath}{\tl_use:N \l_@@_custom_crc_logo_path_tl}
\providecommand{\affiliationLogoPath}
  {\tl_use:N \l_@@_custom_affiliation_logo_path_tl}

\NewDocumentCommand{\crcLogo}{O{1cm}}{%
  \includegraphics[#1]{\crcLogoPath}}

% same for the affiliation.
\NewDocumentCommand{\affiliationLogo}{O{1cm}}{%
  \includegraphics[#1]{\affiliationLogoPath}}

\keys_define:nn { hrule }
{
  color     .tl_set:N   = \l__hrule_color_tl,
  color     .initial:n  = color@tags@line,
  above     .dim_set:N  = \l__hrule_above_dim,
  above     .initial:n  = 0pt,
  below     .dim_set:N  = \l__hrule_below_dim,
  below     .initial:n  = 0pt,
  thickness .dim_set:N  = \l__hrule_thickness_dim,
  thickness .initial:n  = 0.4pt,
}

\ProvideDocumentCommand{\Hrule}{O{}}
{%
  \group_begin:
  \keys_set:nn { hrule } {#1}%
  \par
  \addvspace{ \l__hrule_above_dim }%
  {\color{ \l__hrule_color_tl }\hrule height \l__hrule_thickness_dim}%
  \addvspace{ \l__hrule_below_dim }%
  \group_end:
}

% remodeling for the titlepage where we use some center-environments
\AtBeginEnvironment{center}{
  \vspace*{-2em}
}
%    \end{macrocode}

%    \begin{macrocode}
\seq_new:N \l_@@_sig_pairs_seq
\tl_new:N  \l_@@_sig_id_tl
\tl_new:N  \l_@@_sig_desc_tl
%    \end{macrocode}
%
% \begin{macro}{\printSignature}
%   |\printSignature[<db>]{ {<id>}{<desc>} {<id>}{<desc>} ... }| --
%   one signature block per |{id}{desc}| pair. |<db>| defaults to
%   |person|. Inside |<desc>| you may use |\theAffiliationOfRoleID|,
%   which is set to the person's |ref-institution-id| before the
%   description is typeset.
%    \begin{macrocode}
\NewDocumentCommand{\printSignature}{ O{person} m }
{
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  {
    \par
    \seq_set_split:Nnn \l_@@_sig_pairs_seq { } {#2}
    \int_compare:nNnT { \seq_count:N \l_@@_sig_pairs_seq } > { 0 }
    { \@@_signature_consume_pairs:n {#1} }
  }
}

\tl_new:N \l_@@_signature_role_id_tl
\tl_new:N \l_@@_signature_role_tl
\tl_new:N \l_@@_signature_role_period_tl

\NewDocumentCommand{\printSignaturesWithRole}{ O{person} m m }
{
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  {
    \DTLifdbexists{#1}
    {
      \DTLforeach*[
        \DTLisinlist{\theFundingPeriodNumeral}{\l_@@_signature_role_period_tl}
        \and
        \DTLisinlist{#2}{\l_@@_signature_role_tl}
      ]{#1}{
        \l_@@_signature_role_id_tl     = id,
        \l_@@_signature_role_tl        = role,
        \l_@@_signature_role_period_tl = period
      }{
        \@@_signature_block:nnn
          {#1}{\l_@@_signature_role_id_tl}{#3}
      }
    }
    { \msg_warning:nne { dfg } { database-not-found } {#1} }
  }
}
%    \end{macrocode}
% \end{macro}
%
%   Pops |{id}{desc}| pairs off |\l_@@_sig_pairs_seq| until empty,
%   typesetting one block per pair.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_signature_consume_pairs:n #1
{
  \seq_pop_left:NN \l_@@_sig_pairs_seq \l_@@_sig_id_tl
  \seq_pop_left:NNTF \l_@@_sig_pairs_seq \l_@@_sig_desc_tl
  {
  	\@@_signature_block:nVV {#1} \l_@@_sig_id_tl \l_@@_sig_desc_tl
  	\seq_if_empty:NF \l_@@_sig_pairs_seq
  	{ \@@_signature_consume_pairs:n {#1} }
  }
  {
  	\msg_warning:nnn { crc-proposal } { signature-odd-args } {#1}
  }
}
\msg_new:nnn { crc-proposal } { signature-odd-args }
{ \printSignature\ in\ db\ '#1':\ odd\ number\ of\ tokens,\ %
  expected\ {id}{desc}\ pairs. }
%    \end{macrocode}
%   Typesets a single signature block for person |#2| in db |#1|
%   with description |#3|. Sets |\theAffiliationOfRoleID| from the
%   row's |ref-institution-id| before expanding |#3|.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_signature_block:nnn #1 #2 #3
{
  \DTLgetvalueforkey{\theAffiliationOfRoleID}{ref-affiliation-id}{#1}{id}{#2}
  \DTLgetvalueforkey{\@@tmpDegree}   {academicdegree}{#1}{id}{#2}
  \DTLgetvalueforkey{\@@tmpFirst}    {firstname}     {#1}{id}{#2}
  \DTLgetvalueforkey{\@@tmpLast}     {lastname}      {#1}{id}{#2}
  \begin{tblr}{
  	            width=\linewidth,
  	            colspec={@{}b{3cm}b{1cm}X[b]@{}},
              }
              {\theCRCaffiliationLocation \\ \dfgDate} &  & \faFileSignature                                       \\
              \SetHline{3-3}{tableOuterLines,1pt}
                                                       &  & {
                                                            \dfgShowTag{#2}{academicdegree}{\@@tmpDegree}[#1]\space
                                                              \textcolor{referencePI}{
                                                              \dfgShowTag{#2}{firstname}{\@@tmpFirst}[#1]\space
                                                              \dfgShowTag{#2}{lastname}{\@@tmpLast}[#1]} \\
  	                                                          #3 } \\
  \end{tblr}
  \par\bigskip
}
\cs_generate_variant:Nn \@@_signature_block:nnn { nVV }
%    \end{macrocode}
% If there are multiple institutions mentioned we want to have a list of all of
% them with their affiliation.
% We are getting the possible list of institutions into one command
% Loop over your list and build the sequence.1
%    \begin{macrocode}
\bool_new:N \l_@@_narrow_bool
\bool_new:N \l_@@_institution_abbreviation_bool
\bool_new:N \l_@@_noaddr_bool
\bool_new:N \l_@@_nozip_bool
\bool_new:N \l_@@_noloc_bool
\bool_new:N \l_@@_has_country_bool
\seq_new:N  \l_@@_inst_ids_seq
\tl_new:N   \l_@@_sep_tl
\tl_new:N   \l_@@_inst_sep_tl

\cs_generate_variant:Nn \seq_set_from_clist:Nn { NV }

\NewDocumentCommand{\dfgInstitutionList}{O{person} m o}
{
 \bool_if:NTF \l_@@_class_fastcompile_project_bool
 { \dfgFastReference{#2} }
 {
 \DTLifdbexists{#1}{
  % --- parse options once ---------------------------------------------
  \clist_if_in:nnTF {#3} {abbreviation}
  { \bool_set_true:N \l_@@_institution_abbreviation_bool }
  { \bool_set_false:N \l_@@_institution_abbreviation_bool }
  \clist_if_in:nnTF {#3} {narrow}
  { \bool_set_true:N  \l_@@_narrow_bool
  	\tl_set:Nn \l_@@_sep_tl      {,~}
  	\tl_set:Nn \l_@@_inst_sep_tl {;~} }
  { \bool_set_false:N \l_@@_narrow_bool
  	\tl_set:Nn \l_@@_sep_tl      {\newline}
  	\tl_set:Nn \l_@@_inst_sep_tl {\par\medskip} }
  \clist_if_in:nnTF {#3} {noaddress}
  { \bool_set_true:N \l_@@_noaddr_bool }{ \bool_set_false:N \l_@@_noaddr_bool }
  \clist_if_in:nnTF {#3} {nozip}
  { \bool_set_true:N \l_@@_nozip_bool }{ \bool_set_false:N \l_@@_nozip_bool }
  \clist_if_in:nnTF {#3} {nolocation}
  { \bool_set_true:N \l_@@_noloc_bool }{ \bool_set_false:N \l_@@_noloc_bool }
  \datatool_if_has_key:nnTF {affiliation}{country}
  { \bool_set_true:N \l_@@_has_country_bool }
  { \bool_set_false:N \l_@@_has_country_bool }

  % --- get list of institution ids for this person --------------------
  \DTLgetvalueforkey{\theInstitutionListValue}{ref-institution-id}{#1}{id}{#2}
  \seq_set_from_clist:NV \l_@@_inst_ids_seq \theInstitutionListValue

  % --- iterate --------------------------------------------------------
  \bool_set_true:N \l_tmpa_bool
  \seq_map_inline:Nn \l_@@_inst_ids_seq
  {
  	\bool_if:NTF \l_tmpa_bool
  	{ \bool_set_false:N \l_tmpa_bool }
  	{ \tl_use:N \l_@@_inst_sep_tl }
  	\_@@_one_institution:n {##1}
  }
}
   {
     Database~ \texttt{#1}~ missing.
     \msg_warning:nne { dfg } { database-not-found }{ #1 }
   }
 }
}

\cs_new_protected:Npn \_@@_one_institution:n #1
{
 \DTLifdbexists{institution}{ \DTLgetvalueforkey{\theAffiliationIDValue}{ref-affiliation-id}{institution}{id}{#1}

  \bool_if:NTF \l_@@_institution_abbreviation_bool
  {
    \@@_institution_abbreviation_or_name:nN
      {#1} \l_tmpa_tl
    \cs_set:Npx \theInstitutionNameValue { \exp_not:V \l_tmpa_tl }
  }
  { \DTLgetvalueforkey{\theInstitutionNameValue}{name}{institution}{id}{#1} }
  \DTLifnullorempty{\theInstitutionNameValue}{}
  {
    \dfgShowTag{#1}{\l_@@_institution_label_field_tl}
      {\theInstitutionNameValue}[institution]
  	\tl_use:N \l_@@_sep_tl
  }

  \DTLgetvalueforkey{\theAffiliationNameValue}{name}{affiliation}{id}{\theAffiliationIDValue}
  \dfgShowTag{\theAffiliationIDValue}{name}
    {\theAffiliationNameValue}[affiliation]

  \bool_if:NF \l_@@_noaddr_bool
  {
  	\tl_use:N \l_@@_sep_tl
  	\DTLgetvalueforkey{\theAffiliationStreetValue}{addressStreet}{affiliation}{id}{\theAffiliationIDValue}
    \dfgShowTag{\theAffiliationIDValue}{addressStreet}
      {\theAffiliationStreetValue}[affiliation]
  }

  \bool_if:NF \l_@@_nozip_bool
  {
  	,~
  	\DTLgetvalueforkey{\theAffiliationZIPValue}{addressZIP}{affiliation}{id}{\theAffiliationIDValue}
    \dfgShowTag{\theAffiliationIDValue}{addressZIP}
      {\theAffiliationZIPValue}[affiliation]
  	\bool_if:NF \l_@@_noloc_bool { ~ }
  }

  \bool_if:NF \l_@@_noloc_bool
  {
  	\bool_if:NT \l_@@_nozip_bool { ,~ }
  	\DTLgetvalueforkey{\theAffiliationLocationValue}{location}{affiliation}{id}{\theAffiliationIDValue}
    \dfgShowTag{\theAffiliationIDValue}{location}
      {\theAffiliationLocationValue}[affiliation]
  	\bool_if:NT \l_@@_has_country_bool
  	{
  		\DTLgetvalueforkey{\theAffiliationCountryValue}{country}{affiliation}{id}{\theAffiliationIDValue}
  		\DTLifnullorempty{\theAffiliationCountryValue}{}
      { ~(\dfgShowTag{\theAffiliationIDValue}{country}
          {\theAffiliationCountryValue}[affiliation]) }
  	}
  }
}
   {
     Database~ \texttt{institution}~ missing.
     \msg_warning:nne { dfg } { database-not-found }{ institution }
   }
}
%    \end{macrocode}
% get all the PIs who have a certain role in the crc this can be e.g.
% 'spokesperson', 'steering-committee-member'. the optional argument is to
% specify the database, which is by default 'person'.
%    \begin{macrocode}
\NewDocumentCommand{\getPIsWithRole}{O{person} m O{}}
{%
  \bool_if:NTF \l_@@_class_fastcompile_bool
  { \dfgItemSkipped{dfgPIsWithRole:~#2} }
  {%
    \DTLifdbexists{#1}
    {
      \def\tmpLocalDB{#1}%
      \DTLsort*{lastname}{#1}%
      \begin{tcbraster}[
          raster~ columns=3,
          raster~ equal~ height=rows,
          raster~ column~ skip=4pt,
          raster~ row~ skip=10pt,
          PIbox,
          #3
        ]
        \DTLforeach*[
          \DTLisinlist{\theFundingPeriodNumeral}{\period}
          \and
          \DTLisinlist{#2}{\role}
        ]{#1}{
          \id     = id,
          \role   = role,
          \period = period
        }{%
          \__getperson_one:n {\id}%
        }%
      \end{tcbraster}
    }
    {
      Database~ \texttt{#1}~ missing.
      \msg_warning:nne { dfg } { database-not-found }{ #1 }
    }
  }
}
%    \end{macrocode}
% In the text you can reference to a PI with the following command.
% The name is highlighted and referenced.
%    \begin{macrocode}
\NewDocumentCommand{\getPI}{s m o} {
  % #1: starred version -> firstname
  % #2: id of PI / person
  % #3: optional text, but reference linked to PI 
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  { \IfNoValueTF{#3}{\dfgFastReference{#2}}{#3} }
  {
  \seq_clear:N \l_tmpa_seq
  \seq_set_from_clist:Nn \l_tmpa_seq {#2}%
  \seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq {
  	\exp_not:n {
  		\group_begin:
  		\DTLgetvalueforkey{\thePersonName}{lastname}{person}{id}{##1}
  		\DTLgetvalueforkey{\thePersonFirstName}{firstname}{person}{id}{##1}
  		\datatool_if_null:NTF {\thePersonName}
  		{ \getEntry[person]{##1}{lastname} %<- just to get the error message 
  			\textcolor{error}{\texttt{<?##1?>}}
  		}
  		{
  			\color{referencePI}\bfseries
  			\IfNoValueTF{#3}%

  			{\hyperlink{pi:##1}{\IfBooleanT{#1}
            {\dfgShowTag{##1}{firstname}{\thePersonFirstName}[person]\space}
            \dfgShowTag{##1}{lastname}{\thePersonName}[person]}}
  			{\hyperlink{pi:##1}{#3}}}
  		\group_end:
  	}}
  \seq_use:Nn \l_tmpb_seq {\addnbthinspace{/}\addthinspace}%
  }
}
%    \end{macrocode}
% Very similarly, we want to get a list of the projects.
%    \begin{macrocode}
\NewDocumentCommand \getProjectColor { m }
{
  \exp_args:Nx \color { project \tl_head:n { #1 } }
}
\tl_new:N \l_@@_project_reference_only_tl

\prg_new_protected_conditional:Npnn \@@_project_if_reference_only:n #1
  { T,F,TF }
{
  \DTLgetvalueforkey{\l_@@_project_reference_only_tl}
    {reference-only}{project}{id}{#1}
  \str_if_eq:VnTF \l_@@_project_reference_only_tl { true }
    { \prg_return_true: }
    { \prg_return_false: }
}

\cs_new_protected:Npn \@@_project_reference_only_indicator:
{
  \bool_if:NTF \l_@@_former_project_compact_bool
  {
    \bool_gset_true:N \g_@@_former_project_seen_bool
    {\normalfont\normalcolor\textsuperscript{*}}
  }
  {
    \nobreakspace
    {\normalfont\normalcolor(former~project)}
  }
}

% Project references read naturally in prose but need a compact delimiter in
% narrow table cells.  Keep the two container variants centralized so
% \cs{getProject}, \cs{getProjectPI}, and focused-project fallbacks cannot
% diverge.
\cs_new_protected:Npn \@@_project_reference_seq_use:N #1
{
  \bool_if:NTF \g_@@_tblr_inside_bool
    { \seq_use:Nn #1 {\addnbthinspace/\addthinspace} }
    { \seq_use:Nnnn #1 {~and~} {,~} {,~and~} }
}

\cs_new_protected:Npn \@@_project_reference_clist_use:N #1
{
  \bool_if:NTF \g_@@_tblr_inside_bool
    { \clist_use:Nn #1 {\addnbthinspace/\addthinspace} }
    { \clist_use:Nnnn #1 {~and~} {,~} {,~and~} }
}

\cs_new_protected:Npn \@@_get_project_compact:nn #1#2 {
  % #1: id of project
  % #2: optional text, but reference linked to project
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  {
    \seq_set_from_clist:Nn \l_tmpa_seq {#1}
    \seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq
    {
      \exp_not:n
      { \IfNoValueTF{#2}{\dfgFastReference{##1}}{#2} }
    }
    \@@_project_reference_seq_use:N \l_tmpb_seq
  }
  {
  \seq_clear:N \l_tmpa_seq
  \seq_set_from_clist:Nn \l_tmpa_seq {#1}%
  \seq_set_map:NNn \l_tmpb_seq \l_tmpa_seq {
  	\exp_not:n {
  		\group_begin:
  		\DTLgetvalueforkey{\theProjectNumber}{number}{project}{id}{##1}
  		\datatool_if_null:NTF {\theProjectNumber}
  		{ \getEntry[project]{##1}{number} %<- just to get the error message 
  			\textcolor{error}{\texttt{<?##1?>}}
  		}{
  			\bfseries%
  			\getProjectColor{##1}%
        \@@_project_if_reference_only:nTF {##1}
        {
          \IfNoValueTF{#2}
            {\dfgShowTag{##1}{number}{\theProjectNumber}[project]}
            {#2}%
          \@@_project_reference_only_indicator:
        }
        {
          \IfNoValueTF{#2}%
          {
            \bool_if:NTF \l_@@_class_cv_bool
              { \dfgShowTag{##1}{number}{\theProjectNumber}[project] }
              { \hyperlink{project:##1}
                  {\dfgShowTag{##1}{number}{\theProjectNumber}[project]} }
          }%
          {
            \bool_if:NTF \l_@@_class_cv_bool
              { #2 }
              { \hyperlink{project:##1}{#2} }
          }%
        }
  		}
  		\group_end:
  	}}%
  \@@_project_reference_seq_use:N \l_tmpb_seq
  }
}

\NewDocumentCommand{\getProject}{m o}
{
  \bool_if:NTF \l_@@_custom_project_pi_once_per_section_bool
    { \@@_get_project_with_people:nnn {\BooleanFalse} {#1} {#2} }
    { \@@_get_project_compact:nn {#1} {#2} }
}

\int_new:N \g_@@_project_count_all_int
\prop_new:N \g_@@_project_count_area_prop
\tl_new:N  \l_@@_project_count_id_tl
\tl_new:N  \l_@@_project_count_area_tl
\tl_new:N  \l_@@_project_count_status_tl
\tl_new:N  \l_@@_project_count_consider_for_lists_tl
\tl_new:N  \l_@@_project_count_reference_only_tl

\cs_new_protected:Npn \@@_project_count_increment:n #1
{
  \int_gincr:N \g_@@_project_count_all_int
  \tl_set:Nx \l_tmpa_tl { \tl_upper_case:n {#1} }
  \prop_get:NVNTF \g_@@_project_count_area_prop
    \l_tmpa_tl \l_tmpb_tl
    {
      \prop_gput:NVx \g_@@_project_count_area_prop \l_tmpa_tl
        { \int_eval:n { \l_tmpb_tl + 1 } }
    }
    { \prop_gput:NVn \g_@@_project_count_area_prop \l_tmpa_tl { 1 } }
}

\cs_new_protected:Npn \@@_project_count_build:
{
  \int_gzero:N \g_@@_project_count_all_int
  \prop_gclear:N \g_@@_project_count_area_prop
  \DTLifdbexists{project}
  {
    \DTLifhaskey { project } { project-area }
      { }
      { \DTLaddcolumn { project } { project-area } }
    \DTLforeach*{project}
    {
      \l_@@_project_count_id_tl                 = id,
      \l_@@_project_count_area_tl               = project-area,
      \l_@@_project_count_status_tl             = project-status,
      \l_@@_project_count_consider_for_lists_tl = consider-for-lists,
      \l_@@_project_count_reference_only_tl     = reference-only
    }
    {
      \bool_lazy_all:nT
      {
        { \str_if_eq_p:Vn \l_@@_project_count_consider_for_lists_tl { true } }
        { \str_if_eq_p:Vn \l_@@_project_count_reference_only_tl { false } }
        {
          \bool_lazy_or_p:nn
            { \str_if_eq_p:Vn \l_@@_project_count_status_tl { C } }
            { \str_if_eq_p:Vn \l_@@_project_count_status_tl { N } }
        }
      }
      {
        \DTLifnullorempty{\l_@@_project_count_area_tl}
          {
            \tl_set:Nx \l_@@_project_count_area_tl
              { \tl_head:V \l_@@_project_count_id_tl }
          }
          { }
        \tl_trim_spaces:N \l_@@_project_count_area_tl
        \exp_args:NV \@@_project_count_increment:n
          \l_@@_project_count_area_tl
      }
    }
  }
  { \msg_warning:nnn { dfg } { database-not-found } { project } }
  \bool_gset_true:N \g_@@_project_count_ready_bool
}

\NewDocumentCommand{\getProjectCount}{o}
{
  \bool_if:NF \g_@@_project_count_ready_bool
    { \@@_project_count_build: }
  \dfgShowCalculatedTag{getProjectCount}{project}
  {
    \IfNoValueTF{#1}
      { \int_use:N \g_@@_project_count_all_int }
      {
        \tl_set:Nx \l_tmpa_tl { \tl_upper_case:n {#1} }
        \prop_get:NVNTF \g_@@_project_count_area_prop
          \l_tmpa_tl \l_tmpb_tl
          { \tl_use:N \l_tmpb_tl }
        {
          \msg_warning:nnn { dfg } { invalid-project-count-area } {#1}
          0
        }
      }
  }
}
\clist_new:N \l_@@_person_project_clist
\clist_new:N \l_@@_project_id_clist
\clist_new:N \l_@@_project_number_clist

\NewDocumentCommand{\getPIProject}{s m}{
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  { \dfgFastReference{#2} }
  {
  %
  %  • Argument #1  (optional *‑star)  
  %      – if present, the PI’s *first name* is printed before the last name;  
  %        if the star is omitted only the last name is printed.  
  %
  %  • Argument #2  (mandatory)  
  %      – a comma‑separated list of *person‑IDs* (the field “id” in your
  %        “person” datatool table).  
  %        Example:  `\getPIProject*{per1,per2}`.
  %
  %  What the macro does (high‑level description)  
  %  --------------------------------------------------------------
  %  1. Turns the comma list #2 into a clist:   \l_@@_person_id_clist  
  %  2. For **each** person‑ID in that clist it builds an
  %     “author block” consisting of  
  %        • a coloured, bold hyperlink to the PI’s entry, and  
  %        • the list of projects (formatted by \getProject) that are
  %          attached to that PI.  
  %  3. All author blocks are collected in a second clist
  %     \l_@@_person_project_clist.  
  %  4. Finally the blocks are printed in an *Oxford‑comma* style
  %     using \clist_use:Nnnn.
  %
  %  Internal containers (all declared elsewhere with \clist_new:N)  
  %  --------------------------------------------------------------
  %    \l_@@_person_id_clist          – list of the IDs passed in #2  
  %    \l_@@_person_project_clist     – the final list of “author blocks”  
  %    \l_@@_project_id_clist         – temporary clist that stores the raw
  %                                      CSV string returned by the DB field
  %                                      `ref‑project‑id` for the current PI.  
  %    \l_@@_project_number_clist      – coloured project numbers for the
  %                                      current PI (built by the inner loop).  
  %    \l_@@_project_id_clist (re‑used) – holds the CSV string before it is
  %                                      split into \l_@@_project_id_clist.  
  %    \l_tmpa_clist                  – loop variable used by
  %                                      \clist_map_variable:NNn (holds a *single*
  %                                      project‑ID during the inner loop).  
  %
  %---------------------------------------------------------------------
  %  Detailed walk‑through of the code
  %---------------------------------------------------------------------
  %---------------------------------------------------------------
  %   0.  Initialise the containers
  %---------------------------------------------------------------
  % #2 is a comma‑separated list of person IDs → turn it into a clist
  \clist_set:Nn \l_@@_person_id_clist {#2}
  % containers that will be filled later
  \clist_clear:N \l_@@_person_project_clist
  \clist_clear:N \l_@@_project_id_clist   % (used as a *scratch* clist)

  %---------------------------------------------------------------
  %   1.  Outer loop – one iteration per PI
  %---------------------------------------------------------------
  \clist_map_inline:Nn \l_@@_person_id_clist
  {               % ##1 = the current person ID
  	%---------------------------------------------------------
  	%   a)  Build the *author name* (hyperlinked, coloured,
  	%       bold).  We wrap everything in \exp_not:n so that the
  	%       whole fragment is **not expanded now** – it will be
  	%       expanded later when the final clist is printed.
  	%---------------------------------------------------------
  	\clist_put_right:Nn \l_@@_person_project_clist {
  		\clist_clear:N   \l_@@_project_number_clist
  		\IfBooleanTF{#1}
  		{\getPI*{##1}}
  		{\getPI{##1}}
  		%---------------------------------------------------------
  		%   b)  Pull the raw CSV string that contains *all* project
  		%       IDs belonging to this PI.
  		%---------------------------------------------------------
  		\DTLgetvalueforkey{\l_@@_project_id_clist}
  		{ref-project-id}
  		{person}{id}{##1}

  		%---------------------------------------------------------
  		%   c)  Print the project list inside parentheses.
  		%       The raw CSV string is *still* a token list; we turn it
  		%       into a clist by using the special “variable” version of
  		%       \clist_map_… which gives us a temporary clist variable
  		%       (\l_tmpa_clist) that holds *one* project ID at a time.
  		%---------------------------------------------------------
  		\space(
  		\clist_map_variable:NNn \l_@@_project_id_clist \l_tmpa_clist {
  			% ##1 (here called \l_tmpa_clist) is a single project ID.
  			% \getProject expands that ID to the coloured project number.
  			\clist_put_right:Ne \l_@@_project_number_clist {
  				\getProject{\l_tmpa_clist}
  			}
  		}
  		% finally print the list of coloured project numbers, separated
  		% by a thin space + comma
  		\clist_use:Nn \l_@@_project_number_clist  {\addnbthinspace/\addthinspace}
  		)
  	}   % end of \clist_put_right:Nn  (one author block)
  } % end of outer \clist_map_inline:Nn

  %---------------------------------------------------------------
  %   2.  Typeset the collected author blocks.
  %       \clist_use:Nnnn joins the items with
  %          “~and~”   for the *last* separator,
  %          “,~”      for the *middle* separators,
  %          “,~and~”  for the *penultimate* separator
  %---------------------------------------------------------------
  \clist_use:Nnnn \l_@@_person_project_clist {~and~} {,~} {,~and~}%
  }
}

\clist_new:N \l_@@_person_clist

% Track which projects have already had their PI names expanded by either
% \cs{getProject} or \cs{getProjectPI} in the current section. Chapter
% boundaries also clear the state so references before the first section of a
% new chapter cannot inherit the preceding section's state.
\prop_new:N \g_@@_project_pi_seen_prop
\cs_new_protected:Npn \@@_project_pi_seen_clear:
  { \prop_gclear:N \g_@@_project_pi_seen_prop }
\AddToHook{cmd/chapter/before}[dfg/project-pi-once-per-section]
  { \@@_project_pi_seen_clear: }
\AddToHook{cmd/section/before}[dfg/project-pi-once-per-section]
  { \@@_project_pi_seen_clear: }

% PI details are never appended to reference-only projects, the project
% currently being typeset, or references inside generated tables and lists.
% Otherwise the customization setting selects either the former always-expanded
% \cs{getProjectPI} behaviour or one shared expansion per project and section.
\prg_new_protected_conditional:Npnn \@@_project_pi_if_show_people:n #1
  { T,F,TF }
{
  \@@_project_if_reference_only:nTF {#1}
    { \prg_return_false: }
    {
      \tl_if_eq:VnTF \l__tmp_current_project_tl {#1}
        { \prg_return_false: }
        {
          \bool_if:nTF
            {
              \g_@@_tblr_inside_bool
              || \l_@@_former_project_compact_bool
            }
            { \prg_return_false: }
            {
              \bool_if:NTF \l_@@_custom_project_pi_once_per_section_bool
              {
                \prop_if_in:NnTF \g_@@_project_pi_seen_prop {#1}
                  { \prg_return_false: }
                  {
                    \prop_gput:Nnn \g_@@_project_pi_seen_prop {#1} { }
                    \prg_return_true:
                  }
              }
              { \prg_return_true: }
            }
        }
    }
}

\cs_new_protected:Npn \@@_get_project_with_people:nnn #1#2#3
{
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  { \@@_get_project_compact:nn {#2} {#3} }
  {
  %-----------------------------------------------------------------
  % 0.  Initialise the containers we are going to use.
  %-----------------------------------------------------------------
  %   #2 is a comma‑separated list of *project* IDs → turn it into a clist.
  \clist_set:Nn \l_@@_project_id_clist {#2}
  %   These three clists will be filled during the loops.
  \clist_clear:N \l_@@_person_project_clist   % final result: “project → PI list”
  \clist_clear:N \l_@@_person_id_clist        % temporary list of PIs for one project
  \clist_clear:N \l_@@_person_clist           % temporary list of formatted PI names

  %-----------------------------------------------------------------
  % 1.  Outer loop – one iteration per *project* ID.
  %-----------------------------------------------------------------
  \clist_map_inline:Nn \l_@@_project_id_clist
  {
  	% ##1 = the current project ID
  	%-------------------------------------------------------------
  	%   a)  Put the *project number* (coloured) at the beginning
  	%       of the block that will be stored in
  	%       \l_@@_person_project_clist.
  	%-------------------------------------------------------------
  	\clist_put_right:Nn \l_@@_person_project_clist
  	{%
  		% Reset the per‑project temporaries before we start filling them.
  		\clist_clear:N \l_@@_person_clist
  		\clist_clear:N \l_@@_person_id_clist

		% The coloured project number (e.g. “\color{blue}{12}”)
		\@@_get_project_compact:nn {##1} {#3}

		% Reference-only projects and the current project remain compact. For
		% other projects, the customization setting determines whether PI names
		% are always shown or only on the first reference in this section.
    \@@_project_pi_if_show_people:nT {##1}
    {
		%---------------------------------------------------------
		%   b)  Retrieve the *raw* CSV string that contains all
  		%       person IDs attached to this project.
  		%---------------------------------------------------------
  		\DTLgetvalueforkey
  		{\l_@@_person_id_clist}      % ← will receive something like “per1,per3”
  		{ref-person-id}              % field name in the “project” table
  		{project}{id}{##1}           % look it up for the current project

  		%---------------------------------------------------------
  		%   c)  Build the *list of PI names* for this project.
  		%       We use the “variable” version of \clist_map which
  		%       gives us a temporary clist variable (\l_tmpa_clist)
  		%       that holds a *single* person ID at each iteration.
  		%---------------------------------------------------------
  		\space(%
  		\clist_map_variable:NNn \l_@@_person_id_clist \l_tmpa_clist
  		{
  			% \l_tmpa_clist now expands to one person ID.
  			% We format it with \getPI (or \getPI* if the star was given).
  			\clist_put_right:Ne \l_@@_person_clist
  			{
  				\IfBooleanTF{#1}
  				{\getPI*{\l_tmpa_clist}}
  				{\getPI{\l_tmpa_clist}}
  			}
  		}
  		%---------------------------------------------------------
  		%   d)  Print the formatted PI list, separating consecutive
  		%       names with a thin slash (the macro \addnbthinspace and
  		%       \addthinspace are assumed to be defined elsewhere).
  		%---------------------------------------------------------
		\clist_use:Nn \l_@@_person_clist {\addnbthinspace/\addthinspace}
		  ) % end of the parentheses that surround the PI list
		}
	}   % end of \clist_put_right:Nn   (one *project block*)
  } % end of outer \clist_map_inline:Nn

  %-----------------------------------------------------------------
  % 2.  Typeset the collected project blocks.
  %     \clist_use:Nnnn joins the items with
  %        “~and~”   for the *last* separator,
  %        “,~”      for the *middle* separators,
  %        “,~and~”  for the *penultimate* separator.
  %-----------------------------------------------------------------
  \@@_project_reference_clist_use:N \l_@@_person_project_clist
  }
}

\NewDocumentCommand{\getProjectPI}{s m}
  {
    \exp_args:NnnV \@@_get_project_with_people:nnn
      {#1} {#2} \c_novalue_tl
  }
%    \end{macrocode}
% We also need a way to extract all PIs of a project. 
%    \begin{macrocode}
% \getPIofProject[<properties>]{<PROJECT>}[<delimiter>]
\NewDocumentCommand{\getPIofProject}{O{lastname} m O{\,/\,}}
{
  % #1: list of keys to retrieve from the PIs info
  % #2: ID of PI
  % #3: delimiter 
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  { \dfgFastReference{#2} }
  {

  % #2 is a comma‑separated list of *project* IDs → turn it into a clist.
  \clist_set:Nn \l_@@_project_id_clist {#2}
  %   These three clists will be filled during the loops.
  \clist_clear:N \l_@@_person_project_clist   % final result: “project → PI list”
  \clist_clear:N \l_@@_person_id_clist        % temporary list of PIs for one project
  \clist_clear:N \l_@@_person_clist           % temporary list of formatted PI names

  \DTLgetvalueforkey
  {\l_@@_person_id_clist}      % ← will receive something like “per1,per3”
  {ref-person-id}              % field name in the “project” table
  {project}{id}{\clist_use:N \l_@@_project_id_clist}           % look it
  % up for the current project

  \clist_map_variable:NNn \l_@@_person_id_clist \l_tmpa_clist
  {
  	\DTLgetvalueforkey{\tmpPIacademicdegree}{academicdegree}{person}{id}{\l_tmpa_clist}%
  	\DTLgetvalueforkey{\tmpPIfirstname}{firstname}{person}{id}{\l_tmpa_clist}%
  	\DTLgetvalueforkey{\tmpPIlastname}{lastname}{person}{id}{\l_tmpa_clist}%
  	% \clist_clear:N \l_@@_person_clist
  	% % \l_tmpa_clist now expands to one person ID.
  	% We format it with \getPI (or \getPI* if the star was given).
	\clist_put_right:Ne \l_@@_person_clist
	{
		\clist_if_in:nnT{#1}{academicdegree}
		  {\dfgShowTag{\l_tmpa_clist}{academicdegree}{\tmpPIacademicdegree}[person]\addnbthinspace}
		\clist_if_in:nnT{#1}{firstname}
		  {\dfgShowTag{\l_tmpa_clist}{firstname}{\tmpPIfirstname}[person]\space}
		\clist_if_in:nnT{#1}{lastname}
		  {\dfgShowTag{\l_tmpa_clist}{lastname}{\tmpPIlastname}[person]}
	}
  }   % end of \clist_put_right:Nn   (one *project block*)
  \clist_use:Nn \l_@@_person_clist {#3}
  }
} % end of \NewDocumentCommand
%    \end{macrocode}
% For referencing Aims we need to define a new macro.
%    \begin{macrocode}
\clist_new:N \l_@@_aim_refs_clist
\NewDocumentCommand{\getAim}{O{\l__tmp_current_project_tl} m}
{
  % #1: current project
  % #2: id of aim(s)
  \clist_clear:N \l_@@_aim_refs_clist
  \clist_map_inline:nn { #2 }
  { \clist_put_right:Nn \l_@@_aim_refs_clist { #1-aim-##1 } }
  \exp_args:NV \cref \l_@@_aim_refs_clist
}
%    \end{macrocode}
% For referencing Workpackages we need to define a new macro.
%    \begin{macrocode}
\tl_new:N \l__tmp_current_project_tl
\clist_new:N \l_@@_wp_refs_clist
\NewDocumentCommand{\getWP}{O{\l__tmp_current_project_tl} m}
{
  % #1: current project
  % #2: id of workpackage(s)
  \clist_clear:N \l_@@_wp_refs_clist
  \clist_map_inline:nn { #2 }
  { \clist_put_right:Nn \l_@@_wp_refs_clist { #1-wp-##1 } }
  \exp_args:NV \cref \l_@@_wp_refs_clist
}
%    \end{macrocode}
% The following command must be called within the environment |workpackages|.
%    \begin{macrocode}
\tl_new:N \l_@@_fast_workpackage_name_tl
\keys_define:nn { dfg / fast-workpackage }
{
  name .tl_set:N = \l_@@_fast_workpackage_name_tl,
  unknown .code:n = { }
}

% A nested workpackage starts directly with its authored body; its list label
% already supplies the required separation.  Remove only the immediately
% following spaces and paragraph tokens, without adding interword space.  Later
% paragraph breaks in the authored body remain untouched.
\cs_new_protected:Npn \@@_start_subworkpackage_body:
{
  \peek_meaning_remove_ignore_spaces:NTF \par
    { \@@_start_subworkpackage_body: }
    { \ignorespaces }
}

\NewDocumentCommand{\addWP}{ m m }{
  % #1: workpackage-id
  % #2: key-set
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  {
    \tl_clear:N \l_@@_fast_workpackage_name_tl
    \keys_set:nn { dfg / fast-workpackage } {#2}
  }
  {
    \addEntry[gantt]{gantt-\l__tmp_current_project_tl}{id=#1,#2}
  }
  \str_if_eq:eeTF { \@enumctr } { workpackagesi }
  {
    \bool_if:NTF \l_@@_class_fastcompile_project_bool
    {
      \item \textbf{
        \tl_if_blank:VTF \l_@@_fast_workpackage_name_tl
        { WP~#1 }
        { \tl_use:N \l_@@_fast_workpackage_name_tl }
      }%
    }
    {
      \item \textbf{\getEntry[gantt-\l__tmp_current_project_tl]{#1}{name}}%
    }
  }
  { \item }
  \label{\l__tmp_current_project_tl-wp-#1}%
  \str_if_eq:eeF { \@enumctr } { workpackagesi }
    { \@@_start_subworkpackage_body: }
}
%    \end{macrocode}
% Project collaborations are stored with each project as an undirected list.
% The default plot is a compact focus heatmap containing every active project;
% the focus and its direct collaborators are highlighted.  An arc layout uses
% the same ordered nodes, draws only the focus project's edges, and gives every
% edge the same peak height.  It prints identifiers inside uniformly sized
% nodes and places full-width project-area rules directly below them.  Heatmap
% rows and colors are generated dynamically from |project-area| (with the
% project-ID prefix as fallback); a rotating palette supports any number of
% areas.  Boxes use a shared dynamic column width determined by the widest
% project area, so the grid fills the complete text block after its area labels.  Both
% layouts are deterministic, are generated entirely with TikZ, and omit ending,
% reference-only, and list-excluded projects.
% The built-in area palette cycles when more areas are present than palette
% entries; existing A, B, and Q projects retain their familiar colors.
%    \begin{macrocode}
\dim_new:N  \l_@@_collaboration_plot_x_dim
\dim_new:N  \l_@@_collaboration_plot_y_dim
\dim_new:N  \l_@@_collaboration_plot_x_step_dim
\dim_new:N  \l_@@_collaboration_plot_box_width_dim
\dim_new:N  \l_@@_collaboration_plot_box_gap_dim
\dim_new:N  \l_@@_collaboration_plot_area_label_width_dim
\dim_new:N  \l_@@_collaboration_plot_content_start_dim
\dim_new:N  \l_@@_collaboration_plot_width_dim
\dim_new:N  \l_@@_collaboration_plot_arc_height_dim
\box_new:N  \l_@@_collaboration_plot_area_label_box
\seq_new:N  \l_@@_collaboration_plot_nodes_seq
\seq_new:N  \l_@@_collaboration_plot_areas_seq
\seq_new:N  \l_@@_collaboration_plot_area_palette_seq
\seq_new:N  \l_@@_collaboration_plot_edges_seq
\prop_new:N \l_@@_collaboration_plot_all_status_prop
\prop_new:N \l_@@_collaboration_plot_status_prop
\prop_new:N \l_@@_collaboration_plot_lists_prop
\prop_new:N \l_@@_collaboration_plot_edges_prop
\prop_new:N \l_@@_collaboration_plot_visible_prop
\prop_new:N \l_@@_collaboration_plot_area_prop
\prop_new:N \l_@@_collaboration_plot_area_nodes_prop
\prop_new:N \l_@@_collaboration_plot_area_color_prop
\prop_new:N \l_@@_collaboration_plot_area_color_override_prop
\tl_new:N   \l_@@_collaboration_plot_focus_tl
\tl_new:N   \l_@@_collaboration_plot_layout_tl
\tl_new:N   \l_@@_collaboration_plot_id_tl
\tl_new:N   \l_@@_collaboration_plot_status_tl
\tl_new:N   \l_@@_collaboration_plot_consider_tl
\tl_new:N   \l_@@_collaboration_plot_reference_only_tl
\tl_new:N   \l_@@_collaboration_plot_collaborations_tl
\tl_new:N   \l_@@_collaboration_plot_area_tl
\tl_new:N   \l_@@_collaboration_plot_source_tl
\tl_new:N   \l_@@_collaboration_plot_target_tl
\tl_new:N   \l_@@_collaboration_plot_edge_tl
\tl_new:N   \l_@@_collaboration_plot_edge_left_tl
\tl_new:N   \l_@@_collaboration_plot_edge_right_tl
\tl_new:N   \l_@@_collaboration_plot_label_tl
\tl_new:N   \l_@@_collaboration_plot_color_tl
\tl_new:N   \l_@@_collaboration_plot_caption_tl
\int_new:N  \l_@@_collaboration_plot_group_index_int
\int_new:N  \l_@@_collaboration_plot_row_index_int
\int_new:N  \l_@@_collaboration_plot_node_count_int
\int_new:N  \l_@@_collaboration_plot_area_index_int

\cs_new_protected:Npn \@@_collaboration_plot_merge_area_colors:n #1
{
  \prop_set_from_keyval:Nn \l_tmpa_prop {#1}
  \prop_map_inline:Nn \l_tmpa_prop
    { \prop_put:Nnn \l_@@_collaboration_plot_area_color_override_prop
        {##1} {##2} }
}

\keys_define:nn { dfg / project-collaboration-plot }
{
  layout .choice:,
  layout / heatmap .code:n =
    { \tl_set:Nn \l_@@_collaboration_plot_layout_tl { heatmap } },
  layout / arc .code:n =
    { \tl_set:Nn \l_@@_collaboration_plot_layout_tl { arc } },
  layout / arc-diagram .meta:n = { layout = arc },
  heatmap .meta:n = { layout = heatmap },
  arc .meta:n = { layout = arc },
  arc-diagram .meta:n = { layout = arc },
  area-colors .code:n =
    { \@@_collaboration_plot_merge_area_colors:n {#1} },
  area-colours .meta:n = { area-colors = {#1} },
  area-palette .code:n =
    {
      \clist_if_empty:nF {#1}
        { \seq_set_from_clist:Nn \l_@@_collaboration_plot_area_palette_seq {#1} }
    },
  caption .tl_set:N = \l_@@_collaboration_plot_caption_tl,
  unknown .code:n = { \msg_warning:nnn { dfg } { unknown-key } {#1} }
}

\cs_new_protected:Npn \@@_collaboration_plot_collect_nodes:
{
  \seq_clear:N  \l_@@_collaboration_plot_nodes_seq
  \prop_clear:N \l_@@_collaboration_plot_all_status_prop
  \prop_clear:N \l_@@_collaboration_plot_status_prop
  \prop_clear:N \l_@@_collaboration_plot_lists_prop
  \prop_clear:N \l_@@_collaboration_plot_edges_prop
  \prop_clear:N \l_@@_collaboration_plot_area_prop
  % DATATOOL requires an iterated key to exist as a database column.  Older
  % proposals do not have project-area yet, so create the optional column and
  % let the ID-prefix fallback below handle its empty values.
  \DTLifhaskey { project } { project-area }
    { }
    { \DTLaddcolumn { project } { project-area } }
  \DTLifhaskey { project } { collaborations }
    { }
    { \DTLaddcolumn { project } { collaborations } }
  \DTLforeach*{project}
  {
    \l_@@_collaboration_plot_id_tl = id,
    \l_@@_collaboration_plot_status_tl = project-status,
    \l_@@_collaboration_plot_consider_tl = consider-for-lists,
    \l_@@_collaboration_plot_reference_only_tl = reference-only,
    \l_@@_collaboration_plot_area_tl = project-area,
    \l_@@_collaboration_plot_collaborations_tl = collaborations
  }
  {
    \prop_put:NVV \l_@@_collaboration_plot_all_status_prop
      \l_@@_collaboration_plot_id_tl
      \l_@@_collaboration_plot_status_tl
    \bool_lazy_all:nT
    {
      { \str_if_eq_p:Vn \l_@@_collaboration_plot_consider_tl { true } }
      { \str_if_eq_p:Vn \l_@@_collaboration_plot_reference_only_tl { false } }
      {
        \bool_lazy_or_p:nn
          { \str_if_eq_p:Vn \l_@@_collaboration_plot_status_tl { C } }
          { \str_if_eq_p:Vn \l_@@_collaboration_plot_status_tl { N } }
      }
    }
    {
      \DTLifnullorempty{\l_@@_collaboration_plot_collaborations_tl}
        { \tl_clear:N \l_@@_collaboration_plot_collaborations_tl }
        { }
      \seq_put_right:NV \l_@@_collaboration_plot_nodes_seq
        \l_@@_collaboration_plot_id_tl
      \DTLifnullorempty{\l_@@_collaboration_plot_area_tl}
        { \tl_set:Nx \l_@@_collaboration_plot_area_tl
            { \tl_head:V \l_@@_collaboration_plot_id_tl } }
        { }
      \tl_trim_spaces:N \l_@@_collaboration_plot_area_tl
      \prop_put:NVV \l_@@_collaboration_plot_area_prop
        \l_@@_collaboration_plot_id_tl \l_@@_collaboration_plot_area_tl
      \prop_put:NVV \l_@@_collaboration_plot_status_prop
        \l_@@_collaboration_plot_id_tl
        \l_@@_collaboration_plot_status_tl
      \prop_put:NVV \l_@@_collaboration_plot_lists_prop
        \l_@@_collaboration_plot_id_tl
        \l_@@_collaboration_plot_collaborations_tl
    }
  }
  \seq_sort:Nn \l_@@_collaboration_plot_nodes_seq
  {
    \prop_get:NnN \l_@@_collaboration_plot_area_prop {##1} \l_tmpa_tl
    \prop_get:NnN \l_@@_collaboration_plot_area_prop {##2} \l_tmpb_tl
    \str_compare:eNeTF
      { \tl_use:N \l_tmpa_tl / ##1 }
      <
      { \tl_use:N \l_tmpb_tl / ##2 }
      { \sort_return_same: }
      { \sort_return_swapped: }
  }
}

\cs_new_protected:Npn \@@_collaboration_plot_collect_edge:nn #1#2
{
  \tl_set:Nn \l_@@_collaboration_plot_source_tl {#1}
  \tl_set:Nn \l_@@_collaboration_plot_target_tl {#2}
  \tl_trim_spaces:N \l_@@_collaboration_plot_source_tl
  \tl_trim_spaces:N \l_@@_collaboration_plot_target_tl
  \tl_if_blank:VF \l_@@_collaboration_plot_target_tl
  {
    \prop_if_in:NVTF \l_@@_collaboration_plot_status_prop
      \l_@@_collaboration_plot_target_tl
    {
      \str_if_eq:VVF
        \l_@@_collaboration_plot_source_tl
        \l_@@_collaboration_plot_target_tl
      {
        \str_compare:eNeTF
          { \tl_use:N \l_@@_collaboration_plot_source_tl }
          <
          { \tl_use:N \l_@@_collaboration_plot_target_tl }
          {
            \tl_set:Nx \l_@@_collaboration_plot_edge_tl
              {
                \tl_use:N \l_@@_collaboration_plot_source_tl
                /\tl_use:N \l_@@_collaboration_plot_target_tl
              }
          }
          {
            \tl_set:Nx \l_@@_collaboration_plot_edge_tl
              {
                \tl_use:N \l_@@_collaboration_plot_target_tl
                /\tl_use:N \l_@@_collaboration_plot_source_tl
              }
          }
        \prop_put:NVn \l_@@_collaboration_plot_edges_prop
          \l_@@_collaboration_plot_edge_tl { 1 }
      }
    }
    {
      \prop_if_in:NVF \l_@@_collaboration_plot_all_status_prop
        \l_@@_collaboration_plot_target_tl
      {
        \msg_warning:nnee { dfg } { collaboration-target-not-found }
          { \l_@@_collaboration_plot_source_tl }
          { \l_@@_collaboration_plot_target_tl }
      }
    }
  }
}

\cs_new_protected:Npn \@@_collaboration_plot_collect_edges:
{
  \seq_clear:N \l_@@_collaboration_plot_edges_seq
  \prop_map_inline:Nn \l_@@_collaboration_plot_lists_prop
  {
    \clist_map_inline:nn {##2}
      { \@@_collaboration_plot_collect_edge:nn {##1} {####1} }
  }
  \prop_map_inline:Nn \l_@@_collaboration_plot_edges_prop
    { \seq_put_right:Nn \l_@@_collaboration_plot_edges_seq {##1} }
  \seq_sort:Nn \l_@@_collaboration_plot_edges_seq
    {
      \str_compare:eNeTF {##1} < {##2}
        { \sort_return_same: }
        { \sort_return_swapped: }
    }
}

\cs_new_protected:Npn \@@_collaboration_plot_unpack_edge:n #1
{
  \seq_set_split:Nnn \l_tmpa_seq {/} {#1}
  \seq_pop_left:NN \l_tmpa_seq \l_@@_collaboration_plot_edge_left_tl
  \seq_pop_left:NN \l_tmpa_seq \l_@@_collaboration_plot_edge_right_tl
}

\cs_new_protected:Npn \@@_collaboration_plot_prepare:
{
  \prop_clear:N \l_@@_collaboration_plot_visible_prop
  \seq_clear:N \l_@@_collaboration_plot_areas_seq
  \prop_clear:N \l_@@_collaboration_plot_area_nodes_prop
  \prop_clear:N \l_@@_collaboration_plot_area_color_prop
  \int_zero:N \l_@@_collaboration_plot_area_index_int
  \prop_put:NVn \l_@@_collaboration_plot_visible_prop
    \l_@@_collaboration_plot_focus_tl { 1 }
  \seq_map_inline:Nn \l_@@_collaboration_plot_edges_seq
  {
    \@@_collaboration_plot_unpack_edge:n {##1}
    \bool_lazy_or:nnT
    {
      \str_if_eq_p:VV
        \l_@@_collaboration_plot_edge_left_tl
        \l_@@_collaboration_plot_focus_tl
    }
    {
      \str_if_eq_p:VV
        \l_@@_collaboration_plot_edge_right_tl
        \l_@@_collaboration_plot_focus_tl
    }
    {
      \prop_put:NVn \l_@@_collaboration_plot_visible_prop
        \l_@@_collaboration_plot_edge_left_tl { 1 }
      \prop_put:NVn \l_@@_collaboration_plot_visible_prop
        \l_@@_collaboration_plot_edge_right_tl { 1 }
    }
  }
  \seq_map_inline:Nn \l_@@_collaboration_plot_nodes_seq
  {
    \prop_get:NnN \l_@@_collaboration_plot_area_prop {##1}
      \l_@@_collaboration_plot_area_tl
    \prop_if_in:NVF \l_@@_collaboration_plot_area_nodes_prop
      \l_@@_collaboration_plot_area_tl
    {
      \seq_put_right:NV \l_@@_collaboration_plot_areas_seq
        \l_@@_collaboration_plot_area_tl
      \prop_get:NVNTF \l_@@_collaboration_plot_area_color_override_prop
        \l_@@_collaboration_plot_area_tl
        \l_@@_collaboration_plot_color_tl
      {
        \prop_put:NVV \l_@@_collaboration_plot_area_color_prop
          \l_@@_collaboration_plot_area_tl
          \l_@@_collaboration_plot_color_tl
      }
      {
        \int_incr:N \l_@@_collaboration_plot_area_index_int
        \int_set:Nn \l_tmpa_int
          {
            1 + \int_mod:nn
              { \l_@@_collaboration_plot_area_index_int - 1 }
              { \seq_count:N \l_@@_collaboration_plot_area_palette_seq }
          }
        \prop_put:NVx \l_@@_collaboration_plot_area_color_prop
          \l_@@_collaboration_plot_area_tl
          {
            \seq_item:Nn \l_@@_collaboration_plot_area_palette_seq
              { \l_tmpa_int }
          }
      }
      \prop_put:NVn \l_@@_collaboration_plot_area_nodes_prop
        \l_@@_collaboration_plot_area_tl { }
    }
    \prop_get:NVN \l_@@_collaboration_plot_area_nodes_prop
      \l_@@_collaboration_plot_area_tl \l_tmpa_tl
    \tl_if_blank:VTF \l_tmpa_tl
      { \tl_set:Nn \l_tmpa_tl {##1} }
      { \tl_put_right:Nn \l_tmpa_tl { , ##1 } }
    \prop_put:NVV \l_@@_collaboration_plot_area_nodes_prop
      \l_@@_collaboration_plot_area_tl \l_tmpa_tl
  }
}

\cs_new_protected:Npn \@@_collaboration_plot_set_color:n #1
{
  \tl_set:Nx \l_@@_collaboration_plot_label_tl {#1}
  \prop_get:NnNTF \l_@@_collaboration_plot_area_prop
    {#1} \l_@@_collaboration_plot_area_tl
    { \prop_get:NVN \l_@@_collaboration_plot_area_color_prop
        \l_@@_collaboration_plot_area_tl
        \l_@@_collaboration_plot_color_tl }
    { \tl_set:Nn \l_@@_collaboration_plot_color_tl { grey } }
}

\cs_new_protected:Npn \@@_collaboration_plot_heatmap_cell:n #1
{
  \@@_collaboration_plot_set_color:n {#1}
  \str_if_eq:VVTF
    \l_@@_collaboration_plot_focus_tl
    \l_@@_collaboration_plot_label_tl
  {
    \node[
      anchor=center,
      minimum~width=\dim_use:N \l_@@_collaboration_plot_box_width_dim,
      minimum~height=5.2mm,
      inner~sep=0pt,
      rounded~corners=1.4pt,
      draw=red!78!black,
      fill=red,
      text=white,
      font=\scriptsize\bfseries
    ] at
      (\dim_use:N \l_@@_collaboration_plot_x_dim,
       \dim_use:N \l_@@_collaboration_plot_y_dim)
      { \strut\tl_use:N \l_@@_collaboration_plot_label_tl };
  }
  {
    \prop_if_in:NVTF \l_@@_collaboration_plot_visible_prop
      \l_@@_collaboration_plot_label_tl
    {
      \node[
        anchor=center,
        minimum~width=\dim_use:N \l_@@_collaboration_plot_box_width_dim,
        minimum~height=5.2mm,
        inner~sep=0pt,
        rounded~corners=1.4pt,
        draw=\tl_use:N \l_@@_collaboration_plot_color_tl!48,
        fill=\tl_use:N \l_@@_collaboration_plot_color_tl!14,
        text=\tl_use:N \l_@@_collaboration_plot_color_tl,
        font=\scriptsize\bfseries
      ] at
        (\dim_use:N \l_@@_collaboration_plot_x_dim,
         \dim_use:N \l_@@_collaboration_plot_y_dim)
        { \strut\tl_use:N \l_@@_collaboration_plot_label_tl };
    }
    {
      \node[
        anchor=center,
        minimum~width=\dim_use:N \l_@@_collaboration_plot_box_width_dim,
        minimum~height=5.2mm,
        inner~sep=0pt,
        rounded~corners=1.4pt,
        draw=grey!22,
        fill=white,
        text=grey!70!black,
        font=\scriptsize
      ] at
        (\dim_use:N \l_@@_collaboration_plot_x_dim,
         \dim_use:N \l_@@_collaboration_plot_y_dim)
        { \strut\tl_use:N \l_@@_collaboration_plot_label_tl };
    }
  }
}

\cs_new_protected:Npn \@@_collaboration_plot_heatmap_row:nnn #1#2#3
{
  \clist_if_empty:nF {#1}
  {
    \int_incr:N \l_@@_collaboration_plot_row_index_int
    \dim_set:Nn \l_@@_collaboration_plot_y_dim
    {
      -7mm *
      \int_eval:n { \l_@@_collaboration_plot_row_index_int - 1 }
    }
    \node[
      anchor=east,
      inner~sep=0pt,
      font=\scriptsize\bfseries
    ] at
      (\dim_use:N \l_@@_collaboration_plot_area_label_width_dim,
       \dim_use:N \l_@@_collaboration_plot_y_dim)
      {Project~area~#3};
    \draw[draw=#2,line~width=.75pt,line~cap=round]
      (\dim_eval:n
         { \l_@@_collaboration_plot_area_label_width_dim + .8mm },
       \dim_use:N \l_@@_collaboration_plot_y_dim)
      --
      (\dim_eval:n
         { \l_@@_collaboration_plot_area_label_width_dim + 2.8mm },
       \dim_use:N \l_@@_collaboration_plot_y_dim);
    \int_zero:N \l_@@_collaboration_plot_group_index_int
    \clist_map_inline:nn {#1}
    {
      \int_incr:N \l_@@_collaboration_plot_group_index_int
      \dim_set:Nn \l_@@_collaboration_plot_x_dim
      {
        \l_@@_collaboration_plot_content_start_dim
        + \l_@@_collaboration_plot_box_width_dim / 2
        + \l_@@_collaboration_plot_x_step_dim *
        \int_eval:n { \l_@@_collaboration_plot_group_index_int - 1 }
      }
      \@@_collaboration_plot_heatmap_cell:n {##1}
    }
  }
}
\cs_generate_variant:Nn \@@_collaboration_plot_heatmap_row:nnn { V V n }

\cs_new_protected:Npn \@@_collaboration_plot_heatmap_picture:
{
    % Use the widest project area as the shared column grid.  Each column gets
    % a dynamic box width, and the final cell reaches the right edge of the
    % text block instead of leaving a large unused strip before the caption.
    \dim_zero:N \l_@@_collaboration_plot_area_label_width_dim
    \seq_map_inline:Nn \l_@@_collaboration_plot_areas_seq
      {
        \hbox_set:Nn \l_@@_collaboration_plot_area_label_box
          { \scriptsize\bfseries Project~area~##1 }
        \dim_compare:nNnT
          { \box_wd:N \l_@@_collaboration_plot_area_label_box }
          >
          { \l_@@_collaboration_plot_area_label_width_dim }
          {
            \dim_set:Nn \l_@@_collaboration_plot_area_label_width_dim
              { \box_wd:N \l_@@_collaboration_plot_area_label_box }
          }
      }
    \dim_set:Nn \l_@@_collaboration_plot_content_start_dim
      { \l_@@_collaboration_plot_area_label_width_dim + 4mm }
  \begin{tikzpicture}
    \int_zero:N \l_@@_collaboration_plot_node_count_int
    \seq_map_inline:Nn \l_@@_collaboration_plot_areas_seq
      {
        \prop_get:NnN \l_@@_collaboration_plot_area_nodes_prop {##1}
          \l_tmpa_tl
        \clist_set:NV \l_tmpa_clist \l_tmpa_tl
        \int_set:Nn \l_tmpa_int { \clist_count:N \l_tmpa_clist }
        \int_set:Nn \l_@@_collaboration_plot_node_count_int
          { \int_max:nn { \l_@@_collaboration_plot_node_count_int }
            { \l_tmpa_int } }
      }
    \dim_set:Nn \l_@@_collaboration_plot_box_gap_dim { 1mm }
    \int_compare:nNnTF
      { \l_@@_collaboration_plot_node_count_int } > { 0 }
      {
        \dim_set:Nn \l_@@_collaboration_plot_box_width_dim
        {
          ( \l_@@_collaboration_plot_width_dim
            - \l_@@_collaboration_plot_content_start_dim
            - \l_@@_collaboration_plot_box_gap_dim *
              \int_eval:n
                { \l_@@_collaboration_plot_node_count_int - 1 }
          ) / \l_@@_collaboration_plot_node_count_int
        }
        \dim_set:Nn \l_@@_collaboration_plot_x_step_dim
        {
          \l_@@_collaboration_plot_box_width_dim
          + \l_@@_collaboration_plot_box_gap_dim
        }
      }
      {
        \dim_zero:N \l_@@_collaboration_plot_box_width_dim
        \dim_zero:N \l_@@_collaboration_plot_x_step_dim
      }
    \int_zero:N \l_@@_collaboration_plot_row_index_int
    \seq_map_inline:Nn \l_@@_collaboration_plot_areas_seq
      {
        \prop_get:NnN \l_@@_collaboration_plot_area_nodes_prop {##1}
          \l_tmpa_tl
        \prop_get:NnN \l_@@_collaboration_plot_area_color_prop {##1}
          \l_@@_collaboration_plot_color_tl
        \@@_collaboration_plot_heatmap_row:VVn
          \l_tmpa_tl \l_@@_collaboration_plot_color_tl {##1}
      }
  \end{tikzpicture}
}

\cs_new_protected:Npn \@@_collaboration_plot_arc_place_nodes:
{
  \int_set:Nn \l_@@_collaboration_plot_node_count_int
    { \seq_count:N \l_@@_collaboration_plot_nodes_seq }
  \int_compare:nNnTF
    { \l_@@_collaboration_plot_node_count_int } > { 1 }
    {
      \dim_set:Nn \l_@@_collaboration_plot_x_step_dim
      {
        ( \linewidth - 16mm ) /
        \int_eval:n { \l_@@_collaboration_plot_node_count_int - 1 }
      }
    }
    { \dim_zero:N \l_@@_collaboration_plot_x_step_dim }
  \int_zero:N \l_@@_collaboration_plot_group_index_int
  \seq_map_inline:Nn \l_@@_collaboration_plot_nodes_seq
  {
    \dim_set:Nn \l_@@_collaboration_plot_x_dim
    {
      8mm + \l_@@_collaboration_plot_x_step_dim
      * \l_@@_collaboration_plot_group_index_int
    }
    \coordinate (dfg-collaboration-arc-##1) at
      (\dim_use:N \l_@@_collaboration_plot_x_dim,0);
    \int_incr:N \l_@@_collaboration_plot_group_index_int
  }
}

\cs_new_protected:Npn \@@_collaboration_plot_draw_focus_arc:n #1
{
  \@@_collaboration_plot_unpack_edge:n {#1}
  \tl_clear:N \l_@@_collaboration_plot_target_tl
  \str_if_eq:VVTF
    \l_@@_collaboration_plot_edge_left_tl
    \l_@@_collaboration_plot_focus_tl
    {
      \tl_set_eq:NN \l_@@_collaboration_plot_target_tl
        \l_@@_collaboration_plot_edge_right_tl
    }
    {
      \str_if_eq:VVT
        \l_@@_collaboration_plot_edge_right_tl
        \l_@@_collaboration_plot_focus_tl
      {
        \tl_set_eq:NN \l_@@_collaboration_plot_target_tl
          \l_@@_collaboration_plot_edge_left_tl
      }
  }
  \tl_if_blank:VF \l_@@_collaboration_plot_target_tl
  {
    \@@_collaboration_plot_set_color:n
      { \tl_use:N \l_@@_collaboration_plot_target_tl }
    \draw[
      draw=\tl_use:N \l_@@_collaboration_plot_color_tl,
      line~width=.75pt,
      opacity=.78,
      line~cap=round
    ]
      (dfg-collaboration-arc-\l_@@_collaboration_plot_focus_tl)
      .. controls
      ($ (dfg-collaboration-arc-\l_@@_collaboration_plot_focus_tl)
         + (0,\dim_use:N \l_@@_collaboration_plot_arc_height_dim) $)
      and
      ($ (dfg-collaboration-arc-\l_@@_collaboration_plot_target_tl)
         + (0,\dim_use:N \l_@@_collaboration_plot_arc_height_dim) $)
      ..
      (dfg-collaboration-arc-\l_@@_collaboration_plot_target_tl);
  }
}

\cs_new_protected:Npn \@@_collaboration_plot_arc_node:n #1
{
  \@@_collaboration_plot_set_color:n {#1}
  \str_if_eq:VVTF
    \l_@@_collaboration_plot_focus_tl
    \l_@@_collaboration_plot_label_tl
  {
    \node[
      anchor=center,
      minimum~width=6mm,
      minimum~height=5mm,
      inner~sep=0pt,
      rounded~corners=1pt,
      draw=red!78!black,
      fill=red,
      text=white,
      font=\tiny\bfseries
    ] at (dfg-collaboration-arc-#1) {#1};
  }
  {
    \prop_if_in:NVTF \l_@@_collaboration_plot_visible_prop
      \l_@@_collaboration_plot_label_tl
    {
      \node[
        anchor=center,
        minimum~width=6mm,
        minimum~height=5mm,
        inner~sep=0pt,
        rounded~corners=.8pt,
        draw=\tl_use:N \l_@@_collaboration_plot_color_tl!48,
        fill=\tl_use:N \l_@@_collaboration_plot_color_tl!14,
        text=\tl_use:N \l_@@_collaboration_plot_color_tl,
        font=\tiny\bfseries
      ] at (dfg-collaboration-arc-#1) {#1};
    }
    {
      \node[
        anchor=center,
        minimum~width=6mm,
        minimum~height=5mm,
        inner~sep=0pt,
        rounded~corners=.8pt,
        draw=grey!22,
        fill=white,
        text=grey!70!black,
        font=\tiny
      ] at (dfg-collaboration-arc-#1) {#1};
    }
  }
}

\cs_new_protected:Npn \@@_collaboration_plot_arc_group:nnn #1#2#3
{
  \clist_if_empty:nF {#1}
  {
    \tl_set:Nx \l_tmpa_tl { \clist_item:nn {#1} { 1 } }
    \tl_set:Nx \l_tmpb_tl { \clist_item:nn {#1} { -1 } }
    \draw[draw=#2,line~width=.75pt,line~cap=round]
      ($ (dfg-collaboration-arc-\l_tmpa_tl) + (-3mm,-3.5mm) $)
      --
      ($ (dfg-collaboration-arc-\l_tmpb_tl) + (3mm,-3.5mm) $)
      node[midway,below=.6mm,font=\scriptsize\bfseries] {#3};
  }
}
\cs_generate_variant:Nn \@@_collaboration_plot_arc_group:nnn { V V n }

\cs_new_protected:Npn \@@_collaboration_plot_arc_picture:
{
  \begin{tikzpicture}
    \@@_collaboration_plot_arc_place_nodes:
    % Equal control-point heights give every symmetric cubic arc the same peak.
    \dim_set:Nn \l_@@_collaboration_plot_arc_height_dim { 12mm }
    \seq_map_inline:Nn \l_@@_collaboration_plot_edges_seq
      { \@@_collaboration_plot_draw_focus_arc:n {##1} }
    \seq_map_inline:Nn \l_@@_collaboration_plot_nodes_seq
      { \@@_collaboration_plot_arc_node:n {##1} }
    \seq_map_inline:Nn \l_@@_collaboration_plot_areas_seq
      {
        \prop_get:NnN \l_@@_collaboration_plot_area_nodes_prop {##1}
          \l_tmpa_tl
        \prop_get:NnN \l_@@_collaboration_plot_area_color_prop {##1}
          \l_@@_collaboration_plot_color_tl
        \@@_collaboration_plot_arc_group:VVn
          \l_tmpa_tl \l_@@_collaboration_plot_color_tl {##1}
      }
  \end{tikzpicture}
}

\cs_new_protected:Npn \@@_collaboration_plot_picture:
{
  \str_case:VnF \l_@@_collaboration_plot_layout_tl
  {
    { heatmap } { \@@_collaboration_plot_heatmap_picture: }
    { arc }     { \@@_collaboration_plot_arc_picture: }
  }
  { \@@_collaboration_plot_heatmap_picture: }
}

% hvfloat positions a beside caption relative to the measured object width.
% Give the default plot an explicit full text-width box (without scaling its TikZ
% contents), so the outer caption starts in the margin even for a heatmap with
% only a few project nodes or when the surrounding \linewidth is temporarily
% narrower.  This matches the geometry of the resized Gantt chart.
\cs_new_protected:Npn \@@_collaboration_plot_wide_picture:
{
  \makebox[\dim_use:N \l_@@_collaboration_plot_width_dim][l]
    {\@@_collaboration_plot_picture:}
}

\NewDocumentCommand{\ProjectCollaborationPlot}{ O{} m o }
{
  \group_begin:
  % Capture the normal body width before hvfloat's `wide` option temporarily
  % changes layout dimensions while constructing the outer caption.
  \dim_set:Nn \l_@@_collaboration_plot_width_dim { \textwidth }
  \exp_args:NNV \prop_set_from_keyval:Nn
    \l_@@_collaboration_plot_area_color_override_prop
    \l_@@_custom_collaboration_area_colors_tl
  \exp_args:NNV \seq_set_from_clist:Nn
    \l_@@_collaboration_plot_area_palette_seq
    \l_@@_custom_collaboration_area_palette_tl
  \tl_clear:N \l_@@_collaboration_plot_caption_tl
  \keys_set:nn { dfg / project-collaboration-plot }
  {
    layout = heatmap,
    #1
  }
  \IfNoValueF{#3}
    { \tl_set:Nn \l_@@_collaboration_plot_caption_tl {#3} }
  \tl_set:Nn \l_@@_collaboration_plot_focus_tl {#2}
  \tl_trim_spaces:N \l_@@_collaboration_plot_focus_tl
  \DTLifdbexists{project}
  {
    \@@_collaboration_plot_collect_nodes:
    \prop_if_in:NVTF \l_@@_collaboration_plot_status_prop
      \l_@@_collaboration_plot_focus_tl
    {
      \@@_collaboration_plot_collect_edges:
      \@@_collaboration_plot_prepare:
      \tl_if_blank:VTF \l_@@_collaboration_plot_caption_tl
      {
        \hvFloat[
          capFormat={labelsep=newline},
          wide,
          floatPos=h,
          capPos=outer,
          capVPos=bottom,
          capWidth=n,
          floatCapSep=\marginparsep
        ]
        {figure}
        {\@@_collaboration_plot_wide_picture:}
        {Collaborations~of~\getProject{#2}.}
        {fig:project-collaboration-#2-
          \tl_use:N \l_@@_collaboration_plot_layout_tl}%
      }
      {
        \hvFloat[
          floatPos=h,
          capPos=bottom
        ]
        {figure}
        {\@@_collaboration_plot_picture:}
        {Collaborations~of~\getProject{#2}.~
          \tl_use:N \l_@@_collaboration_plot_caption_tl}
        {fig:project-collaboration-#2-
          \tl_use:N \l_@@_collaboration_plot_layout_tl}%
      }
    }
    {
      \msg_warning:nne { dfg } { collaboration-focus-not-found }
        { \l_@@_collaboration_plot_focus_tl }
      \textcolor{error}
        {Project~collaboration~plot:~unknown~project~'#2'.}
    }
  }
  { \msg_warning:nnn { dfg } { database-not-found } { project } }
  \group_end:
}

% Since the workpackage is closely related to the Gantt chart we continue with
% that.  \cs{GanttPlot} is the plot dispatcher's target.  The old
% \cs{printGantt} spelling remains as a compatibility wrapper.
\tl_new:N \l_@@_gantt_plot_caption_tl
\keys_define:nn { dfg / gantt-plot }
{
  caption .tl_set:N = \l_@@_gantt_plot_caption_tl,
  unknown .code:n = { \msg_warning:nnn { dfg } { unknown-key } {#1} }
}

\NewDocumentCommand{\GanttPlot}{ O{} m o }
{
  \group_begin:
  \tl_clear:N \l_@@_gantt_plot_caption_tl
  \keys_set:nn { dfg / gantt-plot } {#1}
  \IfNoValueF{#3}
    { \tl_set:Nn \l_@@_gantt_plot_caption_tl {#3} }
  \DTLifdbexists{gantt-#2}
  {
    \tl_if_blank:VTF \l_@@_gantt_plot_caption_tl
    {
      \hvFloat[
        capFormat={labelsep=newline},
        wide,
        floatPos=h,
        capPos=outer,
        capVPos=bottom,
        capWidth=.116,
        floatCapSep=\marginparsep
      ]
      {figure}
      {\dfgGanttEnvironment{#2}}
      {Gantt~chart~of~\getProject{#2}.}
      {fig:gantt#2}%
    }
    {
      \hvFloat[
        floatPos=h,
        capPos=bottom
      ]
      {figure}
      {\dfgGanttEnvironment{#2}}
      {Gantt~chart~of~\getProject{#2}.~
        \tl_use:N \l_@@_gantt_plot_caption_tl}
      {fig:gantt-#2}%
    }
  }
  {
    Database~ \texttt{gantt-#2}~ missing.
    \msg_warning:nne { dfg } { database-not-found }{ gantt-#2 }
  }
  \group_end:
}

\NewDocumentCommand{\printGantt}{ m o }
{
  \IfNoValueTF{#2}
    { \printPlot{{Gantt}{#1}} }
    { \printPlot{{Gantt}{#1}[#2]} }
}
%    \end{macrocode}
% \subsubsection{Gantt chart rendering}
%
% The Gantt chart for each project is assembled in two steps:
% \begin{enumerate}
%   \item \cs{dfgGanttContent}\marg{project}: iterates over the
%         |gantt-\meta{project}| database and generates one
%         |\ganttbar| call per row.  Rows where |periodStart = periodEnd|
%         are silently skipped.  The bar style is dispatched via
%         \cs{str\_case:VnF}: |crosshatch| uses a pgfgantt pattern fill;
%         |striped| overlays two colours at 45° with \cs{postaction};
%         |alternative| and |important| use flat fills; the default is
%         a solid |color@gantt@default| bar.
%   \item \cs{dfgGanttEnvironment}\marg{project}: wraps the content in a
%         |pgfgantt| |ganttchart| environment spanning 16 columns (quarters
%         Q3 of year 0 through Q2 of year 5, matching the standard DFG
%         5-year period).  The chart is scaled with \cs{resizebox} to fill
%         the full text width.
% \end{enumerate}
%
% \cs{printPlot}|{{Gantt}{|\meta{project}|}}| is the preferred user-facing
% command; \cs{printGantt} remains a compatibility alias.  The dispatcher
% calls \cs{GanttPlot}, which wraps the chart in an |hvfloat| figure with an
% appropriate caption.  The two \cs{hvFloat} calls differ only in layout: the default
% (no extra caption) uses a wide outer-margin caption layout; the variant
% with an extra caption uses a simpler bottom-caption layout.  Both variants
% use the strict |h| position so the chart remains directly after the work
% packages; the following \cs{FloatBarrier} closes that project-plan block.
%
% \textbf{Quarter numbering:} columns 1--2 correspond to Q3--Q4 of the
% calendar year preceding the funding start; columns 3--16 are Q1--Q4 of
% years 1--4; the final 16th column is Q1--Q2 of year 5.  Bar start/end
% values in the Gantt database should use these numbers directly.
%    \begin{macrocode}
\NewDocumentCommand{\dfgGanttContent}{m}{%
  \DTLforeach*{gantt-#1}{%
  	\ganttWP=id,%
  	\ganttName=name,%
  	\ganttDescription=description,%
  	\ganttPeriodStart=periodStart,%
  	\ganttPeriodEnd=periodEnd,%
  	\ganttPatternbar=style%
  }{\hypersetup{linkcolor=black}%
  	% If we want to omit a bar in the plot,
  	% you need to set periodStart and periodEnd
  	% the same value.
  	\ifdefstrequal{\ganttPeriodStart}{\ganttPeriodEnd}{}{%
  		% if the values are different then there will be a bar.
		\def\ganttBarPlot{
			\sffamily
			\dfgShowTag{\ganttWP}{id}{\getWP{\ganttWP}}[gantt-#1]
			\ifdefempty{\ganttDescription}{}
			  {:~\dfgShowTag{\ganttWP}{description}{\ganttDescription}[gantt-#1]}}

  		\str_case:VnF {\ganttPatternbar}
  		{%
  			{crosshatch}{\ganttbar[bar/.append~ style = {%
  							pattern       = {crosshatch},
  							pattern~ color = {color@gantt@crosshatch},
  							draw           = {color@gantt@frame}
  						}]{\ganttBarPlot}{\ganttPeriodStart}{\ganttPeriodEnd}}%

  			{striped}{\ganttbar[bar/.append~ style = {%
  							fill          = {color@gantt@stripe-one},
  							% the pattern needs to be applied after the filled color
  							postaction    ={pattern={Lines[%
  													angle=45,
  													distance={12pt},
  													line~ width=6pt]},
  									pattern~ color= color@gantt@stripe-two},
  							postaction    = {draw, semithick},
  							draw          = {color@gantt@frame}
  						}]{\ganttBarPlot}{\ganttPeriodStart}{\ganttPeriodEnd}}%

  			{alternative}{\ganttbar[bar/.append~ style = {%
  							fill          = {color@gantt@alternative},
  							draw          = {color@gantt@frame}
  						}]{\ganttBarPlot}{\ganttPeriodStart}{\ganttPeriodEnd}}%

  			{important}{\ganttbar[bar/.append~ style = {%
  							fill          = {color@gantt@important},
  							draw          = {color@gantt@frame}
  						}]{\ganttBarPlot}{\ganttPeriodStart}{\ganttPeriodEnd}}%
  		}
  		{ % default
  			{}{\ganttbar[bar/.append~ style = {%
  							fill          = {color@gantt@default},
  							draw          = {color@gantt@frame}
  						}]{\ganttBarPlot}{\ganttPeriodStart}{\ganttPeriodEnd}}%
  		}
  		\DTLiflastrow{\ganttnewline}{\\}}%
  	\hypersetup{linkcolor=blue}}
}
%    \end{macrocode}
% The following macro makes it easier to debug the position of the bars.
%    \begin{macrocode}
\newcommand{\dfgGanttShowQs}[2]{%
  \bool_if:NTF \l_@@_class_showtags_bool
  {\leavevmode\vbox to\z@{{%
  			\vss\color{color@tags@line}
  			\rlap{\vrule\raise .9em%
  				\hbox{{%
  						\fontsize{4}{0}\selectfont%
  						\ttfamily\,#1:#2}}}}}
  	\textcolor{color@tags@font}{#1}}
  {#1}
}
\NewDocumentCommand{\dfgGanttEnvironment}{m}{
  % #1 : Project ID 
  \resizebox{\linewidth}{!}{
  	\begin{ganttchart}[
  			title~ height=.8,
  			title/.append~ style={draw=none, fill=tableHeadingsBG},
  			dfgTitleTopRule/.style={
  				title/.append~ style={
  					path~ picture={
  						\draw[draw=tableOuterLines,line~ width=2pt]
  							(path~ picture~ bounding~ box.north~ west) --
  							(path~ picture~ bounding~ box.north~ east);
  					}}},
  			dfgTitleBottomRule/.style={
  				title/.append~ style={
  					path~ picture={
  						\draw[draw=tableOuterLines,line~ width=2pt]
  							(path~ picture~ bounding~ box.south~ west) --
  							(path~ picture~ bounding~ box.south~ east);
  					}}},
  			dfgTitleBottomRightRule/.style={
  				title/.append~ style={
  					path~ picture={
  						\draw[draw=tableOuterLines,line~ width=2pt]
  							(path~ picture~ bounding~ box.south~ west) --
  							(path~ picture~ bounding~ box.south~ east);
  						\draw[draw=tableOuterLines,line~ width=2pt]
  							(path~ picture~ bounding~ box.north~ east) --
  							(path~ picture~ bounding~ box.south~ east);
  					}}},
  			title~ label~ font={\bfseries\footnotesize\color{tableHeadingsFont}},
  			canvas/.style={
  					shape=rectangle,
  					draw=none,
  					fill=white,
  					path~ picture={
  						\draw[draw=tableOuterLines,line~ width=2pt]
  							(path~ picture~ bounding~ box.north~ west) --
  							(path~ picture~ bounding~ box.north~ east);
  						\draw[draw=tableOuterLines,line~ width=2pt]
  							(path~ picture~ bounding~ box.south~ west) --
  							(path~ picture~ bounding~ box.south~ east);
  					}},
  			x~ unit = \textwidth/16,
  			y~ unit~ title=0.5cm,
  			y~ unit~ chart=.5cm,
  			vgrid={*1{tableLines,dashed}},
  			%hgrid,
  			%   group label font=\bfseries\footnotesize,
  			%   milestone label font=\scriptsize,
  			bar~ inline~ label~ node/.style={anchor=west},
  			bar~ inline~ label~ anchor=west,
  			bar~ label~ font={\scriptsize\color{tableHeadingsFont}},
  			%  title label font=\bfseries\scriptsize\color{white},
  			% bar/.style={rounded~ corners=1mm},
  			bar~ height=1,
  			inline
  			% NOTE: {1}{16} = 16 quarters = 5 years (2 + 4 + 4 + 4 + 2 quarters).
  			% This is hardcoded. To adapt to a different funding period length,
  			% update the ganttchart range, the \gantttitle blocks below,
  			% and the fundingYears-related fields in the meta keyset.
  		]{1}{16}
		\gantttitle[dfgTitleTopRule]{\dfgFundingYear{1}}{2}
		\gantttitle[dfgTitleTopRule]{\dfgFundingYear{2}}{4}
		\gantttitle[dfgTitleTopRule]{\dfgFundingYear{3}}{4}
		\gantttitle[dfgTitleTopRule]{\dfgFundingYear{4}}{4}
		\gantttitle[dfgTitleTopRule]{\dfgFundingYear{5}}{2}\\
  		%===================
  		% \gantttitle{\crcTMPganttShowQs{Q1}{1}}{1}
  		% \gantttitle{\crcTMPganttShowQs{Q2}{2}}{1}
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q3}{1}}{1}
  		\gantttitle[dfgTitleBottomRightRule]{\dfgGanttShowQs{Q4}{2}}{1}
  		%===================
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q1}{3}}{1}
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q2}{4}}{1}
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q3}{5}}{1}
  		\gantttitle[dfgTitleBottomRightRule]{\dfgGanttShowQs{Q4}{6}}{1}
  		% ===================
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q1}{7}}{1}
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q2}{8}}{1}
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q3}{9}}{1}
  		\gantttitle[dfgTitleBottomRightRule]{\dfgGanttShowQs{Q4}{10}}{1}
  		% ===================
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q1}{11}}{1}
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q2}{12}}{1}
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q3}{13}}{1}
  		\gantttitle[dfgTitleBottomRightRule]{\dfgGanttShowQs{Q4}{14}}{1}
  		% ===================
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q1}{15}}{1}
  		\gantttitle[dfgTitleBottomRule]{\dfgGanttShowQs{Q2}{16}}{1}
  		%\gantttitle{\dfgGanttShowQs{Q3}{19}}{1}
  		%\gantttitle{\dfgGanttShowQs{Q4}{20}}{1}
  		\\
  		\dfgGanttContent{#1}
  	\end{ganttchart}%
  }
}
%    \end{macrocode}
% \subsubsection{TOC entry and work-package helpers}
%
% \cs{dfgTOCprojectPart}\marg{letter}\marg{title} adds a bold chapter-level
% entry to the table of contents coloured in the project colour (|projectA|
% for letter A, etc.).  Call it immediately before the project's
% \cs{chapter} command.
%
%    \begin{macrocode}
\NewDocumentCommand{\dfgTOCprojectPart}{m O{Project~area} m}{
  % #1: project       (kann leer sein)
  % #2: pre-freetext  (default: "Project area")
  % #3: free text     (kann leer sein)
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  {
    \addtocentrydefault{chapter}
      { \tl_if_blank:nF {#1} { \texorpdfstring{\getProjectColor{#1}#1}{} } }
    {
      #2\c_space_tl
      \tl_if_blank:nF {#1} { \texorpdfstring{\getProjectColor{#1}#1}{#1} ~--~ #3 }
    }
  }
}
%    \end{macrocode}
%
% \subsection{CV / Curriculum Vitae}
%
% The CV section produces structured curricula vitae in the DFG-prescribed
% format for each project leader.  The same document class is used for
% both the integrated CV pages inside the main proposal and the standalone
% |crc-cv.tex| document (identified by |cv=true|).
%
% \textbf{Structure per PI:}
% \begin{enumerate}
%   \item \cs{dfgCVheader}\marg{id} — chapter heading with name, academic
%         title and (if present) a QR code linking to the PI's homepage.
%   \item \cs{dfgCVmandatory}\marg{id} — qualification and career table
%         built from all |cv| entries with |cv-type=mandatory|.
%   \item \cs{dfgCVoptional}\marg{id} — the five supplementary sections
%         (supplement, activities, supervision, distinction, other), each
%         rendered only when at least one matching entry exists.
%   \item \cs{dfgCVpublications}\marg{id} — the ten most important
%         publications printed via biblatex; skippable with |skip10pub=true|.
%   \item \cs{dfgCVdataprivacy} — the mandatory GDPR data-privacy statement.
% \end{enumerate}
%
% \cs{dfgCV}\marg{id} is a convenience wrapper that calls all five steps
% in order and manages the bold-author activations around the publications.
%
% Creating a boolean for detecting optional content (used to conditionally
% include the privacy statement when optional sections exist).
%    \begin{macrocode}
\bool_new:N \l_@@_cvoptional_bool
%    \end{macrocode}
% \subsubsection{CV commands}
%
% \paragraph{\cs{dfgCVheader}}
% Renders the standardised CV heading for one PI.  The chapter title
% uses a two-line format: the word \enquote{Curriculum Vitae} in the
% alternative font colour, followed by the PI's full name with academic
% title in bold.  If the PI has a URL in the |person| database, a QR code
% linking to it is placed in the top-right margin on the first CV page
% via |\AddToHookNext{shipout/background}|.  The QR code is omitted when
% the URL field is empty to avoid rendering an empty code.
%    \begin{macrocode}
\bool_if:NT  \l_@@_class_cv_bool {
% multicols for TOC
% https://tex.stackexchange.com/a/314046/98739
\BeforeStartingTOC[toc]{\begin{multicols}{2}}%
\AfterStartingTOC[toc]{\end{multicols}}

% no page number for chapters in TOC
\RedeclareSectionCommands[
  tocraggedpagenumber,
  toclinefill=\tocpageseparator,
  tocindent=0em,
  tocnumwidth=0em,
  tocpagenumberbox=\tocpagenumberbox,%\tocgobble,% <- added
  tocpagenumberformat=\textsf,
]{chapter}
}

\newcommand\dfgReduceSpace{\vspace*{-1.5\baselineskip}}
\NewDocumentCommand{\dfgCVheader}{ m }{%
  % #1: person-id
  \bool_set_false:N \l_@@_cvoptional_bool

  % Single scan: pull all needed fields at once
  \getEntry*[person]{#1}{
  	\theAcademicDegree = academicdegree,
  	\theURLValue       = url,
  	\theNameValue      = lastname,
  	\theFirstNameValue = firstname,
  	\CurrentPosition   = position,
  	\CurrentPositionText   = positionText
  }%
  \addchap[{
      head={CV
        \texorpdfstring{\dfgShowTag{#1}{academicdegree}{\theAcademicDegree}[person]}
          {\theAcademicDegree}\space
        \texorpdfstring{\dfgShowTag{#1}{firstname}{\theFirstNameValue}[person]}
          {\theFirstNameValue}\space
        \texorpdfstring{\dfgShowTag{#1}{lastname}{\theNameValue}[person]}
          {\theNameValue}},
      tocentry={
        \texorpdfstring{\dfgShowTag{#1}{lastname}{\theNameValue}[person]}
          {\theNameValue},\space
        \texorpdfstring{\dfgShowTag{#1}{firstname}{\theFirstNameValue}[person]}
          {\theFirstNameValue}}}]{%
        {\normalsize\textcolor{color@font@alternative}{Curriculum \space Vitae}\\[.5\baselineskip]
	\dfgShowTag{#1}{academicdegree}{\theAcademicDegree}[person]\\[.25\baselineskip]}
	\bfseries
        \dfgShowTag{#1}{firstname}{\theFirstNameValue}[person]\space
        \dfgShowTag{#1}{lastname}{\theNameValue}[person]
  }%
  %\pdfbookmark{CV~\theNameValue, ~~ \theFirstNameValue}{cv-#1}

  % Printing the QR code only on one page next to the headline.
  \AddToHookNext{shipout/background}{%
    \DTLifnullorempty{\theURLValue}
    {}
    {\put(\pagewidth-\marginparwidth,-.05\paperheight){%
			\dfgShowTag{#1}{url}{\qrcode[link,height=1.5cm]{\theURLValue}}[person]}}%
  }

  \begin{tblr}[
  		theme   =main,
  		long
  	]{
  		colspec={X[t]X[4,t]},
  		% $column{2}={font=\bfseries},
  		columns={halign=l},
  		row{odd}={bg=white},
  		row{even}={bg=white},
        row{1}={font=\footnotesize\bfseries\sffamily,
                bg=tableHeadingsBG,
                fg=tableHeadingsFont}
  	}
  	Personal~ Data                                               &                                           \\
	Title                                                        & \dfgShowTag{#1}{academicdegree}{\theAcademicDegree}[person] \\
	First~ name                                                  & \dfgShowTag{#1}{firstname}{\theFirstNameValue}[person] \\
	Name                                                         & \dfgShowTag{#1}{lastname}{\theNameValue}[person] \\
	Current~ position                                            &
\ifdefempty{\CurrentPositionText}
  {\dfgShowTag{#1}{position}{\dfgCategoryName{\CurrentPosition}}[person]}
  {\dfgShowTag{#1}{positionText}{\CurrentPositionText}[person]}
  	\\
  	{Current~ institution(s)/\\ site(s),~ country} & {\dfgInstitutionList{#1} }                \\
  	ORCiD                                                        & \getORCiD{#1}                             \\
  \end{tblr}
  \dfgReduceSpace
}
%    \end{macrocode}
% The next section is about |Qualifications and Career|.
%    \begin{macrocode}
\NewDocumentCommand{\dfgCVmandatory}{ m }{%
  % #1: person-id
    \DTLsortdata{cv-#1}
       {
        periodStart ={descending=true},
        periodEnd   ={descending=true},
        position    ={ascending=true}
         }

  \group_begin:
  \def\tblrbody{}

  % Build the institution-name prop on first use (shared with ProjectsTable)
  \@@_proj_pi_build:

  % Single scan over person table for the three fields shown above
  \getEntry*[person]{#1}{
  	\theDegreeProgramme = degree-programme,
  	\theDoctorateYear   = doctorateYear,
  	\theDoctorate       = doctorate
  }%

  \DTLforeach*[
  	\DTLiseq{\dfgrefpersonid}{#1}
  	\and
  	\DTLiseq{\dfgtype}{mandatory}
  ]{cv-#1}{%
  	\dfgrefpersonid      = ref-person-id,
  	\dfgtype             = type,
  	\dfgyearstart        = periodStart,
  	\dfgyearend          = periodEnd,
  	\dfgpositionText     = positionText,
  	\dfgposition         = position,
  	\dfgrefinstitutionid = ref-institution-id,
  	\dfgdescription      = description
  }{%
  	% Hash lookup instead of two \DTLgetvalueforkey calls
  	\prop_get:NVNTF \g_@@_inst_narrow_prop \dfgrefinstitutionid \theInstAffName
  	{}
  	{ \tl_clear:N \theInstAffName }%

  	\protected@edef\tblrbody{\tblrbody
      \ifdefempty{\dfgyearend}
        {since\space\dfgShowTag{#1}{periodStart}{\dfgyearstart}[cv-#1]}
        {\str_if_eq:eeTF { \dfgyearstart } { \dfgyearend }
        { \dfgShowTag{#1}{periodStart}{\dfgyearstart}[cv-#1] }
        { \dfgShowTag{#1}{periodStart}{\dfgyearstart}[cv-#1]--
          \dfgShowTag{#1}{periodEnd}{\dfgyearend}[cv-#1] }}
  		\ifdefempty{\dfgposition}
		{}{:\space\dfgShowTag{#1}{position}{\dfgposition}[cv-#1]}
  		&
		{\dfgShowTag{#1}{positionText}{\dfgpositionText}[cv-#1]
  			\ifdefempty{\theInstAffName}{}{,\space\theInstAffName}%
			\ifdefempty{\dfgdescription}{}
			  {\\\textit{\dfgShowTag{#1}{description}{\dfgdescription}[cv-#1]}}%
  		}
  		\\
  	}%
  }

  \begin{tblr}[
  		theme  = main,
  		expand = \tblrbody,
  		long
  	]{
  		colspec = {X[.7,t]X[4,t]},
  		columns = {halign=l},
  		row{odd}={bg=white},
  		row{even}={bg=white},
        row{1}={font=\footnotesize\bfseries\sffamily,
                bg=tableHeadingsBG,
                fg=tableHeadingsFont}
  	}
  	\SetCell[c=2]{l}{Qualifications~ and~ Career} &                                      \\
  	\SetRow{tableHeadingsBGalt,font=\footnotesize\bfseries,halign=l}%
  	Stages                      & Periods~ and~ Details                \\
	{Degree\\programme}            & \dfgShowTag{#1}{degree-programme}{\theDegreeProgramme}[person] \\
	Doctorate                   & \dfgShowTag{#1}{doctorateYear}{\theDoctorateYear}[person]\space
                                    \dfgShowTag{#1}{doctorate}{\theDoctorate}[person] \\
  	\SetHline{-}{tableOuterLines,.5pt}%
  	% \SetRow{tableHeadingsBGalt}%
  	% \SetCell{font=\footnotesize\bfseries,halign=l}%
  	% Stages~ of~ academic/professional~ career &                                      \\
  	\tblrbody
  \end{tblr}
  \group_end:
  \dfgReduceSpace
}
%    \end{macrocode}
% The next section is about |Supplementary Career Information|, or
% |Activities in the Research System| or |Supervision of Researchers in Early|
% |Career Phases| since they all are technically the same.
%    \begin{macrocode}
\NewDocumentCommand{\dfgCVoptional}{ m m m }{%
  \def\tblrbody{}
  \DTLforeach*[
  	\DTLiseq{\dfgrefpersonid}{#1}
  	\and
  	\DTLiseq{\dfgtype}{#2}
  ]{cv-#1}{%
  	\dfgrefpersonid      = ref-person-id,
  	\dfgtype             = type,
  	\dfgyearstart        = periodStart,
  	\dfgyearend          = periodEnd,
  	\dfgpositionText     = positionText,
  	\dfgposition         = position,
  	\dfgrefinstitutionid = ref-institution-id,
  	\dfgdescription      = description
  }{%
    % datatool represents an absent value in a numeric column by its null
    % sentinel, which expands like zero in this context.  Normalise those
    % sentinels before testing the optional period fields; description-only
    % CV entries must not acquire a spurious ``0'' in the first column.
    \DTLifnullorempty{\dfgyearstart}{\def\dfgyearstart{}}{}
    \DTLifnullorempty{\dfgyearend}{\def\dfgyearend{}}{}
  	\bool_lazy_and:nnTF
  	  { \tl_if_empty_p:V \dfgyearstart }
  	  { \tl_if_empty_p:V \dfgyearend }
  	{%
		\protected@edef\tblrbody{\tblrbody
        \SetCell[c=2]{l,wd=\dimexpr\textwidth-12pt\relax}
          {\dfgShowTag{#1}{description}{\dfgdescription}[cv-#1]} & \\
  		}%
  	}
  	{%
  		\protected@edef\tblrbody{\tblrbody
        \ifdefempty{\dfgyearstart}
          {
            \ifdefempty{\dfgyearend}
              {}
              {\dfgShowTag{#1}{periodEnd}{\dfgyearend}[cv-#1]\space}
          }
          {
            \ifdefempty{\dfgyearend}
              {since\space\dfgShowTag{#1}{periodStart}{\dfgyearstart}[cv-#1]\space}
              {
                \str_if_eq:eeTF { \dfgyearstart } { \dfgyearend }
                  { \dfgShowTag{#1}{periodStart}{\dfgyearstart}[cv-#1] }
                  { \dfgShowTag{#1}{periodStart}{\dfgyearstart}[cv-#1]--
                    \dfgShowTag{#1}{periodEnd}{\dfgyearend}[cv-#1] }
                \space
              }
          }
        &
        \dfgShowTag{#1}{description}{\dfgdescription}[cv-#1]
        \\
  		}%
  	}%
  }%

  \ifdefempty{\tblrbody}{}{%
  	\begin{tblr}[
  			theme  = main,
  			expand = \tblrbody,
  			long
  	  		]{
             %rowsep=3pt,
  			width = \textwidth,
  			colspec = {X[0.7,t]X[4,t]},
  			columns = {halign=l},
  			row{odd}={bg=white},
  			row{even}={bg=white},
            row{1}={font=\footnotesize\bfseries\sffamily,
                    bg=tableHeadingsBG,
                    fg=tableHeadingsFont}
  		}
  		\SetCell[c=2]{l}{#3} & \\*
      \tblrbody
  	\end{tblr}
  	\bool_set_true:N \l_@@_cvoptional_bool
    \dfgReduceSpace
  }%
}
%    \end{macrocode}
% For the publications we define a custom bibliography template that is
% enumerating the items as required.
%    \begin{macrocode}
\newlist{DFGlist}{enumerate}{1}
\setlist[DFGlist]{leftmargin=*}
\setlist[DFGlist,1]{
  % font=\bfseries,
  % first=\bfseries,
  % after=\normalfont,
  % itemsep=.5\baselineskip,
  % wide,
  label={\bfseries\arabic*.},
  nosep
}
%    \end{macrocode}
% Further on we apply this to the bibliography environment.
%    \begin{macrocode}
\defbibenvironment{DFGlist}
{\begin{DFGlist}\RaggedRight}
{\end{DFGlist}}
{\item}
%    \end{macrocode}
% The next section combines everything and wraps it.
% To have a reference listed in this section you have to write into the
%    \begin{macrocode}
\defbibheading{categoryA}{%
  \par
  \begin{tblr}[ theme=main, long ]{
  		rowhead = 0,
  		colspec = {X[1,t]},
  		row{odd}={bg=white},
  		row{even}={bg=white},
  		%hline{1,2,Z} = {0pt},
            row{1}={font=\footnotesize\bfseries\sffamily,
                    bg=tableHeadingsBG,
                    halign=l,
                    fg=tableHeadingsFont},
  		row{2} = {%bg=tableHeadingsBGalt, fg=tableHeadingsFont,
  			         font=\footnotesize\sffamily, halign=l, valign=t, guard},
  	}Scientific~ results \\*
  	Category~ A~ --~ Articles~ in~ peer-reviewed~ journals,~
  	contributions~ to~ peer-reviewed~ conferences~ or~ to~
  	anthology~ volumes,~ and~ book~ publications              \\
  \end{tblr}
  \vspace*{-1.5\baselineskip}
}

\defbibheading{categoryB}{%
  \par
  \begin{tblr}[ theme=main, long ]{
  		rowhead = 0,
  		colspec = {X[1,t]},
  		row{odd}={bg=white},
  		row{even}={bg=white},
  		%hline{1,2,Z} = {0pt},
            row{1}={font=\footnotesize\bfseries\sffamily,
                    bg=tableHeadingsBG,
                    halign=l,
                    fg=tableHeadingsFont},
  		row{2} = {%bg=tableHeadingsBGalt, fg=tableHeadingsFont,
  			         font=\footnotesize\sffamily, halign=l, valign=t, guard},
  	}Scientific~ results \\*
  	Category~ B~ --~ Any~ other~ form~ of~ published~ results \\
  \end{tblr}
  \vspace*{-1.5\baselineskip}
}

\NewDocumentCommand{\dfgCVpublications}{ m }{%
  % #1: person-id
  \bool_if:NTF \l_@@_class_skipTENpublications_bool
  {%
  	\par
  	\group_begin: \ttfamily
  	Publication~ section~ for~ \getFullName{#1}~ omitted~
  	for~ faster~ compilation.\\
  	To~ enable~ the~ 10~ most~ important~ publications,~
  	go~ to~ the~ documentclass~ options\\ and~ state~
  	'\textbf{skip10pub=false}'.
  	\group_end:
  }{%
  	\tl_gset:Nn \g_@@_current_pi_tl {#1}
  	\newrefcontext[sorting=ydnt]
  	\nocite{*}%
  	\datatool_if_has_key:nnT { person } { name-alias }
  	{
  		\DTLgetvalueforkey { \theAliases } { name-alias } { person } { id } { #1 }
  		\DTLifnullorempty { \theAliases }
  		{ }
  		{ \exp_args:No \addboldnames { \theAliases } }
  	}

  	\renewcommand*{\bibfont}{\footnotesize}%

  	\printbibliography[
  		env          = DFGlist,
  		resetnumbers,
  		keyword      = {#1-A},
  		heading      = categoryA
  	]
  	\printbibliography[
  		env          = DFGlist,
  		resetnumbers,
  		keyword      = {#1-B},
  		heading      = categoryB
  	]

  	\endrefcontext
  	\resetboldnames
  	\tl_gclear:N \g_@@_current_pi_tl
  }%
}

\tl_new:N \g_@@_current_pi_tl
%    \end{macrocode}
% \begin{macro}{\ifIDequal}
%   Conditional macro for use inside \texttt{.bib} files.  Inside an
%   |addendum| field, write \verb|\ifIDequal{pi-id}{text}|; the text is
%   only emitted when the bibliography is being rendered for that PI.
%
%   The current PI is held in |\g_@@_current_pi_tl|, which is set by
%   |\dfgCVpublications| before each \verb|\printbibliography| call.
%
%   The implementation deliberately uses classic \LaTeX{} primitives
%   (|\edef|, |\ifx|, |\csname|) rather than expl3, because |\ifIDequal|
%   is invoked from inside a |biblatex|-rendered bibliography where
%   |\ExplSyntaxOff| is in effect.  Wrapping the variable lookup in
%   |\csname...\endcsname| makes the name resolve correctly regardless
%   of catcode state.
%    \begin{macrocode}
\DeclareFieldFormat{addendum}{\mkbibitalic{#1}}
\ExplSyntaxOff
\protected\long\def\ifIDequal#1#2{%
  \if\relax\detokenize{#2}\relax
    % #2 is empty: do nothing
  \else
    \begingroup
      \edef\dfg@tempa{#1}%
      \edef\dfg@tempb{\csname g_@@_current_pi_tl\endcsname}%
      \ifx\dfg@tempa\dfg@tempb
        \endgroup \par\textcolor{color@font@alternative}{#2}%
      \else
        \endgroup
      \fi
  \fi
}
\ExplSyntaxOn
%    \end{macrocode}
% \end{macro}
% After each section - especially when any content was written for the optional
% parts, a data privacy is needed.
% We only need this section if there has been optional text before. We find this
% out by checking the bool.
%    \begin{macrocode}
\ExplSyntaxOff
\NewDocumentCommand{\dfgCVdataprivacy}{ m }{%
  \begin{tblr}[%
  		theme   =main,
  		long
  	]{%
  		colspec = {
  				X[-1,t]
  				X[10,t]
  			},
  		rows = {bg=white},
  		row{2-Z}={font=\scriptsize},
        row{1}={font=\footnotesize\bfseries\sffamily,
                    halign=l,
                    bg=tableHeadingsBG,
                    fg=tableHeadingsFont},
  	}
  	\SetCell[c=2]{l}
  	Data protection and consent to the processing of optional data &   \\
  	\SetCell{font=\large}\ding{55}  & I (\getFullName*{#1}) expressly consent 
        to the processing of the voluntary
  	(optional) information, including “special categories of personal data” in
  	connection with the DFG’s review and decision-making process regarding my
  	proposal. This also includes forwarding my data to the external reviewers,
  	committee members and, where applicable, foreign partner organisations who
  	are involved in the decision-making process. To the extent that these
  	recipients are located in a third country (outside the European Economic
  	Area), I additionally consent to them being granted access to my data for
  	the above-mentioned purposes, even though a level of data protection
  	comparable to EU law may not be guaranteed. For this reason, compliance with
  	the data protection principles of EU law is not guaranteed in such cases. In
  	this respect, there may be a violation of my fundamental rights and freedoms
  	and resulting damages. This may make it more difficult for me to assert my
    rights under the General Data Protection Regulation (e.g.\ information,
  	rectification, erasure, compensation) and, if necessary, to enforce these
  	rights with the help of authorities or in court.  \\[2pt]
  	& I may \emph{revoke} my consent in whole or in part at any time – with effect for the
  	future, freely and without giving reasons – vis-à-vis the DFG
  	(\href{mailto:postmaster@dfg.de}{postmaster@dfg.de}). The lawfulness of the
  	processing carried out up to that point remains unaffected. Insofar as I
  	transmit \enquote{special categories of personal data} relating to third
  	parties, I confirm that the necessary legitimation under data protection law
    exists (e.g.\ based on consent). \\[2pt]
  	   & I have taken note of the DFG’s Data Protection Notice relating to research
  	funding, which I can access at \url{www.dfg.de/privacy_policy} and I will forward it
  	to such persons whose data the DFG processes as a result of being mentioned in
  	this CV.
  \end{tblr}
}
\ExplSyntaxOn
%    \end{macrocode}
% We wrap everything into one command.
%    \begin{macrocode}
\NewDocumentCommand{\dfgCV}{ m }{%
  % #1: person-id
	\bool_if:NF \l_@@_class_fastcompile_project_bool
	{
 	\DTLifdbexists{cv-#1}{
  \StartTimer\dfgCVheader{#1}\StopTimer{#1:dfgCVheader}
  \StartTimer\dfgCVmandatory{#1}\StopTimer{#1:dfgCVmandatory}
  \StartTimer\dfgCVoptional{#1}{supplement}{Supplementary~ Career~ Information}\StopTimer{#1:dfgCVoptional|supplement}
  \StartTimer\dfgCVoptional{#1}{activities}{Activities~  in~  the~  Research~ System}\StopTimer{#1:dfgCVoptional|activities}
  \StartTimer\dfgCVoptional{#1}{supervision}{Supervision~  of~  Researchers~  in~  Early~  Career~  Phases}\StopTimer{#1:dfgCVoptional|supervision}
  \StartTimer \dfgCVpublications{#1}\StopTimer{#1: dfgCVpublications}
  \StartTimer\dfgCVoptional{#1}{distinction}{Academic~  Distinctions}\StopTimer{#1:dfgCVoptional|distinction}
  \StartTimer\dfgCVoptional{#1}{other}{Other~ Information}\StopTimer{#1:dfgCVoptional|other}

  % We check for the bool at this place because we dont have to enable
  % \LaTeX3-Syntax within the command which would require to put |~| at each space.
  \bool_if:NT \l_@@_cvoptional_bool  {
  	\StartTimer	\dfgCVdataprivacy{#1} \StopTimer{#1:dfgCVdataprivacy}
  }
} 
{\msg_warning:nne { dfg } { database-not-found }{ cv-#1 }}
	}
}
%    \end{macrocode}
% The CV should be printed automatically for all persons with the role |PI|.
%    \begin{macrocode}
\NewDocumentCommand{\dfgCVsection}{ O{person} }{%
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  {
  \DTLifdbexists{#1}{%
  	\DTLsort*{lastname,firstname}{#1}%
  	\DTLforeach*[%start of conditions
  		\DTLisinlist{\theFundingPeriodNumeral}{\period}% 1st condition
  		\and%
  		\DTLisinlist{PI}{\role}% 2nd condition
  	]{#1}{%
  		\id             =id,
  		\period         =period,
  		\role           =role%
  	}{%
	\exp_args:Ne \dfgCV { \id }
  	}
}{ 
   Database \texttt{#1} missing.
  	\msg_warning:nne { dfg } { database-not-found }{ #1 }
  }%
  }
}
%    \end{macrocode}
% Finally we load the metadata and customization provided by the user.
% In case a file is missing a message will be displayed to inform the user.
%    \begin{macrocode}
\NewDocumentCommand{\checkFile}{m}{%
   	\StartTimer
  \file_if_exist:nTF {#1}
  {\ExplSyntaxOff\input{#1}\ExplSyntaxOn}
  {\msg_warning:nne { dfg } { file-not-found }{#1}}%
    \StopTimer{checkFile:#1}
}
%    \end{macrocode}
% There are at least some file we need or should consider checking.
%    \begin{macrocode}
\bool_if:NF \l_@@_class_fastcompile_project_bool
{
  \checkFile{metadata/dfg-metadata.tex}
  \bool_if:NTF \l_@@_class_cv_bool
  { \checkFile{metadata/dfg-metadata-cv.tex} }
  { \msg_warning:nnn { dfg } { cv-entry-omitted }
    {metadata/dfg-metadata-cv.tex} }
  \bool_if:NF \l_@@_class_cv_bool
  { \checkFile{metadata/dfg-metadata-tables.tex} }
}
%    \end{macrocode}
% This is a gimmick but quite fun to experiment with. This is taken from
% \url{https://tex.stackexchange.com/a/732406/98739}. Note that the message is
% written into the |.log|-file, not in the terminal.
%    \begin{macrocode}
\def\dfgFinalComment{Well~ done~ coding!~ Happy~ TeXing.}
\directlua{
  luatexbase.add_to_callback('wrapup_run',
  function ()
  f=io.open("\jobname.log", "a")
  f:write("\dfgFinalComment")
  f:close()
  end,
  "final message"
  )
}
%    \end{macrocode}
% \iffalse
%</cls>
%<*main>
% \fi
% \subsection{Main file}
% In this section we provide a skeleton of files to be used as a starting point
% for your proposal. You can adjust the content anytime.
% The following code block leads to a strange behaviour and \\ in a table are ignored,
% it can be fixed with a minipage around the table.
%    \begin{macrocode}
% \DocumentMetadata{
%   pdfstandard=A-2b,
%   lang=en-EN,
%   % tagging=structure,
%   % uncompress
% }
\documentclass[
  showtags         =true,
  showtags-tables  =false,
  showmarginalia   =true,
  % fastcompile    =true,
  % fastcompile-project =true,
  % fastcompile-project-show-images=true,
  % fastcompile-project-show-publications=false,
  % skip10pub      =true,
  % colorscheme    =rgb,
  % final          =true,
  english % <-- needed here
]{dfg-crc}
%    \end{macrocode}
% We use |includeonly| for the case to compile only one, two or n-many chapters.
% This speeds up the compiling time in case you are working mainly and currently
% on one specific chapter.
%    \begin{macrocode}
%% % \includeonly{
%% %   content/01_general-information,
%% %   content/02_existing-funds-and-requested-funds,
%% %   content/03_project,
%% %   content/04_bylaws-of-the-crc,
%% %   content/05_declarations
%% %}
\begin{document}
\dfgIfFastCompileProjectF{\input{content/00_titlepage}}
\include{content/01_general-information}
\include{content/02_existing-funds-and-requested-funds}
\include{content/03_project}
\include{content/04_bylaws-of-the-crc}
\include{content/05_declarations}
\include{content/99_backmatter}
\end{document}
%    \end{macrocode}
% \iffalse
%</main>
%<*bib>
%<*base>
% \fi
% \subsection{Bibliography Files}
% There are at least two bibliography files in the folder |bib/|.
% One is for the common |bibtex|-entries, the others contain so called
% |strings|.
% \subsubsection{Main Bibliography File}
%    \begin{macrocode}
@Article{FAIR2016,
  	Author          = {Wilkinson, Mark D. and others},
  	Title           = {The {FAIR} Guiding Principles for scientific data management and stewardship},
  	JournalTitle    = {Scientific Data},
  	Date            = {2016-12},
  	DOI             = {10.1038/sdata.2016.18},
  	Keywords        = {{FAIR}},
  	langid          = {english},
  	Number          = {1},
  	Pages           = {160018},
  	ShortJournal    = {Sci Data},
  	URLDate         = {2021-05-31},
  	Volume          = {3}
  }
%    \end{macrocode}
% \iffalse
%</base>
%<*strings>
% \fi
% \subsubsection{Bibliography Strings}
% The |strings| are used for quick and consistent referencing parts repeatedly.
%    \begin{macrocode}
@String {equal      = {\textit{*equal contribution}}}
@String {sharedlast = {\textit{*shared last authorship}}}
%    \end{macrocode}
% \iffalse
%</strings>
%</bib>
%<*custom>
% \fi
% \subsection{Customization File}
% In the file \dfgFile{preamble/dfg-customization} you can adjust settings of
% this template. Further information you find in \cref{doc:customization}.
% If you want to create new commands put them in this file as well.
%    \begin{macrocode}
% \title{<Title>}
% \subtitle{<Subtitle>}
%% \changeSettings{
%% font                        =<nn>,
%% crcLogoPath                 =<file path>,
%% affiliationLogoPath         =<file path>,
%% doiAPIMail                  =<contact email for optional DOI API lookup>,
%% projectPIOncePerSection     =true,
%% salary@prof                 =123600,
%% salary@groupLeader          =102300,
%% salary@postDoc              =88200,
%% salary@medDoc               =111000,
%% salary@PhD                  =81600,
%% salary@research             =67200,
%% salary@nonResearch          =60000,
%% salary@student              =1,
%% salary@assistant            =1,
%% animalHousing@mouse         =0.75,
%% animalHousing@mouseGnotobiotic=3.9,
%% animalHousing@rat           =1.4,
%% thumbindex                  =true,
%% thumbindex@pattern          =<int>,
%% boldnamesinbib              =false,
%% biblatexstyleCV             =<nn>,
%% biblatexstyleFeatureCV      ={<nn>,<nn>},
%% biblatexstyleProposal       =<nn>,
%% biblatexstyleFeatureProposal={<nn>,<nn>},
%%%%%   color section   %%%%%
%% color@reference@boldAuthors =<nn>,
%% color@table@headingsBG      =<nn>,
%% color@table@headingsBGalt   =<nn>,
%% color@table@headingsFont    =<nn>,
%% color@table@rows            =<nn>,
%% color@table@lines           =<nn>,
%% color@table@outerLines      =<nn>,
%% color@table@noValue         =<nn>,
%% color@table@firstColumn     =<nn>,
%% color@table@link            =<nn>,
%% color@table@contFootHead    =<nn>,
%% color@table@caption         =<nn>,
%% color@gantt@frame           =<nn>,
%% color@gantt@default         =<nn>,
%% color@gantt@crosshatch      =<nn>,
%% color@gantt@important       =<nn>,
%% color@gantt@stripe-one      =<nn>,
%% color@gantt@stripe-two      =<nn>,
%% color@thumbindex@bg         =<nn>,
%% color@thumbindex@font       =<nn>,
%% color@tags@font             =<nn>,
%% color@tags@line             =<nn>,
%% color@font@alternative      =<nn>,
%% color@item@i                =<nn>,
%% }
%    \end{macrocode}
% \iffalse
%</custom>
% \fi
% \subsection{DFG salary and animal-housing defaults}
%
% The DFG specifies standardised all-in salary costs (\emph{Personalmittel})
% per position category for the current funding year.  These constants are
% used in the requested-funding staff tables to calculate yearly personnel
% costs from FTE counts.
%
% The values are updated annually and published by the DFG.  Their canonical
% defaults are keys in the |dfg/custom| key family.  Override them together
% with the other proposal settings in |dfg-customization.tex|:
% \begin{dispListing*}{title={Overriding salary and animal-housing rates}}
%   \changeSettings{
%     salary@postDoc      = 90000,
%     animalHousing@mouse = 0.80,
%   }
% \end{dispListing*}
%
% Source: \url{https://www.dfg.de/resource/blob/345094/31cd4b597ee7a1fc711a8f2566010783/60-12-2025-de-data.pdf}
% (status: 2026-01)
%
% The expandable \cs{dfgSalaryProf}, \cs{dfgSalaryGroupLeader},
% \cs{dfgSalaryPostDoc}, \cs{dfgSalaryMedDoc}, \cs{dfgSalaryPhD},
% \cs{dfgSalaryResearch}, \cs{dfgSalaryNonResearch},
% \cs{dfgSalaryStudent}, \cs{dfgSalaryAssistant}, \cs{dfgMouseHousing},
% \cs{dfgMouseHousingGnotobiotic}, and \cs{dfgRatHousing} accessors remain
% available for compatibility.  They expand to the corresponding setting.
% \iffalse
%<*meta>
% \fi
% \subsection{Metadata File}
% The file \dfgFile{metadata/dfg-metadata} provides all or at least most of the meta
% information needed for the proposal. Especially put all entries of |person|,
% |affiliation|, |institution| and |meta| (the proposal title etc.) in here.
% For an explanation how to use and fill the fields see \cref{doc:metadata}.
%    \begin{macrocode}
\addEntry{meta}{
  id                   = {crc}, %<--- id (do not change)
  name                 = {Mechanisms of Host--Microbiome Communication},
  nameAddon            = {From Molecular Interactions to Organ Function},
  number               = {9999},
  fundingPeriodNumeral = {3}, % 1|2|3
  ref-affiliation-id   = {aff1}, % or {aff1,aff2} for two applicants
  fundedSince          = {2019-07-01},
  fundingYears         = {2027|2,2028,2029,2030,2031|1},
  fundingYearsPrevious = {2022|2,2023,2024,2025,2026|1}
}

\addEntry{institution}{
  id                 = {ins1},
  name               = {Institute of Microbial Systems Medicine},
  abbreviation       = {IMSM},
  ref-affiliation-id = {aff1}
}

\addEntry{institution}{
  id                 = {ins2},
  name               = {Department of Translational Biosciences},
  abbreviation       = {DTB},
  ref-affiliation-id = {aff2}
}


\addEntry{affiliation}{
  id            = {aff1},
  name          = {Example University},
  abbreviation  = {EU},
  addressStreet = {University Avenue 1},
  addressZIP    = {12345},
  location      = {Example City},
  country       = {Germany}
}

\addEntry{affiliation}{
  id            = {aff2},
  name          = {Partner University},
  abbreviation  = {PU},
  addressStreet = {Research Road 2},
  addressZIP    = {54321},
  location      = {Partner City},
  country       = {Germany}
}

\addEntry{person}{
  id                   = {per1},
  firstname            = {Kim},
  lastname             = {Muster},
  academicdegree       = {Prof. Dr. rer. nat.},
  period               = {1,2,3},
  role                 = {PI},
  gender               = {d},
  ref-institution-id   = {ins1,ins2},
  ref-project-id       = {A01,A02},
  name-alias           = {
    {Kim Muster},
    {Muster, Kim S.}
  },
  orcid                = {0000-0000-0000-0001},
  doctorateYear        = {2000},
  doctorate            = {Dr. rer. nat., Example University},
  degree-programme     = {Biology, Example University},
  position             = {prof-W3},
  positionText         = {Professor and Director},
  url                  = {https://www.example.org/kim-muster},
  phone                = {+49 000 100-1000},
  email                = {kim.muster@example.org},
  contract-information = {
    C1  = {no},
    C2  = {yes},
    C2a = {2028-12-31},
    C2b = {2029-01-03},
    C3  = {yes},
    C3a = {2054-03-10},
    C4  = {no},
    C4a = {DFG}
  }
}

\addEntry{person}{
  id                   = {per2},
  period               = {2,3},
  firstname            = {Alex},
  lastname             = {Example},
  academicdegree       = {Prof. Dr. phil.},
  position             = {groupLeader},
  positionText         = {Research group leader},
  role                 = {PI,steering-committee-member},
  doctorateYear        = {1999},
  doctorate            = {Dr. phil., Partner University},
  degree-programme     = {Data Science, Partner University},
  gender               = {m},
  ref-institution-id   = {ins2},
  ref-project-id       = {A01,B01,Q01,Q02},
  orcid                = {0000-0000-0000-0002},
  phone                = {+49 000 200-2000},
  email                = {alex.example@example.org},
  contract-information = {
    C1  = {no},
    C2  = {no},
    C2a = {},
    C2b = {},
    C3  = {no},
    C3a = {},
    C4  = {yes},
    C4a = {BMFTR}
  }
}

\addEntry{person}{
  id                   = {per3},
  period               = {2,3},
  firstname            = {Hansi},
  lastname             = {Meier},
  academicdegree       = {Dr. rer. nat.},
  position             = {postDoc},
  positionText         = {Senior research scientist},
  role                 = {PI,steering-committee-member},
  doctorateYear        = {1999},
  doctorate            = {Dr. rer. nat., Partner University},
  degree-programme     = {Microbiology, Partner University},
  gender               = {f},
  ref-institution-id   = {ins2},
  ref-project-id       = {B01,Q03},
  orcid                = {0000-0000-0000-0003},
  phone                = {+49 000 200-3000},
  email                = {hansi.meier@example.org},
  contract-information = {
    C1  = {yes},
    C2  = {no},
    C2a = {},
    C2b = {},
    C3  = {no},
    C3a = {},
    C4  = {yes},
    C4a = {DFG}
  }
}

\addEntry{person}{
  id                   = {per4},
  period               = {2,3},
  firstname            = {Kimmi},
  lastname             = {Müller},
  academicdegree       = {Prof. Dr. rer. nat.},
  position             = {prof-W2},
  positionText         = {Professor of Molecular Medicine},
  role                 = {PI},
  doctorateYear        = {1999},
  doctorate            = {Dr. rer. nat., Partner University},
  degree-programme     = {Molecular Medicine, Partner University},
  gender               = {f},
  ref-institution-id   = {ins2},
  ref-project-id       = {B02},
  orcid                = {0000-0000-0000-0004},
  phone                = {+49 000 200-4000},
  email                = {kimmi.mueller@example.org},
  contract-information = {
    C1  = {yes},
    C2  = {no},
    C2a = {},
    C2b = {},
    C3  = {no},
    C3a = {},
    C4  = {yes},
    C4a = {DFG}
  }
}

\addEntry{person}{
  id                   = {per5},
  period               = {3},
  firstname            = {Friedhelm},
  lastname             = {Redata},
  academicdegree       = {Prof. Dr.-Ing.},
  orcid                = {0000-0000-0000-0005},
  position             = {prof-W2},
  positionText         = {Professor of Research Training},
  role                 = {PI,steering-committee-member},
  doctorateYear        = {1998},
  doctorate            = {Dr.-Ing., Example University},
  degree-programme     = {Biomedical Engineering, Example University},
  gender               = {m},
  ref-institution-id   = {ins1},
  ref-project-id       = {Q02},
  phone                = {+49 000 100-5000},
  email                = {friedhelm.redata@example.org},
  contract-information = {
    C1  = {yes},
    C2  = {yes},
    C2a = {2028-12-31},
    C2b = {2029-01-03},
    C3  = {yes},
    C3a = {2054-03-10},
    C4  = {no},
    C4a = {DFG}
  }
}


\addEntry{project}{
  id                 = {A01},
  project-area       = {A},
  number             = {A01},
  project-status     = {C},
  consider-for-lists = {true},
  reference-only     = {false},
  name               = {Microbial signalling across epithelial barriers},
  project-type       = {research},
  research-area      = {2.21-02},
  ref-person-id      = {per1,per2},
  collaborations     = {A02,B01,B02,Q01},
  legal-issues       = {
  		L1  = no,
  		L1a = no,
  		L2  = no,
  		L2a = no,
  		L3  = no,
  		L4  = no,
  		L5  = no,
  		L5a = no,
  		L6  = no,
  		L7  = no,
  		L7a = no
  	}
}
\addEntry{project}{
  id                 = {A02},
  project-area       = {A},
  number             = {A02},
  project-status     = {N},
  consider-for-lists = {true},
  reference-only     = {false},
  project-type       = {research},
  name               = {Metabolic control of tissue-resident immunity},
  research-area      = {2.21-05},
  ref-person-id      = {per1},
  collaborations     = {B01,Q02},
  legal-issues       = {
    L1  = no,
    L1a = no,
    L2  = yes,
    L2a = no,
    L3  = yes,
    L4  = yes,
    L5  = no,
    L5a = no,
    L6  = yes,
    L7  = no,
    L7a = yes
  }
}

%% Reference-only rows remain available to \getProject but are omitted from
%% generated lists and collaboration plots.
\addEntry{project}{
  id                 = {A00},
  project-area       = {A},
  number             = {A00},
  project-status     = {E},
  consider-for-lists = {false},
  reference-only     = {true},
  project-type       = {research},
  name               = {Former project on microbial community dynamics},
  research-area      = {},
  ref-person-id      = {},
  collaborations     = {}
}

\addEntry{project}{
  id                 = {B01},
  project-area       = {B},
  number             = {B01},
  project-status     = {C},
  consider-for-lists = {true},
  reference-only     = {false},
  project-type       = {research},
  research-area      = {2.21-03,2.21-05,2.22-15},
  name               = {Host defence during microbiome perturbation},
  ref-person-id      = {per3,per2},
  collaborations     = {A01,Q02},
  legal-issues       = {
    L1  = no,
    L1a = no,
    L2  = no,
    L2a = no,
    L3  = no,
    L4  = no,
    L5  = no,
    L5a = no,
    L6  = no,
    L7  = no,
    L7a = no
  }
}
\addEntry{project}{
  id                 = {B02},
  project-area       = {B},
  number             = {B02},
  project-status     = {E},
  consider-for-lists = {true},
  reference-only     = {false},
  project-type       = {research},
  research-area      = {2.22-15},
  name               = {Molecular signatures of tissue regeneration},
  ref-person-id      = {per4},
  collaborations     = {A01},
  legal-issues       = {
  		L1  = yes,
  		L1a = no,
  		L2  = yes,
  		L2a = yes,
  		L3  = yes,
  		L4  = yes,
  		L5  = yes,
  		L5a = no,
  		L6  = yes,
  		L7  = yes,
  		L7a = no
  	}
}
\addEntry{project}{
  id                 = {Q01},
  project-area       = {Q},
  number             = {Q01},
  project-status     = {C},
  consider-for-lists = {true},
  reference-only     = {false},
  project-type       = {service},
  name               = {Integrated imaging and analysis services},
  research-area      = {2.21-02,2.22-15},
  ref-person-id      = {per2},
  collaborations     = {A01},
  legal-issues       = {
    L1  = no,
    L1a = no,
    L2  = no,
    L2a = no,
    L3  = no,
    L4  = no,
    L5  = no,
    L5a = no,
    L6  = no,
    L7  = no,
    L7a = no
  }
}
\addEntry{project}{
  id                 = {Q02},
  project-area       = {Q},
  number             = {Q02},
  project-status     = {C},
  consider-for-lists = {true},
  reference-only     = {false},
  project-type       = {mgk},
  name               = {Integrated Research Training Group},
  research-area      = {},
  ref-person-id      = {per5,per2},
  collaborations     = {A02,B01}
}
\addEntry{project}{
  id                 = {Q03},
  project-area       = {Q},
  number             = {Q03},
  project-status     = {C},
  consider-for-lists = {true},
  reference-only     = {false},
  project-type       = {admin},
  name               = {Central coordination and data stewardship},
  research-area      = {},
  ref-person-id      = {per3},
  collaborations     = {A01,A02,B01,Q01,Q02}
}


\addEntry{person}{
  id                 = {spokesperson},
  role               = {spokesperson,steering-committee-member},
  period             = {1,2,3},
  lastname           = {Sample},
  firstname          = {Morgan},
  academicdegree     = {Prof. Dr. med.},
  gender             = {f},
  position           = {prof-W3},
  positionText       = {CRC spokesperson and professor of systems medicine},
  doctorateYear      = {1998},
  doctorate          = {Dr. med., Example University},
  degree-programme   = {Medicine, Example University},
  ref-institution-id = {ins1},
  ref-affiliation-id = {aff1},
  orcid              = {0000-0000-0000-0006},
  phone              = {+49 000 100-6000},
  email              = {morgan.sample@example.org}
}


\addEntry{person}{
  id                 = {man1},
  role               = {manager},
  period             = {2,3},
  firstname          = {Jamie},
  lastname           = {Coordinator},
  academicdegree     = {Dr. rer. nat.},
  gender             = {d},
  position           = {nonResearch},
  positionText       = {Scientific manager},
  doctorateYear      = {2012},
  doctorate          = {Dr. rer. nat., Partner University},
  degree-programme   = {Life Sciences, Partner University},
  ref-institution-id = {ins2},
  ref-affiliation-id = {aff2},
  orcid              = {0000-0000-0000-0007},
  phone              = {+49 000 200-7000},
  email              = {jamie.coordinator@example.org}
}


\addEntry{person}{
  id                 = {rector},
  role               = {rector},
  period             = {3},
  lastname           = {Rector},
  firstname          = {Robin},
  academicdegree     = {Prof. Dr.},
  gender             = {d},
  position           = {prof},
  positionText       = {Rector of Example University},
  ref-affiliation-id = {aff1},
  phone              = {+49 000 100-8000},
  email              = {rector@example.org}
}

\addEntry{person}{
  id                 = {rector2},
  role               = {rector},
  period             = {3},
  lastname           = {President},
  firstname          = {Casey},
  academicdegree     = {Prof. Dr.},
  gender             = {d},
  position           = {prof},
  positionText       = {President of Partner University},
  ref-affiliation-id = {aff2},
  phone              = {+49 000 200-8000},
  email              = {president@partner.example.org}
}

% \iffalse
%</meta>
%<*meta-cv>
% \fi

\addEntry[cv]{cv-per1}{
  ref-person-id      = {per1},
  cv-type            = {mandatory},
  periodStart        = {2013},
  periodEnd          = {},
  positionText       = {Professor and Director},
  position           = {Professor of Microbial Systems Medicine},
  description        = {Director of the Institute of Microbial Systems Medicine},
  ref-institution-id = {ins1}
}

\addEntry[cv]{cv-per1}{
  ref-person-id      = {per1},
  cv-type            = {mandatory},
  periodStart        = {2005},
  periodEnd          = {2012},
  positionText       = {Associate professor},
  position           = {Associate Professor of Molecular Microbiology},
  description        = {Established an interdisciplinary microbiome research group},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per1}{
  ref-person-id = {per1},
  cv-type       = {supplement},
  description   = {Research visits at international centres for microbiome
    science and systems immunology.}
}

\addEntry[cv]{cv-per1}{
  ref-person-id = {per1},
  cv-type       = {activities},
  description   = {Member of national review panels and organiser of an annual
    interdisciplinary host--microbiome symposium.}
}

\addEntry[cv]{cv-per1}{
  ref-person-id = {per1},
  cv-type       = {supervision},
  description   = {Supervision of doctoral and postdoctoral researchers in
    structured mentoring teams.}
}
\addEntry[cv]{cv-per1}{
  ref-person-id = {per1},
  cv-type       = {distinction},
  description   = {Example University Award for Interdisciplinary Research}
}
\addEntry[cv]{cv-per1}{
  ref-person-id = {per1},
  cv-type       = {distinction},
  description   = {Fellow of the Example Academy of Sciences}
}
\addEntry[cv]{cv-per1}{
  ref-person-id = {per1},
  cv-type       = {other},
  description   = {No commercial interests related to the proposed research.}
}

%% A CV database must exist for every current-period PI.  These compact
%% entries keep the generated CV example complete while per1 demonstrates all
%% optional CV categories above.
\addEntry[cv]{cv-per2}{
  ref-person-id      = {per2},
  cv-type            = {mandatory},
  periodStart        = {2016},
  periodEnd          = {},
  positionText       = {Research group leader},
  position           = {Computational systems biology},
  description        = {Leads the biomedical data-integration group},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per3}{
  ref-person-id      = {per3},
  cv-type            = {mandatory},
  periodStart        = {2018},
  periodEnd          = {},
  positionText       = {Senior research scientist},
  position           = {Microbiology and host defence},
  description        = {Coordinates translational infection research},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per4}{
  ref-person-id      = {per4},
  cv-type            = {mandatory},
  periodStart        = {2015},
  periodEnd          = {},
  positionText       = {Professor of Molecular Medicine},
  position           = {Molecular tissue regeneration},
  description        = {Leads the molecular regeneration programme},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per5}{
  ref-person-id      = {per5},
  cv-type            = {mandatory},
  periodStart        = {2014},
  periodEnd          = {},
  positionText       = {Professor of Research Training},
  position           = {Biomedical engineering education},
  description        = {Directs interdisciplinary doctoral training},
  ref-institution-id = {ins1}
}
% \iffalse
%</meta-cv>
%<*meta-tables>
% \fi




%    \end{macrocode}
% \iffalse
%</meta-tables>
%<*00>
% \fi
% \subsection{Title Page (Proposal specific)}
%    \begin{macrocode}
\pdfbookmark{Titlepage}{titlepage}
\begin{titlepage}
  \def\tmpLocalDB{meta}%
  \vspace*{4em}
  \begin{center}%
  	\large
	\crc\,\dfgCRCNumber\\
    \vspace*{1.5em}
    {\Large\bfseries \dfgCRCName}\\
    \dfgCRCNameAddon\\
	\vspace*{2em}
  	\crcLogo[height=2cm]\\
    \vspace*{2em}
    \theCRCCoordinatingAffiliation\\
    \dfgApplicantAffiliationsTF
      { }
      {\theCRCOtherApplicantAffiliations\\}
	\vspace*{2em}
    {\Large\bfseries Funding Proposal}\\[1em]
	for the \dfgFundingPeriodText\space Funding Period\\
	\dfgFundingYear{1}--%
	\dfgFundingYear{2}--%
	\dfgFundingYear{3}--%
	\dfgFundingYear{4}--%
	\dfgFundingYear{5}
    \dfgIfCVT{\par\textcolor{tableHeadingsFont}{Appendix: Research profiles}}
    \dfgIfFinalF{{\par\large\InfoTeX}}
  	% \iftoggle{crc@chapter}{%
  	%   \par\vspace*{5em}\par
  	%   \begin{crcTitleBox}
  	%       \centering\Huge%
  	%       {\color{rwthRed}%
  	%           \ttfamily%
  	%           content/\textbf{\dfgChapter}.tex}\\
  	%       \Large\dfgCompiled
  	%   \end{crcTitleBox}%
  	% }{}
  	\vfill
  	%
  	%  \crcLogo[height=1cm]
  	\hfill%
  	\affiliationLogo[height=1cm]
  \end{center}
  \clearpage
  \checkFile{content/00_titlepage-colophon}
\end{titlepage}
\begin{titlepage}
  % setting the default database for general information
  \def\tmpLocalDB{meta}
  \begin{center}
	Proposal for the \dfgFundingPeriodText\space Funding Period of\\
	\crc\,\dfgCRCNumber

	\enquote{\bfseries\dfgCRCName: \dfgCRCNameAddon}
  \end{center}
  funded since
  \begin{center}
  	\getEntry{crc}{fundedSince}
  \end{center}
  for
  \begin{center}
	\dfgFundingYear{1}--%
	\dfgFundingYear{2}--%
	\dfgFundingYear{3}--%
	\dfgFundingYear{4}--%
	\dfgFundingYear{5}
  \end{center}
  Coordinating university:
  \begin{center}
	\theCRCCoordinatingAffiliation
  \end{center}
  \dfgApplicantAffiliationsTF
    { }
    {
      Other applicant
      \dfgOtherApplicantAffiliationsTF{university}{universities}:
      \begin{center}
        \theCRCOtherApplicantAffiliations
      \end{center}
    }
  \Hrule[
  	thickness = 1.5pt,
  	above     = 2em,
  	below     = 2em]

  \begin{minipage}[t]{.49\linewidth}
  	\textbf{Spokesperson of\\ the \crc:}\\[1\baselineskip]
  	\getPIsWithRole{spokesperson}[raster columns=1]
  \end{minipage}\hfill%
  \begin{minipage}[t]{.49\linewidth}
  	\textbf{Management or office of\\the \crc:}\\[1\baselineskip]
  	\getPIsWithRole{manager}[raster columns=1]
  \end{minipage}
  \vfill
  \printSignaturesWithRole{spokesperson}{(Spokesperson~of~\crc)}
  \printSignaturesWithRole{rector}
    {(Rector,~chancellor,~or~president~of~
      \getEntry[affiliation]{\theAffiliationOfRoleID}{name})}
\end{titlepage}
\bgroup
\let\cleardoublepage\clearpage% to get the TOC on two pages (left/right)
\pdfbookmark{\contentsname}{Contents}
\tableofcontents
\dfgIfCVT{\KOMAoptions{open=left}}
\egroup
%    \end{macrocode}
% \iffalse
%</00>
%<*01>
% \fi
% \subsection{Content Files (Proposal specific)}
%    \begin{macrocode}
\newrefsection
\chapter{General information}
\printThumbIndex{1}
\section{Key data}
\subsection{Governing bodies of the \crc}
% \subsubsection{Spokesperson of the \thisCRC}
% \getPIsWithRole{spokesperson}

\subsubsection*{Steering Committee of the \thisCRC}

\getPIsWithRole{steering-committee-member}

For the third funding period, the steering committee includes representatives
of both research areas and the Integrated Research Training Group.  The
spokesperson and committee members are elected by the CRC general assembly in
accordance with the bylaws.  The composition is reviewed annually with regard
to scientific breadth, career stage, and equitable participation.

\subsection{Project leaders}
\printTable{ProjectLeaders}

\subsection{Participating institutions}
\printList{ParticipatingInstitutions}

\clearpage
\subsection{Project groups and projects}
\printTable{{Projects}{A}{Microbiota and metabolic pathways}}
\printTable{{Projects}{B}{Immunological circuits}}
\printTable{{Projects}{Q}{Central projects}}
N: New projects started in the \dfgFundingPeriodText\space funding period; %
E: Ending projects not continued in the \dfgFundingPeriodText\space funding
period; %
Research areas according to the German Research Foundation (2024--2028)%
\footnote{\raggedright\url{https://www.dfg.de/resource/blob/331950/fachsystematik-2024-2028-en.pdf}}:
\printList{ResearchAreasFromProjects}


% For the following sections we want to have them
% numbered until 'subsubsection'
\setcounter{secnumdepth}{4}

\clearpage
\section{Research profile of the \crc} %1.2
\begin{dfgSummaryBox}[title={Spotlights: Moving Forward}]
  \item Resolve causal mechanisms of communication between microbial
    communities, epithelial barriers, and tissue-resident immune cells.
  \item Combine spatial profiling, experimental perturbation, and predictive
    modelling across the participating projects.
  \item Translate shared methods into reproducible services, interoperable
    data, and structured training for researchers in early career phases.
\end{dfgSummaryBox}

%% \FloatBarrier % no images in references list.
\defbibnote{frame-references}{%
  \usekomafont{subsection}%
  \bfseries\sffamily References
}
\printbibliography[
  prenote={frame-references},
  heading=none
]


\subsection{Summary of the research programme}%1.2.1

The CRC investigates how microbial and host-derived signals cross epithelial
barriers and influence organ function.  During the previous funding periods,
the consortium established shared cohorts, experimental models, imaging
workflows, and computational methods.  The new programme links these resources
in hypothesis-driven projects that test causality across molecular, cellular,
and tissue scales.

\subsection{Detailed presentation of the research programme}%1.2.2

Project area A examines microbial metabolites and barrier signalling, whereas
project area B focuses on immune circuits and tissue responses.  The central
projects provide imaging, analysis, training, coordination, and research-data
services.  Common samples, harmonised metadata, and reciprocal collaborations
connect the individual work programmes and enable validation across models and
participating institutions.

\subsection{Positioning of the \crc within its general research area}%1.2.3

The programme combines mechanistic microbiome research with systems immunology
and organ physiology.  Its distinguishing feature is the coordinated
validation of candidate signals from discovery cohorts through controlled
experimental systems to tissue-level readouts, supported by shared technology
and transparent data-management standards.

\subsection{National and international cooperation and networking} %1.2.4

The CRC maintains method-oriented collaborations with national infrastructure
networks and international partner laboratories.  Cooperation agreements
define sample and data transfer, authorship, quality assurance, and access to
specialised technologies.  Visiting-researcher and exchange formats are
coordinated through the Integrated Research Training Group.

\section{Research profile of the applicant
  \dfgApplicantAffiliationsTF{university}{universities}} %1.3
\subsection{Strategy and planning}%1.3.1

Example University has identified host--microbiome research as a strategic
priority and supports the CRC through permanent scientific positions, shared
technical platforms, research-data infrastructure, and central administration.
Annual reviews align institutional investments with the scientific milestones
of the consortium.

\subsection{Staff situation} % 1.3.2

The participating units contribute principal investigators, research staff,
technical personnel, data stewards, and administrative support.  Recruitment
planning prioritises timely appointments, transparent selection procedures,
career development, and continuity of essential technical expertise.

\subsection{Research infrastructure} % 1.3.3

The CRC has access to advanced microscopy, flow cytometry, sequencing,
gnotobiotic facilities, secure data storage, and high-performance computing.
Central projects coordinate access, training, maintenance, and quality control
so that methods and datasets remain comparable across all projects.

\section{Support structures} % 1.4
\subsection{Researchers in early career phases} % 1.4.1

Researchers in early career phases receive structured scientific and career
mentoring, transferable-skills training, annual progress reviews, and access to
methods courses and exchange opportunities organised by \getProject{Q02}.

\addEntry[person]{EarlyCareerResearcher}{
  ref-project-id= {A01},
  id              = {KM},
  lastname      = {Musterlich},
  firstname     = {Kimmi},
  financed-by   = {DFG},
  category      = {PhD},
  topic         = {Epithelial sensing of microbial metabolites},
  periodStart   = {2025-04},
  periodEnd     = {2029-06}
}
\addEntry[person]{EarlyCareerResearcher}{
  ref-project-id= {B01},
  id              = {KiM},
  lastname      = {Wunderlich},
  firstname     = {Kimmi},
  financed-by   = {DFG},
  category      = {MD},
  topic         = {Immune signatures during microbiome perturbation},
  periodStart   = {2025-04},
  periodEnd     = {2029-06}
}

%% \getEntry[EarlyCareerResearcher]{KM}{lastname}
\printTable{EarlyCareerResearchers}

\subsection{Promotion of equity and diversity} % 1.4.2

Recruitment, supervision, and committee appointments follow transparent
criteria and are monitored by career stage and gender.  Flexible working
arrangements, mentoring, accessibility measures, and targeted career support
are available through the central coordination project.

\addEntry[GenderEquality]{GenderEqualityStaff}{
  position                             = {PhD}, %PhD|PostDoc
  previous-objective-percentage-female = {40},
  status-quo-number-female             = {20},
  status-quo-percentage-female         = {14},
  future-objective-percentage-female   = {40}
}

\addEntry[GenderEquality]{GenderEqualityStaff}{
  position                             = {postDoc}, %PhD|PostDoc
  previous-objective-percentage-female = {22},
  status-quo-number-female             = {34},
  status-quo-percentage-female         = {44},
  future-objective-percentage-female   = {34}
}
% -----

\addEntry[GenderEquality]{GenderEqualityProjectLeaders}{
  position                             = {postDoc}, %PhD|PostDoc
  previous-objective-percentage-female = {22},
  future-objective-percentage-female   = {34}
}
\addEntry[GenderEquality]{GenderEqualityProjectLeaders}{
  position                             = {groupLeader}, %PhD|PostDoc
  previous-objective-percentage-female = {22},
  future-objective-percentage-female   = {34}
}


\addEntry[GenderEquality]{GenderEqualityProjectLeaders}{
  position                             = {prof-W2}, %PhD|PostDoc
  previous-objective-percentage-female = {22},
  future-objective-percentage-female   = {34}
}

\addEntry[GenderEquality]{GenderEqualityProjectLeaders}{
  position                             = {prof-W3}, %PhD|PostDoc
  previous-objective-percentage-female = {22},
  future-objective-percentage-female   = {34}
}

\clearpage
\subsubsection*{A. Objectives for the participation of female researchers}
\printTable{GenderEqualityStaff}

\subsubsection*{B. Project leaders}
\printTable{GenderEqualityProjectLeaders}

\subsection{Knowledge transfer and science communication} % 1.4.3

The CRC communicates results through open research resources, public lectures,
school and patient-group activities, and dialogue formats with clinical and
societal stakeholders.  Transfer opportunities are assessed early, with clear
procedures for intellectual property, responsible communication, and reusable
research outputs.

\section{Risks in international cooperation} %1.5

International partnerships are reviewed for legal, ethical, export-control,
data-protection, and research-security risks.  Written agreements specify
permitted data and material transfers, access rights, publication principles,
and responsibilities.  The participating universities reassess collaborations
when partners, technologies, or regulatory conditions change.

\section{Considerations on aspects of ecological sustainability in project
  planning and implementation} %1.6

The CRC considers ecological sustainability when planning experiments,
procurement, travel, computing, sample storage, and shared infrastructure.
Projects consolidate measurement campaigns, share equipment and reference
materials, select proportionate data-retention and computing strategies, and
prefer lower-emission travel or remote participation where this is compatible
with the scientific objective.  The steering committee reviews these measures
alongside scientific feasibility, research quality, legal obligations, animal
welfare, and the responsible use of resources.


% ok, let’s go back to the default (from base.tex)
\setcounter{secnumdepth}{2}

\endrefsection
\resetboldnames

%    \end{macrocode}
% \iffalse
%</01>
%<*02>
% \fi
%    \begin{macrocode}
\chapter{Existing funds and requested funds} %2
\printThumbIndex{2}
\section{Existing funds} % 2.1
\subsection{Overview of existing funds for direct costs} %2.1.1

\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year        = 1,
  applicant   = 1000,
  participant = 2000,
  other-funds = 3000
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year        = 2,
  applicant   = 1000,
  participant = 2000,
  other-funds = 3000
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year        = 3,
  applicant   = 1000,
  participant = 2000,
  other-funds = 3000
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year        = 4,
  applicant   = 1000,
  participant = 2000,
  other-funds = 3000
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year        = 5,
  applicant   = 1000,
  participant = 2000,
  other-funds = 3000
}


% New-period values are declared once in the individual project files below.
% The class restores those later declarations from the preceding LaTeX run's
% auxiliary files into the overview database used here.
\printTable{ExistingFundsDirectCosts}


\subsection{Overview of existing staff} % 2.1.2
% Data are reused from project-level RequestedFundingStaff declarations with
% funding-status={existing}.  No separate overview database is required.
\printTable{OverviewExistingStaff}

\subsection{List of existing instrumentation} % 2.1.2
\addEntry[instrumentation]{existingInstrumentation}{
  ref-project-id = {A01},
  quantity       = {1},
  instrument     = {Confocal laser-scanning microscope},
  company        = {Example Instruments GmbH},
  year           = {2025},
  cost           = {250},
  financed-by    = {DFG}
}
\addEntry[instrumentation]{existingInstrumentation}{
  ref-project-id = {A01,B01},
  quantity       = {2},
  instrument     = {Anaerobic workstation},
  company        = {Laboratory Systems AG},
  year           = {2024},
  cost           = {80},
  financed-by    = {Institutional funds}
}

\printTable{ExistingInstrumentation}

\section{Previous and requested funds} %2.2
\subsection{Overview} % 2.2.1

\addEntry[funding]{PreviousRequestedFunding}{
  year            = 1,
  staff           = 1000,
  costs           = 2000,
  instrumentation = 3000,
  fellowships     = 4000,
  globalfunds     = 5000
}
\addEntry[funding]{PreviousRequestedFunding}{
  year            = 2,
  staff           = 1000,
  costs           = 2000,
  instrumentation = 3000,
  fellowships     = 4000,
  globalfunds     = 5000
}
\addEntry[funding]{PreviousRequestedFunding}{
  year            = 3,
  staff           = 1000,
  costs           = 2000,
  instrumentation = 3000,
  fellowships     = 4000,
  globalfunds     = 5000
}
\addEntry[funding]{PreviousRequestedFunding}{
  year            = 4,
  staff           = 1000,
  costs           = 2000,
  instrumentation = 3000,
  fellowships     = 4000,
  globalfunds     = 5000
}
\addEntry[funding]{PreviousRequestedFunding}{
  year            = 5,
  staff           = 1000,
  costs           = 2000,
  instrumentation = 3000,
  fellowships     = 4000,
  globalfunds     = 5000
}


\printTable{PreviousAndCurrentRequestedFunding}

\subsection{Overview of funds requested for staff} % 2.2.2
% data comes from all the 
% \addEntry[funding]{RequestedFunding}{
%    ...
%   category     = {....},
%   funding-type = {staff},
%    ...
% }
\printTable{OverviewOfFundsRequestedForStaff}

\subsection{Overview of funds requested for instrumentation} % 2.2.3

% data comes from all the 
% \addEntry[funding]{RequestedFunding}{
%    ...
%   funding-type = {instrumentation},
%    ...
% }
\printTable{OverviewFundsRequestedInstrumentation}


\section{Upkeep of laboratory animals} % 2.3
\addEntry{UpkeepLaboratoryAnimals}{
  ref-project-id   = {A01},
  species          = {mouse},
  quantity         = {1212},
  weeks-kept       = {43},
  purchasing-costs = {23},
  requested-funds  = {100},
  existing-funds   = {232}
}
\addEntry{UpkeepLaboratoryAnimals}{
  ref-project-id   = {A01,A02},
  species          = {rat},
  quantity         = {2},
  weeks-kept       = {3},
  purchasing-costs = {23.54},
  requested-funds  = {1230},
  existing-funds   = {232}
}
\addEntry{UpkeepLaboratoryAnimals}{
  ref-project-id   = {B01},
  species          = {mouse-gnotobiotic},
  quantity         = {3},
  weeks-kept       = {43},
  purchasing-costs = {23},
  requested-funds  = {201},
  existing-funds   = {132}
}
\printTable{UpkeepLaboratoryAnimals}

%    \end{macrocode}
% \iffalse
%</02>
%<*03>
% \fi
%    \begin{macrocode}
\addtocontents{toc}{%
  % Change style of TOC from here on. (not recommended)
  \RedeclareSectionCommands[
  	tocbeforeskip=0ex,
  	tocentryformat=\normalsize\normalfont
  ]{section}
  \protect\clearpage}
\chapter{Project details} %3
\printThumbIndex{3}

%% Each extracted project file is a complete, copyable status/type example.
%% \printProjectHead creates the general-information section, project title,
%% project leaders, contract information, and legal-issues block from metadata.
\dfgTOCprojectPart{A}{Research Projects}
\input{content/03_project_A01}
\input{content/03_project_A02}

\dfgTOCprojectPart{B}{Research Projects}
\input{content/03_project_B01}
\input{content/03_project_B02}

\dfgTOCprojectPart{Q}{Central Projects}
\input{content/03_project_Q01}
\input{content/03_project_Q02}
\input{content/03_project_Q03}
%    \end{macrocode}
% \iffalse
%</03>
%<*03-project-a01>
% \fi
% \subsection{Complete continuing-project example}
% This file demonstrates the complete heading and command structure for a
% continuing research project (|project-status=C|).
%    \begin{macrocode}
\printProjectHead{A01}

\section{Summary}
\label{A01:summary}

Summarise the continuing project's central question, progress, planned work,
methods, and contribution to the Collaborative Research Centre.

\section{Project progress to date}
\label{A01:project-progress-to-date}

\subsection{Report and current state of research}%
\label{A01:report-and-current-state-of-research}

Report the work and results from the previous funding periods, relate them to
the current state of research, and explain how they motivate the new plan.

\FloatBarrier

\projectPublicationsHeading

%% Add all project-specific publication keys before printing the bibliography.
\projectNocite{FAIR2016}
\printProjectBibliography[heading=none]

\section{Project plan}
\label{A01:project-plan}

\begin{aims}
  \addAim{A} Define the underlying mechanism.
  \addAim{B} Validate the mechanism experimentally.
  \addAim{C} Integrate the findings across the CRC.
\end{aims}

Refer to one aim as \getAim{A}, or to several as \getAim{A,B,C}.

\begin{workpackages}
  \addWP{wp1}{
    name={Mechanistic analysis},
    description={Define the underlying mechanism},
    periodStart={1},
    periodEnd={8},
    style={default},
  }

  Describe the work, methods, milestones, risks, and expected results of
  \getWP{wp1}.

  \begin{workpackages}
    %% Sub-workpackages deliberately have no name key: their authored text is
    %% the visible list item, while description is used only in the Gantt chart.
    \addWP{wp1a}{
      description={Establish the experimental system},
      periodStart={1},
      periodEnd={4},
      style={alternative},
    }
    Establish and validate the experimental system.

    \addWP{wp1b}{
      description={Perform the mechanistic experiments},
      periodStart={3},
      periodEnd={8},
      style={important},
    }
    Perform the mechanistic experiments and define decision points.
  \end{workpackages}

  \addWP{wp2}{
    name={Experimental validation},
    description={Validate and integrate the mechanism},
    periodStart={7},
    periodEnd={16},
    style={striped},
  }

  Describe the validation strategy, expected results, and contingency plan of
  \getWP{wp2}.
\end{workpackages}

\printPlot{{Gantt}{A01}}

\FloatBarrier

\section{Relevance of sex, gender and/or diversity in the research
  project}
\label{A01:relevance-of-sex-gender-and-diversity}

Explain whether and how sex, gender, and diversity affect the research
questions, design, analysis, and interpretation.

\section{Role within the Collaborative Research
  Centre}
\label{A01:role-within-the-collaborative-research-centre}

Describe the project's contribution to the CRC and its principal
collaborations.

%% The heatmap is the default collaboration layout.
\printPlot{{ProjectCollaboration}{A01}}
%% To use the compact arc layout instead, replace the call above with:
%% \printPlot{{ProjectCollaboration}[layout=arc]{A01}
%%   [Optional additional caption text.]}


\section{Differentiation from other funded
  projects}
\label{A01:differentiation-from-other-funded-projects}

Explain how this project differs from, and complements, other funded work of
the project leaders.

\section{Project funding}
\label{A01:project-funding}

\subsection{Previous funding}

Funding of this project within the Collaborative Research Centre started
in July 2019.  Preparatory work was funded by Example University's seed-fund
programme from January 2018 to June 2019 (reference number EU-EXAMPLE-01).

\subsection{Requested funding}

%% Without sum, the class calculates from salary@prof, percentage, and
%% quantity, using half the annual amount in year1 and year5.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A01},
  funding-type   = {staff},
  category       = {prof},
  percentage     = {100},
  quantity = {
    year1 = {2},
    year2 = {2},
    year3 = {2},
    year4 = {2},
    year5 = {2}
  }
}

%% With sum, these concrete yearly amounts override the central salary rate;
%% year1 and year5 below already represent half-years.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A01},
  funding-type   = {staff},
  category       = {PhD},
  percentage     = {65},
  quantity = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  },
  sum = {
    year1 = {26500},
    year2 = {53000},
    year3 = {53000},
    year4 = {53000},
    year5 = {26500}
  }
}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A01},
  funding-type       = {costs}, %staff, costs, ...
  category   = {Laboratory consumables},
  sum = {
  		year1      =  {2112},
  		year2      =  {67},
  		year3      =  {9843},
  		year4      =  {2375},
  		year5      =  {983}
  	}}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A01},
  funding-type       = {costs}, %staff, costs, ...
  category   = {Sequencing and data analysis},
  sum = {
  		year1      =  {1000},
  		year2      =  {2000},
  		year3      =  {3000},
  		year4      =  {4000},
  		year5      =  {5000}
  	}}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A01},
  funding-type       = {instrumentation}, %staff, costs, ...
  category           = {Live-cell imaging system},
  sum = {
  		year1      =  {1000},
  		year2      =  {2000},
  		year3      =  {3000},
  		year4      =  {4000},
  		year5      =  {5000}
  	}}

\printTable{{RequestedFunding}{A01}}





\subsubsection{Requested funding for staff for the new funding period}
\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {A01},
  funding-status     = {existing},
  staff-type         = {research},
  ref-person-id      = {per1},
  field-of-research  = {Microbiology and systems medicine},
  commitment         = {8},
  category           = {prof},
  funding-source     = {State funds},
  description        = {Leads the experimental programme and supervises the
    research staff assigned to the project.}
}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id    = {A01},
  funding-status    = {existing},
  staff-type        = {nonResearch},
  firstname         = {Alex},
  lastname          = {Example},
  academic-degree   = {M.Sc.},
  positionText      = {Technical assistant},
  field-of-research = {Laboratory management},
  ref-institution-id = {ins1},
  commitment        = {20},
  category          = {nonResearch},
  funding-source    = {Core support},
  description       = {Maintains shared laboratory workflows and coordinates
    sample logistics.}
}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {A01},
  funding-status     = {requested},
  staff-type         = {research},
  firstname          = {Researcher},
  lastname           = {TBA},
  academic-degree    = {Dr. rer. nat.},
  positionText       = {Postdoctoral researcher},
  field-of-research  = {Host--microbiome interactions},
  ref-institution-id = {ins2},
  category           = {postDoc},
  description        = {Performs the planned mechanistic experiments and
    integrates molecular and clinical datasets.}
}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id    = {A01},
  funding-status    = {requested},
  staff-type        = {nonResearch},
  firstname         = {Taylor},
  lastname          = {Demo},
  academic-degree   = {B.Sc.},
  positionText      = {Research assistant},
  field-of-research = {Biobanking and data curation},
  ref-institution-id = {ins2},
  category          = {assistant},
  description       = {Supports biobanking, quality control, and structured
    curation of the project datasets.}
}

\printTable{{RequestedFundingStaff}{A01}}

\subsubsection{Requested funding for direct costs for the new funding
  period}

\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id = {A01},
  ref-affiliation-id = {aff2},
  financed-by = {Partner University core support},
  sum = {
		year1      =  {1200},
		year2      =  {500},
		year3      =  {21100},
		year4      =  {5600},
		year5      =  {3400}
	}}

\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id = {A01},
  ref-affiliation-id = {aff1},
  financed-by = {Example University core support},
  sum = {
		year1      =  {11100},
		year2      =  {53800},
		year3      =  {21100},
		year4      =  {600},
		year5      =  {38300}
	}}


\printTable{{RequestedAndExistingFundingDirectCosts}{A01}}

\begin{FundingDirectCostsTable}[Text]
  Laboratory consumables and antibodies & EUR & 15000 \\
  Single-cell sequencing and spatial profiling & EUR & 12000 \\
  Research data storage and analysis & EUR & 3000 \\
\end{FundingDirectCostsTable}


\subsubsection{Requested funding for instrumentation for the new funding
  period}


\begin{FundingDirectCostsTable}[Text]
  Automated live-cell imaging system & EUR & 95000 \\
  Environmental control module & EUR & 18000 \\
  Analysis workstation and software & EUR & 7000 \\
\end{FundingDirectCostsTable}


\printProjectTail
%    \end{macrocode}
% \iffalse
%</03-project-a01>
%<*03-project-a02>
% \fi
% \subsection{Complete new-project example}
% This file demonstrates the complete heading and command structure for a new
% research project (|project-status=N|).  Its scientific-background section is
% intentionally named differently from the progress section of a continuing
% project.
%    \begin{macrocode}
\printProjectHead{A02}

\section{Summary}
\label{A02:summary}

Summarise the new project's central hypothesis, methods, expected results, and
contribution to the Collaborative Research Centre.

\section{Research rationale}
\label{A02:research-rationale}

\subsection{Current state of research and preliminary work}
\label{A02:current-state-of-research-and-preliminary-work}

Describe the relevant state of research, preliminary work, open questions,
and the scientific rationale for the proposed project.

\FloatBarrier

\projectPublicationsHeading
\projectNocite{FAIR2016}
\printProjectBibliography[heading=none]

\section{Project plan}
\label{A02:project-plan}

\begin{aims}
  \addAim{1} Establish the experimental and analytical framework.
  \addAim{2} Test the central hypothesis and validate the findings.
\end{aims}

\begin{workpackages}
  \addWP{wp1}{
    name={Framework and pilot experiments},
    description={Establish the framework and complete pilot experiments},
    periodStart={1},
    periodEnd={7},
    style={default},
  }

  Describe the methods, milestones, expected results, and risks of
  \getWP{wp1} and its contribution to \getAim{1}.

  \addWP{wp2}{
    name={Hypothesis testing and validation},
    description={Test the hypothesis and validate the findings},
    periodStart={6},
    periodEnd={16},
    style={important},
  }

  Describe the validation strategy and contingency plan for \getWP{wp2} and
  \getAim{2}.
\end{workpackages}

\printPlot{{Gantt}{A02}}

\FloatBarrier

\section{Relevance of sex, gender and/or diversity in the research project}
\label{A02:relevance-of-sex-gender-and-diversity}

Explain whether and how sex, gender, and diversity affect the research
questions, design, analysis, and interpretation.

\section{Role within the Collaborative Research Centre}
\label{A02:role-within-the-collaborative-research-centre}

Describe the project's contribution to the CRC and its principal
collaborations.

\printPlot{{ProjectCollaboration}{A02}}

\section{Differentiation from other funded projects of the project leader(s)}
\label{A02:differentiation-from-other-funded-projects}

Explain how this new project differs from, and complements, other funded work
of the project leaders.

\section{Project funding}
\label{A02:project-funding}

\subsection{Previous funding}

State that this is a new CRC project and list related previous funding of the
project leaders where applicable.

\subsection{Requested funding}

%% Automatic staff-cost example: sum is intentionally omitted; the class
%% halves the calculated amounts in year1 and year5.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A02},
  funding-type   = {staff},
  category       = {postDoc},
  percentage     = {100},
  quantity = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  }
}

%% Explicit staff-cost example: sum overrides the central salary calculation;
%% the concrete year1 and year5 amounts below already represent half-years.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A02},
  funding-type   = {staff},
  category       = {PhD},
  percentage     = {65},
  quantity = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  },
  sum = {
    year1 = {26500},
    year2 = {53000},
    year3 = {53000},
    year4 = {53000},
    year5 = {26500}
  }
}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A02},
  funding-type   = {costs},
  category       = {Consumables},
  sum = {
    year1 = {2000},
    year2 = {2000},
    year3 = {2000},
    year4 = {2000},
    year5 = {2000}
  }
}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A02},
  funding-type   = {instrumentation},
  category       = {Specialised instrument},
  sum = {
    year1 = {5000},
    year2 = {0},
    year3 = {0},
    year4 = {0},
    year5 = {0}
  }
}

\printTable{{RequestedFunding}{A02}}

\subsubsection{Requested funding for staff}

%% When no person database row is needed, all display data can be supplied
%% directly.  Leave academic-degree empty when it is unknown.
\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {A02},
  funding-status     = {requested},
  staff-type         = {research},
  firstname          = {Researcher},
  lastname           = {TBA},
  academic-degree    = {},
  positionText       = {Postdoctoral researcher},
  field-of-research  = {Experimental systems medicine},
  ref-institution-id = {ins1},
  category           = {postDoc},
  description        = {Establishes the new experimental platform, performs
    the mechanistic studies, and analyses the resulting datasets.}
}

\printTable{{RequestedFundingStaff}{A02}}

Provide the scientific and organisational justification for every requested
staff position.

\subsubsection{Requested funding of direct costs}

\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id     = {A02},
  ref-affiliation-id = {aff1},
  financed-by        = {State funds},
  sum = {
    year1 = {500},
    year2 = {500},
    year3 = {500},
    year4 = {500},
    year5 = {500}
  }
}

\printTable{{RequestedAndExistingFundingDirectCosts}{A02}}

\begin{FundingDirectCostsTable}[Text]
  Consumables for pilot experiments & EUR & 10000 \\
  External data analysis & EUR & 5000 \\
\end{FundingDirectCostsTable}

\subsubsection{Requested funding for instrumentation}

\begin{FundingDirectCostsTable}[Text]
  Specialised instrument including installation & EUR & 5000 \\
\end{FundingDirectCostsTable}

\printProjectTail
%    \end{macrocode}
% \iffalse
%</03-project-a02>
%<*03-project-b01>
% \fi
% \subsection{Second continuing-project example}
% This compact but complete file demonstrates another continuing research
% project and keeps the funding-category examples used by the dummy proposal.
%    \begin{macrocode}
\printProjectHead{B01}

\section{Summary}
\label{B01:summary}

Summarise the continuing project and the work proposed for the new funding
period.

\section{Project progress to date}
\label{B01:project-progress-to-date}

\subsection{Report and current state of research}
\label{B01:report-and-current-state-of-research}

Report the previous work, published and unpublished results, and the current
state of research.

\FloatBarrier

\projectPublicationsHeading
\projectNocite{FAIR2016}
\printProjectBibliography[heading=none]

\section{Project plan}
\label{B01:project-plan}

\begin{aims}
  \addAim{1} Complete the mechanistic analysis.
  \addAim{2} Validate the findings with CRC partners.
\end{aims}

\begin{workpackages}
  \addWP{wp1}{
    name={Mechanistic analysis},
    description={Complete the mechanistic analysis},
    periodStart={1},
    periodEnd={10},
    style={default},
  }
  Describe \getWP{wp1}, including methods, milestones, and risks.

  \addWP{wp2}{
    name={Collaborative validation},
    description={Validate the findings with CRC partners},
    periodStart={8},
    periodEnd={16},
    style={alternative},
  }
  Describe \getWP{wp2} and its links to \getAim{2}.
\end{workpackages}

\printPlot{{Gantt}{B01}}

\FloatBarrier

\section{Relevance of sex, gender and/or diversity in the research project}
\label{B01:relevance-of-sex-gender-and-diversity}

Explain the relevance of sex, gender, and diversity, or justify why they do
not affect this project's research questions and methods.

\section{Role within the Collaborative Research Centre}
\label{B01:role-within-the-collaborative-research-centre}

Describe the role of the project and its reciprocal collaborations.

\printPlot{{ProjectCollaboration}{B01}}

\section{Differentiation from other funded projects}
\label{B01:differentiation-from-other-funded-projects}

Differentiate the project from other funded work of its project leaders.

\section{Project funding}
\label{B01:project-funding}

\subsection{Previous funding}

State when CRC funding began and list other relevant previous funding.

\subsection{Requested funding}

%% Automatic staff-cost example: sum is intentionally omitted; the class
%% halves the calculated amounts in year1 and year5.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {B01},
  funding-type   = {staff},
  category       = {groupLeader},
  percentage     = {100},
  quantity = {
    year1 = {2},
    year2 = {2},
    year3 = {2},
    year4 = {2},
    year5 = {2}
  }
}

%% Explicit staff-cost example: sum overrides the central salary calculation;
%% the concrete year1 and year5 amounts below already represent half-years.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {B01},
  funding-type   = {staff},
  category       = {postDoc},
  percentage     = {100},
  quantity = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  },
  sum = {
    year1 = {45000},
    year2 = {90000},
    year3 = {90000},
    year4 = {90000},
    year5 = {45000}
  }
}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {B01},
  funding-type       = {globalfunds}, %staff, costs, ...
  category   = {Project-wide data stewardship},
  sum = {
    year1 = {1000},
    year2 = {2000},
    year3 = {3000},
    year4 = {4000},
    year5 = {5000}
  }
}

\printTable{{RequestedFunding}{B01}}

\subsubsection{Requested funding for staff for the new funding period}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {B01},
  funding-status     = {requested},
  staff-type         = {research},
  firstname          = {Researcher},
  lastname           = {TBA},
  academic-degree    = {},
  positionText       = {Research group leader},
  field-of-research  = {Translational microbiology},
  ref-institution-id = {ins2},
  category           = {groupLeader},
  description        = {Coordinates the experimental programme and the
    collaborative validation studies.}
}

\printTable{{RequestedFundingStaff}{B01}}

\subsubsection{Requested funding for direct costs for the new funding period}

\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id     = {B01},
  ref-affiliation-id = {aff2},
  financed-by        = {Institutional funds},
  sum = {
    year1 = {1000},
    year2 = {1000},
    year3 = {1000},
    year4 = {1000},
    year5 = {1000}
  }
}

\printTable{{RequestedAndExistingFundingDirectCosts}{B01}}

\begin{FundingDirectCostsTable}[Text]
  Experimental consumables & EUR & 10000 \\
  Data-processing services & EUR & 5000 \\
\end{FundingDirectCostsTable}

\subsubsection{Requested funding for instrumentation for the new funding
  period}

\begin{FundingDirectCostsTable}[Text]
  No instrumentation requested & EUR & 0 \\
\end{FundingDirectCostsTable}

\printProjectTail
%    \end{macrocode}
% \iffalse
%</03-project-b01>
%<*03-project-b02>
% \fi
% \subsection{Complete ending-project example}
% Ending projects use a deliberately shorter DFG structure: after the general
% information printed by \cs{printProjectHead}, they report project history,
% published results, and closing funding information.  They do not contain a
% new project plan or a request for another funding period.
%    \begin{macrocode}
\printProjectHead{B02}

\section{Project history}
\label{B02:project-history}

\subsection{Report}
\label{B02:report}

\begin{projectReport}
Describe the complete funding history, objectives, methods, results, and
contribution of the ending project.  Citations used only in the report are
printed automatically at the end of this environment.  This dummy citation
also demonstrates the exclusion of a result listed below
\autocite{FAIR2016}.
\end{projectReport}

\subsection{Published project results}
\label{B02:published-project-results}

%% Replace the example key with the project's results.  Use the literal value
%% none only when a category genuinely produced no result; leaving a value
%% empty keeps a visible drafting instruction.
\printProjectResults{
  quality-assured = {FAIR2016},
  other           = none,
  patents         = none
}

\section{Funding}
\label{B02:funding}

Funding of this project within the Collaborative Research Centre started in
April 2018.  The project will be completed by the end of the current funding
period.  Replace these dates and, where applicable, add previous funding under
another DFG programme and its reference number.

\subsection{Project staff in the ending funding period}
\label{B02:project-staff-in-the-ending-funding-period}

%% For an ending project, funding-status=requested is printed as
%% ``Staff funded with approved grant money'', matching the DFG form.
\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {B02},
  funding-status     = {existing},
  staff-type         = {research},
  ref-person-id      = {per4},
  commitment         = {8},
  funding-source     = {State funds},
  field-of-research  = {Molecular tissue regeneration},
  description        = {Led the project, supervised the experimental work,
    and integrated its results across the CRC throughout the ending funding
    period.}
}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {B02},
  funding-status     = {requested},
  staff-type         = {research},
  firstname          = {Researcher},
  lastname           = {TBA},
  academic-degree    = {},
  positionText       = {Postdoctoral researcher},
  field-of-research  = {Regenerative cell biology},
  ref-institution-id = {ins2},
  category           = {postDoc},
  description        = {Completed the final validation experiments and data
    publication from April 2025 until the end of the current funding period.}
}

\printTable{{RequestedFundingStaff}{B02}}

\printProjectTail
%    \end{macrocode}
% \iffalse
%</03-project-b02>
%<*03-project-q01>
% \fi
% \subsection{Complete continuing service-project example}
% Service projects use the continuing-project headings while the prose and work
% packages focus on services, resources, access rules, and collaborative use.
%    \begin{macrocode}

\printProjectHead{Q01}

\section{Summary}
\label{Q01:summary}

Summarise the service portfolio, its scientific purpose, its users, and the
developments planned for the new funding period.

\section{Project progress to date}
\label{Q01:project-progress-to-date}

\subsection{Report and current state of research}
\label{Q01:report-and-current-state-of-research}

Report completed and ongoing services, usage by CRC projects, technical
developments, quality assurance, and relevant service-project research.

\FloatBarrier

\projectPublicationsHeading
\projectNocite{FAIR2016}
\printProjectBibliography[heading=none]

\section{Project plan}
\label{Q01:project-plan}

\begin{aims}
  \addAim{1} Maintain and quality-assure the core service portfolio.
  \addAim{2} Extend the portfolio for new collaborative requirements.
\end{aims}

\begin{workpackages}
  \addWP{wp1}{
    name={Core service provision},
    description={Provide and quality-assure core services},
    periodStart={1},
    periodEnd={16},
    style={default},
  }
  Describe access, sample or data handover, turnaround, quality assurance,
  responsibilities, and capacity for \getWP{wp1}.

  \addWP{wp2}{
    name={Service development},
    description={Develop and validate new service modules},
    periodStart={3},
    periodEnd={14},
    style={alternative},
  }
  Describe development milestones and the projects participating in
  \getWP{wp2}.
\end{workpackages}

\printPlot{{Gantt}{Q01}}

\FloatBarrier

\section{Relevance of sex, gender and/or diversity in the research project}
\label{Q01:relevance-of-sex-gender-and-diversity}

Explain relevance for the service methods and the studies supported by them.

\section{Role within the Collaborative Research Centre}
\label{Q01:role-within-the-collaborative-research-centre}

Describe which projects use the services and how priorities, access, and
collaborations are coordinated.

\printPlot{{ProjectCollaboration}{Q01}}

\section{Differentiation from other funded projects}
\label{Q01:differentiation-from-other-funded-projects}

Differentiate the CRC service from existing institutional infrastructure and
other funded service activities.

\section{Project funding}
\label{Q01:project-funding}

\subsection{Previous funding}

State when the service project began and describe relevant previous funding.

\subsection{Requested funding}

%% Automatic staff-cost example: sum is intentionally omitted; the class
%% halves the calculated amounts in year1 and year5.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q01},
  funding-type   = {staff},
  category       = {nonResearch},
  percentage     = {65},
  quantity = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  }
}

%% Explicit staff-cost example: sum overrides the central salary calculation;
%% the concrete year1 and year5 amounts below already represent half-years.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q01},
  funding-type   = {staff},
  category       = {assistant},
  percentage     = {50},
  quantity = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  },
  sum = {
    year1 = {9000},
    year2 = {18000},
    year3 = {18000},
    year4 = {18000},
    year5 = {9000}
  }
}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q01},
  funding-type       = {costs}, %staff, costs, ...
  category   = {Invitation},
  sum = {
    year1 = {1000},
    year2 = {2000},
    year3 = {3000},
    year4 = {4000},
    year5 = {5000}
  }
}

\printTable{{RequestedFunding}{Q01}}

\subsubsection{Requested funding for staff for the new funding period}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {Q01},
  funding-status     = {requested},
  staff-type         = {nonResearch},
  firstname          = {Service},
  lastname           = {Specialist},
  academic-degree    = {},
  positionText       = {Technical specialist},
  field-of-research  = {Core-facility services},
  ref-institution-id = {ins1},
  category           = {nonResearch},
  description        = {Operates the service platform, performs quality
    control, and supports participating projects.}
}

\printTable{{RequestedFundingStaff}{Q01}}

\subsubsection{Requested funding for direct costs for the new funding period}

\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id     = {Q01},
  ref-affiliation-id = {aff1},
  financed-by        = {Core-facility funds},
  sum = {
    year1 = {1000},
    year2 = {1000},
    year3 = {1000},
    year4 = {1000},
    year5 = {1000}
  }
}

\printTable{{RequestedAndExistingFundingDirectCosts}{Q01}}

\begin{FundingDirectCostsTable}[Text]
  Service-specific consumables & EUR & 10000 \\
  Maintenance and quality assurance & EUR & 5000 \\
\end{FundingDirectCostsTable}

\subsubsection{Requested funding for instrumentation for the new funding
  period}

\begin{FundingDirectCostsTable}[Text]
  Service-platform upgrade & EUR & 5000 \\
\end{FundingDirectCostsTable}

\printProjectTail
%    \end{macrocode}
% \iffalse
%</03-project-q01>
%<*03-project-q02>
% \fi
% \subsection{Complete integrated research training group example}
% The MGK/IRTG project type has its own required narrative and funding
% headings.  This file mirrors that structure instead of pretending it is a
% conventional research project.
%    \begin{macrocode}
\printProjectHead{Q02}

\section{Summary}
\label{Q02:summary}

Summarise the objectives, development, and added value of the Integrated
Research Training Group.

\section{Tabular report}
\label{Q02:tabular-report}

Provide the required tabular report of all researchers funded by the
Integrated Research Training Group to date.

\section{Qualification programme}
\label{Q02:qualification-programme}

Describe the qualification programme, workshops, courses, retreats, career
development measures, and other training activities.

\section{Management and supervision}
\label{Q02:management-and-supervision}

Describe management responsibilities, recruitment, supervision arrangements,
mentoring, conflict-resolution processes, and quality assurance.

\section{Environment of the Integrated Research Training Group}
\label{Q02:environment-of-the-integrated-research-training-group}

Describe the scientific, institutional, interdisciplinary, and international
training environment.

\section{Interim assessment and outlook}
\label{Q02:interim-assessment-and-outlook}

Assess progress during the current funding period and describe priorities and
measurable objectives for the next funding period.

\section{Project funding}
\label{Q02:project-funding}

\subsection{Previous funding}

The Integrated Research Training Group has been funded within the
Collaborative Research Centre since April 2018.  Replace this date and add any
relevant funding under another programme.

%% Declare all monetary rows before the existing-funds overview: that table
%% compares existing direct-cost resources with the requested direct costs.
%% Automatic staff-cost example: sum is intentionally omitted; the class
%% halves the calculated amounts in year1 and year5.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q02},
  funding-type   = {staff},
  category       = {PhD},
  percentage     = {65},
  quantity = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  }
}

%% Explicit staff-cost example: sum overrides the central salary calculation;
%% the concrete year1 and year5 amounts below already represent half-years.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q02},
  funding-type   = {staff},
  category       = {nonResearch},
  percentage     = {50},
  quantity = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  },
  sum = {
    year1 = {15000},
    year2 = {30000},
    year3 = {30000},
    year4 = {30000},
    year5 = {15000}
  }
}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q02},
  funding-type   = {costs},
  category       = {Qualification programme},
  sum = {
    year1 = {2000},
    year2 = {2000},
    year3 = {2000},
    year4 = {2000},
    year5 = {2000}
  }
}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q02},
  funding-type   = {fellowships},
  category       = {Short-term fellowships},
  sum = {
    year1 = {1000},
    year2 = {1000},
    year3 = {1000},
    year4 = {1000},
    year5 = {1000}
  }
}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q02},
  funding-type   = {globalfunds},
  category       = {Training and networking},
  sum = {
    year1 = {3000},
    year2 = {3000},
    year3 = {3000},
    year4 = {3000},
    year5 = {3000}
  }
}

\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id     = {Q02},
  ref-affiliation-id = {aff2},
  financed-by        = {Graduate-school funds},
  sum = {
    year1 = {1000},
    year2 = {1000},
    year3 = {1000},
    year4 = {1000},
    year5 = {1000}
  }
}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {Q02},
  funding-status     = {existing},
  staff-type         = {nonResearch},
  firstname          = {Taylor},
  lastname           = {Trainer},
  academic-degree    = {},
  positionText       = {Training coordinator},
  field-of-research  = {Structured doctoral training},
  ref-institution-id = {ins2},
  commitment         = {20},
  funding-source     = {Partner University core funds},
  description        = {Coordinates recruitment, course administration,
    progress monitoring, mentoring, and quality assurance for the
    qualification programme.}
}

\subsection{Existing funds for the new funding period}

Describe the coordination, training, staff, and direct-cost resources made
available to the Integrated Research Training Group by the participating
institutions.

\subsubsection*{Existing staff}

\printTable{{RequestedFundingStaff}{Q02}}

\printTable{{RequestedAndExistingFundingDirectCosts}{Q02}}

\subsection{Requested funding}

\printTable{{RequestedFunding}{Q02}}

\subsection{Requested funding for staff}

\begin{FundingDirectCostsTable}[Text]
  Doctoral-researcher position: interdisciplinary research and participation
    in the complete qualification programme & EUR & 5000 \\
\end{FundingDirectCostsTable}

\subsection{Requested funding for direct costs}

\begin{FundingDirectCostsTable}[Text]
  Workshops and transferable-skills courses & EUR & 10000 \\
  Visiting researchers and networking & EUR & 5000 \\
\end{FundingDirectCostsTable}

\subsection{Requested funding for fellowships}

\begin{FundingDirectCostsTable}[Text]
  Short-term research fellowships: state the type of fellowship, average
    number of fellows, average duration, monthly allowance per person, and
    justification & EUR & 5000 \\
\end{FundingDirectCostsTable}

\subsection{Requested global funds}

\begin{FundingDirectCostsTable}[Text]
  Training and networking measures: explain the purpose, allocation rules,
    selection process, and administration & EUR & 15000 \\
\end{FundingDirectCostsTable}

\printProjectTail
%    \end{macrocode}
% \iffalse
%</03-project-q02>
%<*03-project-q03>
% \fi
% \subsection{Complete central administrative-project example}
% The central administrative project has a dedicated DFG structure.  It does
% not reuse the summary, research-progress, publication, project-plan, or
% instrumentation headings of a continuing research project.
%    \begin{macrocode}
\printProjectHead{Q03}

\section{Documentation of the central activities of the Collaborative
  Research Centre}
\label{Q03:documentation-of-central-activities}

Document governance and decision-making, scientific coordination, reporting,
internal communication, data stewardship, publication support, equal-
opportunity measures, early-career support, outreach, and the interfaces with
all applicant and participating institutions.  Distinguish CRC-specific tasks
from permanent institutional duties and state responsibilities, workflows,
results from the current period, and priorities for the new funding period.

\section{Project funding}
\label{Q03:project-funding}

%% The existing-funds overview includes the requested direct-cost total, so
%% all monetary records are declared before either table is printed.
%% Automatic staff-cost example: sum is intentionally omitted.  The class
%% applies the half-year factor to year1 and year5.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q03},
  funding-type   = {staff},
  category       = {nonResearch},
  percentage     = {100},
  quantity = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  }
}

%% Explicit staff-cost example: the stated sums override the salary settings;
%% year1 and year5 below already represent half-years.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q03},
  funding-type   = {staff},
  category       = {assistant},
  percentage     = {50},
  quantity = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  },
  sum = {
    year1 = {12500},
    year2 = {25000},
    year3 = {25000},
    year4 = {25000},
    year5 = {12500}
  }
}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q03},
  funding-type   = {costs},
  category       = {Central coordination and communication},
  sum = {
    year1 = {2000},
    year2 = {2000},
    year3 = {2000},
    year4 = {2000},
    year5 = {2000}
  }
}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q03},
  funding-type   = {globalfunds},
  category       = {Central measures},
  sum = {
    year1 = {2000},
    year2 = {2000},
    year3 = {2000},
    year4 = {2000},
    year5 = {2000}
  }
}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {Q03},
  funding-status     = {existing},
  staff-type         = {nonResearch},
  ref-person-id      = {man1},
  field-of-research  = {Research management},
  commitment         = {20},
  funding-source     = {Partner University core funds},
  description        = {Coordinates governance, reporting, internal
    communication, central measures, and interfaces with applicant and
    participating institutions.}
}

\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id     = {Q03},
  ref-affiliation-id = {aff1},
  financed-by        = {Central university funds},
  sum = {
    year1 = {1000},
    year2 = {1000},
    year3 = {1000},
    year4 = {1000},
    year5 = {1000}
  }
}

\subsection{Existing funds for the new funding period}

Describe the central staff, facilities, and direct-cost resources contributed
by the applicant and participating institutions.

\subsubsection*{Existing staff}

\printTable{{RequestedFundingStaff}{Q03}}

\printTable{{RequestedAndExistingFundingDirectCosts}{Q03}}

\subsection{Requested funding for the new funding period}

\printTable{{RequestedFunding}{Q03}}

\subsection{Requested funding for staff}

\begin{FundingDirectCostsTable}[Text]
  Scientific coordination: justify the category, percentage, period, and
    CRC-specific responsibilities & EUR & 5000 \\
\end{FundingDirectCostsTable}

\subsection{Requested funding for direct costs}

\begin{FundingDirectCostsTable}[Text]
  Governance meetings and scientific exchange & EUR & 10000 \\
  Communication and outreach & EUR & 5000 \\
\end{FundingDirectCostsTable}

\subsection{Requested global funds}

\begin{FundingDirectCostsTable}[Text]
  Central measures: explain the purpose, allocation rules, selection process,
    and administration & EUR & 10000 \\
\end{FundingDirectCostsTable}

\printProjectTail

%    \end{macrocode}
% \iffalse
%</03-project-q03>
%<*04>
% \fi
%    \begin{macrocode}
\chapter{Bylaws of the Collaborative Research Centre} %4
\printThumbIndex{4}
\cohead{Bylaws of the \crc}%
\cehead{Bylaws of the \crc}%

\begin{bylaws}
  \item Name, coordinating
    \dfgApplicantAffiliationsTF{university}{universities}, and purpose of the \crc
  \begin{bylaws}
	\item The \crc (CRC) \enquote{\dfgCRCName\space --\space\dfgCRCNameAddon}
      is a legally dependent institution of \theCRCaffiliation.

    \item The \crc conducts interrelated research on microbial signalling,
      epithelial barriers, immune regulation, and organ function.  It is
      divided into research project areas and central projects.

    \item The \crc promotes interaction with other research institutions,
      supports researchers in early career phases, and fosters responsible
      international cooperation, equity, and equal opportunity.
  \end{bylaws}

  \item Membership and governing bodies
  \begin{bylaws}
    \item Members are the project leaders and persons appointed to central
      scientific or administrative responsibilities by the general assembly.
    \item The governing bodies are the general assembly, the spokesperson, and
      the steering committee.  The general assembly elects the spokesperson
      and steering committee for the applicable funding period.
    \item The steering committee prepares strategic and budgetary decisions,
      monitors milestones, and reports to the general assembly at least once
      per year.
  \end{bylaws}

  \item Decisions and allocation of shared resources
  \begin{bylaws}
    \item Decisions are normally taken by simple majority of members present;
      changes to these bylaws require a two-thirds majority.
    \item Shared funds and infrastructure are allocated through documented,
      transparent procedures based on scientific need, feasibility, and equal
      access across participating projects.
    \item Members disclose conflicts of interest and do not participate in the
      corresponding deliberation or decision.
  \end{bylaws}

  \item Research integrity, equity, and conflict resolution
  \begin{bylaws}
    \item All members follow the applicable rules of good research practice,
      data protection, animal welfare, research ethics, and occupational safety.
    \item The CRC implements equal-opportunity and accessibility measures and
      monitors participation in recruitment, training, and governance.
    \item Concerns may be raised confidentially with the spokesperson, the CRC
      management, or the competent independent offices of the participating
      institutions.
  \end{bylaws}

  \item Research-data governance
  \begin{bylaws}
    \item Projects document data, code, samples, access rights, retention, and
      publication in project-specific data-management plans.
    \item Central data stewardship defines common metadata and quality
      standards, manages controlled access, and supports publication according
      to the FAIR principles and applicable legal requirements.
  \end{bylaws}
\end{bylaws}
%    \end{macrocode}
% \iffalse
%</04>
%<*05>
% \fi
%    \begin{macrocode}
\chapter{Declarations} %5
\printThumbIndex{5}
I/We hereby confirm the accuracy of the information contained in the proposal, including the research profiles.

The \emph{DFG Rules of Procedure for Dealing with Scientific Misconduct}
(\emph{Verfahrensordnung zum Umgang mit wissenschaftlichem Fehlverhalten –
  VerfOwF})
apply to individuals with a high level of scientific/\-academic responsibility in connection with funding proposals submitted by universities. The applicant \dfgApplicantAffiliationsTF{university confirms}{universities confirm} that all individuals with a high level of scientific/\-academic responsibility in the project proposal submitted by the \dfgApplicantAffiliationsTF{university}{universities} (cf. programme guidelines, DFG form 50.06) recognise the \emph{DFG Rules of Procedure for Dealing with Scientific Misconduct} as legally binding by submitting a corresponding declaration of commitment.

In submitting this proposal, all project leaders undertake to comply with the
relevant discipline-specific research ethics guidelines, to determine whether
a statement from the responsible ethics committee is required and, where
necessary, to obtain it in good time before the start of funding.  They will
inform the DFG immediately if an ethics committee expresses substantive
concerns or issues a negative statement and will submit the statement if the
DFG requests it.

The DFG takes the protection of your personal data very seriously.
Please note the DFG’s data protection notice on research funding, which can be viewed and downloaded at
\url{www.dfg.de/privacy_policy}

Please forward this information to those individuals whose data will be processed by the DFG because they are mentioned in your proposal.

I/We have read the DFG’s data protection notice.

I/We consent to the processing and transfer of special categories of personal
data (including the data of all parties involved) for the purposes stated in the
Privacy Policy if, after careful consideration, I/we provide such data either
now or at a later date.\par
\vfill

\printSignaturesWithRole{spokesperson}{(Spokesperson~of~\crc)}
\printSignaturesWithRole{rector}
  {(Rector,~chancellor,~or~president~of~
    \getEntry[affiliation]{\theAffiliationOfRoleID}{name})}
%    \end{macrocode}
% \iffalse
%</05>
%<*99>
% \fi
% \subsection{Backmatter File}
% The final page suppresses running headers and page numbers and delegates the
% complete layout to the project-overview table defined by the class.
%    \begin{macrocode}
\pagestyle{empty}
\printTable{projectOverview}
%    \end{macrocode}
% \iffalse
%</99>
%<*test-project-collaboration>
% \fi
% \subsection{Project collaboration plot test}
% This focused test is deliberately independent of the proposal metadata.  It
% contains active, ending, and reference-only projects; duplicate and
% reverse-only declarations; and calls both supported collaboration layouts.
%    \begin{macrocode}
%% Compile from the generated local directory with:
%%   lualatex -interaction=nonstopmode -halt-on-error test-project-collaboration.tex
%%
%% This test is deliberately self-contained.  The fast project option prevents
%% the proposal metadata from loading; immediately after \begin{document} the
%% two fast-mode booleans are reset so the dummy \addEntry data and plots below
%% are processed normally.
\documentclass[
  fastcompile-project = true,
  english
]{dfg-crc}

\begin{document}

\ExplSyntaxOn
\bool_set_false:N \l_@@_class_fastcompile_project_bool
\bool_set_false:N \l_@@_class_fastcompile_bool
\ExplSyntaxOff

%% #1 is either empty or a complete project-area assignment; #2 is the
%% project id, #3 status (C/N/E), #4 collaborations, and #5 reference-only.
\NewDocumentCommand{\AddDummyProjectEntry}{m m m m m}{
  \addEntry{project}{
    id                 = {#2},
    #1
    number             = {#2},
    name               = {Dummy project #2},
    project-status     = {#3},
    project-type       = {research},
    consider-for-lists = {true},
    reference-only     = {#5},
    ref-person-id      = {},
    collaborations     = {#4},
    research-area      = {},
    legal-issues       = {
      L1  = {no},
      L1a = {},
      L2  = {no},
      L2a = {},
      L3  = {no},
      L4  = {no},
      L5  = {no},
      L5a = {},
      L6  = {no},
      L7  = {no},
      L7a = {}
    }
  }
}
%% Omitting the optional area leaves the project-area database column absent
%% until the first plot and therefore exercises both schema and ID fallbacks.
\NewDocumentCommand{\AddDummyProject}{o m m m m}{
  \IfNoValueTF{#1}
    { \AddDummyProjectEntry{}{#2}{#3}{#4}{#5} }
    { \AddDummyProjectEntry{project-area={#1},}{#2}{#3}{#4}{#5} }
}

%% Active project area A.  A11 repeats B06 deliberately to test that an
%% undirected relation declared twice is collapsed.
\AddDummyProject{A02}{C}{}{false}
\AddDummyProject{A03}{C}{}{false}
\AddDummyProject{A05}{C}{}{false}
\AddDummyProject{A09}{C}{}{false}
\AddDummyProject{A10}{C}{}{false}
\AddDummyProject{A11}{C}{B06}{false}
\AddDummyProject{A12}{N}{}{false}
\AddDummyProject{A13}{N}{}{false}

%% A04 is ending and A00 is reference-only.  Neither may occur in a plot.
\AddDummyProject{A04}{E}{}{false}
\AddDummyProject{A00}{C}{}{true}

%% Active project area B.  The A04 relation checks ending-project filtering.
\AddDummyProject{B01}{C}{}{false}
\AddDummyProject{B04}{C}{}{false}
\AddDummyProject{B05}{C}{}{false}
\AddDummyProject{B06}{C}
  {A00,A04,A11,A12,B01,B04,B05,B07,B10}
  {false}
\AddDummyProject{B07}{C}{}{false}
\AddDummyProject{B08}{C}{}{false}
\AddDummyProject{B09}{C}{}{false}
\AddDummyProject{B10}{N}{}{false}

%% Active project area Q.  Q02 declares B06 in the reverse direction only.
\AddDummyProject{Q01}{C}{}{false}
\AddDummyProject{Q02}{C}{B06}{false}
\AddDummyProject{Q03}{C}{}{false}
\AddDummyProject{Q04}{C}{}{false}

%% The first plot is deliberately called before any project-area key has been
%% entered.  It exercises the missing-column and ID-prefix fallbacks.
\printPlot{{ProjectCollaboration}{B06}}

\clearpage

%% Explicit project areas need not match the project-ID prefix.  The longer
%% service-area label exercises dynamic label measurement, while the options
%% exercise explicit color mappings for otherwise unknown areas.
\AddDummyProject[C]{X01}{C}{B06}{false}
\AddDummyProject[Shared services]{Y01}{N}{}{false}
\ExplSyntaxOn
\@@_project_count_build:
\prop_get:NnN \g_@@_project_count_area_prop { C } \l_tmpa_tl
\int_compare:nNnF { \l_tmpa_tl } = { 1 }
  { \PackageError{test}{Expected~one~project~in~dynamic~area~C}{} }
\prop_get:NnN \g_@@_project_count_area_prop { SHARED~SERVICES } \l_tmpa_tl
\int_compare:nNnF { \l_tmpa_tl } = { 1 }
  { \PackageError{test}{Expected~one~project~in~dynamic~Shared~services~area}{} }
\ExplSyntaxOff
\printPlot{{ProjectCollaboration}[
  area-colors={C=cyan!70!black,Shared services=orange!80!black}
]{B07}}

\clearpage

%% Select the low arc layout explicitly.  Every displayed arc should reach the
%% same vertical peak, IDs should sit inside the boxes, and each area rule should
%% span its boxes; additional caption text follows the id.
\printPlot{{ProjectCollaboration}[
  layout=arc,
  area-palette={orange!80!black,violet!75!black,teal!70!black}
]{B06}
  [Dummy metadata; A04 and A00 are intentionally omitted.]}

\end{document}
%    \end{macrocode}
% \iffalse
%</test-project-collaboration>
%<*test-existing-funds-direct-costs>
% \fi
% \subsection{Existing direct-cost overview test}
% This focused two-pass test prints section 2.1.1 before declaring the
% project-level rows.  On the following run, the auxiliary-file mirror must
% restore those rows early enough for the table and the assertions.
%    \begin{macrocode}
%% Compile from the generated local directory with:
%%   latexmk -lualatex -g -halt-on-error test-existing-funds-direct-costs.tex
\documentclass[english,final=true]{dfg-crc}

\providecommand{\dfgDirectCostsAuxReady}{0}

%% Ending-period values remain explicit because they describe the preceding
%% funding period rather than the project requests below.
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year=1, applicant=4300, participant=1200, other-funds=500
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year=2, applicant=0, participant=0, other-funds=0
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year=3, applicant=0, participant=0, other-funds=0
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year=4, applicant=0, participant=0, other-funds=0
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year=5, applicant=0, participant=0, other-funds=0
}

\begin{document}

\section*{Overview of existing funds for direct costs}

%% The second and later passes must see the rows restored from the auxiliary
%% file before the live project declarations below are encountered.
\ifnum\dfgDirectCostsAuxReady=1\relax
  \ExplSyntaxOn
  \cs_set_eq:NN
    \@@_direct_costs_test_show_saved:nnN
    \@@_show_calculated_number:nnN
  \cs_set_protected:Npn
    \@@_show_calculated_number:nnN #1#2#3 { }
  \cs_new_protected:Npn \@@_direct_costs_test_expect:nnn #1#2#3
  {
    \getSumRequestedFundingDirectCosts
      [RequestedAndExistingFundingDirectCostsOverview]{#1}{#2}
    \DTLconverttodecimal {\SumRequestedFundingDirectCosts} \l_tmpa_tl
    \fp_compare:nNnF {\l_tmpa_tl} = {#3}
    {
      \PackageError{direct-costs-test}
        {Expected~#1/#2~sum~#3,~got~\SumRequestedFundingDirectCosts}
        {The~section~2.1.1~overview~classification~is~incorrect.}
    }
  }
  \@@_direct_costs_test_expect:nnn {1}{applicant}{5000}
  \@@_direct_costs_test_expect:nnn {1}{participant}{2100}
  \@@_direct_costs_test_expect:nnn {1}{other-funds}{300}
  \@@_direct_costs_test_expect:nnn {1}{all}{7400}
  \@@_direct_costs_test_expect:nnn {all}{applicant}{25000}
  \@@_direct_costs_test_expect:nnn {all}{participant}{10500}
  \@@_direct_costs_test_expect:nnn {all}{other-funds}{1500}
  \@@_direct_costs_test_expect:nnn {all}{all}{37000}
  \cs_set_eq:NN
    \@@_show_calculated_number:nnN
    \@@_direct_costs_test_show_saved:nnN
  \iow_term:n
    {DIRECT~COSTS~TEST~PASS:~auxiliary~restore,~classification,~and~totals}
  \ExplSyntaxOff
\fi

\printTable{ExistingFundsDirectCosts}

%% These rows intentionally occur after the overview.  aff1 is the applicant
%% affiliation in the generated metadata; aff2 is a participating affiliation.
\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id     = {A01},
  ref-affiliation-id = {aff1},
  financed-by        = {Applicant university core support},
  sum = {
    year1 = {5000}, year2 = {5000}, year3 = {5000},
    year4 = {5000}, year5 = {5000}
  }
}
\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id     = {B01},
  ref-affiliation-id = {aff2},
  financed-by        = {Participating university core support},
  sum = {
    year1 = {2100}, year2 = {2100}, year3 = {2100},
    year4 = {2100}, year5 = {2100}
  }
}
\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id     = {Q01},
  ref-affiliation-id = {other-funds},
  financed-by        = {External grant},
  sum = {
    year1 = {300}, year2 = {300}, year3 = {300},
    year4 = {300}, year5 = {300}
  }
}

\makeatletter
\protected@write\@auxout{}{%
  \string\gdef\string\dfgDirectCostsAuxReady{1}}
\makeatother

\end{document}
%    \end{macrocode}
% \iffalse
%</test-existing-funds-direct-costs>
%<*test>
% \fi
% The focused release regression test covers the four staff-roster groups and
% the automatic monetary calculation used when staff rows omit |sum|.
%    \begin{macrocode}
\documentclass[
  english,
  final=true
]{dfg-crc}

% Check the shipped defaults before exercising proposal-specific overrides.
\ExplSyntaxOn
\fp_compare:nNnF { \dfgSalaryProf } = { 123600 }
  {
    \PackageError{test}
      {Expected~default~professor~salary~123600,~got~\dfgSalaryProf}
      {The~default~salary~setting~is~incorrect.}
  }
\fp_compare:nNnF { \dfgMouseHousing } = { 0.75 }
  {
    \PackageError{test}
      {Expected~default~mouse~housing~rate~0.75,~got~\dfgMouseHousing}
      {The~default~animal-housing~setting~is~incorrect.}
  }
\bool_if:NF \l_@@_custom_project_pi_once_per_section_bool
  {
    \PackageError{test}
      {Expected~projectPIOncePerSection~to~default~to~true}
      {The~project/PI~reference~setting~has~the~wrong~default.}
  }
\ExplSyntaxOff

\changeSettings{
  salary@prof                   = 120000,
  salary@PhD                    = 80000,
  animalHousing@mouse           = 0.80,
  animalHousing@mouseGnotobiotic= 4.10,
  animalHousing@rat             = 1.50,
}

% A preamble declaration is immediately mirrored into the proposal-wide
% overview database and exercises the non-empty instrumentation-table branch.
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A01},
  funding-type   = {instrumentation},
  category       = {Test microscope},
  sum            = {
    year1 = {10000},
    year2 = {0},
    year3 = {0},
    year4 = {0},
    year5 = {0}
  }
}

\begin{document}

\changeSettings{projectPIOncePerSection=false}
\section*{Natural-language project-reference lists}

Two projects: \getProject{A01,B01}.

Three projects: \getProject{A01,B01,Q01}.

\begin{tblr}{colspec={lX[l]}}
Two table projects   & \getProject{A01,B01}       \\
Three table projects & \getProject{A01,B01,Q01}   \\
PI command in table  & \getProjectPI{A01,B01}     \\
\end{tblr}

% The focused-project fallback has no project database but should retain the
% same natural-language separators for its visible identifiers.
\ExplSyntaxOn
\bool_set_true:N \l_@@_class_fastcompile_project_bool
\ExplSyntaxOff
Fast-mode projects: \getProject{A01,B01,Q01}.
Fast-mode project with PI command: \getProjectPI{B01}.
\begin{tblr}{colspec={lX[l]}}
Fast table & \getProject{A01,B01,Q01} \\
\end{tblr}
\ExplSyntaxOn
\bool_set_false:N \l_@@_class_fastcompile_project_bool
\ExplSyntaxOff

\changeSettings{projectPIOncePerSection=true}
\section*{Project/PI references once per section}

First reference through \verb|\getProject|: \getProject{B01}.

Repeated reference through \verb|\getProjectPI|: \getProjectPI{B01}.

Mixed repeated/new list through \verb|\getProject|: \getProject{B01,Q01}.

\section*{Project/PI state reset at the next section}

First reference after reset through \verb|\getProjectPI|: \getProjectPI{B01}.

Repeated reference after reset through \verb|\getProject|: \getProject{B01}.

\changeSettings{projectPIOncePerSection=false}
\section*{Repeated project/PI names enabled}

First reference with repetition enabled: \getProjectPI{B01}.

Second reference with repetition enabled: \getProjectPI{B01}.

Compact \verb|\getProject| with repetition enabled: \getProject{B01}.

\begingroup
\ExplSyntaxOn
\tl_set:Nn \l__tmp_current_project_tl {B01}
\ExplSyntaxOff
Current-project reference: \getProjectPI{B01}.
\endgroup

\changeSettings{projectPIOncePerSection=true}

\section*{Requested funding for staff for the new funding period}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {A01},
  ref-person-id      = {per1},
  funding-status     = {existing},
  staff-type         = {research},
  field-of-research  = {Microbiome research},
  ref-institution-id = {ins1},
  commitment         = {8},
  category           = {prof},
  funding-source     = {University funds},
  description        = {
    Coordinates sample processing and integrates microbiome measurements with
    the project's experimental work.
  }
}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {A01},
  funding-status     = {existing},
  staff-type         = {nonResearch},
  firstname          = {Bob},
  lastname           = {Existing},
  academic-degree    = {--},
  positionText       = {Technical assistant},
  field-of-research  = {Laboratory support},
  ref-institution-id = {ins2},
  commitment         = {10},
  category           = {nonResearch},
  funding-source     = {University funds},
  description        = {
    Maintains the sample archive, prepares laboratory material, and documents
    quality-control procedures.
  }
}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {A01},
  funding-status     = {requested},
  staff-type         = {research},
  lastname           = {TBA},
  positionText       = {Postdoctoral researcher},
  field-of-research  = {Immunometabolism},
  ref-institution-id = {ins1,ins2},
  category           = {postDoc},
  description        = {
    Performs the mechanistic experiments, analyses the multi-omics data, and
    prepares the resulting manuscripts.
  }
}

\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {A01},
  funding-status     = {requested},
  staff-type         = {nonResearch},
  firstname          = {Dana},
  lastname           = {Requested},
  academic-degree    = {--},
  positionText       = {Technical assistant},
  field-of-research  = {Cell culture},
  ref-institution-id = {ins2},
  category           = {nonResearch},
  description        = {
    Supports cell-culture experiments, records reagent use, and performs the
    routine technical quality checks.
  }
}

\printTable{{RequestedFundingStaff}{A01}}

\clearpage
\section*{Overview of existing staff reused in chapter 2}

% The explicit database option lets this focused test read the live rows above.
% In the proposal, \printTable{OverviewExistingStaff} uses the auxiliary-file
% mirror because chapter 2 precedes the individual project declarations.
\printTable[RequestedFundingStaff]{OverviewExistingStaff}

\clearpage
\section*{Automatic calculation of requested staff funding}

The following two entries deliberately omit the \texttt{sum} key.  The full-
year values and their half-year counterparts are:
\begin{itemize}
  \item Professor: \(\num{120000} \times 100/100 \times 2
        = \num{240000}\), or \(\num{120000}\) in years 1 and 5.
  \item Doctoral researcher: \(\num{80000} \times 65/100 \times 1
        = \num{52000}\), or \(\num{26000}\) in years 1 and 5.
\end{itemize}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A01},
  funding-type   = {staff},
  category       = {prof},
  percentage     = {100},
  quantity       = {
    year1 = {2},
    year2 = {2},
    year3 = {2},
    year4 = {2},
    year5 = {2}
  }
}

\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A01},
  funding-type   = {staff},
  category       = {PhD},
  percentage     = {65},
  quantity       = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  }
}

\ExplSyntaxOn
\@@_funding_sum_set:Nnnnn \l_tmpa_tl
  {RequestedFunding}{A01}{staff}{sum-year1}
\fp_compare:nNnF {\l_tmpa_tl} = {146000}
  {
    \PackageError{test}
      {Expected~half-year~1~staff~sum~146000,~got~\l_tmpa_tl}
      {The~automatic~salary~calculation~is~incorrect.}
  }
\@@_funding_sum_set:Nnnnn \l_tmpa_tl
  {RequestedFunding}{A01}{staff}{sum-year2}
\fp_compare:nNnF {\l_tmpa_tl} = {292000}
  {
    \PackageError{test}
      {Expected~full-year~2~staff~sum~292000,~got~\l_tmpa_tl}
      {The~automatic~salary~calculation~is~incorrect.}
  }
\@@_funding_sum_set:Nnnnn \l_tmpa_tl
  {RequestedFunding}{A01}{staff}{sum-year5}
\fp_compare:nNnF {\l_tmpa_tl} = {146000}
  {
    \PackageError{test}
      {Expected~half-year~5~staff~sum~146000,~got~\l_tmpa_tl}
      {The~automatic~salary~calculation~is~incorrect.}
  }
\@@_funding_sum_set:Nnnnn \l_tmpa_tl
  {RequestedFunding}{A01}{staff}
  {sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
\fp_compare:nNnF {\l_tmpa_tl} = {1168000}
  {
    \PackageError{test}
      {Expected~five-year~staff~sum~1168000,~got~\l_tmpa_tl}
      {The~automatic~salary~calculation~is~incorrect.}
  }
\iow_term:n
  {TEST~PASS:~custom~staff~sums~=~146000/292000/146000~and~1168000~total}
\ExplSyntaxOff

\printTable{{RequestedFunding}{A01}}

Expected combined amount in years 1 and 5: \num{146000}; in years 2--4:
\num{292000}. Expected amount over all five funding columns: \num{1168000}.

\clearpage
\section*{Requested-instrumentation overview states}

\addEntry[funding]{NoInstrumentationFunding}{
  ref-project-id = {A01},
  funding-type   = {costs},
  category       = {Consumables},
  sum            = {
    year1 = {1000},
    year2 = {1000},
    year3 = {1000},
    year4 = {1000},
    year5 = {1000}
  }
}
\OverviewFundsRequestedInstrumentationTable[NoInstrumentationFunding]

\printTable{OverviewFundsRequestedInstrumentation}

\clearpage
\section*{Configurable animal-housing rates}

\addEntry{UpkeepLaboratoryAnimals}{
  ref-project-id   = {A01},
  species          = {mouse},
  quantity         = {10},
  weeks-kept       = {4},
  purchasing-costs = {20},
  requested-funds  = {100},
  existing-funds   = {0}
}
\addEntry{UpkeepLaboratoryAnimals}{
  ref-project-id   = {A01},
  species          = {mouse-gnotobiotic},
  quantity         = {2},
  weeks-kept       = {4},
  purchasing-costs = {20},
  requested-funds  = {50},
  existing-funds   = {0}
}
\addEntry{UpkeepLaboratoryAnimals}{
  ref-project-id   = {A01},
  species          = {rat},
  quantity         = {3},
  weeks-kept       = {4},
  purchasing-costs = {25},
  requested-funds  = {75},
  existing-funds   = {0}
}
\printTable{UpkeepLaboratoryAnimals}

\end{document}
%    \end{macrocode}
% \iffalse
%</test>
%<*cv>
% \fi
% Starting now a template CV file.
%    \begin{macrocode}
\documentclass[english,cv]{dfg-crc}
\begin{document}
\input{content/00_titlepage}
\dfgCVsection
% %% \dfgCV{MM}
\end{document}
%    \end{macrocode}
% \iffalse
%</cv>
%</file>
% \fi
% \printindex
%\endinput
