% \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>% Literal bracket tokens in expl3 parsers are not bracket pairs.
%<cls>% chktex-file 15
%<cls>% chktex-file 17
%<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.3.0}
\def\dfgVersionDate{2026-10-20}
%</internal|cls>
%<*internal>
\iffalse
%</internal>
%<*changelog>
## CHANGELOG
### 2026-10-20 version 0.3.0
- Add first-funding-period numbers and percentages, including gender breakdowns
  and totals, to the project-leader equality table in section 1.4.2 B, only
  for third-funding-period proposals. Document commands for the table values
  and keep the statistics cache consistent across grouped calls.
- Default to the DFG female-only project-leader overview, including third-period
  status-quo counts and percentages. Use
  `\printTable[all-sexes]{GenderEqualityProjectLeaders}` for f/m/d figures
  in all three periods, alongside the objective columns. Display options
  apply to one table, with options before the table name.

### 2026-10-20 version 0.2.18
- Update all seven standard salary defaults to the DFG personnel rates for
  2027, with matching documentation, template comments, and default checks.
- Add expandable `\getValue{key}` access to all customization settings,
  including live numeric rates, text, booleans, dimensions, and mode-specific
  bibliography aliases. Document formatting, local scope, and unknown-key
  errors; add regression coverage for all 72 settings.
- Sort the existing-instrumentation table by project ID, including alternate
  databases, while retaining shared equipment as a single row.

### 2026-10-16 version 0.2.17
- Add `\printFrameBibliography` for chapter 1 references. With
  `emphasizeEntries=true`, entries tagged `frametext-highlight` are bold;
  project highlights remain independent and the normal bibliography font
  size is preserved. Update the starter chapter and document the keyword.

### 2026-10-15 version 0.2.16
- Let `aims[label={RDM Aims}]` set the numbered item prefix and the name
  used by `\cref`, `\Cref`, and `\getAim`, independently for each list.
- Keep custom aim labels compatible with expl3 releases that do not
  provide the `\str_mdfive_hash:V` variant.

### 2026-10-15 version 0.2.15
- Keep project references inside `\getPIWithProject` and the legacy
  `\getPIProject` compact, so PI names are not repeated inside the project
  list. Starred forms still include first names, independently of
  `projectPIOncePerSection`.

### 2026-10-11 version 0.2.14
- Make validation warnings identify the rejected item, accepted values or
  required format, and whether the value is ignored, retained, or replaced.
  Fix funding-period and institution-order diagnostics and the animal-species
  choice list; require complete staff-funding category names.

### 2026-10-09 version 0.2.13
- Ignore surrounding spaces in research-area codes when processing project
  headings, overview tables, and individual research-area lookups.
- Keep the generated class header and footer filename as `dfg-crc.cls` in
  both development and release extraction, independent of the output directory.

### 2026-10-08 version 0.2.12
- Emit each legacy PI/project command's deprecation warning only once per
  LaTeX run, including repeated calls inside groups and lowercase aliases.
  Calls through the replacement commands remain warning-free.
- Use `\frontmatter` for Roman-numbered preliminary pages and `\mainmatter`
  before Chapter 1 to restart Arabic page numbering at 1. Existing proposal
  drivers need the same update because template update targets preserve them.
- Narrow the first column of `OverviewExistingStaff` from `X[4,l]` to
  `X[3,l]`, retaining equal-width institution columns. Break the junior
  research group leader label before "leaders". Maintain this in the DTX
  class source rather than a proposal customization override.
- Add the proposal workspace's standalone `test-overview-staff.tex` layout
  test: 85 complete fictional staff records, seven categories, and nine real
  affiliations. It uses an isolated database, documents a two-pass LuaLaTeX
  build, and has been checked in the rendered PDF.

### 2026-10-07 version 0.2.11
- Add lowercase aliases for PI and project commands, including
  `\getpiwithproject`, `\getprojectwithpi`, and `\getpiofproject`, preserving
  starred forms, optional arguments, formatting, links, and legacy warnings.
- Accept the mixed spellings `\getPIwithProject`, `\getProjectwithPI`, and
  `\getPIOfProject` alongside the canonical command names.
- Prevent tables printed immediately after headings from overlapping them at
  natural page breaks; `\printTable` adds a guarded `\null\nobreak`.

### 2026-10-02 version 0.2.10
- Show field-name placeholders for missing staff metadata in fast compilation,
  and render fast database and project references as red typewriter
  placeholders such as <person-id>.
- Add the opt-in fastcompile-show-tags option. When enabled, fast reference
  annotations identify the source row and requested lookup path, including
  project-number lookups.
- Add ID-oriented person-first and project-first PI references; warn when the
  older getPIProject and getProjectPI commands are used.
- Let PIReferenceFirstName make unstarred getPI, person-first PI/project
  references, and getPIofProject include first names. Project-first references
  continue to use last names unless starred.

### 2026-10-02 version 0.2.8
- Let an explicit empty `positionText` in a `RequestedFundingStaff` row
  suppress the person's prefilled position; omitted values still inherit it.

### 2026-09-27 version 0.2.7
- Allow `color@reference@PI=current` to inherit the surrounding text color
  in PI references; named colors and the black default remain supported.
- Document the customization hook for footnote-sized bibliographies with
  `\bibitemsep=0pt`, explaining inherited entry spacing and the separate
  compact CV publication list.
- Move thumb-index labels 2 mm towards the text block on both page sides,
  preserving tab dimensions and placement for either label orientation.
- Explicitly center project identifiers vertically in the project overview.
- Embed the second Gantt stripe colour in the PDF pattern so macOS viewers
  render it correctly; retain per-chart palette changes and stripe geometry.
- Add one baseline of space above section, subsection, and subsubsection
  headings; continue body text on the next line without an extra blank line.
  Document the existing paragraph breaks before and after `\printTable`.
- Add `thumbindex@orientation=outwards|inwards` to `\changeSettings`.
  Keep outward-facing labels by default; inward-facing labels turn 180 degrees
  on both left and right pages without changing tab placement.

### 2026-09-18 version 0.2.6
- Expand all twelve example CVs with three career stages, all five optional
  sections, two fictional category-A articles, and a category-B dataset each.
  Rebuild the standalone CV appendix and its framed inclusion in the manual.
- Link each name printed by `\getPIofProject` (including its starred form)
  to the PI table, using the same target and reference styling as `\getPI`.
- Add `\getPIofProject*` for full PI names joined with commas and a final
  “and”; explicit properties and a custom final separator remain supported.
- Use one shared consortium dataset for the local proposal, local CV appendix,
  and manual: twelve PIs, six A projects, six B projects, and three Q projects.
  Generate individual project files and career/optional CV records for every PI,
  with explicitly fictional publication examples selected by person keywords.
- Add rendered Gantt examples for all five bar styles, a custom colour palette,
  and grayscale fills/patterns. Explain preamble-wide colour settings versus
  grouped changes for a single chart, with links from the relevant descriptions.
- Build the embedded proposal from the manual's shared project and PI metadata:
  six A projects, six B projects, three Q projects, and twelve PIs. Include
  every active project chapter and use former project A00 for the ending-project
  example, keeping B02 new as declared in the documentation.
- Embed the complete final-mode CV appendix beside the proposal example and
  distribute its standalone PDF through the documentation build, CTAN archive,
  CI artifacts, and `update-all`. Frame and label every imported CV page.
- Add stable labels to rendered example boxes and clickable example references
  to command and environment descriptions, including the CV entry points.
- Make `dfgLocation`, `dfgDate`, `dfgTitle`, and `InfoTeX` available before
  customization is loaded and configurable through `\changeSettings`.
  Preserve pre-class definitions and direct redefinitions; replace the fixed
  submission date with the generic `\providecommand{\dfgDate}{<date>\xspace}`.
- Reorganize the manual into shared commands, a proposal-order walkthrough,
  and a separate metadata/configuration reference. Introduce record creation,
  lookup, reference traversal, and dispatcher syntax before specialised output.
- Consolidate repeated galleries and shared PI/project metadata; keep rendered
  examples beside their explanations and retain all built-in table/list/plot
  targets. Explain new, continuing, ending, and reference-only projects and
  distinguish status from service, training, and administration project types.

### 2026-09-17 version 0.2.5
- Include the complete fictional starter proposal as a chapter in the manual
  and distribute its standalone PDF. Show imported pages at 82% size inside a
  frame, with a separate-document label and the manual page number outside.
  Generate its final-mode wrapper
  from the DTX; `make doc` builds the proposal before importing every page.
- Complete the rendered gallery for all built-in table, list, and plot targets,
  including female-researcher objectives, project-leader participation, all
  finance overviews, animal upkeep, filtered research areas, and plot aliases.
  Group examples in proposal order and show the input records for each new table.
- Restore page breaking for wide example boxes after disabling side-by-side
  layout; allow long input listings and table results to continue across pages.
- Expand the complete A06 funding example to all five funding groups: staff,
  direct costs, fellowships, global funds, and instrumentation. Show annual
  amounts and a one-off equipment purchase, with combined yearly totals.
- Add six complete funding/personnel examples: existing and requested equipment,
  doctoral candidates, named staff and vacancies, annual staff quantities, and
  existing direct-cost funding. Show every input record and explain units,
  ongoing/completed doctorates, and the custom-database table option.
- Add practical live examples for branching metadata lookups, person statistics,
  staff counts, nested and cross-project references, contact
  cards, bibliographies, research areas, applicant wording, rules, and signatures.
  Show the funding records and the salary setting in the requested-funding
  example. Extract the complete input records for project and PI table examples
  from the same DTX fixtures. Render table results outside their code boxes.
  Demonstrate the project-status legend, automatic funding-period wording, and
  research-area list with its DFG classification footnote.
- Expand the independent manual fixtures to six active A projects, six B
  projects, three Q projects, twelve PIs, six institutions, and four affiliations.
  Include continuing/new research, service, training, administration, and a
  former-project reference. Add live examples throughout the command reference,
  including PI/project links, project counts, names, institution options, role
  cards, metadata retrieval, and project/PI overview tables.
- Demonstrate explicit and current-project collaboration/Gantt plots, layout
  aliases, connecting arcs, captions, and area colours. Add live `TableEnv`
  column/row options, aim/work-package references, signatures, figures, and
  publication results. Give repeated plot examples unique figure labels.
- Nest individual generated-file descriptions beneath a shared implementation
  section, including the customization file and the documentation fixtures.
- Typeset the manual with `dfg-crc` itself and add executable code/result
  examples for metadata lookups, references, lists, contact cards, boxes,
  tables, and collaboration plots. Use stacked output for wide examples.
- Add opt-in `documentation=true` to load manual fixtures explicitly, without
  importing proposal customizations, metadata, or default bibliography files.
  Generate all documentation fixtures from the DTX.

### 2026-09-17 version 0.2.4
- Add `\get[database]{id}{relation}{field}` for generic `ref-<database>-id`
  traversal, including multi-step paths, multiple IDs, destination deduplication,
  explicit reference-key spellings, and direct/starred lookup compatibility.
  Keep final-value formatting and destination `showtags` annotations. Preserve
  stored ID order, separate results with commas, and warn without emitting
  dangling separators when a branch cannot be resolved.
- Retain database keyset information when focused builds skip metadata rows,
  so shorthand reference paths are consumed correctly for custom databases too.
- Add 33 reference-lookup regression cases to `make check`, including custom
  keysets, multiple IDs, shared destinations, finite cyclic paths, missing data,
  direct/starred compatibility, and focused-build placeholders. Check rendered
  separators and duplicate removal in the PDF when Poppler is available.

### 2026-09-17 version 0.2.3
- Add flowing, balanced participating-institution columns with `columns=2`,
  `columns=3`, etc., and configurable `column sep` (12 pt by default).
  Keep each affiliation and its institutions together, without equal-height
  row padding. Retain `raster columns` for aligned rows and reset layout and
  sorting options for each call.
- Start flowing institution lists with a paragraph break and a medium vertical
  skip. Remove the extra 7 pt gap between an affiliation heading and its
  institutions; retain 10 pt between affiliation groups.
- Recognize parent and nested work packages together in `\getWP`, preserving
  hierarchical sorting and range boundaries, including lists such as
  `\getWP{wp1a,wp1b,wp2,wp3a,wp3b}`.
- Include project-local existing direct costs in focused fast-build totals,
  instead of displaying zero; retain accumulation across multiple funding rows.
- Default `biblatexstyleFeatureProposal` to empty, so changing bibliography
  styles does not implicitly pass the unsupported `dashed=false` option.
- Prevent tables from overlapping preceding text by ending paragraphs before
  `\printTable`, using a shared 6 pt gap, and removing negative spacing from
  `TableEnv` and its captions.
- Reserve `local/test.tex` for manual experiments. Maintain the general
  regression document in `ci/test-template.tex` and compile its copy as
  `local/test-template.tex`; extraction and automated checks leave the manual
  file untouched.
- Add 30 command-option checks and 10 participating-institution layout cases
  to the DTX and `make check`, covering defaults, empty/leading/legacy options,
  precedence, grouped names, arguments, databases, boolean flags, PI rasters,
  column widths and gaps, spacing, sorting, filtering, and duplicate removal.
  Extend funding and work-package regressions for the corrected cases and
  retain the new test logs and PDFs as CI artifacts.
- Install Poppler utilities for CTAN checks and report missing PDF-inspection
  tools before running the installation test. Refine ChkTeX suppressions for
  expl3 bracket parsing and TikZ coordinate syntax.

### 2026-09-17 version 0.2.2
print fast-compilation project identifiers in bold black while retaining error colours
add a 7 pt gap below affiliation headings in participating-institution boxes
standardize leading options for lists and role-based PI rasters, combining
sorting, formatting, database selection, and layout before the main argument
while retaining compatible trailing options and grouped list names
add configurable raster columns and spacing to participating-institution lists,
with one affiliation per cell and compatible count/alphabetical sorting

### 2026-09-17 version 0.2.1
align PI-box titles ragged right and reserve the tallest title's height
throughout each raster, keeping the contact information aligned after wrapping
increase the default column gap to 12 pt in both PI rasters
allow a line break between phone and email while keeping each contact intact
and retaining the one-em gap when both fit on the same line
print affiliation names in bold in `\printList{ParticipatingInstitutions}`

### 2026-09-14 version 0.2.0
typeset fenced README code in the PDF manual with a monospaced verbatim font
align the default thumb-index stack with the current text block, dividing
`\textheight` into equal tabs while retaining explicit page-edge margin settings
print person-specific institutions through `\printList{{Institutions}{id}}`
throughout the class and examples, retaining `\dfgInstitutionList` as an alias
show `\printPlot` as the Gantt command in the manual and clarify the distinct
thumb-index show, hide, and reset operations
accept lowercase plot types with or without a project ID, including
`\printPlot{{gantt}{B06}}` and `\printPlot{{collaborations}{B06}}`
open the user documentation with an overview of the proposal template and
move log-message guidance into troubleshooting
keep the changelog as a separate generated file instead of including it in
the documentation PDF

### 2026-09-14 version 0.1.8
bold entire project bibliography entries tagged `<project-id>-highlight`
when `emphasizeEntries` is enabled, without affecting other project lists
document that one highlight keyword per distinct project is enough even when
several PIs from that project coauthor an entry
align numbered section and subsection titles in a shared 12 mm number column
increase the default text height by 5 mm with 20 mm top and 15 mm bottom margins,
without changing the inner binding or outer note margins
separate each staff member's name from the job description with a normal space
move the text block 5 mm toward the binding by using 25 mm inner and 20 mm
outer margins without changing its width or the binding correction
remove the trailing blank Gantt row and leave a very small gap before its
bottom rule

### 2026-09-14 version 0.1.7
place collaboration-plot captions below the image with or without optional
caption text, matching the Gantt-chart caption layout

### 2026-09-14 version 0.1.6
reserve binding space with the configurable `BCOR` option (5 mm by default),
while keeping a 160 mm text block and fitting notes into the narrower outer margin
give thumb-index tabs regular rounded corners and rotated labels that fit the
outer marginal column on both sides of a two-sided page
separate the `WP` or `WPs` prefix from work-package numbers with a narrow,
unbreakable space while retaining sorted and compressed references
remove project-area letters below collaboration-plot nodes and show connecting
arcs only when `arcs=true` is requested; align wide plots with the text edge
on both sides of a spread
omit empty staff positions without warnings, placeholders, or extra lines;
align numbered staff descriptions with a hanging indent
tighten heading, caption, project-header, legal-issue, PI-card, bibliography,
and aims-box typography and spacing
reduce the shared gap above generated tables to 4 pt and match dashed Gantt
vertical grid lines to the horizontal rule colour
place Gantt captions below the chart whether or not additional caption text
is supplied, keeping the default `Fig.` label visible
abbreviate English figure caption labels to `Fig.`
keep direct-cost table headings with their tables at page boundaries
use the footnote-sized project bibliography wrapper for project reports and
published-result lists

### 2026-09-07 version 0.1.5
apply the default table font size at theme scope so cell-local declarations
such as `font=\bfseries` retain `\footnotesize`, while explicit size
declarations remain available as overrides
document the table-font inheritance and override behaviour

### 2026-09-04 version 0.1.4
add `make update-all` to rebuild and copy both the generated class and manual
PDF into a separately controlled proposal worktree
allow existing non-research staff to omit `field-of-research` without a
warning or a missing-value placeholder, and grey out the empty cell as not
applicable
keep the `to` connector in compact `\getWP` ranges at normal font weight and
retain references to nested work packages under later parent work packages,
with focused regression coverage
warn when a `RequestedFundingStaff` row omits both `ref-person-id` and
`ref-institution-id`, because its institution cannot otherwise be resolved
render staff job descriptions as itemized lists with consistent indentation
make the generic `TableEnv` options argument genuinely optional by defaulting
it to an empty option list
make `ProjectLeadersTable` follow `projectsTableInstitutionAbbreviations` when
choosing full institution names or abbreviations, with regression coverage
increase the default vertical spacing between and after rows of PI boxes
printed by `\getPIsWithRole`

### 2026-08-07 version 0.1.3
allow generated plots in focused project builds when
`fastcompile-project-show-images=true`, retaining the project metadata they need
make the collaboration arc diagram the default project-collaboration plot, with
an `arcs=false`/`no-arcs` option and explicit heatmap selection
add the unified `\printProject` command for project heads and tails while
retaining the original commands as compatibility interfaces
give PI, work-package, and aim references independent configurable colours
format generic table body text consistently at footnote size, including
table-cell content that overrides theme row settings
correct collaboration-plot colour propagation, width and node placement, and
support suppressing connecting arcs without suppressing project nodes
document singular/plural-sensitive contract-question wording and avoid a
documentation-driver list-label dimension overflow

### 2026-08-03 version 0.1.2
default |\ProjectsTable| to full institution names and refine the optional abbreviation mode with small, table-local, alphabetically sorted legends containing only the institutions used in each table
warn when one institution abbreviation denotes different institution names, and retain the corrected non-empty legend check
treat |id| as a database-local unique key: a later |\addEntry| with the same identifier warns, removes every earlier matching row, and becomes the stored entry
tighten the former-project legend spacing, vertically center project identifiers, and add release regressions for the new defaults and duplicate-ID replacement

### 2026-08-03 version 0.1.1
add the |projectsTableInstitutionAbbreviations| setting to choose compact institution abbreviations with a full-name legend or full institution names without a legend in |ProjectsTable|
make |resetThumbIndex| public so manually separated document parts can restart the thumb-index sequence
document the new ProjectsTable display setting, the public thumb-index reset command, and the post-0.1.0 CTAN update procedure

### 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.3.0 (2026-10-20)**.

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 PDF manual combines this introduction with the detailed user and code
documentation. Release history is kept separately in `CHANGELOG.md`.

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`.

Two-sided pages reserve 30 mm on the binding edge by default: a 25 mm inner
margin plus `BCOR=5mm`. Pass a different KOMA `BCOR` class option to adjust
the binding correction; `BCOR=8mm` gives 33 mm on the inner edge and a 157 mm
text block. The default 160 mm text block leaves a 20 mm outer margin for the
rotated thumb index and marginal notes.
The 20 mm top and 15 mm bottom margins give the text block 5 mm more height
than the previous 20 mm margins; the footer remains included in the page layout.
By default, the thumb-index tabs span the text block from top to bottom and
divide its current height into equal slots. Set `thumbindex@topmargin` or
`thumbindex@bottommargin` to a page-edge distance to override either end.
Use `\changeSettings{thumbindex@orientation=inwards}` to turn the labels
180 degrees towards the text block. The default `outwards` points the tops
of the letters towards the outer page edge on both left and right pages.
Labels sit 2 mm towards the text block from the center of each tab.
Numbered section and subsection titles start at the same horizontal position
after a shared 12 mm number column. Section, subsection, and subsubsection
headings have one baseline of space above them; following text starts on the
next line without an additional blank line.

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 update-all TARGET_DIR=/path/to/proposal-worktree`: rebuilds and copies
`dfg-crc.cls`, `crc-proposal-documentation-and-code.pdf`, and the standalone
`dfg-crc-proposal-example.pdf` and `dfg-crc-cv-example.pdf` into that 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 test-workpackage-references`: compiles the focused nested-work-package
reference and range-formatting regression. <br>
> `make test-aim-references`: checks custom aim labels, forward references,
plural references, ranges, and list option scope. <br>
> `make test-bibliography-highlights`: checks frame and project entry
highlighting, font sizes, options, and isolation from ordinary lists. <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 proposal-doc-example`: builds the complete documentation consortium proposal in final
mode as `dfg-crc-proposal-example.pdf`. <br>
> `make cv-doc-example`: builds the complete twelve-PI CV appendix in final
mode as `dfg-crc-cv-example.pdf`. <br>
> `make doc`: builds both PDFs first, then includes all their pages in the user
documentation, followed by the implementation reference. <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,
  fastcompile-project-show-funding-tables=true,
  english
]{dfg-crc}
```

`fastcompile-project` skips metadata loading and most `\addEntry` execution,
calculated project heads, generated tables/lists and plots, 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. Project identifiers in focused
fast compilation are red typewriter placeholders such as <A03>. Set
`fastcompile-project-show-images=true` to load the project metadata and render
images and generated plots 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. Use
`\printProjectBibliography` for project publication lists; plain
`\printbibliography` uses biblatex's normal font and bypasses the
project-publication switch.

To use footnote-sized text and remove extra space between bibliography entries,
add this hook to `preamble/dfg-customization.tex` (outside `\changeSettings`):

```latex
\AddToHook{package/biblatex/after}{%
  \renewcommand*{\bibfont}{\normalfont\footnotesize}%
  \setlength{\bibitemsep}{0pt}%
}
```

The hook waits until `biblatex` has loaded because the customization file is
read earlier. `\bibitemsep` controls the extra gap between entries; change
`0pt` to `2pt`, for example, for a small gap. It does not change line spacing
within an entry. Without an override, the bibliography style supplies its
spacing; the alphabetic styles inherit the standard list gap (4 pt plus
2 pt minus 1 pt in the default 10 pt setup). The CV's custom `DFGlist` already
uses `nosep` and is configured separately through its `itemsep` list option.

With `emphasizeEntries=true`, a full project bibliography entry is bold when
its `.bib` keywords include the current project ID followed by `-highlight`,
for example `B06-highlight`. One such keyword is enough even if two PIs from
Project B06 coauthor the entry. An entry may also carry another project's
highlight keyword when it should be bold in that project's list. The
`B06-project` keyword is optional project metadata; it does not trigger bold
type. Other keywords, including CV selectors such as `pabst-A`, can remain in
the same field. To use only whole-entry highlighting, set
`emphasizeAuthors=false` and `emphasizeEntries=true`.

For the frame-text references in chapter 1, use `\printFrameBibliography`
with the same options as `\printbibliography`. With `emphasizeEntries=true`,
entries tagged `frametext-highlight` are bold in this list. Project-specific
highlight keywords do not affect it, and the normal bibliography font size
is preserved. For example:

```latex
\changeSettings{emphasizeEntries=true}
\defbibnote{frame-references}{%
  \usekomafont{subsection}%
  \bfseries\sffamily References
}
\printFrameBibliography[prenote={frame-references},heading=none]
```

The `.bib` entry may combine keywords, for example
`keywords = {pabst-A,B06-highlight,frametext-highlight}`. The keyword selects
formatting only; cite the entry or use `\nocite` to include it as usual.
Existing chapter 1 files need the command replacement above because template
updates preserve edited chapter files.

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. The three project-local funding tables
remain visible by default. Set
`fastcompile-project-show-funding-tables=false` to suppress them too. Focused
mode processes their local rows and sums but does not restore or populate
proposal-wide overview databases. 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
# Or update the class, compiled manual, and complete example PDF:
make update-all TARGET_DIR=/path/to/proposal-worktree
```

Both targets verify that `TARGET_DIR` is the root of a different Git worktree,
copy the requested release files, and show their resulting Git status.
`update-class` copies only `dfg-crc.cls`; `update-all` first rebuilds the manual
and then copies the class, `crc-proposal-documentation-and-code.pdf`, and
`dfg-crc-proposal-example.pdf` and `dfg-crc-cv-example.pdf`. Neither
target overwrites the proposal repository's README, changelog, or licence. They
do not store the destination, inspect its remote, commit, or push. Review and
commit the updates 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-existing-funds-direct-costs.tex`,
`local/test-project-collaboration.tex`,
`local/test-workpackage-references.tex`, `local/test-participating-institutions.tex`,
`local/test-command-options.tex`, `local/test-reference-lookups.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.

The manual uses `dfg-crc` itself, with `documentation=true` to load only its
explicit fictional fixtures. The DTX driver maintains executable `dfgExample`
boxes: code on the left, rendered output on the right. Add `[dfg wide]` for
wide results below their code. `make doc` regenerates the fixtures and compiles
the examples; incomplete setup fragments remain code-only. This does not
read or overwrite the manual scratch file `local/test.tex`.

The manual and local examples share the DTX `meta` records: twelve PIs, six institutions,
four affiliations, and fifteen active projects (A01--A06, B01--B06, Q01--Q03),
plus a former project. The embedded proposal uses these same metadata in
`local/`, with individual files for all fifteen active projects and the former
project A00. The local CV uses the same twelve PIs, with matching career records
and explicitly fictional publications for each person. Examples use `dfg project=A03` when they need the context
normally established by a project heading. Project overviews and the PI roster follow their code boxes at normal size
and may span pages; collaboration plots retain the available text width.

`make test-participating-institutions` checks flowing/raster column widths,
active-PI filtering, shared-institution deduplication, sorting, spacing above
columns, and option scope. `make test-command-options` checks omitted/empty,
leading/legacy options, precedence, grouped command specifications, mandatory
arguments, custom databases, boolean flags, and per-call defaults for lists,
tables, plots, and PI rasters. `make test-reference-lookups` covers generic
reference paths, branching ID lists, destination deduplication, diagnostics,
and focused-build placeholders.

The standalone regression document is maintained in `ci/test-template.tex`.
`make test` copies it to `local/test-template.tex` before compiling it.
`local/test.tex` is reserved for manual experiments and is neither generated
nor compiled by the template checks.

## 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
`\printList{{Institutions}{<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. A row without `ref-person-id` must provide
`ref-institution-id`; otherwise the class warns because it cannot resolve the
institution or assign existing staff to an affiliation in the proposal-wide
overview. Existing non-research staff may omit `field-of-research`; that empty
table cell is then greyed out as not applicable without a warning. Empty
staff positions are omitted without a warning or an empty line. The job
descriptions printed below each requested-funding staff table use flush-left
number labels and a hanging indent so continuation lines align with the first
line of description text. A normal interword space separates the bold name
from the description.

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 `\get[database]{id}{field}` prints a metadata field. Add reference
steps to retrieve fields from linked rows, for example
`\get[person]{MM}{institution}{name}` or
`\get[person]{MM}{institution}{affiliation}{name}`. Each step follows
`ref-<database>-id`; the full key spelling is also accepted, as in
`\get[person]{MM}{ref-institution-id}{name}`. This works from any source
database, including named databases populated with a separate keyset.
Multiple reference IDs are followed in their stored order and the resulting
values are separated by commas. A destination row reached more than once is
printed only once; different rows with identical names remain separate.
Missing or empty references warn and contribute no value. The terminal field
keeps its formatting and `showtags` annotation. Focused fast compilation uses
the source ID placeholder, as with `\getEntry`. `\get*` retains the starred
multi-field assignment syntax of `\getEntry*`.

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. Unstarred references distinguish shared PI surnames with the first given-name
  initial (K. Schneider / C. Schneider), or the full given name when initials also match.
  This rule applies across projects and funding periods, including project-first references.
  Explicit display text bypasses it; starred references retain full given 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 `\printList{{Institutions}{<person-id>}}` prints institutions and
  parent affiliations assigned to a person. Put formatting and database options
  before the specification, for example
  `\printList[database=person,abbreviation,narrow]{{Institutions}{MM}}`.

Command `\printList{ParticipatingInstitutions}` lists participating institutions
  across the proposal, with affiliation names in bold. Use `columns=2` (or
  `columns=3`, etc.) to flow whole affiliation groups down balanced columns.
  Short groups follow one another without being padded to the height of a
  neighbouring group. Groups stay together; reading order is down each column.
  `column sep=16pt` changes the gap (default: 12 pt). Flowing lists start a
  new paragraph with a medium vertical skip above the columns.
  The default layout remains a one-column raster, with 12 pt between columns
  and 10 pt between rows. For aligned rows, pass `raster columns=2` or another
  `tcbraster` option through the optional list argument. Sorting defaults to
  `order=count`; use `order=alpha` for alphabetical affiliation order. The
  legacy bare `count` and `alpha` options remain supported.

Put all list options before the specification, as with `\printPlot`.
Plain and grouped list names are both accepted. Older trailing options remain
supported; leading settings take precedence when the same key occurs twice.

```latex
\printList[columns=2]{ParticipatingInstitutions}
\printList[columns=3,column sep=16pt,order=alpha]{ParticipatingInstitutions}
\printList[order=alpha,raster columns=2]{{ParticipatingInstitutions}}
```

Command `\getPersonInformation` with `[database]` `{person-id-list}` prints complete formatted
  PI/contact-information blocks, with a 12 pt column gap in the two-column raster.

Command `\getPIsWithRole` with `[options]` `{role}` prints formatted current-period people
  carrying a given role. Put database and raster settings in the leading options,
  for example `\getPIsWithRole[database=person,raster columns=2]{PI}`.
  Use `\getPIsWithRole[academicdegree-below]{steering-committee-member}`
  to put the degree on a separate line below the name within the same PI box.
  The option applies only to that call; the default (or `academicdegree-below=false`)
  keeps the degree inline after the name.
  The default three-column raster has a 12 pt column gap;
  rows and the following content are separated by 20 pt. Explicit raster options
  can override that spacing.

PI-box titles are ragged right and top-aligned. All titles within one raster
reserve the height of its tallest title, so wrapped names or academic degrees
do not misalign the contact information. Recompile until the equal-height
layout settles; a clean build can require three LaTeX passes. Phone and email
stay individually unbroken, with a one-em gap that permits a line break
between them when they do not fit together.

Use `\getPIWithProject*` with `{person-id-list}` to print each PI with their
  assigned project identifiers in parentheses, without repeating the projects'
  PI names; the star includes first names. The older
  `\getPIProject` command remains available but warns that it is deprecated.

Use `\getProjectWithPI*` with `{project-id-list}` to print each project with
  its assigned PIs; the star includes first names. The older `\getProjectPI`
  command remains available but warns that it is deprecated. 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. The starred form defaults to first and last names,
  separating earlier names with commas and only the last with “and”.

Command `\getProject*` with `{project-id-list}` `[text]` prints a linked project
  reference. The star always prints project identifiers only, independently of
  `projectPIOncePerSection`. 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{{collaborations}{A01}}` prints the default
full-width arc layout for A01, with project nodes and unlabelled area rules.
Its boxes align with the text edge on both sides of a two-sided page.
Its caption always appears below the plot; a final optional argument adds
caption text there.
Add `[arcs=true]` before the plot specification to draw the connecting arcs,
or use `[layout=heatmap]` for the heatmap. 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}}`. Inside a project, omit
the ID: `\printPlot{{gantt}}` and `\printPlot{{collaborations}}` use the
current project. Options precede the plot specification, for example
`\printPlot[caption={Additional details}]{{gantt}}` or
`\printPlot[arcs=true]{{collaborations}{B06}}`. With an explicit ID, use the
same leading caption option:
`\printPlot[caption={Additional details}]{{gantt}{B06}}`. The older `Gantt` and
`ProjectCollaboration` type names remain available. In project source files,
`caption={}` marks where optional caption text can be added to either plot;
left empty, the default caption is still printed.

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. `\getWP` places a narrow, unbreakable space after `WP` or `WPs`.

The `aims` environment accepts a custom prefix shared by the numbered items
and references:

```tex
\begin{aims}[label={RDM Aims}]
  \addAim{data} Document research data.
  \addAim{reuse} Publish reusable datasets.
\end{aims}
See \getAim{data,reuse}.
```

This prints `RDM Aims 1:` and `RDM Aims 2:`, with `RDM Aims 1 and 2` in
the reference. `\cref` and `\Cref` also use the custom prefix. Its text is
used unchanged for single and multiple references; ordinary `aims` lists
retain `Aim`/`Aims`. Other list options, such as `start=3`, remain available.
Compile twice after changing labels to update forward references.

Use `resume` to continue numbering from the previous `aims` list. Repeat
the custom label to keep it in both the items and their cross-references:

```tex
\begin{aims}[label={RDM Aims},resume]
  \addAim{archive} Archive the datasets for long-term access.
\end{aims}
See \getAim{archive}.
```

Following the two-item list above, this prints `RDM Aims 3:` and references
it as `RDM Aims 3`. `[resume]` alone continues the number with the default
`Aim`/`Aims` prefix. Numbering resumes from the previous `aims` list,
regardless of its label text; custom labels do not create separate counters.

### 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.

The optional database defaults to `person`. Counts include people whose
`role` list contains `PI` and whose `period` list contains the requested
funding period. The total-row commands sum `postDoc`, `groupLeader`,
`prof-W2`, and `prof-W3`. Gender is `f`, `m`, or `d`; percentages are rounded
integers without a percent sign and return zero when the denominator is zero.

```tex
% First-period table values: women across all four career categories.
\getGenderPhaseTotal{f}{1}
\getGenderPhasePercentage{f}{1}\%
% Female W3 professors: number, percentage, and all-gender total.
\getPositionGenderPhaseAmount{prof-W3}{f}{1}
\getPositionGenderPhasePercentage{prof-W3}{f}{1}\%
\getPositionPhaseTotal{prof-W3}{1}
```

Change the last argument to `2` or `3` to query another funding period.
These commands are available independently of the current proposal period.
Section 1.4.2 B adds the first-period Number and Percentage columns only for
proposals with `fundingPeriodNumeral = {3}`. Maintain historical PI records
with their appropriate `period` membership to populate these columns.
The statistics count people; the share of projects with female leadership
requires a separate calculation.

The project-leader table defaults to the female-only DFG layout. For a
third-period proposal, periods 1 and 2 each show Number/Percentage; period 3
shows its original objective (from `future-objective-percentage-female`) and
current Number/Percentage. The person records' period-3 membership supplies
these current counts. Percentages always use all genders as the denominator.
Select the expanded f/m/d comparison, including third-period counts and
percentages alongside its objective columns, for a single table:

```tex
\printTable{GenderEqualityProjectLeaders}            % female-only DFG view
\printTable[all-sexes]{GenderEqualityProjectLeaders} % expanded f/m/d view
```

Each call starts in female-only mode; `[all-sexes]` affects only that table.
Put options before the table name. Combine `database=MyObjectives,all-sexes`
to use a custom
objectives database. The prose count and percentage commands are unaffected.

### 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. For CTAN updates after the initial release, set `\update{true}` in
%<dev>   `dfg-crc.pkg`. Keep the CTAN path
%<dev>   `/macros/luatex/latex/dfg-crc`, and omit `\home` when it duplicates
%<dev>   the repository URL.
%<dev>3. Do not include the generated `dfg-crc.cls` in the CTAN archive. CTAN
%<dev>   requires files generated from a documented source and installer to be
%<dev>   omitted; the PDF manual and example PDF are documentation exceptions.
%<dev>4. Confirm that `bossert@itc.rwth-aachen.de` is registered as the second
%<dev>   address of CTAN member `lukascbossert`. Keep release information in
%<dev>   separate Announcement and Note fields; CTAN explicitly accepted that
%<dev>   structure for the initial release.
%<dev>5. 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>6. 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>7. Before a public release, run the complete template check:
%<dev>
%<dev>   ```
%<dev>   make check
%<dev>   ```
%<dev>
%<dev>8. Run the official online validator with
%<dev>   `make ctan-validate`.
%<dev>9. 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>
%<*docindex>
actual '='
quote '!'
level '>'
preamble "\n \\begin{theindex}\n \\makeatletter\\scan@allowedfalse\n"
postamble "\n\n \\end{theindex}\n"
item_x1 "\\efill\n \\subitem "
item_x2 "\\efill\n \\subsubitem "
delim_0 "\\pfill "
delim_1 "\\pfill "
delim_2 "\\pfill "
heading_prefix "{\\bfseries\\hfil "
heading_suffix "\\hfil}\\nopagebreak\n"
headings_flag 1
%</docindex>
%<*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>
% Keep the output directory separate from the filename in generated comments.
\BaseDirectory{.}
\UseTDS
\usedir{local}
\generate{
  \file{dfg-crc.cls}
    {\from{crc-proposal-documentation-and-code.dtx}{file,cls}}
}
\usedir{}
\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,example-data}}
  \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-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}}
  \file{local/test-workpackage-references.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,test-workpackage-references}}
  \file{local/test-reference-lookups.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,test-reference-lookups}}
  \file{local/test-command-options.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,test-command-options}}
  \file{local/test-participating-institutions.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,test-participating-institutions}}
%
% template adjusted below
%
  \file{local/crc-proposal.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,main}}
  \file{local/dfg-crc-proposal-example.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,doc-proposal}}
  \file{local/dfg-crc-cv-example.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,doc-cv}}
  \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,doc-projects}}
  \file{local/content/03_project_research-example.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,research-example}}
  \file{local/content/03_project_A00.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-ending}}
  \file{local/content/03_project_A03.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-a03}}
  \file{local/content/03_project_A04.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-a04}}
  \file{local/content/03_project_A05.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-a05}}
  \file{local/content/03_project_A06.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-a06}}
  \file{local/content/03_project_B03.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-b03}}
  \file{local/content/03_project_B04.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-b04}}
  \file{local/content/03_project_B05.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-b05}}
  \file{local/content/03_project_B06.tex}{\from{crc-proposal-documentation-and-code.dtx}{file,03-project-b06}}
  \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-new}}
  \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{\jobname.mst}{\from{\jobname.dtx}{docindex}}
  \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
  \generate{
    \file{\jobname-doc-data.tex}{\from{\jobname.dtx}{file,meta}}
    \file{\jobname-doc-table-a.tex}{\from{\jobname.dtx}{file,doc-table-a}}
    \file{\jobname-doc-table-b.tex}{\from{\jobname.dtx}{file,doc-table-b}}
    \file{\jobname-doc-table-q.tex}{\from{\jobname.dtx}{file,doc-table-q}}
    \file{\jobname-doc-table-pis.tex}{\from{\jobname.dtx}{file,doc-table-pis}}
    \file{\jobname-doc-examples.bib}{\from{\jobname.dtx}{file,bib,base}}
  }
  \expandafter\endgroup
\fi
%</internal>
%<*driver>
\providecommand*\InfoTeX{}
% The developer installer puts the class in local/; the public installer puts
% it beside the DTX. Both builds use the same class and embedded example data.
\IfFileExists{./local/dfg-crc.cls}
  {\def\dfgDocClass{local/dfg-crc}}
  {\def\dfgDocClass{dfg-crc}}
\PassOptionsToPackage{hyperindex=false}{hyperref}
\documentclass[documentation=true,english,final=true,twoside=false]{\dfgDocClass}
\usepackage{doc}
\usepackage{pdfpages}
\usepackage{newunicodechar}
\newunicodechar{−}{\ensuremath{-}}
\providecommand{\pkg}[1]{\textsf{#1}}
\usepackage{imakeidx}
\makeindex[options=-s \jobname.mst]
\tcbuselibrary{documentation,listings,breakable,skins}
\usepackage{markdown}
\markdownSetup{
  rendererPrototypes = {
    inputFencedCode = {\VerbatimInput[fontfamily=tt]{#1}},
  },
}
\setmonofont[
  Ligatures={NoCommon,NoDiscretionary,NoRequired,NoContextual}
]{TeX Gyre Cursor}
\definecolor{codeblue}{RGB}{0,84,159}
\definecolor{codegray}{RGB}{100,100,100}
\definecolor{Definition}{RGB}{0,84,159}
\tcbset{
  index actual={=},index quote={!},index level={>},
  docexample/.add style={}{
    colframe=codeblue,colback=white,breakable,enhanced jigsaw,
    documentation listing options={style=tcbdocumentation,escapeinside={(*}{*)}}
  },
  dfg wide/.style={sidebyside=false,breakable,enhanced jigsaw},
  dfg project/.store in=\dfgDocExampleProject,
}
\newtcblisting[auto counter,number within=chapter]{dfgExample}[2][]{
  enhanced,breakable,colback=white,colframe=codeblue,
  colbacktitle=codeblue,coltitle=white,fonttitle=\bfseries\sffamily,
  title={Example \thetcbcounter: #2},
  title after break={Example \thetcbcounter: #2 (continued)},
  dfg project={},
  listing and text,sidebyside,sidebyside align=top seam,
  lefthand ratio=.48,sidebyside gap=6mm,
  boxrule=.5pt,arc=1mm,left=2mm,right=2mm,top=2mm,bottom=2mm,
  before skip=8pt,after skip=10pt,
  listing options={language={[LaTeX]TeX},basicstyle=\ttfamily\footnotesize,
    breaklines=true,columns=fullflexible,keepspaces=true,showstringspaces=false},
  before lower={\normalfont\normalsize\raggedright\setlength{\textwidth}{\linewidth}\hvFloatSet{nonFloat=true}\dfgDocExampleContext},
  #1
}
\newtcbinputlisting[use counter from=dfgExample]{\dfgTableSetup}[2]{
  enhanced,breakable,colback=white,colframe=codeblue,
  colbacktitle=codeblue,coltitle=white,fonttitle=\bfseries\sffamily,
  title={Example \thetcbcounter: #2},
  title after break={Example \thetcbcounter: #2 (continued)},
  listing only,listing file={\jobname-doc-table-#1.tex},
  boxrule=.5pt,arc=1mm,left=2mm,right=2mm,top=2mm,bottom=2mm,
  before skip=8pt,after skip=10pt,
  listing options={language={[LaTeX]TeX},basicstyle=\ttfamily\footnotesize,
    breaklines=true,columns=fullflexible,keepspaces=true,showstringspaces=false}
}
\makeatletter
\ExplSyntaxOn
\cs_new_protected:Npn \dfgDocExampleContext
  {
    % Example headings show the class typography without changing the manual's
    % section counters, contents, or hyperlink destinations.
    \cs_set_eq:NN \dfgDocSection \section
    \cs_set_eq:NN \dfgDocSubsection \subsection
    \cs_set_eq:NN \dfgDocSubsubsection \subsubsection
    \RenewDocumentCommand \section {s o m} {\dfgDocSection*{##3}}
    \RenewDocumentCommand \subsection {s o m} {\dfgDocSubsection*{##3}}
    \RenewDocumentCommand \subsubsection {s o m} {\dfgDocSubsubsection*{##3}}
    \tl_set:No \l__tmp_current_project_tl {\dfgDocExampleProject}
    \exp_args:NV \__dfg_project_results_prepare:n \l__tmp_current_project_tl
    % hvFloat stores its label before caption packages install their own
    % label command. Prefix that stored label locally for each live example.
    \cs_set_eq:NN \dfgDocOriginalFloatCaption \do@@hvFloat
    \cs_set_protected:Npn \do@@hvFloat [##1]##2##3
      {\dfgDocOriginalFloatCaption[##1]{##2}
        {doc-example-\thetcbcounter-##3}}
  }
\ExplSyntaxOff
\makeatother
% Resolve example-project preview pages by named PDF destinations. This keeps
% the excerpts correct when earlier proposal pages change length.
\directlua{
  local function register_pages(filename, pattern, prefix)
  local pdf = pdfe.open(filename)
  if pdf then
    local pages = {}
    for number, entry in ipairs(pdfe.pagestotable(pdf)) do
      pages[entry[3]] = number
    end
    local function value(entry)
      if entry[1] == 10 then
        local kind, result = pdfe.getfromreference(entry[2])
        return result
      end
      return entry[2]
    end
    local function visit(node)
      local names = pdfe.getarray(node, 'Names')
      if names then
        local entries = pdfe.arraytotable(names)
        for index, entry in ipairs(entries) do
          if math.fmod(index, 2) == 1 then
            local id = value(entry):match(pattern)
            if id then
              local destination = pdfe.getarray(value(entries[index+1]), 'D')
              local page = pages[pdfe.arraytotable(destination)[1][3]]
              if page then
                token.set_macro(prefix .. id, tostring(page), 'global')
              end
            end
          end
        end
      end
      local children = pdfe.getarray(node, 'Kids')
      if children then
        for _, entry in ipairs(pdfe.arraytotable(children)) do visit(value(entry)) end
      end
    end
    local names = pdfe.getdictionary(pdfe.getcatalog(pdf), 'Names')
    if names then
      local destinations = pdfe.getdictionary(names, 'Dests')
      if destinations then visit(destinations) end
    end
    pdfe.close(pdf)
  end
  end
  register_pages('dfg-crc-proposal-example.pdf', '^project:(.+)$', 'dfgDocProjectPage')
  register_pages('dfg-crc-cv-example.pdf', '^doc[-]cv:(.+)$', 'dfgDocCVPage')
}
\newcommand*{\dfgDocProjectExcerpt}[2]{%
  \ifcsname dfgDocProjectPage#1\endcsname
    \includegraphics[page=\csname dfgDocProjectPage#1\endcsname,
      trim=25mm #2 15mm 17mm,clip,width=\linewidth]{dfg-crc-proposal-example.pdf}%
  \else
    \PackageError{dfg-crc documentation}{Missing example project destination #1}
      {Rebuild the standalone example proposal with make proposal-doc-example.}%
  \fi
}

\newcommand*{\dfgDocCVExcerpt}[1]{%
  \ifcsname dfgDocCVPage#1\endcsname
    \centering
    \includegraphics[page=\csname dfgDocCVPage#1\endcsname,
      width=\linewidth,height=.65\textheight,keepaspectratio]{dfg-crc-cv-example.pdf}%
  \else
    \PackageError{dfg-crc documentation}{Missing example CV destination #1}
      {Run make cv-doc-example before compiling the manual.}%
  \fi
}
\newcommand*{\dfgExampleRef}[1]{\hyperref[#1]{Example~\ref*{#1}}}
% Keep the manual's labels outside each reduced, framed example page.
\newcommand*{\dfgDocImportedPage}[1]{%
  \thispagestyle{empty}%
  \begin{tikzpicture}[remember picture,overlay]
    \node[anchor=north,font=\small\sffamily\bfseries,text=codeblue]
      at ([yshift=-12mm]current page.north)
      {#1\enspace\textperiodcentered\enspace separate document};
    \node[anchor=south,font=\small\sffamily,text=codegray]
      at ([yshift=10mm]current page.south)
      {Manual page \thepage};
  \end{tikzpicture}%
}
\NewDocumentCommand{\dfgFile}{m}{\texttt{#1.tex}}
\changeSettings{thumbindex=false,doiAPIMail={}}
\input{\jobname-doc-data.tex}
\addbibresource{\jobname.bib}
\addbibresource{\jobname-doc-examples.bib}
\def\MacroFont{\ttfamily\scriptsize}
\let\AltMacroFont\MacroFont
\AtBeginDocument{
  \MakeShortVerb{\|}
  \def\theCodelineNo{\color{codegray}\scriptsize\arabic{CodelineNo}\space}
  \CodelineNumbered\DisableCrossrefs\RecordChanges
  \setlength{\hfuzz}{2pt}
  \setlength{\emergencystretch}{3em}
  \RedeclareSectionCommands[beforeskip=2ex,afterskip=1ex]{section,subsection,subsubsection}
  \ihead{\texttt{dfg-crc} \dfgVersion}\ohead{\headmark}
  \ifoot*{}\cfoot*{}\ofoot*{\pagemark}
}
\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\\\href{mailto:bossert@itc.rwth-aachen.de}{bossert@itc.rwth-aachen.de}}
\title{The \texttt{dfg-crc} class\\User guide and implementation}
\date{Version \dfgVersion\quad\dfgVersionDate}
\begin{document}
\hypersetup{pdftitle={The dfg-crc class: user guide and implementation},
  pdfauthor={Lukas C. Bossert},pdfsubject={dfg-crc documentation}}
\frontmatter
\maketitle
\chapter*{About this manual}
This manual is typeset with the \texttt{dfg-crc} class itself. Executable
examples show their source on the left and the rendered result on the right.
Wide tables and plots put the result below the code. All examples use the
fictional people, institutions, and projects embedded in the DTX.

Setup fragments, shell commands, and bibliography source records are shown
as code only. Complete proposal and CV examples follow the user guide, before the
implementation reference; see Chapters~\ref{chap:complete-example-proposal}
and~\ref{chap:complete-example-cv}.

\blockcquote[195]{Hoare1973}{Documentation must be regarded as an integral part of the process of design and coding.}

Built with \InfoTeX.
\tableofcontents
\mainmatter
\chapter{Shared commands and first steps}
The \texttt{dfg-crc} class is a starting point for a Collaborative Research
Centre proposal and the accompanying CV section.  Authors write the proposal
chapters and maintain structured records for people, institutions, projects,
work packages, and funding.  The class uses those records to create project
headings, references, tables, collaboration plots, Gantt charts, and totals
that stay consistent across the document.

The supplied files include a complete example proposal, example CV, and
customization file.  Start with the generated examples to see how the source
files fit together, then replace their content and metadata with those of your
own centre.  This chapter introduces the commands reused throughout the proposal.
Chapter~\ref{chap:proposal-walkthrough} then follows the proposal itself;
Chapter~\ref{chap:manual-reference} collects the complete key and settings reference.  Applicants should still compare the result
with the current DFG forms and programme rules.

\section{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.

To update a separately controlled proposal worktree, use
\texttt{make update-class TARGET\_DIR=/path/to/proposal-worktree} for the class
alone.  Use \texttt{make update-all TARGET\_DIR=/path/to/proposal-worktree} to
rebuild the manual and copy \texttt{dfg-crc.cls},
\texttt{crc-proposal-documentation-and-code.pdf}, \texttt{dfg-crc-proposal-example.pdf}, and
\texttt{dfg-crc-cv-example.pdf}.  Both targets require the
destination to be the root of another Git worktree and report the affected
files without committing or pushing them.  They leave the destination's
README, changelog, and licence unchanged.

\section{How to read the examples}
The examples use the same class commands as a proposal. In the template data,
\texttt{per1} is Kim Sample, \texttt{per2} is Alex Example, and \texttt{A01}
is their shared project. The manual has twelve PIs and fifteen active projects:
|A01|--|A06|, |B01|--|B06|, and |Q01|--|Q03|. Research projects include both
continuing and new projects; Q projects demonstrate service, research training,
and administration. |A00| is a former, reference-only project and is excluded
from active counts. Outputs are compiled from the displayed source.

Small examples place code beside its result; wide examples put the result below
and allow it to continue onto another page. Headings inside live examples are
unnumbered so they do not change the manual's outline. The complete shared metadata are
listed once in Section~\ref{sec:manual-fixtures}. Finance examples show their
additional input records at the point of use. Optional settings normally go
immediately after the command, before its required arguments.

\section{Declare records with \texorpdfstring{\cs{addEntry}}{addEntry}}
\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}.  An |id| is unique within its database.  If a
  later call reuses the same |id|, the class issues a warning, removes all
  earlier rows with that |id|, and stores the later entry instead.  The same
  |id| may still be used in a different database.  Entries without an |id|,
  such as ordinary funding and staff rows, remain append-only.

  See \dfgExampleRef{ex:manual-declare-a-record-and-retrieve-its-fields}, \dfgExampleRef{ex:manual-requested-funding-for-a-project}.
\end{docCommand}

A keyset defines the accepted fields; a database stores the resulting rows.
Omit the optional keyset when it has the same name as the database, for
example |\addEntry{person}{...}|. Give it explicitly for a separate collection,
as below. Braces protect commas inside values. Use stable IDs rather than
repeating names in the prose.

\begin{dfgExample}[label={ex:manual-declare-a-record-and-retrieve-its-fields}]{Declare a record and retrieve its fields}
\addEntry[person]{ManualContacts}{
  id        = {example-contact},
  firstname = {Kim},
  lastname  = {Sample}
}
\getEntry[ManualContacts]{example-contact}{firstname}\space
\getEntry[ManualContacts]{example-contact}{lastname}
\end{dfgExample}

Store proposal records in |metadata/dfg-metadata.tex|, or in another metadata
file loaded by the proposal. Tables share those records. The standard databases
are |meta| (the CRC), |person|, |project|, |institution|, and |affiliation|;
funding and staff tables use the named collections introduced with each table.
Full field definitions are in Section~\ref{doc:metadata}.

\section{Read, store, and compare fields}
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.  Project identifiers are typeset in bold black; other
  row identifiers use a quiet grey placeholder.  Error diagnostics retain
  the configured \texttt{error} colour.  Starred multi-field lookups initialise their destination
  macros to empty values without touching a database.

  \medskip
  Examples:
  \begin{dfgExample}[label={ex:manual-field-lookup-and-alternative-identifier}]{Field lookup and alternative identifier}
\getEntry[person]{per9}{lastname}\par
\getEntry[project]{A06}{name}[number]\par
\def\tmpLocalDB{person}
\getEntry{per9}{firstname}
\end{dfgExample}


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

  See \dfgExampleRef{ex:manual-field-lookup-and-alternative-identifier}.
\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{dfgExample}[label={ex:manual-retrieve-several-fields-at-once}]{Retrieve several fields at once}
\getEntry*[person]{per8}{
  \exampleFirst = firstname,
  \exampleLast = lastname,
  \exampleDegree = academicdegree
}
\exampleDegree\space
\exampleFirst\space\exampleLast
\end{dfgExample}
  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.

  See \dfgExampleRef{ex:manual-retrieve-several-fields-at-once}.
\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}.

  See \dfgExampleRef{ex:manual-field-lookup-and-alternative-identifier}.
\end{docCommand}


\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}.

  See \dfgExampleRef{ex:manual-compare-a-database-entry-against-something}, \dfgExampleRef{ex:manual-conditionally-print-an-affiliation}.
\end{docCommand}

For example, compare the surname of |per6| against an expected value.

\begin{dfgExample}[label={ex:manual-compare-a-database-entry-against-something}]{Compare a database entry against something.}
\compareEntry[person]{per6}{lastname}{Hartmann}
  {The surname matches.}{The surname differs.}
\end{dfgExample}

The next example prints an affiliation only when the institution refers to it.
\begin{dfgExample}[label={ex:manual-conditionally-print-an-affiliation}]{Conditionally print an affiliation}
\compareEntry[institution]{ins3}{ref-affiliation-id}{aff3}
  {\getEntry[affiliation]{aff3}{name}}
  {Another university}
\end{dfgExample}

\section{Follow references between records}
A |ref-institution-id| value links a person to institutions; each institution's
|ref-affiliation-id| links it to a university or other parent organisation.
Use one brace argument per step, ending with the field to print. Multiple IDs
are followed automatically, so prose stays correct when affiliations change.

\begin{docCommand}{get}{\oarg{database}\marg{id}\marg{field or reference}\ldots}
  Read a field directly, or follow metadata references before reading the
  final field. Each intermediate argument names a destination database and
  follows the current row's |ref-<database>-id| field. The source database
  defaults to \cs{tmpLocalDB}. No institution or affiliation ID needs to be
  repeated in the document text.

  \begin{dfgExample}[label={ex:manual-follow-metadata-references}]{Follow metadata references}
\get[person]{per7}{lastname}\par
\get[person]{per7}{institution}{name}\par
\get[person]{per7}{institution}{affiliation}{name}\par
\get[project]{B04}{person}{lastname}\par
\get[RequestedFundingStaff]{per6}{person}[ref-person-id]{institution}{name}
\end{dfgExample}

  The full reference-key spelling also works:
  |\get[person]{MM}{ref-institution-id}{ref-affiliation-id}{name}|.
  Traversal is generic: a |ref-other-unit-id| field points to rows of the
  |other-unit| database. The source may be any database populated by
  \refCom{addEntry}, including one using a separately named keyset. Each
  destination is matched by its |id| field. The lookup follows only the
  explicitly requested path; an affiliation reached through an institution
  therefore needs both steps.

  A reference value may contain multiple comma-separated IDs. All branches
  are followed in stored order, and the resulting values are separated by
  commas. Repeated destination rows are printed once, in first-occurrence
  order. For example, two institutions of one university yield two institution
  names but only one affiliation name when the path ends at that university.
  Different rows with the same name are still distinct results.

  Missing databases, rows, fields, and empty reference lists use the existing
  lookup warnings and contribute no value; valid branches still render without
  dangling separators. The final value retains its LaTeX formatting and the
  \refKey{showtags} annotation identifies the destination row and field.
  Focused fast compilation consumes the path but prints the source ID
  placeholder, just like \refCom{getEntry}.

  With no following step, a full reference key returns its raw ID list:
  |\get[person]{MM}{ref-institution-id}|. An existing scalar field takes
  precedence over a shorthand relation name, so a following prose group is
  not absorbed. Use the explicit |ref-<database>-id| spelling if the names
  conflict. For a custom source identifier column, append the existing
  |[id-field]| argument after the first field/reference argument; destination
  rows still use |id|. The starred |\get*| form delegates to
  \refCom{getEntry*} for assignments and does not traverse references.

  See \dfgExampleRef{ex:manual-follow-metadata-references}, \dfgExampleRef{ex:manual-raw-reference-ids-and-resolved-organisation-names}.
\end{docCommand}

Two institution IDs may lead to the same affiliation. The final destination
is printed once, so this also works when a person's metadata changes later.
\begin{dfgExample}[label={ex:manual-raw-reference-ids-and-resolved-organisation-names}]{Raw reference IDs and resolved organisation names}
IDs: \get[person]{per7}{ref-institution-id}\par
Institutions: \get[person]{per7}{institution}{name}\par
Affiliation:
\get[person]{per7}{institution}{affiliation}{name}
\end{dfgExample}

A lookup may branch at several steps: from a project to its PIs, then to their
institutions and affiliations. Shared affiliations are still deduplicated.
\begin{dfgExample}[label={ex:manual-find-the-affiliations-behind-a-project}]{Find the affiliations behind a project}
\getProject*{B04}\par
PIs: \get[project]{B04}{person}{lastname}\par
Affiliations:
\get[project]{B04}{person}{institution}{affiliation}{name}
\end{dfgExample}

\section{Names and references in prose}
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}.

  See \dfgExampleRef{ex:manual-names-with-and-without-academic-titles}.
\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.

  See \dfgExampleRef{ex:manual-names-with-and-without-academic-titles}.
\end{docCommands}

\begin{dfgExample}[label={ex:manual-names-with-and-without-academic-titles}]{Names with and without academic titles}
\getName{per9}\par
\getFullName{per9}\par
\getFullName*{per9}
\end{dfgExample}

PI and project commands also have all-lowercase aliases, with identical
arguments, starred forms, formatting, and links. For example,
|\getpiwithproject{per6}| is equivalent to |\getPIWithProject{per6}|, and
|\getpiofproject*{B05}| is equivalent to |\getPIofProject*{B05}|.
This also applies to |\getPI|, |\getPIsWithRole|, |\getProject|,
|\getProjectColor|, |\getProjectCount|, |\getProjectWithPI|,
|\getPIOfProjectWithProject|, and the legacy commands |\getPIProject| and
|\getProjectPI|. Legacy aliases share the same once-per-command, per-LaTeX-run deprecation
warning as their canonical spelling.
The mixed spellings |\getPIwithProject|, |\getProjectwithPI|, and
|\getPIOfProject| are accepted as well. Other capitalizations remain
case-sensitive in TeX.

\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.
  If multiple PI records share a lastname, unstarred references automatically
  add the first given-name initial. For example, PI records for Kai Markus
  Schneider and Carolin V. Schneider are printed as \textbf{K.~Schneider} and
  \textbf{C.~Schneider}. If the initial is also shared, the full firstname is
  used instead. The comparison includes all records with role \texttt{PI} or
  \texttt{Co-PI}, independently of funding period or project selection.
  Project-first references inherit this distinction, for example
  \textbf{A04 (K.~Schneider)} and \textbf{B09 (C.~Schneider)}.
  With the optional \meta{text} argument, \meta{text} is printed instead, but
  the hyperlink still points to the PI.
  Set \texttt{PIReferenceFirstName=true} with \refCom{changeSettings} to make
  the unstarred command include the firstname too. The starred form always
  includes it. This setting also applies to \refCom{getPIProject} and
  \refCom{getPIofProject}. \refCom{getProjectPI} keeps project PI names to
  lastnames with automatic disambiguation unless its starred form is used.
  Shared PI surnames use the initial rule even with
  \texttt{PIReferenceFirstName=true}; use the star to force full firstnames.
  Explicit display text bypasses automatic disambiguation. Fast project
  compilation retains the usual ID placeholder without reading the database.

  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}.

  See \dfgExampleRef{ex:manual-reference-one-or-multiple-pis}.
\end{docCommands}

\begin{dfgExample}[label={ex:manual-reference-one-or-multiple-pis}]{Reference one or multiple PIs.}
\getPI{per6}\par
\getPI*{per6,per8}\par
\getPI{spokesperson}[the spokesperson]
\end{dfgExample}

\begin{docCommand}{getProject}{\sarg\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.
  The starred form always uses this compact project-only representation,
  independently of \refKey{projectPIOncePerSection} and its first-reference
  state.
  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.

  See \dfgExampleRef{ex:manual-reference-one-or-multiple-projects}.
\end{docCommand}

\begin{dfgExample}[label={ex:manual-reference-one-or-multiple-projects}]{Reference one or multiple projects.}
\changeSettings{projectPIOncePerSection=false}
\getProject{A03,B04,Q01}\par
\getProject{A06}[the modelling project]\par
\getProject*{A00}
\end{dfgExample}

\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.

  See \dfgExampleRef{ex:manual-count-active-projects}.
\end{docCommand}

\begin{dfgExample}[label={ex:manual-count-active-projects}]{Count active projects.}
All: \getProjectCount\par
Area A: \getProjectCount[A]\par
Area B: \getProjectCount[B]\par
Area Q: \getProjectCount[Q]
\end{dfgExample}

\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.

  See \dfgExampleRef{ex:manual-reference-current-and-external-crcs}.
\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.

  See \dfgExampleRef{ex:manual-reference-current-and-external-crcs}.
\end{docCommands}

\begin{dfgExample}[label={ex:manual-reference-current-and-external-crcs}]{Reference current and external CRCs.}
\CRC{9999}\par
\CRC*{9999}\par
\CRC*[External CRC title]{999}\par
\TRR*[External CRC/TRR title]{999}
\end{dfgExample}

\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
  project identifiers in parentheses using \cs{getProject}|*|, without
  repeating the projects' PI names.

  The starred version prints firstnames in addition to lastnames.

  See \dfgExampleRef{ex:manual-print-pis-with-their-projects}.
\end{docCommands}

\begin{dfgExample}[label={ex:manual-print-pis-with-their-projects}]{Print PIs with their projects.}
\changeSettings{projectPIOncePerSection=false}
\getPIProject{per6,per11}\par\medskip
\getPIProject*{per6,per11}
\end{dfgExample}

Use \cs{getPIWithProject} for the same person-first output. It takes person
ids and prints each PI followed by their project list. The legacy
\cs{getPIProject} remains available but warns that it is deprecated.

\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.

  See \dfgExampleRef{ex:manual-print-projects-with-their-pis}.
\end{docCommands}

\begin{dfgExample}[label={ex:manual-print-projects-with-their-pis}]{Print projects with their PIs.}
\changeSettings{projectPIOncePerSection=false}
\getProjectPI{A03,B04}\par\medskip
\getProjectPI*{A03,B04}
\end{dfgExample}

Use \cs{getProjectWithPI} for the same project-first output. It takes project
ids and prints each project followed by its PI list. The legacy
\cs{getProjectPI} remains available but warns that it is deprecated.

\begin{docCommand}{getPIOfProjectWithProject}{\sarg\marg{project-id-list}}
  Print the PIs of one or more projects, followed by each project's compact
  reference in parentheses. The argument is a comma-separated list of project
  ids, matching the project named after \enquote{OfProject} in the command.
  The starred form includes firstnames; the
  \texttt{PIReferenceFirstName=true} setting also enables firstnames in the
  unstarred form.
\end{docCommand}

\begin{docCommand}{getPIofProject}{\sarg\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. Each name links to its row
  in the PI table and uses the same reference styling as \refCom{getPI}. 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 |\,/\,|.

  The starred form defaults to |firstname,lastname| and joins names as
  ``Alice Example, Bob Sample and Carol Demo''. With two PIs it uses only
  ``and''; with one PI it adds no separator. Explicit properties still override
  the default. In the starred form, an explicit trailing delimiter replaces
  only the final ``and'' separator; earlier names remain comma-separated.

  See \dfgExampleRef{ex:manual-print-the-pis-of-a-project}.
\end{docCommand}

\begin{dfgExample}[label={ex:manual-print-the-pis-of-a-project}]{Print the PIs of a project.}
\getPIofProject{B05}\par
\getPIofProject[firstname,lastname]{B05}[; ]\par
\getPIofProject*{Q02}\par
\getPIofProject*{Q03}\par
\getPIofProject*[lastname]{Q03}
\end{dfgExample}

\section{Change shared settings}
\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.

  See \dfgExampleRef{ex:manual-set-proposal-text-in-the-customization-file}.
\end{docCommand}
Put proposal-wide settings in |preamble/dfg-customization.tex|. For example,
|\changeSettings{salary@PhD=83700}| sets the annual salary used in funding
calculations. Table, list, and plot options apply to a single call; shared
settings establish defaults. The full list is in Section~\ref{doc:customization}.

\begin{docCommand}{getValue}{\marg{customization key}}
  Read the current value of any key accepted by \refCom{changeSettings}.
  The command is expandable and follows local changes, so numeric values can
  also be used in \cs{num} and calculations. For example:
\begin{dispListing*}{title={Using customization values in text}}
Housing costs are \num{\getValue{animalHousing@mouse}}\,EUR per mouse per week.
The annual postdoctoral rate is \num{\getValue{salary@postDoc}}\,EUR.
The configured font is \getValue{font}.
Thumb index enabled: \getValue{thumbindex}.
The reference color is \getValue{color@reference@PI}.
\end{dispListing*}
  These examples read the configured values without changing them. With no
  override, \texttt{animalHousing@mouse} returns \texttt{0.75}; the getter
  uses the same stored rate as the animal-housing table. It returns a value
  without a currency or unit suffix; add those in the surrounding text.

  Booleans return \texttt{true} or \texttt{false}; dimensions return points.
  Automatic thumb-index margins return \texttt{auto}, and orientation returns
  \texttt{inwards} or \texttt{outwards}. Text and formatting values retain their
  LaTeX commands. The compatibility keys \texttt{biblatexstyle} and
  \texttt{biblatexstyleFeature} read the current document mode's CV or proposal
  setting. Leading and trailing spaces around a key are ignored; unknown keys
  raise an error. This interface covers customization keys, not arbitrary
  commands or packages defined in the customization file.
\end{docCommand}

\begin{docKeys}[doc parameter={=\meta{text}}]{
  {doc name=dfgLocation}, {doc name=dfgDate},
  {doc name=dfgTitle}, {doc name=InfoTeX}
}
  Override the matching public commands through \cs{changeSettings}, including
  from |preamble/dfg-customization.tex|. The defaults are |<Location>|,
  |<date>|, the quoted CRC name from metadata, and |LuaLaTeX (via Overleaf).|,
  respectively. The first three commands append \cs{xspace}; |InfoTeX| prints
  its value exactly. Values are stored without expansion, so references and
  formatting can be used in them. No fixed submission date is supplied.
  See \dfgExampleRef{ex:manual-set-proposal-text-in-the-customization-file}.
\end{docKeys}

\begin{dfgExample}[label={ex:manual-set-proposal-text-in-the-customization-file}]{Set proposal text in the customization file}
\changeSettings{
  dfgLocation = {Example City},
  dfgDate     = {30 September 2026},
  dfgTitle    = {Collaborative research programme},
  InfoTeX    = {LuaLaTeX, local build}
}
\dfgTitle\par
\dfgLocation, \dfgDate\par
\InfoTeX
\end{dfgExample}

These macros already exist when the customization file is read, so direct
overrides with \cs{renewcommand} work there too. For the three
space-aware commands, include |\xspace| yourself when using |\renewcommand|.
Definitions supplied before loading the class are preserved until explicitly
overridden. If both interfaces assign a value, the last assignment wins.

\section{Tables, lists, and plots: one calling convention}
The dispatcher selects a named output and passes its arguments to it. Put
settings in the leading square brackets. A simple target needs one pair of
braces; a target with arguments uses an outer pair around the entire sequence:
|\printTable{ProjectLeaders}|, |\printTable{{Projects}{A}{Area title}}|.
The following chapter introduces each built-in target beside its result.

\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.  The gap above a table
  is set by |presep=6pt| in the shared \cs{SetTblrOuter} call below; adjust
  that value to change the gap above generated tables.
  Put options before the table specification. For example,
  |\printTable[all-sexes]{GenderEqualityProjectLeaders}| selects the expanded
  gender overview for that call only.
  The command inserts \cs{par} before and after its output, so surrounding
  text always starts in separate paragraphs, even without blank source lines.
  Directly after a heading, it also inserts a zero-height box and a no-break
  penalty. This prevents the table from overlapping the heading at a page
  break; a manual \cs{null} before \cs{printTable} is unnecessary.

  See \dfgExampleRef{ex:manual-project-leaders-and-their-affiliations}, \dfgExampleRef{ex:manual-requested-funding-for-a-project}, \dfgExampleRef{ex:manual-laboratory-animals-purchase-housing-and-funding}.
\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.  Put sorting, formatting, database, and
  raster settings together in this leading option list, as with
  \cs{printPlot}.  Both |{ParticipatingInstitutions}| and
  |{{ParticipatingInstitutions}}| are accepted as the list specification.
  Older trailing options remain supported, with leading settings taking
  precedence.  A person's institutions use
  |\printList{{Institutions}{per1}}|; that form needs the person ID, while
  |\printList{ParticipatingInstitutions}| lists participating institutions
  across the proposal, with affiliation names in bold.


  See \dfgExampleRef{ex:manual-flowing-institution-columns}, \dfgExampleRef{ex:manual-alphabetical-institution-raster}, \dfgExampleRef{ex:manual-one-person-with-multiple-institutions}.
\end{docCommand}

\cs{printPlot} uses the same convention: |\printPlot[options]{{type}{project-id}}|.
Within a project, omit the ID to use that project. The complete option and
result examples follow the work-package declarations in
Section~\ref{sec:manual-plot-examples}.

\chapter{Build the proposal in order}
\label{chap:proposal-walkthrough}
\label{sec:manual-table-guide}
Follow the generated proposal from the title page through general information,
finances, individual projects, bylaws, declarations, and back matter. Each
output example pairs its source with its result. All sixteen built-in table
targets, all three lists, and both plot types appear at their point of use.
The shared metadata are documented once in Section~\ref{sec:manual-fixtures};
table-specific records are shown directly before their printing command.

\section{Title page and applicant universities}

\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.

  See \dfgExampleRef{ex:manual-choose-applicant-wording-from-metadata}.
\end{docCommand}

\begin{dfgExample}[label={ex:manual-choose-applicant-wording-from-metadata}]{Choose applicant wording from metadata}
\dfgApplicantAffiliationsTF
  {Applicant university:}
  {Applicant universities:}
\theCRCaffiliation.
\end{dfgExample}

\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}.

  See \dfgExampleRef{ex:manual-configure-and-print-the-title-page-logos}.
\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}.

  See \dfgExampleRef{ex:manual-configure-and-print-the-title-page-logos}.
\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}.

  See \dfgExampleRef{ex:manual-a-horizontal-rule-with-custom-spacing}.
\end{docCommand}

\begin{dfgExample}[label={ex:manual-a-horizontal-rule-with-custom-spacing}]{A horizontal rule with custom spacing}
Scientific objectives
\Hrule[color=blue,thickness=.6pt,above=4pt,below=6pt]
Experimental approach
\end{dfgExample}

Use your own logo files in a proposal. This example substitutes the bundled
placeholder image so the size options can be tried without external files.

\begin{dfgExample}[label={ex:manual-configure-and-print-the-title-page-logos}]{Configure and print the title-page logos}
\changeSettings{
  crcLogoPath=example-image,
  affiliationLogoPath=example-image
}
\crcLogo[width=.4\linewidth]\quad
\affiliationLogo[width=.4\linewidth]
\end{dfgExample}

\section{General information}
\subsection{Key data: governing bodies and contact details}
\begin{docCommand}{getPersonInformation}{\oarg{database}\marg{person-id-list}}
  Print full PI contact details, including institutions and contact fields.
  The database defaults to |person|. Use explicit person IDs for a selected
  pair; use \cs{getPIsWithRole} below to select people by their metadata role.

  See \dfgExampleRef{ex:manual-contact-details-for-two-selected-pis}.
\end{docCommand}

\begin{dfgExample}[label={ex:manual-contact-details-for-two-selected-pis},dfg wide]{Contact details for two selected PIs}
\getPersonInformation[person]{per1,per2}
\end{dfgExample}

\begin{docCommand}{getPIsWithRole}{\oarg{options}\marg{role}}
  Print persons with the given \meta{role} in PI boxes.  Put all options
  before the role, for example |database=person,raster columns=2|.
  The database defaults to \texttt{person}.  Only persons belonging to
  the current funding period are shown.  The default three-column raster
  has a 12\,pt column gap.  Rows of boxes and the content after the raster
  are separated by 20\,pt.  Raster settings in \meta{options} are passed to
  the underlying \refPkg{tcolorbox} raster and may override those defaults.
  Use |academicdegree-below| to place the academic degree on a separate
  line below the name, inside the same PI-box title.  This applies only to
  the current call; omitting the option or setting |academicdegree-below=false|
  keeps the degree inline after the name.  For example:
  |\getPIsWithRole[academicdegree-below]{steering-committee-member}|.
  The contact markers in each PI box are controlled globally with
  |\changeSettings{PIcontactStyle=icons}| (the default),
  |PIcontactStyle=text| for the labels ``Phone:'' and ``E-Mail:'', or
  |PIcontactStyle=none| to suppress both markers.
  Older calls with a bare database name or trailing raster options remain
  supported; leading settings take precedence over trailing settings.

  In both this raster and the two-column raster of \cs{getPersonInformation},
  titles are ragged right and top-aligned.  Each title reserves the height of
  the tallest title in its raster, keeping the contact information aligned
  when names or academic degrees wrap.  Equal-height groups settle over
  successive LaTeX runs; a clean build can require three passes.
  Phone and email each remain unbroken, but their one-em separating space
  permits a line break when both contacts do not fit on the same line.

  See \dfgExampleRef{ex:manual-print-all-pis-with-a-given-role}.
\end{docCommand}

\begin{dfgExample}[label={ex:manual-print-all-pis-with-a-given-role},dfg wide]{Print all PIs with a given role.}
\getPIsWithRole[raster columns=2]{steering-committee-member}
\end{dfgExample}

\subsection{Project leaders}
The table resolves each PI's institutions and affiliations from the shared
metadata (Section~\ref{sec:manual-fixtures}). Declare those records once;
changing a name or institution then updates every table and reference.

\begin{dfgExample}[label={ex:manual-project-leaders-and-their-affiliations},dfg wide,listing above* text]{Project leaders and their affiliations}
\printTable{ProjectLeaders}
\end{dfgExample}

\subsection{Participating institutions}
  Use |columns=2| or |columns=3| to flow affiliation groups down balanced
  columns, keeping each affiliation with its institutions. Short groups follow
  one another without equal-height row padding. Reading order is down each
  column. The gap defaults to 12\,pt; set |column sep=16pt| to change it.
  Flowing lists start a new paragraph with \cs{medskipamount} space above them.

  Without |columns|, participating institutions use one raster cell per
  affiliation, including its institutions. The default is one column,
  with a 12\,pt column gap and
  a 10\,pt row gap.  Pass |raster columns=2| or other \refPkg{tcolorbox}
  raster options through \meta{options}.  Sorting defaults to |order=count|;
  |order=alpha| sorts affiliations alphabetically.  The bare |count| and
  |alpha| options remain accepted.
  \begin{dfgExample}[label={ex:manual-flowing-institution-columns},dfg wide]{Flowing institution columns}
\printList[columns=2]{ParticipatingInstitutions}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-three-flowing-institution-columns},dfg wide]{Three flowing institution columns}
\printList[columns=3,column sep=16pt]{ParticipatingInstitutions}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-alphabetical-institution-raster},dfg wide]{Alphabetical institution raster}
\printList[order=alpha,raster columns=2]{ParticipatingInstitutions}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-institution-raster-ordered-by-pi-count},dfg wide]{Institution raster ordered by PI count}
\printList[order=count,raster columns=3]{ParticipatingInstitutions}
\end{dfgExample}




\subsection{Project groups and projects}
\label{sec:manual-consortium-tables}
Projects are grouped by their area. The same command serves each area; the
second argument supplies the heading. The shared dataset contains six A,
six B, and three Q projects, declared once in Section~\ref{sec:manual-fixtures}.

\begin{dfgExample}[label={ex:manual-project-overview-area-a},dfg wide,listing above* text]{Project overview: area A}
\printTable{{Projects}{A}{Microbiota and metabolic pathways}}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-project-overview-area-b},dfg wide,listing above* text]{Project overview: area B}
\printTable{{Projects}{B}{Immune mechanisms and clinical translation}}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-service-training-and-administration-projects},dfg wide,listing above* text]{Service, training, and administration projects}
\printTable{{Projects}{Q}{Shared services, training, and coordination}}
\end{dfgExample}

The status legend can follow the project overview. The funding-period wording
and research-area list are taken from metadata, so they stay consistent with
the tables. The footnote remains in the normal page flow.

\begin{dfgExample}[label={ex:manual-project-status-legend-and-research-areas},dfg wide,listing above* text]{Project-status legend and research areas}
{\footnotesize
N: New projects started in the \theFundingPeriodText\space funding period;\space
E: Ending projects not continued in the \theFundingPeriodText\space funding period;\space
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}\par}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-research-areas-excluding-selected-projects},dfg wide,listing above* text]{Research areas excluding selected projects}
\printList[A01,B01]{ResearchAreasFromProjects}
\end{dfgExample}

The optional argument of |ResearchAreasFromProjects| excludes the listed
project IDs from the collection of research areas.

\begin{dfgExample}[label={ex:manual-look-up-research-area-descriptions}]{Look up research-area descriptions}
\dfgResearchAreasList{2.21-02}\par
\dfgResearchAreasList{2.21-05}
\end{dfgExample}

\paragraph{Person-specific institution lists}
\label{sec:manual-person-lists}
Use |\printList{{Institutions}{per7}}| to print the institutions assigned to
person \texttt{per7}.  The person ID is required.  For a non-default database,
use |\printList[database=other]{{Institutions}{per7}}|; the database defaults to
\texttt{person}.  Put formatting options in the same leading list, as in
|\printList[database=person,abbreviation,narrow]{{Institutions}{per7}}|.
The older bare-database and trailing-formatting forms remain supported.
The list 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}
The former \cs{dfgInstitutionList} spelling remains as a compatibility alias.

\begin{dfgExample}[label={ex:manual-one-person-with-multiple-institutions}]{One person with multiple institutions}
\get[person]{per7}{ref-institution-id}\par
\printList{{Institutions}{per7}}
\medskip
\printList[abbreviation,narrow,noaddress,nozip,nolocation]
  {{Institutions}{per7}}
\end{dfgExample}

\subsection{Frame-text references}
\begin{docCommand}{printFrameBibliography}{\oarg{biblatex options}}
  Print the frame-text bibliography, forwarding the optional arguments to
  \cs{printbibliography} and preserving its normal font size. With
  \refKey{emphasizeEntries} enabled, a complete entry is bold when its
  \texttt{keywords} field contains \texttt{frametext-highlight}. Project
  highlight keywords do not affect this list; the frame keyword does not
  affect project lists or inline citations. Like project bibliographies,
  output is suppressed when \refKey{fastcompile-project-show-publications}
  is disabled.
\end{docCommand}

Add the keyword to the publication's existing keywords, for example
|keywords = {pabst-A,B06-highlight,frametext-highlight}|. The keyword controls
formatting, not inclusion: cite the entry or add it with \cs{nocite} as usual.
Enable \refKey{emphasizeEntries} in \cs{changeSettings}, then use:
\begin{dispListing}
\defbibnote{frame-references}{%
  \usekomafont{subsection}%
  \bfseries\sffamily References
}
\printFrameBibliography[
  prenote={frame-references},
  heading=none
]
\end{dispListing}
Replace the plain \cs{printbibliography} call in existing chapter 1 files;
template updates preserve those edited files.

\subsection{Research profile: summaries and highlighted statements}
\begin{docEnvironment}{dfgBoxEnv}{\oarg{further specifications}}
  Box environment to be used for highlighting things
  To be used in \dfgFile{content}.
  See \dfgExampleRef{ex:manual-highlight-text-with-a-box-environment}.
\end{docEnvironment}

\begin{dfgExample}[label={ex:manual-highlight-text-with-a-box-environment}]{Highlight text with a box environment}
\begin{dfgBoxEnv}[title={Research question}]
How do host and microbiome communicate?
\end{dfgBoxEnv}
\end{dfgExample}

% \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}

  See \dfgExampleRef{ex:manual-example-use-of-a-summary-box}.
\end{docEnvironment}

\begin{dfgExample}[label={ex:manual-example-use-of-a-summary-box}]{Example use of a summary box}
\begin{dfgSummaryBox}[title={Next steps}]
  \item Validate biomarkers.
  \item Share the results.
\end{dfgSummaryBox}
\end{dfgExample}

\begin{docCommand}{dfgBox}{\oarg{further specifications}}
  Box environment to be used for anything.
  To be used anywhere in the text.

  See \dfgExampleRef{ex:manual-example-of-a-minimal-box}.
\end{docCommand}
\begin{dfgExample}[label={ex:manual-example-of-a-minimal-box}]{Example of a minimal box }
\dfgBox[title={Research finding}]
  {Microbial signals shape immunity.}
\end{dfgExample}

\subsection{Tables and figures in the scientific narrative}
Use the following environments when the prose needs a table or a figure that
is not one of the predefined metadata tables.

\begin{docEnvironment}{TableEnv}{\marg{column specification}
    \oarg{table options}\marg{caption}\marg{label}}
  Typeset a generic long table using the template's main table theme.  The
  optional \meta{table options} are inserted into the inner
  \refPkg{tabularray} specification and default to an empty option list, so
  the square brackets may be omitted when no additional options are needed.
  Table text defaults to \cs{footnotesize} at theme scope.  Consequently,
  cell-local declarations such as |font=\bfseries| or |font=\itshape| retain
  the default size; include an explicit size such as |font=\normalsize\bfseries|
  only when a table or cell should override it.

  See \dfgExampleRef{ex:manual-tableenv-with-column-and-row-options}, \dfgExampleRef{ex:manual-new-continuing-and-ending-project-structures}.
\end{docEnvironment}

\begin{dfgExample}[label={ex:manual-tableenv-with-column-and-row-options}]{TableEnv with column and row options}
\begin{TableEnv}{X[2,l] X[1,r]}[
  row{1}={font=\bfseries},
  rowsep=3pt,
  column{2}={halign=r}
]{Projects by area}{tab:manual-area-counts}
Area & Projects \\
A & \getProjectCount[A] \\
B & \getProjectCount[B] \\
Q & \getProjectCount[Q]
\end{TableEnv}
\end{dfgExample}


\subsection{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}}

  See \dfgExampleRef{ex:manual-a-figure-with-a-caption}.
\end{docCommand}


\begin{dfgExample}[label={ex:manual-a-figure-with-a-caption}]{A figure with a caption}
\hvFloat[capPos=bottom]{figure}
  {\includegraphics[width=\linewidth]{example-image}}
  {Example artwork and its caption.}
  {fig:manual-hvfloat}
\end{dfgExample}

\subsection{Early-career researchers and equality objectives}
\label{sec:manual-researcher-tables}
\begin{docCommand}{EarlyCareerResearchersTable}{\oarg{database}}
  List doctoral candidates from |EarlyCareerResearcher|, using the |person|
  keyset. This is a named training roster, separate from the monetary staff
  request. |PhD| and |MD| select the row colours. An empty |periodEnd| prints
  an ongoing appointment as \enquote{since}; bold names can mark completed
  doctorates, as explained by the table legend.

  See \dfgExampleRef{ex:manual-doctoral-candidates-completed-ongoing-and-medical-projects}.
\end{docCommand}

\begin{dfgExample}[label={ex:manual-doctoral-candidates-completed-ongoing-and-medical-projects},dfg wide,listing above* text]{Doctoral candidates: completed, ongoing, and medical projects}
\addEntry[person]{EarlyCareerResearcher}{
  id             = {doc-phd-completed},
  ref-project-id = {A01},
  firstname      = {Robin},
  lastname       = {\textbf{Meyer}},
  financed-by    = {DFG},
  category       = {PhD},
  topic          = {Microbial metabolites and epithelial signalling},
  periodStart    = {2021-10},
  periodEnd      = {2025-09}
}
\addEntry[person]{EarlyCareerResearcher}{
  id             = {doc-phd-ongoing},
  ref-project-id = {B03},
  firstname      = {Alex},
  lastname       = {Reed},
  financed-by    = {University},
  category       = {PhD},
  topic          = {Tissue-resident immune-cell programming},
  periodStart    = {2025-04},
  periodEnd      = {}
}
\addEntry[person]{EarlyCareerResearcher}{
  id             = {doc-md},
  ref-project-id = {B04},
  firstname      = {Sam},
  lastname       = {Taylor},
  financed-by    = {DFG},
  category       = {MD},
  topic          = {Clinical markers of cross-organ inflammation},
  periodStart    = {2026-04},
  periodEnd      = {2026-09}
}
\printTable{EarlyCareerResearchers}
\end{dfgExample}

\subsubsection*{A. Objectives for the participation of female researchers}
This example supplies the previous objective, observed number and percentage,
and future objective for doctoral and postdoctoral researchers. All figures are
fictitious. Use the |GenderEquality| keyset for both equality tables.

\begin{dfgExample}[label={ex:manual-a-objectives-for-the-participation-of-female-researchers},dfg wide,listing above* text]{A. Objectives for the participation of female researchers}
\addEntry[GenderEquality]{GenderEqualityStaff}{
  position                                = {PhD},
  previous-objective-percentage-female    = {40},
  status-quo-number-female                = {12},
  status-quo-percentage-female            = {50},
  future-objective-percentage-female      = {50}
}
\addEntry[GenderEquality]{GenderEqualityStaff}{
  position                                = {postDoc},
  previous-objective-percentage-female    = {40},
  status-quo-number-female                = {4},
  status-quo-percentage-female            = {40},
  future-objective-percentage-female      = {50}
}
\printTable{GenderEqualityStaff}
\end{dfgExample}

\subsubsection*{B. Project leaders}
Here the records specify objectives for each career category. Status-quo counts
and percentages are calculated from the |gender|, |position|, and funding-period
membership of the |person| records shown in
Section~\ref{sec:manual-consortium-tables}. Only proposals with
|fundingPeriodNumeral = {3}| show the additional first-funding-period columns,
using membership in period~1. By default, the table shows only female
numbers and percentages. For a third-period proposal, it follows DFG
form~60.200: periods~1 and~2 each have Number/Percentage columns; period~3
has its original objective and current Number/Percentage columns. The
existing |future-objective-percentage-female| field supplies that period~3
objective. Include period~3 membership in the person records to calculate
the proposed leadership composition.

Pass |[all-sexes]| before the table name in \refCom{printTable} to select
the expanded f/m/d comparison. For a third-period proposal, every period includes Number and
Percentage columns for f/m/d, alongside the previous period's objective and
the proposed period's future objective. All percentages use the complete f/m/d population in the
same career category (or across the four categories in the total row).
Do not enter these calculated values again in the objectives database;
include historical PIs with the appropriate |period| membership.

\begin{dispListing}
\printTable{GenderEqualityProjectLeaders}            % default: female-only
\printTable[all-sexes]{GenderEqualityProjectLeaders} % f/m/d for all periods
\end{dispListing}

\begin{docKey}{all-sexes}{\docKeyChoices{true,false}}{initially \texttt{false}}
  A per-table option for \cs{GenderEqualityProjectLeadersTable}. The bare flag
  |[all-sexes]| selects f/m/d counts and percentages, including period~3 in a
  third-period proposal, alongside the previous/future objectives.
  Omit the option (or use |[all-sexes=false]|) for the female-only DFG layout.
  Percentages always use all genders as their denominator. The option affects
  only the current table and does not change subsequent tables or prose commands.
  Use |[database=MyObjectives,all-sexes]| for a custom objectives database;
  the older bare database argument also remains supported.
\end{docKey}

\begin{dfgExample}[label={ex:manual-b-project-leaders-objectives-and-calculated-participation},dfg wide,listing above* text]{B. Project leaders: objectives and calculated participation}
\addEntry[GenderEquality]{GenderEqualityProjectLeaders}{
  position                                = {postDoc},
  previous-objective-percentage-female    = {40},
  future-objective-percentage-female      = {50}
}
\addEntry[GenderEquality]{GenderEqualityProjectLeaders}{
  position                                = {groupLeader},
  previous-objective-percentage-female    = {40},
  future-objective-percentage-female      = {50}
}
\addEntry[GenderEquality]{GenderEqualityProjectLeaders}{
  position                                = {prof-W2},
  previous-objective-percentage-female    = {40},
  future-objective-percentage-female      = {50}
}
\addEntry[GenderEquality]{GenderEqualityProjectLeaders}{
  position                                = {prof-W3},
  previous-objective-percentage-female    = {40},
  future-objective-percentage-female      = {50}
}
\printTable{GenderEqualityProjectLeaders}
\end{dfgExample}

\subsubsection{Use the same statistics in prose}
\begin{description}
  \item[\cs{getPositionGenderPhaseAmount}]
    \oarg{database}\marg{position}\marg{gender}\marg{period} prints the count
    for one position/gender/period tuple.
    See \dfgExampleRef{ex:manual-person-counts-and-percentages-for-a-funding-period}.

  \item[\cs{getPositionPhaseTotal}]
    \oarg{database}\marg{position}\marg{period} prints the all-gender total.
    See \dfgExampleRef{ex:manual-person-counts-and-percentages-for-a-funding-period}.

  \item[\cs{getGenderPhaseTotal}]
    \oarg{database}\marg{gender}\marg{period} prints the all-position total.
    See \dfgExampleRef{ex:manual-person-counts-and-percentages-for-a-funding-period}.

  \item[\cs{getPositionGenderPhasePercentage}]
    \oarg{database}\marg{position}\marg{gender}\marg{period} prints the
    rounded integer percentage value within a position.
    See \dfgExampleRef{ex:manual-person-counts-and-percentages-for-a-funding-period}.

  \item[\cs{getGenderPhasePercentage}]
    \oarg{database}\marg{gender}\marg{period} prints the rounded integer
    percentage value across all counted positions.
    See \dfgExampleRef{ex:manual-person-counts-and-percentages-for-a-funding-period}.

\end{description}

The period argument is the funding-period number, not a calendar year.
Percentage commands return a number; append |\%| when using it in prose.
The commands below retrieve the numbers printed in section~1.4.2~B for any
funding period, independently of which proposal period is currently selected.
Use |f|, |m|, or |d| for the gender. The supported table positions are
|postDoc|, |groupLeader|, |prof-W2|, and |prof-W3|. The total-row commands
sum these four positions and count each person with |role=PI| once per period;
a person belonging to several periods is counted in each matching period.
The optional database defaults to |person|. Percentages are rounded to the
nearest integer and return zero if their denominator is zero. These are
person statistics; calculating the share of projects with female leadership
requires a separate calculation that counts each project once.

\begin{dispListing}
% First funding period: female W3 professors, number and percentage.
\getPositionGenderPhaseAmount{prof-W3}{f}{1}
\getPositionGenderPhasePercentage{prof-W3}{f}{1}\%
% All genders within the same career category.
\getPositionPhaseTotal{prof-W3}{1}
% First-period total row: female project leaders, number and percentage.
\getGenderPhaseTotal{f}{1}
\getGenderPhasePercentage{f}{1}\%
% Second-period total row: change only the final argument.
\getGenderPhaseTotal{f}{2}
\getGenderPhasePercentage{f}{2}\%
\end{dispListing}
\begin{dfgExample}[label={ex:manual-person-counts-and-percentages-for-a-funding-period}]{Person counts and percentages for a funding period}
W3 professors in period 3:
\getPositionPhaseTotal{prof-W3}{3}.\par
Women among them:
\getPositionGenderPhaseAmount{prof-W3}{f}{3}
(\getPositionGenderPhasePercentage{prof-W3}{f}{3}\%).\par
Women across counted positions:
\getGenderPhaseTotal{f}{3}
(\getGenderPhasePercentage{f}{3}\%).
\end{dfgExample}

\section{Existing and requested funds}
The proposal-wide tables combine institutional resources and project requests.
The class transfers project declarations through the auxiliary files, so
compile with |latexmk| until the totals settle. The project-level declarations
and their local tables follow in Section~\ref{sec:manual-project-funding}.

\subsection{Finances: existing funds and resources}
\label{sec:manual-existing-finances}
The following overviews precede the project chapters in a proposal. By default,
current-period figures are restored from project declarations through the
auxiliary file; compile again after changing those declarations. Custom databases
in the next two examples isolate their inputs from the other demonstrations.

\subsubsection*{Existing funds for direct costs}
The five historical rows use full EUR amounts. Current-period rows group funds
by |ref-affiliation-id|: the applicant affiliation |aff1|, another participant
|aff2|, and the special value |other-funds|. Funding-source text does not choose
the column. In a proposal, declare the current rows in
|RequestedAndExistingFundingDirectCosts| and use
|\printTable{ExistingFundsDirectCosts}| to collect them automatically.

\begin{dfgExample}[label={ex:manual-existing-direct-costs-previous-and-new-funding-periods},dfg wide,listing above* text]{Existing direct costs: previous and new funding periods}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year                 = {1},
  applicant            = {2000},
  participant          = {1000},
  other-funds          = {500}
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year                 = {2},
  applicant            = {2000},
  participant          = {1000},
  other-funds          = {500}
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year                 = {3},
  applicant            = {2000},
  participant          = {1000},
  other-funds          = {500}
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year                 = {4},
  applicant            = {2000},
  participant          = {1000},
  other-funds          = {500}
}
\addEntry[funding]{PreviousExistingFundsDirectCosts}{
  year                 = {5},
  applicant            = {2000},
  participant          = {1000},
  other-funds          = {500}
}
\addEntry[funding]{ManualExistingCosts}{
  ref-project-id       = {A01},
  ref-affiliation-id   = {aff1},
  financed-by          = {Example core or third-party funds},
  sum                  = {year1 = {4000}, year2 = {4000}, year3 = {4000}, year4 = {4000}, year5 = {4000}}
}
\addEntry[funding]{ManualExistingCosts}{
  ref-project-id       = {A01},
  ref-affiliation-id   = {aff2},
  financed-by          = {Example core or third-party funds},
  sum                  = {year1 = {2000}, year2 = {2000}, year3 = {2000}, year4 = {2000}, year5 = {2000}}
}
\addEntry[funding]{ManualExistingCosts}{
  ref-project-id       = {A01},
  ref-affiliation-id   = {other-funds},
  financed-by          = {Example core or third-party funds},
  sum                  = {year1 = {1000}, year2 = {1000}, year3 = {1000}, year4 = {1000}, year5 = {1000}}
}
\printTable[ManualExistingCosts]{ExistingFundsDirectCosts}
\end{dfgExample}

\subsubsection*{Existing staff}
These records inherit institutions from the PI metadata already shown.
The custom database supplies all columns read by the overview; empty organisation
fields allow the person's institution references to be used. The overview counts existing staff at applicant and participating
affiliations. In a proposal, add them to |RequestedFundingStaff| and use
|\printTable{OverviewExistingStaff}| without a database override.

\begin{dfgExample}[label={ex:manual-existing-staff-by-affiliation-and-career-category},dfg wide,listing above* text]{Existing staff by affiliation and career category}
\addEntry[staff]{ManualExistingStaff}{
  ref-project-id       = {A01},
  funding-status       = {existing},
  staff-type           = {research},
  ref-person-id        = {per1},
  lastname             = {Sample},
  category             = {prof-W3},
  ref-institution-id   = {},
  ref-affiliation-id   = {},
  field-of-research    = {Life sciences},
  commitment           = {8},
  funding-source       = {State funds}
}
\addEntry[staff]{ManualExistingStaff}{
  ref-project-id       = {A02},
  funding-status       = {existing},
  staff-type           = {research},
  ref-person-id        = {per6},
  lastname             = {Hartmann},
  category             = {prof-W2},
  ref-institution-id   = {},
  ref-affiliation-id   = {},
  field-of-research    = {Life sciences},
  commitment           = {8},
  funding-source       = {State funds}
}
\addEntry[staff]{ManualExistingStaff}{
  ref-project-id       = {B03},
  funding-status       = {existing},
  staff-type           = {research},
  ref-person-id        = {per11},
  lastname             = {Sato},
  category             = {prof-W2},
  ref-institution-id   = {},
  ref-affiliation-id   = {},
  field-of-research    = {Life sciences},
  commitment           = {8},
  funding-source       = {State funds}
}
\printTable[ManualExistingStaff]{OverviewExistingStaff}
\end{dfgExample}

\begin{docCommand}{ExistingInstrumentationTable}{\oarg{database}}
  List equipment already available to the projects. The database defaults to
  |existingInstrumentation| and uses the |instrumentation| keyset. The |cost|
  field is in thousands of euros: |250| means EUR\,250,000. A comma-separated
  |ref-project-id| lists shared equipment once for several projects.
  Rows are sorted in ascending order by |ref-project-id|; shared equipment
  is ordered by its listed project IDs and remains a single row.

  See \dfgExampleRef{ex:manual-existing-instrumentation-including-shared-equipment}.
\end{docCommand}

\begin{dfgExample}[label={ex:manual-existing-instrumentation-including-shared-equipment},dfg wide,listing above* text]{Existing instrumentation, including shared equipment}
\addEntry[instrumentation]{existingInstrumentation}{
  ref-project-id = {A01},
  quantity       = {1},
  instrument     = {Confocal laser-scanning microscope},
  company        = {Example Instruments},
  year           = {2025},
  cost           = {250},
  financed-by    = {DFG}
}
\addEntry[instrumentation]{existingInstrumentation}{
  ref-project-id = {A01,B03},
  quantity       = {2},
  instrument     = {Anaerobic workstation},
  company        = {Example Laboratory Systems},
  year           = {2024},
  cost           = {80},
  financed-by    = {University funds}
}
\printTable{ExistingInstrumentation}
\end{dfgExample}

\subsection{Finances: previous funding and new requests}
\label{sec:manual-requested-finances}
The next table combines five historical rows with the current requests declared
in the funding examples. Its new-period amounts include the earlier |A02|
requests, the equipment records below, and the complete |A06| request in
Section~\ref{sec:manual-project-funding}. These records are collected from the
auxiliary file even when their declarations follow the overview. All input
amounts are full EUR; do not duplicate a project declaration to populate this
overview.

\begin{dfgExample}[label={ex:manual-previous-funding-and-current-requests-across-all-five-groups},dfg wide,listing above* text]{Previous funding and current requests across all five groups}
\addEntry[funding]{PreviousRequestedFunding}{
  year                 = {1},
  staff                = {100000},
  costs                = {20000},
  instrumentation      = {30000},
  fellowships          = {5000},
  globalfunds          = {10000}
}
\addEntry[funding]{PreviousRequestedFunding}{
  year                 = {2},
  staff                = {100000},
  costs                = {20000},
  instrumentation      = {0},
  fellowships          = {5000},
  globalfunds          = {10000}
}
\addEntry[funding]{PreviousRequestedFunding}{
  year                 = {3},
  staff                = {100000},
  costs                = {20000},
  instrumentation      = {0},
  fellowships          = {5000},
  globalfunds          = {10000}
}
\addEntry[funding]{PreviousRequestedFunding}{
  year                 = {4},
  staff                = {100000},
  costs                = {20000},
  instrumentation      = {0},
  fellowships          = {5000},
  globalfunds          = {10000}
}
\addEntry[funding]{PreviousRequestedFunding}{
  year                 = {5},
  staff                = {100000},
  costs                = {20000},
  instrumentation      = {0},
  fellowships          = {5000},
  globalfunds          = {10000}
}
\printTable{PreviousAndCurrentRequestedFunding}
\end{dfgExample}

The staff overview counts requested positions by category and year; salary
percentages affect monetary costs, not the number of positions. This example
uses a separate database, |ManualStaffRequest|, to show precisely these two
records. Pass that database as the leading optional argument. In a proposal,
use |RequestedFunding| for the records and omit the table's optional argument
to collect requests across all projects. Projects without requested positions
remain visible with empty-value markers.

\begin{dfgExample}[label={ex:manual-requested-staff-positions-by-category-and-year},dfg wide,listing above* text]{Requested staff positions by category and year}
\addEntry[funding]{ManualStaffRequest}{
  ref-project-id = {B03},
  funding-type   = {staff},
  category       = {PhD},
  percentage     = {65},
  quantity       = {
    year1 = {1}, year2 = {1}, year3 = {2}, year4 = {2}, year5 = {1}
  }
}
\addEntry[funding]{ManualStaffRequest}{
  ref-project-id = {Q01},
  funding-type   = {staff},
  category       = {postDoc},
  percentage     = {100},
  quantity       = {
    year1 = {0}, year2 = {1}, year3 = {1}, year4 = {1}, year5 = {0}
  }
}
\printTable[ManualStaffRequest]{OverviewOfFundsRequestedForStaff}
\end{dfgExample}

Requested equipment belongs in |RequestedFunding| with
|funding-type={instrumentation}|. Unlike existing-equipment purchase costs,
the yearly |sum| values are full EUR amounts. The overview collects these
project declarations through the auxiliary file; two compilations may be
needed after adding or changing them. Its result also includes the |A06|
imaging workstation declared in the complete project-funding example in Section~\ref{sec:manual-project-funding}.

\begin{dfgExample}[label={ex:manual-requested-instrumentation-by-project-and-year},dfg wide,listing above* text]{Requested instrumentation by project and year}
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {Q01},
  funding-type   = {instrumentation},
  category       = {Live-cell imaging system},
  sum            = {
    year1 = {150000},
    year2 = {0},
    year3 = {0},
    year4 = {0},
    year5 = {0}
  }
}
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {B03},
  funding-type   = {instrumentation},
  category       = {Automated sample preparation},
  sum            = {
    year1 = {0},
    year2 = {0},
    year3 = {45000},
    year4 = {0},
    year5 = {0}
  }
}
\printTable{OverviewFundsRequestedInstrumentation}
\end{dfgExample}

\subsubsection*{Upkeep of laboratory animals}
Each row specifies the animal count, average weeks kept, purchase cost per
animal, and requested and existing funds in EUR. Housing rates come from the
class settings; |mouse|, |rat|, and |mouse-gnotobiotic| select the species/rate.

\begin{dfgExample}[label={ex:manual-laboratory-animals-purchase-housing-and-funding},dfg wide,listing above* text]{Laboratory animals: purchase, housing, and funding}
\addEntry{UpkeepLaboratoryAnimals}{
  ref-project-id       = {A01},
  species              = {mouse},
  quantity             = {100},
  weeks-kept           = {12},
  purchasing-costs     = {25},
  requested-funds      = {9000},
  existing-funds       = {3000}
}
\addEntry{UpkeepLaboratoryAnimals}{
  ref-project-id       = {B03},
  species              = {rat},
  quantity             = {20},
  weeks-kept           = {8},
  purchasing-costs     = {40},
  requested-funds      = {1600},
  existing-funds       = {800}
}
\addEntry{UpkeepLaboratoryAnimals}{
  ref-project-id       = {A02},
  species              = {mouse-gnotobiotic},
  quantity             = {30},
  weeks-kept           = {10},
  purchasing-costs     = {50},
  requested-funds      = {6000},
  existing-funds       = {2500}
}
\printTable{UpkeepLaboratoryAnimals}
\end{dfgExample}

\subsection{Refer to financial totals in prose}

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.
    See \dfgExampleRef{ex:manual-requested-positions-and-multi-year-direct-costs}.

  \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.
    See \dfgExampleRef{ex:manual-project-counts-and-funding-totals}.

  \item[\cs{getTotalSumRequestedFunding}]
    \oarg{database}\marg{year}\marg{type} has the same proposal-wide scope and
    additionally accepts |type=all| for the grand total.
    See \dfgExampleRef{ex:manual-project-counts-and-funding-totals}.

  \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.
    See \dfgExampleRef{ex:manual-project-counts-and-funding-totals}.

  \item[\cs{getTotalSumRequestedFunds}]
    \oarg{database}\marg{project}\marg{sum-fields} prints a project total
    across all funding types.
    See \dfgExampleRef{ex:manual-project-counts-and-funding-totals}.

  \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}

For example:
\begin{dfgExample}[label={ex:manual-project-counts-and-funding-totals}]{Project counts and funding totals}
Area A projects: \getProjectCount[A]\par
Staff: \getSumRequestedFunding{all}{staff}\par
Total: \getTotalSumRequestedFunding{all}{all}\par
A02 staff, year 1:
\getSumRequestedFunds{A02}{staff}{sum-year1}\par
A02 total, year 1:
\getTotalSumRequestedFunds{A02}{sum-year1}
\end{dfgExample}

Use the optional project argument to compare a project with the full request.
Here |1| is the first funding-year column; |PhD| is the staff category.
\begin{dfgExample}[label={ex:manual-requested-positions-and-multi-year-direct-costs}]{Requested positions and multi-year direct costs}
A02 doctoral positions, year 1:
\getCountRequestedStaff[A02]{1}{PhD}.\par
All doctoral positions, year 1:
\getCountRequestedStaff{1}{PhD}.\par
A02 direct costs, years 1 and 2:
\getSumRequestedFunds{A02}{costs}{sum-year1,sum-year2}\,EUR.
\end{dfgExample}

\section{Individual projects}
\label{sec:manual-project-status}
\subsection{Choose the structure from project status and type}
Set |project-status| in the project's metadata: |N| for new, |C| for continuing,
and |E| for ending. This is independent of |project-type|: |research|,
|service|, |mgk| (integrated research training), or |admin| (central coordination).
Changing metadata adjusts the generated heading and some tables; it does not
rewrite the authored sections. Start from the matching generated content file.

\begin{dfgExample}[label={ex:manual-new-continuing-and-ending-project-structures},dfg wide]{New, continuing, and ending project structures}
\begin{TableEnv}{X[1,l] X[2,l] X[3,l]}[row{1}={font=\bfseries}]
  {Choose a project structure}{tab:manual-project-status}
Status & Background & Forward-looking content \\
N: new & Research rationale and preliminary work
  & Project plan, collaborations, and requested funding \\
C: continuing & Progress to date and current state of research
  & Project plan, collaborations, and requested funding \\
E: ending & Project history, report, and published results
  & Closing funding and staff from the ending period
\end{TableEnv}
\end{dfgExample}

The starter files |03_project_A02.tex| and |03_project_A01.tex| demonstrate
new and continuing research projects, respectively. Both have a summary,
aims, work packages, a timeline, the relevance of sex/gender/diversity,
the project's CRC role, differentiation from other grants, and project funding.
The ending example |03_project_A00.tex| instead contains a report, three result
categories, and closing funding information; it does not request a new period
or present a new work programme.

For service projects, |03_project_Q01.tex| uses the continuing structure but
focuses on services, access, capacity, and quality assurance. The training
example |03_project_Q02.tex| and coordination example |03_project_Q03.tex|
have dedicated content structures. Their headings, like ending-project
headings, omit the research-area line. A |reference-only=true| project is a
separate concept: it records a former project for references and is excluded
from active counts. The manual's |A00| demonstrates this case.

\subsection{Start and finish a project}
\begin{docCommand}{printProject}{\marg{specification}}
  Use the unified project-boundary interface.  Start a project with its id and
  finish the active project without repeating that id:
  \begin{dispListing}
    \printProject{{Head}{A01}}
    \ldots
    \printProject{{Tail}}
  \end{dispListing}
  The \texttt{Head} form delegates to \refCom{printProjectHead}; the
  \texttt{Tail} form delegates to \refCom{printProjectTail}.  The original
  commands remain available as compatibility fallbacks.

  See \dfgExampleRef{ex:manual-new-project-heading-excerpt-from-the-starter-proposal}, \dfgExampleRef{ex:manual-ending-project-heading-excerpt-from-the-starter-proposal}.
\end{docCommand}

\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
  \refKey{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.

  See \dfgExampleRef{ex:manual-continuing-project-heading-excerpt-from-the-starter-proposal}.
\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.

  See \dfgExampleRef{ex:manual-continuing-project-heading-excerpt-from-the-starter-proposal}.
\end{docCommand}

These commands manage complete pages and bibliography sections. The following
code/result examples therefore show the beginning of the actual example
proposal pages, rather than running a project wrapper inside the manual's
own section. The complete proposal and inline examples share the same
metadata. The omitted project body belongs between the two commands.
Former project |A00| illustrates the ending-project structure; it remains
excluded from active project counts and funding requests.

\begin{dfgExample}[label={ex:manual-new-project-heading-excerpt-from-the-starter-proposal},dfg wide,listing and comment,
  comment={\dfgDocProjectExcerpt{A02}{200mm}}]{New project: heading excerpt from the example proposal}
% In project metadata: project-status = {N}
\printProject{{Head}{A02}}
% Summary, research rationale, plan, and funding.
\printProject{{Tail}}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-continuing-project-heading-excerpt-from-the-starter-proposal},dfg wide,listing and comment,
  comment={\dfgDocProjectExcerpt{A01}{200mm}}]{Continuing project: heading excerpt from the example proposal}
% In project metadata: project-status = {C}
\printProjectHead{A01}
% Summary, progress to date, plan, and funding.
\printProjectTail
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-ending-project-heading-excerpt-from-the-starter-proposal},dfg wide,listing and comment,
  comment={\dfgDocProjectExcerpt{A00}{218mm}}]{Ending project: heading excerpt from the example proposal}
% In project metadata: project-status = {E}
\printProject{{Head}{A00}}
% Project history, published results, closing funding.
\printProject{{Tail}}
\end{dfgExample}

\subsection{Publications for new and continuing projects}
\begin{docCommand}{projectPublicationsHeading}{}
  Print the standard project-publications subsection heading only when
  \refKey{fastcompile-project-show-publications} is enabled.

  See \dfgExampleRef{ex:manual-project-publications-with-the-standard-heading}.
\end{docCommand}

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

  See \dfgExampleRef{ex:manual-project-publications-with-the-standard-heading}.
\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.
  Project bibliography entries are typeset in \cs{footnotesize}.  With
  \refKey{emphasizeEntries} enabled, an entry carrying the current project's
  \texttt{<project-id>-highlight} keyword is printed in bold.  A direct
  \cs{printbibliography} call bypasses this formatting, the font setting,
  and the publication-output switch.

  See \dfgExampleRef{ex:manual-project-publications-with-the-standard-heading}.
\end{docCommand}

A local |refsection| keeps this example's bibliography independent of the
manual. In an ordinary project, use the reference section established by the
project wrapper. The leading options are passed to |biblatex|.
\begin{dfgExample}[label={ex:manual-project-publications-with-the-standard-heading},dfg wide,dfg project=A02]{Project publications with the standard heading}
\begin{refsection}
\projectPublicationsHeading
\projectNocite{FAIR2016}
\printProjectBibliography[heading=none]
\end{refsection}
\end{dfgExample}

\subsection{Project plan: aims and work packages}

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

\begin{docEnvironment}{aims}{\oarg{options}}
  Environment to be used in a project section to summarize in a condensed way the aims of the project.
  Use |label={RDM Aims}| to replace the default |Aim| prefix, keeping the
  item number and colon. The same text is used verbatim for singular and
  plural references through \cs{cref}, \cs{Cref}, and \refCom{getAim},
  including references outside the list or before it. Compile twice after
  changing labels. Without this option, the defaults remain |Aim| and |Aims|.
  Other list options, such as |start=3| and |itemsep=2pt|, are passed to
  \pkg{enumitem}.

  Use |resume| to continue numbering from the previous |aims| list.
  Repeat the custom prefix, as in |[label={RDM Aims},resume]|, to keep it
  in the numbered items and their cross-references. With |[resume]| alone,
  numbering continues but the prefix returns to the default |Aim|/|Aims|.
  Resuming uses the previous |aims| list regardless of its label text;
  custom labels do not create separate counters.

  See \dfgExampleRef{ex:manual-aims-and-their-references}.
\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}.

  See \dfgExampleRef{ex:manual-aims-and-their-references}.
\end{docCommand}

These aim and work-package examples use project |A03| as their current
project, as normally established by \cs{printProjectHead}.

\begin{dfgExample}[label={ex:manual-aims-and-their-references},dfg project=A03]{Aims and their references}
\begin{aims}
  \addAim{manual-a} Identify pathways.
  \addAim{manual-b} Validate biomarkers.
  \addAim{manual-c} Test interventions.
\end{aims}
See \getAim{manual-a,manual-b,manual-c}.
\begin{aims}[label={RDM Aims}]
  \addAim{manual-rdm-a} Document research data.
  \addAim{manual-rdm-b} Publish reusable datasets.
\end{aims}
See \getAim{manual-rdm-a,manual-rdm-b}.
\begin{aims}[label={RDM Aims},resume]
  \addAim{manual-rdm-c} Archive the datasets.
\end{aims}
Continued as \getAim{manual-rdm-c}.
\end{dfgExample}

\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}.

  See \dfgExampleRef{ex:manual-aims-and-their-references}, \dfgExampleRef{ex:manual-references-to-another-project-s-work-packages}.
\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}.

  See \dfgExampleRef{ex:manual-work-packages-and-their-references}, \dfgExampleRef{ex:manual-nested-work-packages-and-mixed-references}.
\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.

  See \dfgExampleRef{ex:manual-work-packages-and-their-references}, \dfgExampleRef{ex:manual-nested-work-packages-and-mixed-references}.
\end{docCommand}

\begin{dfgExample}[label={ex:manual-work-packages-and-their-references},dfg project=A03]{Work packages and their references}
\begin{workpackages}
  \addWP{manual-wp1}{
    name={Identify pathways},
    description={Pathway discovery},
    periodStart=1, periodEnd=6,
    style={alternative}
  }
  Collect and analyse samples.
  \addWP{manual-wp2}{
    name={Validate biomarkers},
    description={Validation},
    periodStart=7, periodEnd=12,
    style={important}
  }
  Test independent cohorts.
\end{workpackages}
See \getWP{manual-wp1,manual-wp2}.
\end{dfgExample}


Furthermore, PI, work-package, and aim references each have an independent
color setting. They default to |black| and are independent of
\refKey{color@reference@boldAuthor}. Configure them with \cs{changeSettings}:
\begin{dispListing}
  \changeSettings{
    color@reference@PI  = my-blue,
    color@reference@WP  = my-blue,
    color@reference@Aim = my-blue
  }
\end{dispListing}

\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}|.
  Consecutive references under the same parent work package are compacted into
  a range.  Its |to| connector uses the surrounding font weight while the
  |WPs| prefix and endpoint labels stay bold. A narrow, unbreakable space
  separates |WP| or |WPs| from its number. References under later parent
  work packages remain separate and are not discarded during compaction.

  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}.
  Parent and nested work packages can be combined in one call, for example
  |\getWP{wp1a,wp1b,wp2,wp3a,wp3b}|. The parent |wp2| is retained alongside
  the nested items; sorting follows the hierarchy and ranges do not cross
  parent boundaries.

  See \dfgExampleRef{ex:manual-work-packages-and-their-references}, \dfgExampleRef{ex:manual-nested-work-packages-and-mixed-references}.
\end{docCommand}

For this example the current project is |B04|. Parent and nested work packages
can be referenced together; nested ranges stay within their parent.
\begin{dfgExample}[label={ex:manual-nested-work-packages-and-mixed-references},dfg wide,dfg project=B04,leftlower=12mm]{Nested work packages and mixed references}
\begin{workpackages}
  \addWP{manual-nested-1}{name={Discovery}}
  \begin{workpackages}
    \addWP{manual-nested-1a}{} Recruit participants.
    \addWP{manual-nested-1b}{} Profile samples.
    \addWP{manual-nested-1c}{} Validate signals.
  \end{workpackages}
  \addWP{manual-nested-2}{name={Translation}}
  Test the selected intervention.
\end{workpackages}
See \getWP{manual-nested-1a,manual-nested-1b,manual-nested-1c,manual-nested-2}.
\end{dfgExample}

The next example is in |A03|. Its explicit |[B04]| argument points back to
the work packages above, while |[A03]| selects the earlier aim example.
\begin{dfgExample}[label={ex:manual-references-to-another-project-s-work-packages},dfg project=A03]{References to another project's work packages}
Exchange samples with
\getWP[B04]{manual-nested-1a,manual-nested-2}.\par
This supports \getAim[A03]{manual-a,manual-c}.
\end{dfgExample}






While some keys have been described already, here is what is missing so far:
\begin{docKey}{style}{\docKeyChoices{default,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}.

  See \dfgExampleRef{ex:manual-gantt-five-bar-styles},
  \dfgExampleRef{ex:manual-gantt-custom-colours}, and
  \dfgExampleRef{ex:manual-gantt-grayscale}.
\end{docKey}

\subsection{Timeline and collaboration plots}
\begin{docCommand}{printPlot}{\oarg{options}\marg{plot specification}}
  Print a Gantt or collaboration plot.  Use the lowercase type names
  |gantt| and |collaborations| in the braced specification.  The second
  braced item selects a project, as in |\printPlot{{gantt}{B06}}| or
  |\printPlot{{collaborations}{B06}}|.  Omit the project ID inside a project
  to use its current ID: |\printPlot{{gantt}}| or
  |\printPlot{{collaborations}}|.  Without a current project, give the ID.
  Place plot options before the specification, for example
  |\printPlot[arcs=true]{{collaborations}{B06}}| or
  |\printPlot[caption={Additional details}]{{gantt}}|.  Use the same leading
  caption option with an explicit ID, as in
  |\printPlot[caption={Additional details}]{{gantt}{B06}}|.
  Captions stay below plots; older trailing captions remain supported.
  For either plot type, an empty |caption={}| leaves the default caption intact
  and serves as a placeholder for additional project-specific text.
  The former type names |Gantt| and |ProjectCollaboration| and the singular
  lowercase |collaboration| remain accepted.

  The collaboration arc diagram is the default.  Select the heatmap with
  |layout=heatmap|.  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.

  See \dfgExampleRef{ex:manual-gantt-chart-of-the-current-project}, \dfgExampleRef{ex:manual-current-project-connections-as-arcs}, \dfgExampleRef{ex:manual-explicit-project-heatmap-and-caption}.
  For bar colours and patterns, see
  \dfgExampleRef{ex:manual-gantt-five-bar-styles} and
  \dfgExampleRef{ex:manual-gantt-custom-colours}.
\end{docCommand}

\paragraph{Live plot variants}
\label{sec:manual-plot-examples}
For examples without an explicit ID, the current project is |A03|, as it
would be after |\printProjectHead{A03}|. Specifying |B04| overrides that
context for that call. Each example starts with the default plot options.

\begin{dfgExample}[label={ex:manual-collaborations-of-the-current-project},dfg wide,dfg project=A03]{Collaborations of the current project}
\printPlot{{collaborations}}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-explicit-id-overrides-the-current-project},dfg wide,dfg project=A03]{Explicit ID overrides the current project}
\printPlot{{collaborations}{B04}}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-current-project-connections-as-arcs},dfg wide,dfg project=A03]{Current-project connections as arcs}
\printPlot[arcs=true]{{collaborations}}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-current-project-heatmap},dfg wide,dfg project=A03]{Current-project heatmap}
\printPlot[layout=heatmap]{{collaborations}}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-explicit-project-heatmap-and-caption},dfg wide,dfg project=A03]{Explicit-project heatmap and caption}
\printPlot[layout=heatmap,caption={Shared experimental platforms.}]
  {{collaborations}{B04}}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-custom-project-area-colours},dfg wide,dfg project=A03]{Custom project-area colours}
\printPlot[layout=heatmap,area-colors={A=teal,B=orange,Q=violet}]
  {{collaborations}{A03}}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-layout-aliases-and-additional-caption},dfg wide,dfg project=A03]{Layout aliases and additional caption}
\printPlot[arc-diagram,caption={Partners of the imaging service.}]
  {{collaborations}{Q01}}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-gantt-chart-of-the-current-project},dfg wide,dfg project=A03]{Gantt chart of the current project}
\printPlot[caption={Discovery followed by validation.}]{{gantt}}
\end{dfgExample}

\begin{dfgExample}[label={ex:manual-gantt-chart-with-explicit-project-id},dfg wide,dfg project=A03]{Gantt chart with explicit project ID}
\printPlot{{gantt}{A03}}
\end{dfgExample}

For older sources, |Gantt| means |gantt|; |ProjectCollaboration| and
|collaboration| mean |collaborations|. These aliases render the same results
and accept the same leading options.

\paragraph{Gantt bar styles and colours}
\label{sec:manual-gantt-colours}
Choose a bar's appearance with the \refKey{style} key of \refCom{addWP}.
The three solid fills are |default|, |alternative|, and |important|;
|crosshatch| adds a hatch pattern, and |striped| alternates two colours.
The following example defines one work package of each style in |B06|.
Its five rows are reused in the palette examples below, so the colours can
be compared without changing the work plan.

\begin{dfgExample}[label={ex:manual-gantt-five-bar-styles},dfg wide,dfg project=B06,leftlower=12mm]{Five Gantt bar styles}
\begin{workpackages}
  \addWP{manual-colour-default}{
    name={Baseline}, description={Default},
    periodStart=1, periodEnd=6, style={default}
  }
  \addWP{manual-colour-alternative}{
    name={Parallel analysis}, description={Alternative},
    periodStart=3, periodEnd=9, style={alternative}
  }
  \addWP{manual-colour-important}{
    name={Validation}, description={Important},
    periodStart=7, periodEnd=12, style={important}
  }
  \addWP{manual-colour-crosshatch}{
    name={Integration}, description={Crosshatch},
    periodStart=9, periodEnd=14, style={crosshatch}
  }
  \addWP{manual-colour-striped}{
    name={Joint experiments}, description={Striped},
    periodStart=11, periodEnd=16, style={striped}
  }
\end{workpackages}
\printPlot[caption={One row for each built-in bar style.}]{{gantt}{B06}}
\end{dfgExample}

For a document-wide palette, put \cs{changeSettings} in
|preamble/dfg-customization.tex|. These colour settings are applied at
|\begin{document}|. They accept colour names and xcolor mixes such as
|teal!45|. The |frame| colour controls the outline of the bars, while
|crosshatch| controls the hatch strokes and |stripe-one|/|stripe-two|
control the two alternating stripe colours.
\begin{dispListing*}{title={Document-wide Gantt palette: place in the customization file}}
\changeSettings{
  color@gantt@default     = {teal!45},
  color@gantt@alternative = {orange!50},
  color@gantt@important   = {violet!70},
  color@gantt@crosshatch  = {black!25},
  color@gantt@stripe-one  = {teal!20},
  color@gantt@stripe-two  = {teal!80},
  color@gantt@frame       = {black!50}
}
\end{dispListing*}

To recolour just one chart after the document has started, use
\cs{colorlet} on the live colour names inside a group. The next example
also defines an RGB colour; the surrounding group restores the previous
palette afterwards. The colour names are set before \refCom{printPlot};
they are not plot options.

\begin{dfgExample}[label={ex:manual-gantt-custom-colours},dfg wide,dfg project=B06]{Custom colours for one Gantt chart}
\begingroup
\definecolor{ganttOcean}{RGB}{0,114,178}
\colorlet{color@gantt@default}{ganttOcean!45}
\colorlet{color@gantt@alternative}{teal!50}
\colorlet{color@gantt@important}{orange!90}
\colorlet{color@gantt@crosshatch}{violet!35}
\colorlet{color@gantt@stripe-one}{ganttOcean!25}
\colorlet{color@gantt@stripe-two}{ganttOcean!55}
\colorlet{color@gantt@frame}{black!50}
\printPlot[caption={Custom fills, coloured hatching, and two-tone stripes.}]
  {{gantt}{B06}}
\endgroup
\end{dfgExample}

For grayscale output, use different gray levels and retain the hatch and
stripe patterns. The following chart uses the same work packages and dates;
its black outlines make the bar boundaries explicit.

\begin{dfgExample}[label={ex:manual-gantt-grayscale},dfg wide,dfg project=B06]{Grayscale Gantt bars with patterns}
\begingroup
\colorlet{color@gantt@default}{black!20}
\colorlet{color@gantt@alternative}{black!35}
\colorlet{color@gantt@important}{black!50}
\colorlet{color@gantt@crosshatch}{black!25}
\colorlet{color@gantt@stripe-one}{white}
\colorlet{color@gantt@stripe-two}{black!35}
\colorlet{color@gantt@frame}{black}
\printPlot[caption={Grayscale fills with hatching and stripes.}]{{gantt}{B06}}
\endgroup
\end{dfgExample}

\subsection{Individual project funding}
\label{sec:manual-project-funding}
The example below adds a funding request for |A06|, whose project metadata
are already loaded. It covers all five funding groups: |staff|, |costs|,
|fellowships|, |globalfunds|, and |instrumentation|. The doctoral position at
65\% uses the configured annual salary; the other groups specify full EUR
amounts directly, including a one-off equipment purchase. The year headings
and partial-year factors come from |meta.fundingYears|. The earlier |A02|
funding examples use separate records.

\begin{dfgExample}[label={ex:manual-requested-funding-for-a-project},dfg wide,listing above* text,after={\par\clearpage}]{Requested funding for a project}
\changeSettings{salary@PhD=83700}
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A06},
  funding-type   = {staff},
  category       = {PhD},
  percentage     = {65},
  quantity       = {
    year1 = {1},
    year2 = {1},
    year3 = {1},
    year4 = {1},
    year5 = {1}
  }
}
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A06},
  funding-type   = {costs},
  category       = {consumables},
  sum            = {
    year1 = {1000},
    year2 = {2000},
    year3 = {2000},
    year4 = {2000},
    year5 = {1000}
  }
}
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A06},
  funding-type   = {fellowships},
  category       = {Short-term research fellowships},
  sum            = {
    year1 = {3000},
    year2 = {6000},
    year3 = {6000},
    year4 = {6000},
    year5 = {3000}
  }
}
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A06},
  funding-type   = {globalfunds},
  category       = {Training and networking},
  sum            = {
    year1 = {1500},
    year2 = {3000},
    year3 = {3000},
    year4 = {3000},
    year5 = {1500}
  }
}
\addEntry[funding]{RequestedFunding}{
  ref-project-id = {A06},
  funding-type   = {instrumentation},
  category       = {Imaging workstation},
  sum            = {
    year1 = {20000},
    year2 = {0},
    year3 = {0},
    year4 = {0},
    year5 = {0}
  }
}
\printTable{{RequestedFunding}{A06}}
\end{dfgExample}

The project staff roster describes who does the work. It uses |staff| records
in |RequestedFundingStaff|; monetary requests remain separate |funding|
records. Existing staff may inherit their name and institution through
|ref-person-id|. Use |lastname={TBA}| for an unnamed requested position.
The |description| text is printed as a numbered job description below the table.

\begin{dfgExample}[label={ex:manual-project-staff-an-existing-investigator-and-a-doctoral-vacancy},dfg wide,listing above* text]{Project staff: an existing investigator and a doctoral vacancy}
\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id    = {B03},
  funding-status    = {existing},
  staff-type        = {research},
  ref-person-id     = {per11},
  field-of-research = {Immunology},
  commitment        = {8},
  funding-source    = {State funds},
  description       = {Supervises the experiments and data analysis.}
}
\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id     = {B03},
  funding-status     = {requested},
  staff-type         = {research},
  lastname           = {TBA},
  positionText       = {Doctoral researcher (65\%)},
  field-of-research  = {Immunology},
  ref-institution-id = {ins1},
  category           = {PhD},
  description        = {Performs longitudinal experiments and prepares the thesis.}
}
\printTable{{RequestedFundingStaff}{B03}}
\end{dfgExample}

Existing direct-cost funding is declared separately from new requests. The
following records identify the participating affiliations and funding sources;
the |sum| values are full EUR amounts for each funding-year column.

\begin{dfgExample}[label={ex:manual-existing-direct-cost-funding-from-two-sources},dfg wide,listing above* text]{Existing direct-cost funding from two sources}
\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id     = {B03},
  ref-affiliation-id = {aff1},
  financed-by        = {University core funds},
  sum                = {
    year1 = {1000}, year2 = {2000}, year3 = {2000}, year4 = {2000}, year5 = {1000}
  }
}
\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id     = {B03},
  ref-affiliation-id = {aff2},
  financed-by        = {Partner university},
  sum                = {
    year1 = {500}, year2 = {1000}, year3 = {1000}, year4 = {1000}, year5 = {500}
  }
}
\printTable{{RequestedAndExistingFundingDirectCosts}{B03}}
\end{dfgExample}

\begin{docEnvironment}{FundingDirectCostsTable}{\oarg{heading}}
  Typeset a three-column breakdown of direct costs.  Its optional heading and
  the table stay together when there is insufficient space left on a page.
  The currency column uses its natural width so that codes such as EUR fit
  in the selected font; the description column fills the remaining width.

  See \dfgExampleRef{ex:manual-explain-individual-direct-cost-items}.
\end{docEnvironment}

\begin{dfgExample}[label={ex:manual-explain-individual-direct-cost-items}]{Explain individual direct-cost items}
\begin{FundingDirectCostsTable}[Consumables]
  Assay reagents & EUR & 1200 \\
  Culture media & EUR & 800 \\
\end{FundingDirectCostsTable}
\end{dfgExample}

\subsection{Report and results of an ending project}
\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.

  See \dfgExampleRef{ex:manual-published-results-of-an-ending-project}.
\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.

  See \dfgExampleRef{ex:manual-published-results-of-an-ending-project}.
\end{docEnvironment}

\begin{dfgExample}[label={ex:manual-published-results-of-an-ending-project},dfg wide,dfg project=A00]{Published results of an ending project}
\begin{refsection}
\begin{projectReport}
  Follow the FAIR principles \cite{FAIR2016}
  and document software design \cite{Hoare1973}.
\end{projectReport}
\printProjectResults{
  quality-assured={FAIR2016},
  other=none,
  patents=none
}
\end{refsection}
\end{dfgExample}

For |project-status=E|, the staff table reuses
|\printTable{{RequestedFundingStaff}{project-id}}|. Rows with
|funding-status=requested| describe staff funded with approved grant money
in the ending period, rather than a request for a new period. The complete
B02 example shows this closing table together with its input records.

\section{Bylaws and declarations}
The bylaws are authored prose in |content/04_bylaws-of-the-crc.tex|. Use the
applicant-wording helper introduced with the title page for singular or plural
university names. The declaration file |content/05_declarations.tex| then
prints the required signatures from the same person metadata.

\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.

  See \dfgExampleRef{ex:manual-signature-blocks}.
\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.

  See \dfgExampleRef{ex:manual-select-signatories-by-role}.
\end{docCommand}

\begin{dfgExample}[label={ex:manual-signature-blocks},dfg wide]{Signature blocks}
\printSignature{
  {spokesperson}{(Spokesperson of \thisCRC)}
  {rector}{(Rector of Example University)}
}
\end{dfgExample}

The role-based form resolves the affiliation for each signatory; it avoids
repeating names or maintaining a separate list of rectors in the content.
\begin{dfgExample}[label={ex:manual-select-signatories-by-role},dfg wide]{Select signatories by role}
\printSignaturesWithRole{rector}{%
  Rector of
  \get[affiliation]{\theAffiliationOfRoleID}{name}}
\end{dfgExample}

\section{Back matter: compact project overview}
The closing overview reuses the project and PI records already used in general
information. No separate database is needed.

\begin{dfgExample}[label={ex:manual-compact-project-overview-for-the-closing-pages},dfg wide,listing above* text]{Compact project overview for the closing pages}
\printTable{projectOverview}
\end{dfgExample}

\chapter{Metadata and configuration reference}
\label{chap:manual-reference}
This chapter collects the detailed field definitions, class settings, CV and
bibliography conventions, and maintenance notes. Read it as a reference while
working through the preceding proposal examples.

\section{Metadata, databases and keysets}
\label{doc:metadata}
This reference lists the accepted fields for each keyset. The walkthrough
introduces the records at their point of use; consult this section when adding
fields or choosing a non-default value. The class stores records with
\refPkg{datatool}.

\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.
\subsection{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}*)           = {Doe},
  (*\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 Doe},{M. S. Doe}},
  (*\refKey{orcid}*)              = {0000-0002-3555-7218},
  (*\refKey{email}*)              = {max.doe@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}.
The generated wording for the yes/no keys \refKey{C1}--\refKey{C4} is
singular/plural sensitive.  It is adjusted automatically to match the number
of project leaders and institutions represented in the proposal.
\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}



\subsection{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}*)       ={Doe},
    (*\refKey{academicdegree}*) ={Prof. Dr. rer. nat.},
    (*\refKey{role}*)           ={PI},
    \ldots
    (*\refKey{name-alias}*)       ={{Maxi Doe},{Maximilian Doe}},
    (*\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.

  See \dfgExampleRef{ex:manual-generate-the-cv-appendix-or-select-one-person}.
\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}.

  See \dfgExampleRef{ex:manual-generate-the-cv-appendix-or-select-one-person}.
\end{docCommand}

The starter CV loads person and career records from
|metadata/dfg-metadata.tex| and |metadata/dfg-metadata-cv.tex|. The following
example shows the first CV page produced by the complete appendix. Its first
PI is |per2| (Alex Example); selecting just that person produces the same CV.
The local proposal, CV appendix, and manual use the same twelve-PI consortium.
All pages, including the privacy statement, follow in
Chapter~\ref{chap:complete-example-cv}.

\begin{dfgExample}[label={ex:manual-generate-the-cv-appendix-or-select-one-person},dfg wide,listing and comment,
  comment={\dfgDocCVExcerpt{per2}}]{Generate the CV appendix or select one person}
\documentclass[english,cv,final=true]{dfg-crc}
\begin{document}
\dfgCVsection
% For one person, replace the line above with:
% \dfgCV{per2}
\end{document}
\end{dfgExample}

\subsection{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}.

Within an \refCom{addEntry}|{project}{...}| entry, the
\refKey{ref-person-id} field is reserved exclusively for the person or persons
who are PIs of that project. Every person listed in this field is interpreted
as a project PI; no other person roles are inspected or considered. Persons
associated with the project only in another role must therefore not be included
in this field.

\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.
  Spaces around individual codes are ignored, e.g.\ |2.21-02, 2.22-31|.
\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 arc layout shows all active projects
  on one axis and highlights the focus project and its direct collaborators.
  Set |arcs=true| to draw the connecting arcs, or select the optional
  heatmap layout.  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}

\subsection{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}*) = {Sample},
    (*\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.

\subsection{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}

\subsection{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}{positionText}{=\meta{text}}{}
  Optional replacement for the staff description in the requested-funding
  table. When supplied, it is printed instead of the translated
  \refKey{category} name. If omitted or empty, the category name is printed.
  The category still determines the salary 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}

\subsection{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 position is optional: omitting |positionText| inherits the central
  person's position, whereas an explicit |positionText={}| suppresses it.
  If the resulting position is empty, its line and parentheses are omitted
  without a missing-field warning.
  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.
  It may be empty or omitted for existing non-research staff; in that case the
  empty cell receives the |tableNoValue| background and no missing-field
  warning is issued.  It remains an
  applicable, warning-checked value for the other three staff groups.
  \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 is an item
  in the applicable existing- or requested-staff list. Its number is the
  flush-left item label; academic degree, first name, last name, and all
  continuation lines share a consistent hanging indent. The bold name and
  description are separated by a normal interword space.
  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.  When \refKey{ref-person-id} is empty or omitted,
  \refKey{ref-institution-id} must be supplied explicitly.  The class warns at
  declaration time if both keys are empty, because the institution cannot be
  inherited and an existing staff member could not be assigned to an
  affiliation in \refCom{OverviewExistingStaffTable}.
\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.  In particular, this
  compatibility key does not replace the required \refKey{ref-institution-id}
  on a row that has no \refKey{ref-person-id}.
\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.
An unnamed or otherwise unreferenced person therefore needs an explicit
|ref-institution-id|; omitting both it and |ref-person-id| produces a warning
when the roster row is declared.
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 category column uses |X[3,l]|, reduced from |X[4,l]|; each affiliation
column remains |X[1,c]|. The label reads \enquote{Junior research group}
on its first line and \enquote{leaders} on its second line. This layout is
maintained in the class source, so a proposal customization override is not
needed after updating the generated class.

The proposal workspace contains a standalone layout test at
\path{proposal-overleaf-com/__admin/scripts/test-overview-staff.tex}.
It declares 85 complete fictional staff records across all seven categories
and nine real affiliations in an isolated database, independently of project
auxiliary files. The source lists the expected counts and build commands.
Run LuaLaTeX twice from the proposal workspace; the PDF is written to
\path{output/pdf/test-overview-staff.pdf}. The test PDF labels the counts as
illustrative rather than proposal totals.

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.


\subsection{Shared identifiers and CRC metadata}
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{printList}
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}
\section{Adjustments and Customizations}
\label{doc:customization}

\subsection{Documentclass options}
\begin{docCommand}{documentclass}{\marg{key=value}}
  Adjust on a metalevel various options (e.g.
  \refKey{showmarginalia},
  \refKey{fastcompile},
  \refKey{fastcompile-show-tags},
  \refKey{fastcompile-project},
  \refKey{fastcompile-project-show-images},
  \refKey{fastcompile-project-show-publications},
  \refKey{fastcompile-project-show-funding-tables},
  \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.

  See \dfgExampleRef{ex:manual-generate-the-cv-appendix-or-select-one-person}.
\end{docCommand}

\begin{docKey}{BCOR}{=\meta{dim}}{initially \texttt{5mm}}
  Reserve binding space on the inner edge of each page.  The class passes this
  KOMA-Script option to \pkg{geometry} as its binding offset.  With the
  default 30\,mm nominal inner margin, |BCOR=5mm| gives 35\,mm of inner
  clearance and a 160\,mm text block; |BCOR=8mm| gives 38\,mm and 157\,mm.
\end{docKey}

\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-show-tags}
  {\docKeyChoices{true,false}}
  {initially \texttt{false}.}
  Show database provenance annotations during either fast-compilation mode.
  In focused project mode, annotations show the starting row and requested
  lookup path because metadata rows are skipped. This option has no effect
  outside fast compilation; final mode disables the annotations.
\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 unless
  \refKey{fastcompile-project-show-images} needs project rows, and executes only
  the three project-local funding entry types when
  \refKey{fastcompile-project-show-funding-tables} is enabled. It 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. Apart
  from the optional project funding tables, 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 and generated plots encountered in the selected project while
  \refKey{fastcompile-project} is active.  Project entries from the metadata
  file are retained for database-backed plots such as
  |\printPlot{{ProjectCollaboration}{B06}}|; other metadata entries,
  calculated headings, generated tables and the remaining fast-mode work stay
  disabled.  With the default value, \pkg{graphicx} stays in draft mode,
  displays image placeholders, and \refCom{printPlot} emits the usual skipped
  item notice.
\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}{fastcompile-project-show-funding-tables}
  {\docKeyChoices{true,false}}
  {initially \texttt{true}.}
  Show or suppress \cs{RequestedFundingTable},
  \refCom{RequestedFundingStaffTable}, and
  \cs{RequestedAndExistingFundingDirectCostsTable} while
  \refKey{fastcompile-project} is active. Focused mode processes only the
  corresponding project-local |RequestedFunding|, |RequestedFundingStaff|, and
  |RequestedAndExistingFundingDirectCosts| entries. Local staff-cost and total
  calculations remain available, including the per-year and full-period sums
  of existing direct-cost rows. Multiple rows accumulate in those local sums.
  Missing staff-table values use field-name placeholders such as
  |<firstname>| instead of ``not provided'' in fast compilation, since
  metadata needed for inherited values may have been skipped.
  Auxiliary-file restoration and proposal-wide overview caches stay disabled. This option has no effect on
  ordinary or final builds, where these tables are always rendered.
\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. During fast compilation,
  \refKey{fastcompile-show-tags} controls whether these annotations appear.
  In focused project mode, annotations identify the starting row and full
  requested field path because skipped metadata cannot supply destination row
  identifiers. Final mode disables annotations.
\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{fastcompile-project-show-funding-tables}*)=true,
    (*\refKey{skip10pub}*)      =false,
    (*\refKey{fastcompile-project-show-publications}*)=true,
    (*\refKey{colorscheme}*)    =cmyk
  ]{dfg-crc}
\end{dispListing*}

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



Read these settings in text with \refCom{getValue}, for example
|\num{\getValue{animalHousing@mouse}}\,EUR|.

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{docKey}{PIReferenceFirstName}{\docKeyChoices{true,false}}{initially \texttt{false}}
  Include the firstname in unstarred \refCom{getPI} references. The starred
  form always includes it. Set this through \refCom{changeSettings}; it also
  affects person-first \refCom{getPIProject} and \refCom{getPIofProject}.
  Project-first \refCom{getProjectPI} references keep lastnames unless the
  command is starred. Shared PI surnames are automatically disambiguated by
  the first given-name initial in unstarred references, regardless of this
  setting. If that initial is also shared, the full firstname is used.
  Use the starred command to request full firstnames explicitly.
\end{docKey}

\begin{docKey}{projectsTableInstitutionAbbreviations}{\docKeyChoices{true,false}}{initially \texttt{false}}
  Control the institution display in \cs{ProjectsTable} and
  \cs{ProjectLeadersTable}.  With \texttt{true}, both tables use compact
  institution abbreviations; each projects table is followed by a tightly set
  legend containing only the abbreviations used in that table, sorted
  alphabetically by abbreviation.  Reusing one abbreviation for different
  institution names raises a package warning.  With \texttt{false}, full
  institution names are printed and no legend is added.
\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{126600}},
  {doc name=salary@groupLeader,
   doc description=initially \texttt{105000}},
  {doc name=salary@postDoc,
   doc description=initially \texttt{90600}},
  {doc name=salary@medDoc,
   doc description=initially \texttt{112200}},
  {doc name=salary@PhD,
   doc description=initially \texttt{83700}},
  {doc name=salary@research,
   doc description=initially \texttt{69000}},
  {doc name=salary@nonResearch,
   doc description=initially \texttt{61500}},
  {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}\textbar\texttt{auto}}]{
    {
      doc name = thumbindex@topmargin,
      doc description = initially \texttt{auto},
    },
    {
      doc name = thumbindex@bottommargin,
      doc description = initially \texttt{auto},
    },
  }
  With \texttt{auto}, the first tab starts at the top of the text block and the
  last tab ends at its bottom; the tabs divide the current \cs{textheight} into
  \refKey{thumbindex@pattern} equal slots.  Set either key to a dimension to
  place that end of the tab stack the specified distance from the corresponding
  page edge.  With the default \texttt{auto} values, the dimensions are
  recalculated for the current page layout, so changes to the text height also
  change the thumb-index spacing.
\end{docKeys}


\begin{docKey}{thumbindex@width}{=\meta{dim}}{initially \texttt{1.2cm}}
  Define how far a thumb-index tab extends into the outer margin.  The default
  12\,mm tab fits inside the 13\,mm marginal column.
\end{docKey}

\begin{docKey}{thumbindex@orientation}{\docKeyChoices{outwards,inwards}}{initially \texttt{outwards}}
  Choose which way the thumb-index text faces on both left and right pages.
  With \texttt{outwards}, the tops of the letters point towards the outer page
  edge (the existing orientation). With \texttt{inwards}, they point towards
  the text block: the label is turned by 180 degrees. The tab's position,
  dimensions, and slot order stay the same. In both orientations the label
  is inset 2\,mm from the tab center towards the text block on each page side.
  Set |\changeSettings{thumbindex@orientation=inwards}| in
  |preamble/dfg-customization.tex| to flip the labels.
\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 author names in bibliographies.
\end{docKey}

\begin{docKey}{color@reference@PI}{=\meta{colorname} or \texttt{current}}{initially \texttt{black}}
  Define the color of references to principal investigators. Use |current|
  to inherit the surrounding text color at each reference instead of applying
  a fixed color. This applies to \cs{getPI} (including its starred and custom-text
  forms) and the project-reference commands that use it. Set this key in the
  preamble, for example:
  \begin{dispListing}
    \changeSettings{color@reference@PI=current}
    % Or use a named xcolor color:
    \changeSettings{color@reference@PI=blue}
  \end{dispListing}
\end{docKey}

\begin{docKey}{color@reference@WP}{=\meta{colorname}}{initially \texttt{black}}
  Define the color of references to work packages.
\end{docKey}

\begin{docKey}{color@reference@Aim}{=\meta{colorname}}{initially \texttt{black}}
  Define the color of references to aims.
\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@lines}{=\meta{colorname}}{initially \texttt{black-10}}
  Define the color for inner table lines.
\end{docKey}


\begin{docKey}{color@table@outerLines}{=\meta{colorname}}{initially \texttt{black}}
  Define the color for outer table lines and both the horizontal rules and
  dashed vertical grid lines in Gantt charts.
\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}.
  Set these keys with \refCom{changeSettings} in the customization file,
  before the document starts. For rendered examples and grouped overrides
  of an individual chart, see
  \dfgExampleRef{ex:manual-gantt-five-bar-styles},
  \dfgExampleRef{ex:manual-gantt-custom-colours}, and
  \dfgExampleRef{ex:manual-gantt-grayscale}.
\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 empty
    },
  }
  Adjust the citation and bibliography style separately for standalone CVs
  and proposals.  The feature values are comma-separated additional
  \pkg{biblatex} package options.  Proposal features default to empty so
  changing styles does not pass unsupported options.  Add style-specific
  options such as \texttt{dashed=false} explicitly when supported.
  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 = {},
  }
\end{dispListing*}

\paragraph{Bibliography font and entry spacing}
The length \cs{bibitemsep} controls the extra vertical gap between bibliography
entries, independently of the line spacing within an entry. A gap can already
be present without a template override: the alphabetic styles inherit
\cs{itemsep}, which is |4pt plus 2pt minus 1pt| in the default 10\,pt setup.
Other bibliography styles may supply different defaults.

To use footnote-sized text and remove this extra gap, add the following hook
outside \cs{changeSettings} in |preamble/dfg-customization.tex|. The file is
read before \pkg{biblatex}, so its lengths and font command must be changed
after the package has loaded.
\begin{dispListing*}{title={Compact bibliographies through the customization file.}}
\AddToHook{package/biblatex/after}{%
  \renewcommand*{\bibfont}{\normalfont\footnotesize}%
  \setlength{\bibitemsep}{0pt}%
}
\end{dispListing*}
This applies to ordinary \cs{printbibliography} calls and to
\refCom{printProjectBibliography} and \refCom{printFrameBibliography}.
Replace |0pt| with |2pt|, for example, to
keep a small extra gap. The CV publication environment |DFGlist| uses
|nosep| already; to add space there, set |itemsep=2pt| after |nosep| in its
list configuration. There is no \cs{changeSettings} key for entry spacing.

\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{docKey}{emphasizeEntries}
  {\docKeyChoices{true,false}}
  {initially \texttt{false}.}
  Bold a complete entry in \cs{printProjectBibliography} when its
  \texttt{Keywords} field contains the current project ID followed by
  \texttt{-highlight}.  For example, \texttt{B06-highlight} applies only to
  Project B06. In \cs{printFrameBibliography}, the keyword
  \texttt{frametext-highlight} selects complete entries instead. Each keyword
  applies only to its corresponding bibliography context.
  This setting is independent of \refKey{emphasizeAuthors},
  which controls name highlighting.  A \texttt{B06-project} keyword alone does
  not trigger bold type.  To show only the keyword-selected full entries in
  bold, use \texttt{emphasizeAuthors=false} together with
  \texttt{emphasizeEntries=true}.
\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{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}}
  Set the tab's \meta{color} and displayed \meta{string} for following pages.
  Place this command before a \cs{clearpage} if the new tab should appear on
  the next page.
\end{docCommand}

\begin{docCommand}{printThumbIndexOff}{}
  Remove the tab from following pages.  This changes visibility only.
\end{docCommand}

\begin{docCommand}{resetThumbIndex}{}
  Reset the thumb-index slot counter.  The next \cs{printThumbIndex} call
  starts at the first slot again.  This changes only the position counter;
  use \cs{printThumbIndexOff} separately if the current tab should be hidden.
\end{docCommand}


\subsection{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.

  See \dfgExampleRef{ex:manual-an-orcid-from-metadata}.
\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.

  See \dfgExampleRef{ex:manual-an-orcid-from-metadata}.
\end{docCommand}


\begin{dfgExample}[label={ex:manual-an-orcid-from-metadata}]{An ORCiD from metadata}
\ORCiD{0000-0000-0000-0001}\par
\getORCiD{per1}\par
\getORCiDvalue{per1}
\end{dfgExample}

\section{Bibliography/Publication}
\subsection{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}
\subsection{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}


\subsection{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 Doe},
    {M. Doe},
    {Doe, Max H.},
    {Doe, 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}.


\subsection{Providing publication information}
\label{sec:manual-cv-publications}

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}

To bold the complete bibliography entry only in Project B06, add its
project-specific highlight keyword alongside any publication keywords:
\begin{dispListing}
  @article{...,
    keywords = {pabst-A,B06-highlight},
  }
\end{dispListing}
This affects project bibliography lists, including project-report references
and published-result lists.  The same entry is not bolded in other projects
unless their own \texttt{<project-id>-highlight} keyword is present.  Set
\texttt{emphasizeEntries=true} in \cs{changeSettings} to enable this feature.
Only one highlight keyword per distinct project is needed, even when several
PIs from that project coauthor the publication.  For a publication to be bold
in both B06 and Q04, use each keyword once:
\begin{dispListing}
  @article{...,
    keywords = {pabst-A,B06-highlight,Q04-highlight},
  }
\end{dispListing}
The optional \texttt{B06-project} keyword can record project membership for
other workflows, but it does not activate \refKey{emphasizeEntries}.  Existing
CV-selection keywords such as \texttt{pabst-A} can stay in the same field.

For the frame-text bibliography in chapter 1, add
\texttt{frametext-highlight} and use \refCom{printFrameBibliography}:
\begin{dispListing}
  @article{...,
    keywords = {pabst-A,B06-highlight,frametext-highlight},
  }
\end{dispListing}
With \texttt{emphasizeEntries=true}, this entry is bold in both the B06
project bibliography and the frame-text bibliography. Neither keyword
changes formatting in other bibliography contexts or in inline citations.

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}



\section{Automatic wording and list cardinality}
\paragraph{Automatic singular, plural, and cardinality-dependent output}

The class derives the following visible wording and layout from the number of
metadata items.  These are the places where changing a one-item list to two or
more items changes more than the retrieved data itself.

\begin{description}
  \item[Project PIs]
    \refCom{printProjectHead} counts the comma-separated PI ids in the
    project's \refKey{ref-person-id} field.  Exactly one id selects the
    singular branch; two or more ids select the plural branch.  The field is
    required, so an empty list is invalid metadata; internally it falls back
    to the singular branch.

    This PI count controls all of the following output:
    \par\noindent\textbullet\space the heading \enquote{Project leader} or
        \enquote{Project leaders};
    \par\noindent\textbullet\space the \cs{getPersonInformation} layout, which
        shows one PI in a single card and several PIs in a two-column raster
        of cards;
    \par\noindent\textbullet\space contract question C1, which uses
        \enquote{project leader at the institution} or
        \enquote{project leaders at the institutions};
    \par\noindent\textbullet\space contract question C2, which switches between
        \enquote{Does the above mentioned person hold a fixed-term position?}
        and \enquote{Do any of the above mentioned persons hold fixed-term
        positions?};
    \par\noindent\textbullet\space contract question C3, which switches between
        \enquote{Will the above mentioned person} and
        \enquote{Will one or more of the above-mentioned persons};
    \par\noindent\textbullet\space contract question C4, which again uses singular or plural
        \enquote{project leader(s)} and \enquote{institution(s)}; and
    \par\noindent\textbullet\space contract answers, where PI surnames are appended in parentheses
        only when several PIs must be distinguished.  Lists of dates or other
        follow-up values likewise append surnames when more than one matching
        PI contributes a value.

  \item[Research areas]
    In \refCom{printProjectHead}, one value in the project's
    \refKey{research-area} field produces the heading
    \enquote{Research area}; two or more values produce
    \enquote{Research areas}.

  \item[Applicant affiliations]
    \refCom{dfgApplicantAffiliationsTF} selects its first argument for one id
    in |meta.ref-affiliation-id| and its second argument for two or more ids.
    This helper controls:
    \par\noindent\textbullet\space whether the title page prints an additional-applicant block;
    \par\noindent\textbullet\space \enquote{applicant university} or
        \enquote{applicant universities} in the existing-direct-costs table;
    \par\noindent\textbullet\space the Chapter~1 heading \enquote{Research profile of the applicant
        university/universities};
    \par\noindent\textbullet\space \enquote{coordinating university/universities} in the Chapter~4
        bylaws heading; and
    \par\noindent\textbullet\space both the noun and verb in the Chapter~5 declaration:
        \enquote{The applicant university confirms} or
        \enquote{The applicant universities confirm}.

    On the title page, \cs{dfgOtherApplicantAffiliationsTF} applies the
    same rule after the first, coordinating affiliation has been removed:
    exactly two applicant affiliations in total produce
    \enquote{Other applicant university}, while three or more produce
    \enquote{Other applicant universities}.

  \item[Existing-staff overview]
    \refCom{OverviewExistingStaffTable} uses the number of applicant
    affiliations for its spanning group heading: one applicant id produces
    \enquote{applicant university}, while several produce
    \enquote{applicant universities}.  Other affiliation columns do not
    affect this wording.

  \item[One-, two-, and longer-item lists]
    Several formatters change punctuation rather than nouns.  In prose,
    \refCom{getPI}, \refCom{getProject}, \refCom{getProjectPI}, and
    \refCom{getPIProject} print one item without a separator, two items with
    \enquote{and}, and three or more with commas plus a final
    \enquote{and}.  Project and PI references inside tables instead use compact
    slash separators.  The complete applicant-name, applicant-location, and
    other-applicant lists exposed by \cs{theCRCaffiliation},
    \cs{theCRCaffiliationLocation}, and
    \cs{theCRCOtherApplicantAffiliations} use the same natural-language rule.
    \refCom{printList}|{ResearchAreasFromProjects}| uses a comma for exactly
    two items and a final \enquote{and} for lists of three or more.
\end{description}

Fixed text written directly in project content is not altered automatically;
authors must choose its singular or plural form themselves.

\section{Project-area entries in the contents}
\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*}


\section{Optional inputs and diagnostics}
\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}


\section{Troubleshooting}

The class reports missing or inconsistent data in the terminal and the
\texttt{.log} file.  If your editor does not collect those messages, this
command shows the class messages together:

\begin{dispListing*}{title={Show DFG class messages in a log file}}
grep 'Package dfg' <filename>.log
\end{dispListing*}

\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}

\section{Complete shared metadata for the examples}
\label{sec:manual-fixtures}
The following records define the people, institutions, affiliations, and
projects used throughout the live examples. They are extracted from the same
DTX records loaded by this manual and generated into
|local/metadata/dfg-metadata.tex| for the local proposal and CV. Matching career
records are generated into |local/metadata/dfg-metadata-cv.tex|. The shared data
are listed once here to avoid repeating the setup before every PI and project
table. Adapt these declarations for your own consortium, then use the table and
list commands from the walkthrough. The final command produces the project-leader table already shown
in the general-information section.

\dfgTableSetup{pis}{Shared input records for the proposal examples}

\section{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 focused targets \texttt{make test-command-options} and
\texttt{make test-participating-institutions} run 30 argument/option checks and
10 layout cases, respectively. The command-options fixture also checks
14 document-text cases: the generic date, early customization, later settings,
direct redefinitions, deferred references, and local scope. Both targets are
included in \texttt{make check}.
The general regression fixture lives in \texttt{ci/test-template.tex}; its
build copy is \texttt{local/test-template.tex}. The manual scratch file
\texttt{local/test.tex} is neither generated nor compiled by these checks.

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{Maintaining executable examples}
The driver uses |documentation=true| to keep the class typography and rendering
commands while loading its fixtures explicitly. This option defaults to false;
it suppresses automatic proposal customization, metadata, and bibliography
inputs. It is intended for this manual, not for ordinary proposals.
The fixtures and the manual driver are maintained in the DTX. A documentation
build extracts them again, so the manual needs no private proposal files.

Add runnable examples with the manual's |dfgExample| environment. Its required
argument is the title; add a stable |label={ex:manual-name}| option and refer
to it from the relevant command description with |\dfgExampleRef{ex:manual-name}|.
Add |dfg wide| to the options for full-width output
below the code. Each example executes the displayed code in a local group.
Floating output is set to non-floating inside the result panel. Use the
fictional IDs |per1|, |per2|, |ins1|, |aff1|, and |A01| where possible.
Use |dfg project=A03| on the example environment when an example needs a
current-project context, and explain that context in the surrounding text.
Keep data-only declarations, incomplete preamble fragments, full-document
project wrappers, external commands, and BibTeX records in |dispListing|.
The shared project and PI metadata are listed once with |\dfgTableSetup|
in the reference chapter; live table examples and the generated local proposal
use those same records. Maintain matching |cv-person-id| career records in the
|meta-cv| block and fictional bibliography records with |person-id-A| or
|person-id-B| keywords for every PI included in the example CV appendix.
Project-boundary examples show labelled excerpts from the standalone proposal,
because those commands change pages, headers, and bibliography scope.
Running |make doc| checks that the PDFs contain all fifteen active project
chapters, the ending-project example, and twelve PI CVs before compiling the
manual. Inspect the PDF
as well as the build log after changing a layout example.

\chapter{Complete example proposal}
\label{chap:complete-example-proposal}
The following pages show the complete fictional proposal generated from this
DTX using the same metadata as the documentation examples: twelve PIs, six
projects in area A, six in area B, and three in area Q. The title page, general
information, financial overviews, all fifteen active project descriptions, the
former project A00, bylaws, declarations, and back matter are included.
The scientific text, people, figures, and funding values are illustrative.

The proposal is built with |final=true|, which suppresses draft tags and margin
diagnostics. Each imported page is reduced to 82\% and framed, with an
\enquote{Example proposal} label above it. The proposal's own page numbers,
headers, and thumb index remain inside the frame; the manual page number appears
below it, clearly separating the two documents.
For the proposal's own clickable references and bookmarks, open the accompanying
\href{dfg-crc-proposal-example.pdf}{standalone example proposal PDF}.

To regenerate the manual and both complete examples from the DTX, run |make doc| in the template
repository. Use |make proposal-doc-example| to build only the standalone
example. Both the local proposal and the final-mode documentation build use
the same metadata and chapter inputs in |local/|. Its generated wrapper is:
\begin{dispListing}
\PassOptionsToClass{final=true}{dfg-crc}
\input{crc-proposal.tex}
\end{dispListing}

\IfFileExists{dfg-crc-proposal-example.pdf}{%
  \includepdf[pages=-,scale=0.82,frame=true,fitpaper=false,
    pagecommand={\dfgDocImportedPage{Example proposal}},
    link=true,linkname=example-proposal]{dfg-crc-proposal-example.pdf}%
}{%
  \PackageError{dfg-crc documentation}{Complete example proposal PDF missing}
    {Run make proposal-doc-example before compiling the manual.}%
}

\chapter{Complete example CV appendix}
\label{chap:complete-example-cv}
The following pages contain the complete fictional CV appendix generated from
|crc-cv.tex| and the shared consortium metadata. It includes the cover, contents,
and all twelve PI CVs. Each shows three career stages, supplementary research
information, activities, supervision, distinctions, and further information,
followed by two category-A articles, a category-B dataset, and the privacy
statement. The bibliography records
are explicitly fictional and use person-specific selection keywords such as
|per12-A| and |per12-B|. Replace them with real publications and the appropriate keywords,
as explained in Section~\ref{sec:manual-cv-publications}. See \dfgExampleRef{ex:manual-generate-the-cv-appendix-or-select-one-person}
for the code that selects all PIs or one person.

As with the proposal, the CV is built with |final=true|. Every imported page
is reduced to 82\%, framed, and labelled \enquote{Example CV appendix}; the
manual page number stays outside the frame. Open the accompanying
\href{dfg-crc-cv-example.pdf}{standalone example CV PDF} for its own clickable
references and bookmarks. Run |make cv-doc-example| to regenerate just that
PDF, or |make doc| to rebuild both examples and this manual from the DTX.

\IfFileExists{dfg-crc-cv-example.pdf}{%
  \includepdf[pages=-,scale=0.82,frame=true,fitpaper=false,
    pagecommand={\dfgDocImportedPage{Example CV appendix}},
    link=true,linkname=example-cv]{dfg-crc-cv-example.pdf}%
}{%
  \PackageError{dfg-crc documentation}{Complete example CV PDF missing}
    {Run make cv-doc-example before compiling the manual.}%
}

\DocInput{\jobname.dtx}
\appendix
\chapter{Repository guide}
\markdownInput{README.md}
\chapter{Licence}
\markdownInput{LICENCE.md}
\printbibliography
\end{document}
%</driver>
% \fi
% \chapter{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
% \section{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}
% \subsection{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
  Check~the~key~spelling~and~the~keys~documented~for~this~family.~^^J
  The~value~was~supplied~\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 field is simply not created for the rejected value, and
%   subsequent keys in the same \refCom{addEntry} call continue to be parsed.
%   Diagnostics list input values users can supply, not internal variable
%   names. List-valued keys report each rejected item separately, preserving
%   valid items. Format checks use |invalid-format| with examples; handlers
%   that replace an invalid choice use |invalid-value-fallback| and name the
%   replacement. Date warnings explicitly state that the input is retained.
%    \begin{macrocode}
\msg_new:nnn { dfg } { invalid-value }
{
  Invalid~value~'#1'~for~key~'\l_keys_path_str'.~^^J^^J
  Allowed~values~are:~'#2'.~^^J
  This~value~is~ignored.~^^J
  The~value~was~supplied~\msg_line_context:.
}
\msg_new:nnn { dfg } { invalid-value-fallback }
{
  Invalid~value~'#1'~for~key~'\l_keys_path_str'.~^^J^^J
  Allowed~values~are:~'#2'.~^^J
  Using~'#3'~instead.~^^J
  The~value~was~supplied~\msg_line_context:.
}
\msg_new:nnn { dfg } { invalid-format }
{
  Invalid~value~'#1'~for~key~'\l_keys_path_str'.~^^J^^J
  Expected~#2.~This~value~is~ignored.~^^J
  The~value~was~supplied~\msg_line_context:.
}
\msg_new:nnn { dfg } { unknown-name }
{
  Unknown~#1~'#2'.~^^J
  Allowed~values~are:~'#3'.~^^J
  A~mismatch~marker~is~printed.~^^J
  The~value~was~used~\msg_line_context:.
}
\msg_new:nnn { dfg } { unknown-institution-order }
{
  Invalid~order~'#1'~for~ParticipatingInstitutions.~^^J
  Allowed~values~are:~'alpha,~count'.~Using~'alpha'~instead.~^^J
  The~order~was~supplied~\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.
}
\msg_new:nnn { dfg } { plot-current-project-missing }
{
  Cannot~print~the~'#1'~plot:~no~current~project~has~been~set.~Start~a~
  project~first,~or~pass~an~explicit~project~ID.
}
%    \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 }
{
  Invalid~date~'#2'~for~key~'\l_keys_path_str'~(field~'#1').~^^J
  Expected~YYYY-MM-DD,~for~example~2026-10-11,~or~an~empty~value.~^^J
  The~supplied~value~is~retained;~correct~its~format~in~the~source.~^^J
  The~value~was~supplied~\msg_line_context:.
}
%    \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-institution-required }
{
  RequestedFundingStaff~entry~for~project~'#1'~has~neither~ref-person-id~nor~
  ref-institution-id.~Provide~ref-institution-id~when~the~person~is~not~
  referenced;~otherwise~the~institution~cannot~be~resolved.
}
\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 } { duplicate-institution-abbreviation }
{
  Institution~abbreviation~'#1'~is~assigned~to~different~institutions:~^^J
  '#2'~and~'#3'~(institution~ids:~#4).~^^J
  Use~a~unique~abbreviation~for~each~institution.
}
\msg_new:nnn { dfg } { duplicate-entry-id }
{
  Duplicate~id~'#2'~in~database~'#1'.~^^J
  The~earlier~row(s)~are~removed;~the~later~entry~replaces~them.~^^J
  The~replacement~is~\msg_line_context:.
}
\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}
% \subsection{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,
  BCOR      =5mm,
  headings  =optiontoheadandtoc,
  parskip   =half-,
  numbers   =noenddot,
  toc       =indentunnumbered
}{scrbook}
%    \end{macrocode}
% \subsection{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}
% The manual loads explicit example inputs, independent of proposal files.
%    \begin{macrocode}
documentation .bool_set:N = \l_@@_class_documentation_bool,
documentation .initial:n = false,
%    \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{fastcompile-project-show-funding-tables}: Retain the three
% project-local funding tables in aggressive project drafting mode.  The
% option defaults to |true| and has no effect outside that mode.
%    \begin{macrocode}
fastcompile-project-show-funding-tables .bool_set:N = \l_@@_class_fastcompile_project_show_funding_tables_bool,
fastcompile-project-show-funding-tables .initial:n  = true,
%    \end{macrocode}
% \refKey{fastcompile-show-tags}: Enables provenance overlays during fast
% compilation. Focused project lookups show their source row and requested
% field path because metadata rows are skipped.
%    \begin{macrocode}
fastcompile-show-tags .bool_set:N = \l_@@_class_fastcompile_show_tags_bool,
fastcompile-show-tags .initial:n  = false,
%    \end{macrocode}
% \refKey{showtags}: Enables provenance overlays for direct database values and
% concise source labels for calculated values in ordinary builds. During fast
% compilation, \refKey{fastcompile-show-tags} controls the setting instead.
%    \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_true:N  \l_@@_class_fastcompile_project_show_funding_tables_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_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_if:NTF \l_@@_class_fastcompile_show_tags_bool
      { \bool_set_true:N \l_@@_class_showtags_bool }
      { \bool_set_false:N \l_@@_class_showtags_bool }
  }
}
\LoadClass{scrbook}
\PassOptionsToPackage{table}{xcolor} % getting rid of errors and conflicts.
\RequirePackage{xcolor}
%    \end{macrocode}
% \subsection{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.
% \subsection{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}
% Public document text exists before the customization file is read. Keep
% externally supplied definitions (including InfoTeX from the build command).
\providecommand{\dfgLocation}{
  \bool_if:NTF \l_@@_class_fastcompile_bool
    { \textcolor{error}{<Location>} }
    { <Location> }\xspace
}
\providecommand{\dfgDate}{
  \bool_if:NTF \l_@@_class_fastcompile_bool
    { \textcolor{error}{<date>} }
    { <date> }\xspace
}
\providecommand{\dfgTitle}{\enquote{\get[meta]{crc}{name}}\xspace}
\providecommand{\InfoTeX}{LuaLaTeX~ (via~ Overleaf).}
\bool_new:N \l_@@_custom_thumbindex_topmargin_set_bool
\bool_new:N \l_@@_custom_thumbindex_bottommargin_set_bool
\dim_new:N \l_@@_custom_thumbindex_topmargin_dim
\dim_new:N \l_@@_custom_thumbindex_bottommargin_dim
\int_new:N \l_@@_custom_thumbindex_rotation_int
\tl_new:N \l_@@_custom_pi_contact_style_tl
\keys_define:nn { dfg / custom  }
{
  % Assign without expansion; metadata references resolve when printed.
  dfgLocation .code:n = \cs_set:Npn \dfgLocation {#1\xspace},
  dfgDate     .code:n = \cs_set:Npn \dfgDate {#1\xspace},
  dfgTitle    .code:n = \cs_set:Npn \dfgTitle {#1\xspace},
  InfoTeX     .code:n = \cs_set:Npn \InfoTeX {#1},

  % 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,
  PIReferenceFirstName .bool_set:N =
    \l_@@_custom_pi_reference_firstname_bool,
  PIReferenceFirstName .initial:n = false,
  % Project tables use full institution names by default. Set true for
  % compact abbreviations and a table-local full-name legend.
  projectsTableInstitutionAbbreviations .bool_set:N =
    \l_@@_custom_projects_table_institution_abbreviations_bool,
  projectsTableInstitutionAbbreviations .initial:n = false,
  % Contact labels in PI boxes: icons (default), text labels, or no labels.
  PIcontactStyle .tl_set:N = \l_@@_custom_pi_contact_style_tl,
  PIcontactStyle .initial:n = icons,
  % 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  = 126600,
  salary@groupLeader          .fp_set:N   = \l_@@_custom_salary_group_leader_fp,
  salary@groupLeader          .initial:n  = 105000,
  salary@postDoc              .fp_set:N   = \l_@@_custom_salary_postdoc_fp,
  salary@postDoc              .initial:n  = 90600,
  salary@medDoc               .fp_set:N   = \l_@@_custom_salary_meddoc_fp,
  salary@medDoc               .initial:n  = 112200,
  salary@PhD                  .fp_set:N   = \l_@@_custom_salary_phd_fp,
  salary@PhD                  .initial:n  = 83700,
  salary@research             .fp_set:N   = \l_@@_custom_salary_research_fp,
  salary@research             .initial:n  = 69000,
  salary@nonResearch          .fp_set:N   = \l_@@_custom_salary_nonresearch_fp,
  salary@nonResearch          .initial:n  = 61500,
  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 text block into \meta{pattern} equal-height slots by
  % default.  Explicit page-edge margins can override either end of the stack.
  % 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 .code:n =
    {
      \str_if_eq:nnTF {#1} {auto}
        { \bool_set_false:N \l_@@_custom_thumbindex_topmargin_set_bool }
        {
          \dim_set:Nn \l_@@_custom_thumbindex_topmargin_dim {#1}
          \bool_set_true:N \l_@@_custom_thumbindex_topmargin_set_bool
        }
    },
  thumbindex@topmargin .initial:n = auto,
  %
  thumbindex@bottommargin .code:n =
    {
      \str_if_eq:nnTF {#1} {auto}
        { \bool_set_false:N \l_@@_custom_thumbindex_bottommargin_set_bool }
        {
          \dim_set:Nn \l_@@_custom_thumbindex_bottommargin_dim {#1}
          \bool_set_true:N \l_@@_custom_thumbindex_bottommargin_set_bool
        }
    },
  thumbindex@bottommargin .initial:n = auto,
  %
  thumbindex@width     .dim_set:N  = \l_@@_custom_thumbindex_width_dim,
  thumbindex@width .initial:n  = 1.2cm,
  %
  thumbindex@orientation .choice:,
  thumbindex@orientation / outwards .code:n =
    \int_zero:N \l_@@_custom_thumbindex_rotation_int,
  thumbindex@orientation / inwards .code:n =
    \int_set:Nn \l_@@_custom_thumbindex_rotation_int {180},
  thumbindex@orientation .initial:n = outwards,
  thumbindex@orientation .value_required:n = true,
  %
  thumbindex@font .tl_set:N = \l_@@_custom_thumbindex_font_tl,
  thumbindex@font .initial:n = \bfseries\Huge,
  % \paragraph{Bibliography keys}
  % |emphasizeAuthors| controls the bold-name mechanism.  When true (the
  % default), it marks every PI's name in bold across all bibliography and
  % citation lists.
  % |emphasizeEntries| independently bolds entire bibliography entries with
  % the current project ID plus |-highlight| in project lists, or with
  % |frametext-highlight| in the frame-text list.
  % 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,
  emphasizeEntries           .bool_set:N = \l_@@_custom_emphasize_entries_bool,
  emphasizeEntries           .initial:n  = false,
  %
  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 = {},
  % 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@reference@PI .tl_set:N           = \l_@@_custom_referencePI_tl,
  color@reference@PI .initial:n          = black,
  color@reference@WP .tl_set:N           = \l_@@_custom_referenceWP_tl,
  color@reference@WP .initial:n          = black,
  color@reference@Aim .tl_set:N          = \l_@@_custom_referenceAim_tl,
  color@reference@Aim .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} }
%    \end{macrocode}
% Read live storage, not cached input: typed values are normalised, grouped
% changes unwind, and internal overrides remain visible. Keep the registry
% in sync with all public keys in |dfg/custom|.
%    \begin{macrocode}
\prop_const_from_keyval:Nn \c_@@_custom_getters_prop
  {
    font = { \tl_use:N \l_@@_custom_font_tl },
    fontspec = { \tl_use:N \l_@@_custom_fontspec_tl },
    sansfont = { \tl_use:N \l_@@_custom_sansfont_tl },
    sansfontspec = { \tl_use:N \l_@@_custom_sansfontspec_tl },
    crcLogoPath = { \tl_use:N \l_@@_custom_crc_logo_path_tl },
    affiliationLogoPath = { \tl_use:N \l_@@_custom_affiliation_logo_path_tl },
    projectPIOncePerSection = { \bool_if:NTF \l_@@_custom_project_pi_once_per_section_bool {true} {false} },
    PIReferenceFirstName = { \bool_if:NTF \l_@@_custom_pi_reference_firstname_bool {true} {false} },
    projectsTableInstitutionAbbreviations = { \bool_if:NTF \l_@@_custom_projects_table_institution_abbreviations_bool {true} {false} },
    PIcontactStyle = { \tl_use:N \l_@@_custom_pi_contact_style_tl },
    collaborationAreaColors = { \tl_use:N \l_@@_custom_collaboration_area_colors_tl },
    salary@prof = { \fp_use:N \l_@@_custom_salary_prof_fp },
    salary@groupLeader = { \fp_use:N \l_@@_custom_salary_group_leader_fp },
    salary@postDoc = { \fp_use:N \l_@@_custom_salary_postdoc_fp },
    salary@medDoc = { \fp_use:N \l_@@_custom_salary_meddoc_fp },
    salary@PhD = { \fp_use:N \l_@@_custom_salary_phd_fp },
    salary@research = { \fp_use:N \l_@@_custom_salary_research_fp },
    salary@nonResearch = { \fp_use:N \l_@@_custom_salary_nonresearch_fp },
    salary@student = { \fp_use:N \l_@@_custom_salary_student_fp },
    salary@assistant = { \fp_use:N \l_@@_custom_salary_assistant_fp },
    animalHousing@mouse = { \fp_use:N \l_@@_custom_animal_mouse_fp },
    animalHousing@mouseGnotobiotic = { \fp_use:N \l_@@_custom_animal_mouse_gnotobiotic_fp },
    animalHousing@rat = { \fp_use:N \l_@@_custom_animal_rat_fp },
    thumbindex = { \bool_if:NTF \l_@@_custom_thumbindex_bool {true} {false} },
    thumbindex@pattern = { \int_use:N \l_@@_custom_thumbindexpattern_int },
    thumbindex@width = { \dim_use:N \l_@@_custom_thumbindex_width_dim },
    thumbindex@font = { \tl_use:N \l_@@_custom_thumbindex_font_tl },
    doiAPIMail = { \tl_use:N \l_@@_custom_doi_api_mail_tl },
    emphasizeAuthors = { \bool_if:NTF \l_@@_custom_emphasize_authors_bool {true} {false} },
    emphasizeEntries = { \bool_if:NTF \l_@@_custom_emphasize_entries_bool {true} {false} },
    biblatexstyleCV = { \tl_use:N \l_@@_custom_biblatexstyle_cv_tl },
    biblatexstyleFeatureCV = { \tl_use:N \l_@@_custom_biblatexfeatures_cv_tl },
    biblatexstyleProposal = { \tl_use:N \l_@@_custom_biblatexstyle_proposal_tl },
    biblatexstyleFeatureProposal = { \tl_use:N \l_@@_custom_biblatexfeatures_proposal_tl },
    color@reference@boldAuthor = { \tl_use:N \l_@@_custom_referenceBoldAuthor_tl },
    color@reference@PI = { \tl_use:N \l_@@_custom_referencePI_tl },
    color@reference@WP = { \tl_use:N \l_@@_custom_referenceWP_tl },
    color@reference@Aim = { \tl_use:N \l_@@_custom_referenceAim_tl },
    color@gantt@frame = { \tl_use:N \l_@@_custom_gantt_frame_tl },
    color@gantt@default = { \tl_use:N \l_@@_custom_gantt_default_tl },
    color@gantt@alternative = { \tl_use:N \l_@@_custom_gantt_alternative_tl },
    color@gantt@crosshatch = { \tl_use:N \l_@@_custom_gantt_crosshatch_tl },
    color@gantt@important = { \tl_use:N \l_@@_custom_gantt_important_tl },
    color@gantt@stripe-one = { \tl_use:N \l_@@_custom_gantt_stripe_one_tl },
    color@gantt@stripe-two = { \tl_use:N \l_@@_custom_gantt_stripe_two_tl },
    color@table@headingsBG = { \tl_use:N \l_@@_custom_tableHeadingsBG_tl },
    color@table@headingsBGalt = { \tl_use:N \l_@@_custom_tableHeadingsBGalt_tl },
    color@table@headingsFont = { \tl_use:N \l_@@_custom_tableHeadingsFont_tl },
    color@table@rows = { \tl_use:N \l_@@_custom_tableRows_tl },
    color@table@lines = { \tl_use:N \l_@@_custom_tableLines_tl },
    color@table@outerLines = { \tl_use:N \l_@@_custom_tableOuterLines_tl },
    color@table@noValue = { \tl_use:N \l_@@_custom_tableNoValue_tl },
    color@table@firstColumn = { \tl_use:N \l_@@_custom_tableFirstColumn_tl },
    color@table@link = { \tl_use:N \l_@@_custom_tableLink_tl },
    color@table@contFootHead = { \tl_use:N \l_@@_custom_tableContFootHead_tl },
    color@table@caption = { \tl_use:N \l_@@_custom_tableCaption_tl },
    color@thumbindex@bg = { \tl_use:N \l_@@_custom_thumbIndexBG_tl },
    color@thumbindex@font = { \tl_use:N \l_@@_custom_thumbIndexFont_tl },
    color@tags@font = { \tl_use:N \l_@@_custom_colorTagsFont_tl },
    color@tags@line = { \tl_use:N \l_@@_custom_colorTagsLine_tl },
    color@font@alternative = { \tl_use:N \l_@@_custom_colorfontalternative_tl },
    color@item@i = { \tl_use:N \l_@@_custom_color_item_i_tl },
    dfgLocation = { \dfgLocation },
    dfgDate = { \dfgDate },
    dfgTitle = { \dfgTitle },
    InfoTeX = { \InfoTeX },
    collaborationAreaPalette = { \tl_use:N \l_@@_custom_collaboration_area_palette_tl },
    thumbindex@topmargin = { \bool_if:NTF \l_@@_custom_thumbindex_topmargin_set_bool { \dim_use:N \l_@@_custom_thumbindex_topmargin_dim } {auto} },
    thumbindex@bottommargin = { \bool_if:NTF \l_@@_custom_thumbindex_bottommargin_set_bool { \dim_use:N \l_@@_custom_thumbindex_bottommargin_dim } {auto} },
    thumbindex@orientation = { \int_compare:nNnTF {\l_@@_custom_thumbindex_rotation_int} = {0} {outwards} {inwards} },
    biblatexstyle = { \bool_if:NTF \l_@@_class_cv_bool {\tl_use:N \l_@@_custom_biblatexstyle_cv_tl} {\tl_use:N \l_@@_custom_biblatexstyle_proposal_tl} },
    biblatexstyleFeature = { \bool_if:NTF \l_@@_class_cv_bool {\tl_use:N \l_@@_custom_biblatexfeatures_cv_tl} {\tl_use:N \l_@@_custom_biblatexfeatures_proposal_tl} }
  }
\msg_new:nnn { dfg } { unknown-customization-value }
  { Unknown~customization~key~'#1'~in~\string\getValue.
    ~Use~a~key~supported~by~\string\changeSettings. }
\cs_new:Npn \@@_get_custom_value:n #1
  {
    \prop_if_in:NnTF \c_@@_custom_getters_prop {#1}
      { \exp_args:Ne \use:n { \prop_item:Nn \c_@@_custom_getters_prop {#1} } }
      { \msg_expandable_error:nnn {dfg} {unknown-customization-value} {#1} }
  }
\NewExpandableDocumentCommand \getValue { m }
  { \exp_args:Ne \@@_get_custom_value:n { \tl_trim_spaces:n {#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 }
\bool_if:NF \l_@@_class_documentation_bool
{
\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}
% \subsection{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 two-sided A4 layout uses a 25\,mm inner margin plus the KOMA-Script
% |BCOR| binding correction (initially 5\,mm), and a 20\,mm outer margin.
% Geometry applies |BCOR| as its binding offset, leaving a 160\,mm text block
% at the default setting.  The outer margin accommodates a 13\,mm note column
% and a 2\,mm separation from the text, with 5\,mm spare.  On verso pages,
% the binding and outer margins, notes, and thumb index all switch sides.
% The top margin is 20\,mm and the bottom margin 15\,mm.  This gives the text
% block 5\,mm more height than the former 20\,mm bottom margin while retaining
% the footer.  Reserve 20\,pt for two-line project running heads.  The
% header remains outside the text block, so its height does not change the
% 20\,mm top margin or the text height.
%    \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,
  headheight     =20pt,
  top            =20mm,
  bottom         =15mm,
  inner          =25mm,
  outer          =20mm,
  bindingoffset  =\ta@bcor,
  marginparsep   =2mm,
  marginparwidth =13mm,
  % 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}
  % Inherited reference colors are resolved at the call site. Keep the
  % concrete alias available for PI tables and other fixed-color layouts.
  \tl_if_eq:NnTF \l_@@_custom_referencePI_tl {current}
    { \colorlet{referencePI}{black} }
    { \colorlet{referencePI}{\l_@@_custom_referencePI_tl} }
  \colorlet{referenceWP}{\l_@@_custom_referenceWP_tl}
  \colorlet{referenceAim}{\l_@@_custom_referenceAim_tl}
  % 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_true:N  \l_@@_class_fastcompile_project_show_funding_tables_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}
% \subsection{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} in |referenceWP| colour.  Bold face is
% scoped to the prefix and label itself so range connectors remain at the
% surrounding font weight.
%
% \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 }
                left=0mm,right=0pt,
         colupper=blue,
  		]
  		\colorlet{referencePI}{tableHeadingsFont}
  		\colorlet{referenceWP}{tableHeadingsFont}
  		\colorlet{referenceAim}{tableHeadingsFont}},
  after={\end{dfgBoxEnv}},
  wide=\parindent,
  leftmargin=*,
  % font=\normalfont,
  % first=\bfseries,
  topsep=3pt,
  font=\bfseries,
  % nosep,
  label={Aim~ \arabic*:},
  ref = {\arabic*},
  %  resume
}
%    \end{macrocode}
% The public |label| option is a prefix, not enumitem's complete label
% format. Keep the original list and counter so existing list settings and
% numeric \cs{ref} values remain valid. A stable type per prefix prevents a
% later list from renaming earlier references. Store its name in the aux file
% so cleveref knows it before constructing formats and forward references on
% the next run. Other enumitem options pass through unchanged.
% Expand the label explicitly: older expl3 releases provide the hash
% function without its V variant.
%    \begin{macrocode}
\tl_new:N \l_@@_aim_label_tl
\tl_new:N \l_@@_aim_options_tl
\tl_new:N \l_@@_aim_type_tl
\keys_define:nn { dfg / aims }
{
  label .tl_set:N = \l_@@_aim_label_tl,
  label .value_required:n = true,
}
\NewCommandCopy\dfgOriginalAims\aims
\NewCommandCopy\dfgOriginalEndAims\endaims
\cs_new_protected:Npn \@@_aims_begin:n #1
  { \dfgOriginalAims[#1] }
\RenewDocumentEnvironment{aims}{ O{} }
{
  \tl_set:Nn \l_@@_aim_label_tl { \q_no_value }
  \keys_set_known:nnN { dfg / aims } {#1} \l_@@_aim_options_tl
  \quark_if_no_value:NF \l_@@_aim_label_tl
  {
    \tl_set:Ne \l_@@_aim_type_tl
      { dfg-aim-\exp_args:NV \str_mdfive_hash:n \l_@@_aim_label_tl }
    \exp_args:NnV \crefalias { aimsi } \l_@@_aim_type_tl
    \protected@write\@auxout{}
    {
      \string\dfgAimReferenceName
        {\l_@@_aim_type_tl}{\exp_not:V \l_@@_aim_label_tl}
    }
    \tl_put_left:Ne \l_@@_aim_options_tl
    {
      label={\exp_not:V \l_@@_aim_label_tl
        \exp_not:n {~\arabic*:}},
      \exp_not:n {ref={\arabic*},}
    }
  }
  \exp_args:NV \@@_aims_begin:n \l_@@_aim_options_tl
}
{ \dfgOriginalEndAims }
%    \end{macrocode}
% \subsection{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{100}{50}\selectfont
            FAST~COMPILE
          }
        }
      }
    }
  }
}
%    \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}
% \subsection{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}.
%  Sections use 12\,pt bold type; subsections and subsubsections use
%  10\,pt type for a compact hierarchy.
%  Section, subsection, and subsubsection headings have one baseline of
%  space above them. Body text starts on the next line with no additional
%  after-skip or first-line indent; zero after-skip does not make a run-in heading.
%  Numbered section and subsection titles use the same 12\,mm number column,
%  so the title text begins at one horizontal position throughout the project
%  information block.  This also gives wrapped titles a matching hang indent.
% 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{10}{10}\selectfont}
\setkomafont{subsubsection}{\fontsize{10}{10}\selectfont}
\renewcommand*{\chapterformat}{\makebox[12mm][l]{\thechapter\autodot}}
\renewcommand*{\sectionformat}{\makebox[12mm][l]{\thesection\autodot}}
\renewcommand*{\subsectionformat}{\makebox[12mm][l]{\thesubsection\autodot}}
\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= 1\baselineskip,
  afterskip= 0pt,
  runin=false,
  afterindent=false
]{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}
% \subsection{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 commands
% =============================================================================

% Store the ORCiD value pulled from the database.
\providecommand{\theORCiDValue}{}

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

% --- Pure value-only lookup (no immediate output) ---------------------------
% Fetch the ORCiD value from the database into \theORCiDValue.
% Useful when the value has already been loaded by a previous multi-fetch step,
% or when formatting is needed later.
\NewDocumentCommand{\getORCiDvalue}{O{person} m}
{%
  % #1: Database (default is person)
  % #2: Person id
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  { \cs_set:Npn \theORCiDValue { } }
  { \DTLgetvalueforkey{\theORCiDValue}{orcid}{#1}{id}{#2} }%
}

% --- Formatting a preloaded ORCiD value ------------------------------------
% Expects \theORCiDValue to be set (for example via \getORCiDvalue or
% per \getEntry*[...]{id}{\theORCiDValue=orcid, ...}).
\NewDocumentCommand{\formatORCiD}{O{person} m}
{%
  % #1: Database (for warnings / tag overlay)
  % #2: Person id (for warnings / 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]%
  }%
}

% --- Convenience command: fetch + format in a single call -------------------
% Keep the same API as the original \getORCiD so existing calls continue
% to work.
\NewDocumentCommand{\getORCiD}{O{person} m}
{%
  % #1: Database (default is person)
  % #2: Person id
  \bool_if:NF \l_@@_class_fastcompile_project_bool
  {
    \getORCiDvalue[#1]{#2}%
    \formatORCiD[#1]{#2}%
  }
}

% --- Inline variant for literal ORCiD values --------------------------------
% For direct values without database lookup.
\NewDocumentCommand{\ORCiD}{m}
{(\raisebox{-1pt}{\orcidIcon}\,\href{https://orcid.org/#1}{#1})}
%    \end{macrocode}
% \subsection{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 |90600| formats as |90,600| 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}
% \subsection{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}
% \subsection{Custom table definition}
% \paragraph{Base Table Theme}
% Defines the shared templates and outer settings used by all table themes.
% The table font size is established as an ambient declaration here instead of
% through a |rows={font=...}| property.  A more specific cell property such as
% |font=\bfseries| replaces a row font property, but it inherits an ambient
% \cs{footnotesize}; an explicit size in the cell property can still override
% the default.
%    \begin{macrocode}
% Reduce tabularray's default 1.5\bigskipamount above every generated table.
% Change presep here to adjust the gap before tables printed by \printTable.
\SetTblrOuter[tblr]{label=none,entry=none,presep=6pt,headsep=4pt}
% For long tables:
\cs_new_protected:Npn \mytblr_basecode: {
  \footnotesize
  % 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}%
  }
  % Keep all text rendered below a table at least at footnote size.
  \SetTblrStyle{note-tag}{font=\footnotesize}
  \SetTblrStyle{note-sep}{font=\footnotesize}
  \SetTblrStyle{note-text}{font=\footnotesize}
  \SetTblrStyle{remark-tag}{font=\footnotesize}
  \SetTblrStyle{remark-sep}{font=\footnotesize}
  \SetTblrStyle{remark-text}{font=\footnotesize}
  % 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{
    % 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,
   font=\footnotesize,
   halign=l
  }
  \SetTblrStyle{caption}{halign=l}
  \SetTblrTemplate{caption}{simple}
  \SetTblrInner{%
  	row{odd}={bg=tableRows},
  	width=\linewidth,
  	hline{1,Z}={1pt,fg=tableOuterLines},
  	rowhead      = 1,
  	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   = .9,
    rowsep    = 1pt,
  	row{1}       = {
  		bg       = tableHeadingsBG,
  		fg       = tableHeadingsFont,
        font     = \bfseries,
  		halign   = {c},
  		valign   = {t},
        abovesep = 3pt,
  		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 generic long-table environment.  Its second argument supplies additional
% tabularray options and defaults to an empty option list.
% Let tabularray measure the caption normally; negative skips can pull it
% into the preceding paragraph or the top rule of the table.
%    \begin{macrocode}
\NewDocumentEnvironment{TableEnv}{ m O{} m m }
{
  % #1: colspec
  % #2: further options
  % #3: caption
  % #4: label
  \par
  \begin{tblr}[%
  	%  expand=\tblrbody,
  	theme=main,
  	label  ={#4},
    entry  ={#3},
  	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}\par}
%    \end{macrocode}
% At the final part of projects the costs must be listed more granularly.
% Keep the optional heading and the unbreakable table in one minipage, so
% the heading cannot be left alone at a page boundary.
% Measure the currency column at its natural width: a fixed 0.5cm column
% is too narrow for EUR in some document fonts.  The X description column
% absorbs the width difference while the amount column stays rightmost.
%    \begin{macrocode}
\NewDocumentEnvironment{FundingDirectCostsTable}{O{}}
{\par\noindent
  \begin{minipage}{\linewidth}
  \tl_if_blank:nF {#1}
    {\noindent\textbf{\sffamily#1}\par}
  \begin{tblr}[%
  	theme=plain, label=none, entry=none]{
  	colspec={
  			X[t]
        Q[t,r]
			Q[t,si={table-format=9}]
  		},
  }
}
{\end{tblr}
  \end{minipage}\par}

%    \end{macrocode}
%    \begin{macrocode}
\RequirePackage{caption}
\captionsetup{%
  % format=llapx,
  hypcap=false,
  format=plain,
  singlelinecheck=off,
  labelsep={colon}, % saving space
  %justification=RaggedRight,
  font={footnotesize,sf},
  labelfont={
  		sf,
  		bf, % bold face
  	}
}
% KOMA's caption name also applies to figures boxed by hvFloat.
\renewcaptionname{english}{\figurename}{Fig.}
\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=13mm,
  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:
          }
      }
  }
% 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}
    }
  }
  {
    \bool_if:NF \l_@@_class_documentation_bool
    {
    \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.
% A second part of the hook selects the full-entry bold face. The frame and
% project bibliography wrappers set a local keyword only while printing
% their list; biblatex groups each item, so the font change does not leak into the
% following entry.  The hook runs after \cs{bibfont} and before the entry's
% fields are printed.
%    \begin{macrocode}
\tl_new:N \l_@@_bibentry_highlight_keyword_tl
\AtEveryBibitem{
  \clearfield{url}
  \clearfield{month}
  \clearfield{note}
  \clearfield{issn}
  \clearfield{isbn}
  \clearlist{language}
  \tl_if_empty:NF \l_@@_bibentry_highlight_keyword_tl
  {
    \exp_args:NV \ifkeyword \l_@@_bibentry_highlight_keyword_tl
      {\bfseries}{}
  }}
%    \end{macrocode}
% \subsection{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}
% \subsection{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}
% enumitem creates a dedicated counter for each custom-list level but does not
% expose the parent relation to cleveref.  Register that relation so nested
% work-package references sort by parent first and ranges never cross parents.
\apptocmd{\cref@resetby}
  {\cref@ifstreq{#1}{workpackagesii}{\def#2{workpackagesi}}{}}
  {}
  {\PackageError{dfg}
    {Unable~to~register~the~nested~work-package~counter}
    {Nested~work-package~references~may~be~sorted~incorrectly.}}
% labelcref requires one reference type for mixed parent/child lists.
% Keep the parent-counter registration above for sorting and range boundaries.
\crefalias{workpackagesii}{workpackagesi}
\crefname{workpackagesi}{\color{referenceWP}\textbf{WP}}{\color{referenceWP}\textbf{WPs}}
\creflabelformat{workpackagesi}{\color{referenceWP}#2\textbf{#1}#3}
\crefname{workpackagesii}{\color{referenceWP}\textbf{WP}}{\color{referenceWP}\textbf{WPs}}
\creflabelformat{workpackagesii}{\color{referenceWP}#2\textbf{#1}#3}

\crefname{aimsi}{\bfseries\color{referenceAim}Aim}{\bfseries\color{referenceAim}Aims}
\creflabelformat{aimsi}{\color{referenceAim}#2\color{referenceAim}\bfseries#1\color{referenceAim}#3}
% Aux-file entry point: use the authored spelling for both reference forms.
\NewDocumentCommand{\dfgAimReferenceName}{m m}
{
  \crefname{#1}{\bfseries\color{referenceAim}#2}
    {\bfseries\color{referenceAim}#2}
  \Crefname{#1}{\bfseries\color{referenceAim}#2}
    {\bfseries\color{referenceAim}#2}
  \creflabelformat{#1}
    {\color{referenceAim}##2\bfseries##1##3}
  % The kernel reads aux files in a group, after cleveref's format setup.
  % Preserve only the names globally; cleveref's format builders already
  % make global definitions without leaking their temporary variables.
  \clist_map_inline:nn { cref,Cref }
  {
    \cs_gset_eq:cc {##1@#1@name} {##1@#1@name}
    \cs_gset_eq:cc {##1@#1@name@plural} {##1@#1@name@plural}
  }
  \@crefdefineallformats{#1}
}


% \subsection{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, only for web documents.
  	%  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}
% \subsection{\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= {},
%     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.
% \subsection{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|.  In the default
% |auto| mode, the margins are derived from the current text-block position and
% \cs{textheight}, so the slot height is \cs{textheight}| / pattern|.  The
% calculation runs when the tab is drawn, allowing later layout changes to
% affect the thumb-index grid.
%
% \textbf{Placement:}
% \cs{thumb\_place\_node:nnnn} draws an absolutely-positioned TikZ node
% on the current page using |remember picture,overlay|.  Its reference point
% is |(current page.north west/east) -| followed by
% |(0, topmargin + height*(index-1/2))|, centering each tab in its slot.
% The rectangular tab has 7pt rounded corners and is shifted 7pt past the
% page boundary, clipping the outer corners while retaining the configured
% visible depth.  Its label is rotated 90 degrees in opposite directions on
% facing pages so the tab stays within the marginal column. The default
% |thumbindex@orientation=outwards| points the tops of the letters towards the
% outer edge. Choosing |inwards| adds 180 degrees to the label rotation on
% both sides, without changing the tab geometry.
% The label is inset 2\,mm towards the text block on either side; paired
% horizontal kerns leave the tab dimensions and placement unchanged.
%
% \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).
% \cs{resetThumbIndex} resets the slot counter so that the next
% \cs{printThumbIndex} call starts at the first slot again.  This is useful
% when a manually inserted section should begin a new thumb-index sequence.
%    \begin{macrocode}
\int_new:N \l_thumb_index_int
\int_zero:N \l_thumb_index_int
%    \end{macrocode}
% The effective margins follow the current text block unless overridden with
% explicit page-edge dimensions.  Calculate them when drawing each tab rather
% than at class load time, when page geometry may not yet be final.
%    \begin{macrocode}
\dim_new:N \l_thumb_height_dim
\dim_new:N \l_thumb_topmargin_dim
\dim_new:N \l_thumb_bottommargin_dim
\cs_new_protected:Npn \thumb_compute_height:
{
  \bool_if:NTF \l_@@_custom_thumbindex_topmargin_set_bool
    { \dim_set_eq:NN \l_thumb_topmargin_dim
        \l_@@_custom_thumbindex_topmargin_dim }
    {
      \dim_set:Nn \l_thumb_topmargin_dim
        { 1in + \voffset + \topmargin + \headheight + \headsep }
    }
  \bool_if:NTF \l_@@_custom_thumbindex_bottommargin_set_bool
    { \dim_set_eq:NN \l_thumb_bottommargin_dim
        \l_@@_custom_thumbindex_bottommargin_dim }
    {
      \dim_set:Nn \l_thumb_bottommargin_dim
        {
          \paperheight
          - ( 1in + \voffset + \topmargin + \headheight + \headsep )
          - \textheight
        }
    }
  \dim_set:Nn \l_thumb_height_dim
    {
      ( \paperheight - \l_thumb_topmargin_dim
        - \l_thumb_bottommargin_dim )
      / \l_@@_custom_thumbindexpattern_int
    }
}
%    \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,
		minimum~ width  = \dim_eval:n
		  { \l_@@_custom_thumbindex_width_dim + 7pt },
		outer~ sep      = 0pt,
  		font            = \tl_use:N \l_@@_custom_thumbindex_font_tl,
		inner~ sep      = 1mm,
  	}
}
%    \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:nnnn #1#2#3#4
{
  %  #1 = west|east    (anchor direction)
  %  #2 = shift past the page edge
  %  #3 = label rotation
  %  #4 = node contents
  \thumb_compute_height:
  \begin{tikzpicture}[remember~ picture,overlay]
  	\node[
  		thumb,
  		anchor  =#1,
		rectangle,
		rounded~ corners=7pt,
		xshift  =#2
  	]
  	% ---------------------------------------------------------
  	%   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_thumb_topmargin_dim
            + \l_thumb_height_dim * (\l_thumb_index_int - 1)
            + \l_thumb_height_dim / 2
  		}) $)
	{
      % Inset the text by 2mm; opposite kerns preserve the tab dimensions.
      \str_if_eq:nnTF {#1}{west}
        {\kern2mm}{\kern-2mm}
      \rotatebox[origin=c]{#3}{#4}
      \str_if_eq:nnTF {#1}{west}
        {\kern-2mm}{\kern2mm}
    };
  \end{tikzpicture}
}

\NewDocumentCommand{\evenpageletterthumb}{m}
{
  \thumb_place_node:nnnn {west}{-7pt}
    {\int_eval:n {90 + \l_@@_custom_thumbindex_rotation_int}}{#1}
}
\NewDocumentCommand{\oddpageletterthumb}{m}
{
  \thumb_place_node:nnnn {east}{7pt}
    {\int_eval:n {-90 + \l_@@_custom_thumbindex_rotation_int}}{#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{\resetThumbIndex}{}
{
  \int_zero:N \l_thumb_index_int
}
\NewDocumentCommand{\printThumbIndexOff}{}
{
  \lehead[]{}
  \lohead[]{}
}
%    \end{macrocode}
% \subsection{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 -----------------------------------

  \bool_if:NTF \l_@@_class_documentation_bool
    {\tl_const:Nn \c_@@_boldnames_bibfile_tl {\jobname-boldAuthors.bib}}
    {\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}
% \subsection{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 { dfg } { invalid-value }
  			{ #1 } { 1 , 2 , 3 }
  		}
  	} ,
  fundingPeriodNumeral / unknown .code:n =
  	{
      \msg_warning:nnnn { dfg } { 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:nnne { dfg } { invalid-value } {##1}
      { \clist_use:Nn \l_@@_keys_tmp_clist {,~} } }
  }
}
%    \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
% |{person-a,person-b,person-c}| and |{person-a, person-b, person-c}| 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} }
  	}
    { \msg_warning:nnnn { dfg } { invalid-value } {#2}
      { yes,~no,~or~an~empty~value } }
  }
}
%    \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
\clist_const:Nn \c_@@_funding_staff_categories_clist
  { prof, groupLeader, postDoc, medDoc, PhD, research,
    nonResearch, student, assistant }
\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},
  positionText .code:n =
  \DTLnewdbentry{\l_@@_database_name_tl}{positionText}{#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
        \clist_if_in:NnTF \c_@@_funding_staff_categories_clist {#1}
  			{
  				\DTLnewdbentry{\l_@@_database_name_tl}{category}{#1}
  			}
  			{
          \msg_warning:nnne { dfg } { invalid-value }{ #1 }
          { \clist_use:Nn \c_@@_funding_staff_categories_clist {,~} }
  			}
  		}
  		{
  			% 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},
}

% Category warnings list the currently registered keys, so the diagnostic
% stays in sync with the category-name property list, including extensions.
\seq_new:N \l_@@_diagnostic_keys_seq
\cs_new_protected:Npn \@@_collect_diagnostic_keys:N #1
{
  \seq_clear:N \l_@@_diagnostic_keys_seq
  \prop_map_inline:Nn #1
    { \seq_put_right:Nn \l_@@_diagnostic_keys_seq {##1} }
}
\cs_new_protected:Npn \@@_warn_unknown_name:nnN #1#2#3
{
  \@@_collect_diagnostic_keys:N #3
  \msg_warning:nneee { dfg } { unknown-name } {#1} {#2}
    { \seq_use:Nn \l_@@_diagnostic_keys_seq {,~} }
}
\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} }
  {
    \@@_collect_diagnostic_keys:N \g_@@_dfg_category_names_prop
    \msg_warning:nnne { dfg } { invalid-value } {#1}
      { \seq_use:Nn \l_@@_diagnostic_keys_seq {,~} }
  }
}

\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-format } {#1}
      { a~non-negative~integer~or~decimal~using~a~decimal~point,
        ~for~example~0,~10,~or~10.5 } }
  },
  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
\tl_new:N \l_@@_requested_funding_staff_validate_institution_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,
  ref-institution-id .tl_set:N =
    \l_@@_requested_funding_staff_validate_institution_tl,
  unknown .code:n = { }
}

\cs_new_protected:Npn
  \@@_requested_funding_staff_warn_missing_institution:
{
  \msg_warning:nne { dfg } { requested-staff-institution-required }
    { \l_@@_requested_funding_staff_validate_project_tl }
}

\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
  \tl_clear:N \l_@@_requested_funding_staff_validate_institution_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 } }
  \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_institution_tl }
  }
  { \@@_requested_funding_staff_warn_missing_institution: }
}
%    \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 }{
        mouse,~ 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:nnnnn { dfg } { invalid-value-fallback }{#1}
      {crosshatch,~striped,~important,~alternative,~default}{default}
  		\DTLnewdbentry{\l_@@_database_name_tl}{style}{default}
  	},
}
%    \end{macrocode}
% \subsection{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.
% In fast-project mode, skipped metadata prevents resolving the destination
% row of a reference chain; the annotation records its source row and full
% requested field path instead.
%
%    \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}
\tl_new:N \l_@@_add_entry_id_tl
\tl_new:N \l_@@_add_entry_existing_row_tl

\keys_define:nn { dfg / add-entry-id-probe }
{
  id      .tl_set:N = \l_@@_add_entry_id_tl,
  unknown .code:n   = { }
}

\cs_new_protected:Npn \@@_add_entry_replace_duplicate_id:n #1
{
  \tl_clear:N \l_@@_add_entry_id_tl
  \keys_set:nn { dfg / add-entry-id-probe } {#1}
  \tl_if_blank:VF \l_@@_add_entry_id_tl
  {
    \DTLifhaskey { \l_@@_database_name_tl } { id }
    {
      \DTLgetrowforkey
        { \l_@@_add_entry_existing_row_tl }
        { \l_@@_database_name_tl }
        { id }
        { \l_@@_add_entry_id_tl }
      \tl_if_blank:VF \l_@@_add_entry_existing_row_tl
      {
        \msg_warning:nnee { dfg } { duplicate-entry-id }
          { \l_@@_database_name_tl }
          { \l_@@_add_entry_id_tl }
        \DTLforeach { \l_@@_database_name_tl }
          { \l_tmpa_tl = id }
        {
          \str_if_eq:VVT \l_tmpa_tl \l_@@_add_entry_id_tl
            { \DTLremovecurrentrow }
        }
      }
    }
    { }
  }
}

\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 } }
  \@@_add_entry_replace_duplicate_id:n {#3}
  \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} }
}

% Focused project builds retain the project rows needed by generated plots when
% images are enabled, plus the rows needed by the three local funding tables.
% In particular, do not populate or restore any proposal-wide overview database
% through the auxiliary file.
\cs_new_protected:Npn \@@_fast_project_add_entry:nnn #1#2#3
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_images_bool
  {
    \str_if_eq:nnT {#1/#2} {/project}
      { \@@_add_entry:nnn {project} {project} {#3} }
    \str_if_eq:nnT {#1} {gantt}
      { \@@_add_entry:nnn {#1} {#2} {#3} }
  }
  \bool_if:NT \l_@@_class_fastcompile_project_show_funding_tables_bool
  {
    \str_case:nn {#1/#2}
    {
      {funding/RequestedFunding}
      {
        \@@_add_entry:nnn {#1} {#2} {#3}
        \@@_funding_cache_entry:nn {#2} {#3}
      }
      {staff/RequestedFundingStaff}
        { \@@_add_entry:nnn {#1} {#2} {#3} }
      {funding/RequestedAndExistingFundingDirectCosts}
      {
        \@@_add_entry:nnn {#1} {#2} {#3}
        \@@_funding_cache_entry:nn {#2} {#3}
      }
    }
  }
}

% Retain only the database-to-keyset mapping when focused builds skip rows.
% The get parser needs the schema to consume reference paths without values.
\prop_new:N \g_@@_database_keyset_prop
\NewDocumentCommand \addEntry { O{} m m }
{
  \tl_if_blank:nTF {#1}
    {\prop_gput:Nnn \g_@@_database_keyset_prop {#2}{#2}}
    {\prop_gput:Nnn \g_@@_database_keyset_prop {#2}{#1}}
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
  { \@@_fast_project_add_entry:nnn {#1} {#2} {#3} }
  {
  \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 }
{ { \textcolor{error}{\texttt{<#1>}} } }

% Project IDs stay prominent when metadata lookups are skipped. Scope the
% style locally so following text and error diagnostics keep their colours.
\cs_new_protected:Npn \@@_fast_project_reference:n #1
{ \dfgFastReference{#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} }
    {
      \dfgShowTag {#3}{#4}
        {
          \str_if_eq:eeTF {#2} {project}
            { \@@_fast_project_reference:n {#3} }
            { \dfgFastReference{#3} }
        }
        [#2]
    }
  }
  {
    \IfBooleanTF{#1}
    { \@@_get_entry_multi:nnnn  {#2}{#3}{#4}{#5} }
    { \@@_get_entry_single:nnnn {#2}{#3}{#4}{#5} }%
  }
}

%    \end{macrocode}
% \paragraph{Reference-aware lookup (\cs{get})}
% Parse relation steps before rendering, so metadata containing braces cannot
% become part of the path. The walker carries its path in arguments rather
% than shared scratch variables; this also permits branching reference lists.
%    \begin{macrocode}
\tl_new:N \l_@@_get_path_db_tl
\tl_new:N \l_@@_get_path_id_tl
\tl_new:N \l_@@_get_path_id_field_tl
\tl_new:N \l_@@_get_path_scan_db_tl
\tl_new:N \l_@@_get_path_field_tl
\tl_new:N \l_@@_get_path_tl
\tl_new:N \l_@@_get_path_keyset_tl
\tl_new:N \l_@@_get_path_target_tl
\tl_new:N \l_@@_get_path_value_tl
\seq_new:N \l_@@_get_path_values_seq
\seq_new:N \l_@@_get_path_annotation_seq
\prop_new:N \l_@@_get_path_seen_prop

\NewDocumentCommand{\get}{s O{\tmpLocalDB} m m O{id}}
{
  \IfBooleanTF{#1}
    {\getEntry*[#2]{#3}{#4}[#5]}
    {
      \group_begin:
      \tl_set:Ne \l_@@_get_path_db_tl {#2}
      \tl_set:Ne \l_@@_get_path_id_tl {#3}
      \tl_set:Nn \l_@@_get_path_id_field_tl {#5}
      \tl_set_eq:NN \l_@@_get_path_scan_db_tl \l_@@_get_path_db_tl
      \tl_clear:N \l_@@_get_path_tl
      \seq_clear:N \l_@@_get_path_annotation_seq
      \@@_get_path_scan:n {#4}
    }
}

\prg_new_protected_conditional:Npnn \@@_get_path_if_has_key:nn #1#2 {TF}
{
  \datatool_if_has_key:nnTF {#1}{#2}
    {\prg_return_true:}
    {
      \prop_get:NnNF \g_@@_database_keyset_prop {#1}
        \l_@@_get_path_keyset_tl
        {\tl_set:Nn \l_@@_get_path_keyset_tl {#1}}
      \exp_args:NV \keys_if_exist:nnTF \l_@@_get_path_keyset_tl {#2}
        {\prg_return_true:}{\prg_return_false:}
    }
}
\prg_generate_conditional_variant:Nnn \@@_get_path_if_has_key:nn {Vn} {TF}

\cs_new_protected:Npn \@@_get_path_scan:n #1
{
  \tl_put_right:Nn \l_@@_get_path_tl {{#1}}
  \seq_put_right:Nn \l_@@_get_path_annotation_seq {#1}
  \tl_set:Nn \l_@@_get_path_field_tl {#1}
  \tl_set:Nn \l_@@_get_path_target_tl {#1}
  \regex_match:nnTF {\A ref-.+-id \Z} {#1}
    {
      \regex_replace_once:nnN {\A ref-(.+)-id \Z} {\1}
        \l_@@_get_path_target_tl
      \@@_get_path_next:
    }
    {
      % An actual scalar field takes precedence over a database shorthand.
      \@@_get_path_if_has_key:VnTF \l_@@_get_path_scan_db_tl {#1}
        {\@@_get_path_finish:}
        {
          \@@_get_path_if_has_key:VnTF \l_@@_get_path_scan_db_tl {ref-#1-id}
            {\@@_get_path_next:}
            {
              \DTLifdbexists{#1}
                {\@@_get_path_next:}
                {\@@_get_path_finish:}
            }
        }
    }
}
% xparse preserves following prose when no optional braced step is present.
\NewDocumentCommand{\@@_get_path_next:}{g}
{
  \IfNoValueTF{#1}
    {\@@_get_path_finish:}
    {
      \tl_set_eq:NN \l_@@_get_path_scan_db_tl \l_@@_get_path_target_tl
      \@@_get_path_scan:n {#1}
    }
}

\cs_new_protected:Npn \@@_get_path_missing:nnn #1#2#3
{
  \tl_clear:N \l_@@_get_path_value_tl
  \bool_if:NF \lTblrMeasuringBool
    {\msg_warning:nnnnn {dfg}{missing-key}{#1}{#2}{#3}}
}
\cs_new_protected:Npn \@@_get_path_read:nnnn #1#2#3#4
{
  \tl_clear:N \l_@@_get_path_value_tl
  \tl_if_blank:nTF {#1}
    {\msg_warning:nnn {dfg}{database-name-not-given}{#2-/-#3}}
    {
      \DTLifdbexists{#1}
        {
          \datatool_if_has_key:nnTF {#1}{#3}
            {
              \datatool_if_has_key:nnTF {#1}{#4}
                {
                  \DTLgetvalueforkey{\l_@@_get_path_value_tl}{#3}{#1}{#4}{#2}
                  \DTLifnullorempty{\l_@@_get_path_value_tl}
                    {\@@_get_path_missing:nnn {#1}{#2}{#3}} {}
                }
                {\@@_get_path_missing:nnn {#1}{#2}{#4}}
            }
            {\@@_get_path_missing:nnn {#1}{#2}{#3}}
        }
        {\msg_warning:nnn {dfg}{database-not-found}{#1}}
    }
}

\cs_new_protected:Npn \@@_get_path_walk:nnnw #1#2#3#4#5\q_stop
{
  \tl_if_eq:nnTF {#5}{\q_nil}
    {
      \prop_if_in:NnF \l_@@_get_path_seen_prop {{#1}{#2}{#4}}
        {
          \prop_put:Nnn \l_@@_get_path_seen_prop {{#1}{#2}{#4}} {}
          \@@_get_path_read:nnnn {#1}{#2}{#4}{#3}
          \tl_if_empty:NF \l_@@_get_path_value_tl
            {
              \seq_put_right:Ne \l_@@_get_path_values_seq
                {
                  \exp_not:N \dfgShowTag {#2}{#4}
                    {\exp_not:V \l_@@_get_path_value_tl}[#1]
                }
            }
        }
    }
    {
      \tl_set:Nn \l_@@_get_path_target_tl {#4}
      \regex_replace_once:nnN {\A ref-(.+)-id \Z} {\1}
        \l_@@_get_path_target_tl
      \use:e
        {
          \exp_not:N \@@_get_path_read:nnnn {#1}{#2}
            {ref-\l_@@_get_path_target_tl-id}{#3}
        }
      \tl_if_empty:NF \l_@@_get_path_value_tl
        {
          % Freeze both the destination database and the complete ID list
          % before recursion changes the local lookup variables.
          \use:e
            {
              \exp_not:N \@@_get_path_branch:nnn
                {\l_@@_get_path_target_tl}
                {\exp_not:V \l_@@_get_path_value_tl}
                {\exp_not:n {#5}}
            }
        }
    }
}
\cs_new_protected:Npn \@@_get_path_branch:nnn #1#2#3
{
  \clist_map_inline:nn {#2}
    {\@@_get_path_walk:nnnw {#1}{##1}{id}#3\q_stop}
}
\cs_new_protected:Npn \@@_get_path_finish:
{
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
    {
      \tl_set:Ne \l_tmpa_tl
        {\seq_use:Nn \l_@@_get_path_annotation_seq {/}}
      \use:e
        {
          \exp_not:N \dfgShowTag
            {\exp_not:V \l_@@_get_path_id_tl}
            {\exp_not:V \l_tmpa_tl}
            {
              \exp_not:n
                {
                  \str_if_eq:VnTF \l_@@_get_path_db_tl {project}
                    {\@@_fast_project_reference:n {\l_@@_get_path_id_tl}}
                    {\dfgFastReference{\l_@@_get_path_id_tl}}
                }
            }
            [\exp_not:V \l_@@_get_path_db_tl]
        }
    }
    {
      \seq_clear:N \l_@@_get_path_values_seq
      \prop_clear:N \l_@@_get_path_seen_prop
      \use:e
        {
          \exp_not:N \@@_get_path_walk:nnnw
            {\l_@@_get_path_db_tl}{\l_@@_get_path_id_tl}
            {\l_@@_get_path_id_field_tl}
            \exp_not:V \l_@@_get_path_tl \exp_not:N \q_nil \exp_not:N \q_stop
        }
      \seq_use:Nn \l_@@_get_path_values_seq {,~}
    }
  \group_end:
}

% --- 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}
% \subsection{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.
%
% All three commands check |fastcompile| first and emit a \cs{dfgItemSkipped}
% placeholder instead of running the real command when compilation speed
% is prioritised. Focused project mode makes narrow exceptions when
% |fastcompile-project-show-funding-tables=true|: the three project-local
% funding tables are rendered from their retained local rows; when
% |fastcompile-project-show-images=true|, plots are rendered from retained
% project metadata. During real rendering the commands 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:
{
  \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 }
}

\cs_new:Npn \@@_print_table_name:n #1
{
  \tl_if_head_is_group:nTF {#1}
    { \@@_print_table_name_aux:w #1 \q_stop }
    {#1}
}

\cs_new:Npn \@@_print_table_name_aux:w #1#2 \q_stop {#1}

\prg_new_protected_conditional:Npnn
  \@@_print_table_if_fast_project_funding:n #1 { TF }
{
  \bool_lazy_all:nTF
  {
    { \l_@@_class_fastcompile_project_bool }
    { \l_@@_class_fastcompile_project_show_funding_tables_bool }
  }
  {
    \str_case_e:nnF { \@@_print_table_name:n {#1} }
    {
      {RequestedFunding} { \prg_return_true: }
      {RequestedFundingStaff} { \prg_return_true: }
      {RequestedAndExistingFundingDirectCosts} { \prg_return_true: }
    }
    { \prg_return_false: }
  }
  { \prg_return_false: }
}

\cs_new_protected:Npn \@@_print_table_dispatch:nn #1#2
{
  \@@_print_table_if_fast_project_funding:nTF {#2}
  {
    \@@_former_project_context:n
    {
      \setcounter{rowNumber}{0}
      \@@_print_thing_call:nnn {Table} {#1} {#2}
    }
  }
  { \@@_print_thing:nnnn {Table} {#1} {#2} {\setcounter{rowNumber}{0}} }
}

\NewDocumentCommand{\printTable}{ o +m }{%
  % Finish the preceding paragraph before a table theme changes the font.
  \par
  % Anchor the table after a heading before tabularray calculates page space.
  % Otherwise its page-start topskip correction can overlap the heading.
  \if@nobreak
    \null\nobreak
  \fi
  \IfNoValueTF {#1}
    { \@@_print_table_dispatch:nn { } {#2} }
    { \@@_print_table_dispatch:nn { [#1] } {#2} }
  \par
}

% Person-specific institution lists also run inside tables and PI cards.
% Call their formatter directly so a nested list does not reset the outer
% former-project context; this also preserves its focused-build output.
\cs_new_protected:Npn \@@_print_list_dispatch:nn #1#2
{
  \str_if_eq:eeTF { \@@_print_table_name:n {#2} } { Institutions }
    { \@@_print_thing_call:nnn { List } {#1} {#2} }
    { \@@_print_thing:nnnn { List } {#1} {#2} { } }
}

\NewDocumentCommand{\printList}{ o +m o }{%
  % Accept old trailing options, but let the leading options take precedence.
  \IfNoValueTF {#3}
  {
    \IfNoValueTF {#1}
      { \@@_print_list_dispatch:nn { } {#2} }
      { \@@_print_list_dispatch:nn { [#1] } {#2} }
  }
  {
    \IfNoValueTF {#1}
      { \@@_print_list_dispatch:nn { [#3] } {#2} }
      { \@@_print_list_dispatch:nn { [#3,#1] } {#2} }
  }
}

% Database-aware list commands share one leading option list. Bare existing
% database names remain valid for compatibility with the previous interface.
\tl_new:N \l_@@_list_database_tl
\tl_new:N \l_@@_list_options_tl
\keys_define:nn { @@ / list-options }
{
  database .tl_set:N = \l_@@_list_database_tl,
}
\cs_new_protected:Npn \@@_list_options:n #1
{
  \tl_set:Nn \l_@@_list_database_tl {person}
  \tl_clear:N \l_@@_list_options_tl
  \tl_if_blank:nF {#1}
  {
    \DTLifdbexists{#1}
      { \tl_set:Nn \l_@@_list_database_tl {#1} }
      {
        \keys_set_known:nnN { @@ / list-options } {#1}
          \l_@@_list_options_tl
      }
  }
}

\cs_new_protected:Npn \@@_print_plot_dispatch:nn #1#2
{
  \bool_lazy_all:nTF
  {
    { \l_@@_class_fastcompile_project_bool }
    { \l_@@_class_fastcompile_project_show_images_bool }
  }
  {
    \@@_former_project_context:n
    { \@@_print_thing_call:nnn {Plot} {#1} {#2} }
  }
  { \@@_print_thing:nnnn {Plot} {#1} {#2} { } }
}

\NewDocumentCommand{\printPlot}{ o +m }{%
  \IfNoValueTF {#1}
  { \@@_print_plot_dispatch:nn { } {#2} }
  { \@@_print_plot_dispatch:nn { [#1] } {#2} }%
}

\newcounter{rowNumber}
%    \end{macrocode}
% \subsection{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
% \InstitutionsList maps institution ids through \_@@_one_institution:n
% and uses \par\medskip between multiple institutions in the standard layout.
% Keep the institution label in sync with the ProjectsTable display setting.
\NewDocumentCommand{\dfgPLInstitutionList}{m}{%
  \bool_if:NTF \l_@@_custom_projects_table_institution_abbreviations_bool
    { \printList[abbreviation]{{Institutions}{#1}} }
    { \printList{{Institutions}{#1}} }
}

\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{.7cm}t{1.6cm}X[1.2,t]t{1.3cm}},
  		column{1} = { fg = referencePI, halign = l, valign = m },
  		column{2} = { halign = c, valign = m },
  		column{3} = { halign = c, valign = m },
  		column{4} = { halign = l, valign = m },
  		column{5} = { halign = c, valign = m },
  		rowhead   = 1,
  		row{1}    = {
  			            bg     = tableHeadingsBG,
  			            fg     = tableHeadingsFont,
  			            font   = \bfseries,
  			            guard
  		            },
  	}
  	Project~ leader
  	 & \mbox{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_clear_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
  			}%
  		}%
  	}%
  }
}

\int_new:N \l_@@_participating_columns_int
\dim_new:N \l_@@_participating_column_sep_dim
\tl_new:N \l_@@_participating_order_tl
\tl_new:N \l_@@_participating_raster_options_tl
\keys_define:nn { @@ / participating-institutions }
{
  columns .int_set:N = \l_@@_participating_columns_int,
  columns .value_required:n = true,
  column~sep .dim_set:N = \l_@@_participating_column_sep_dim,
  column~sep .value_required:n = true,
  order .choice:,
  order / alpha .code:n =
    { \tl_set:Nn \l_@@_participating_order_tl {alpha} },
  order / count .code:n =
    { \tl_set:Nn \l_@@_participating_order_tl {count} },
  order / unknown .code:n =
    {
      \msg_warning:nnn { dfg } { unknown-institution-order } {#1}
      \tl_set:Nn \l_@@_participating_order_tl {alpha}
    },
  alpha .meta:n = { order=alpha },
  count .meta:n = { order=count },
}

\cs_new_protected:Npn \@@_participating_institutions_raster:n #1
{
  \begin{tcbraster}[
    raster~ columns=1,
    raster~ equal~ height=rows,
    raster~ column~ skip=12pt,
    raster~ row~ skip=10pt,
    #1]
    \tl_use:N \l_@@_output_tl
  \end{tcbraster}
}

% Flow whole affiliation boxes down balanced columns without equal-height rows.
\cs_new_protected:Npn \@@_participating_institutions_columns:
{
  \par\addvspace{\medskipamount}
  \setlength{\columnsep}{\l_@@_participating_column_sep_dim}
  \setlength{\multicolsep}{0pt}
  \int_compare:nNnTF {\l_@@_participating_columns_int} > {1}
  {
    \begin{multicols}{\int_use:N \l_@@_participating_columns_int}
      \raggedcolumns
      \tl_use:N \l_@@_output_tl
    \end{multicols}
  }
  { \tl_use:N \l_@@_output_tl }
}

\NewDocumentCommand{\ParticipatingInstitutionsList}{ O{count} }
{%
  \group_begin:
  % Zero selects the existing raster; columns=1,2,... selects flowing columns.
  \int_zero:N \l_@@_participating_columns_int
  \dim_set:Nn \l_@@_participating_column_sep_dim {12pt}
  % Accept the legacy alpha/count options as well as order and raster keys.
  \tl_set:Nn \l_@@_participating_order_tl {count}
  \keys_set_known:nnN { @@ / participating-institutions } {#1}
    \l_@@_participating_raster_options_tl
  \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:VnF \l_@@_participating_order_tl
  {
  	{ 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:nne { dfg } { unknown-institution-order }
    { \l_@@_participating_order_tl }%
  	\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 -------------------------------------------------
  \seq_map_inline:Nn \l_@@_affiliations_seq {%
    \int_compare:nNnTF {\l_@@_participating_columns_int} > {0}
    {
      \tl_put_right:Nn \l_@@_output_tl
      {
        \begin{tcolorbox}[blankest,before~upper=\RaggedRight,
          before={\par\noindent},after={\par\addvspace{10pt}}]
      }
    }
    {
      % Preserve the raster's own before/after hooks for row placement.
      \tl_put_right:Nn \l_@@_output_tl
        {\begin{tcolorbox}[blankest,before~upper=\RaggedRight]}
    }%
  	\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 \textbf{%
          \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
  	}%
    \tl_put_right:Nn \l_@@_output_tl {\end{tcolorbox}}%
  }
  \seq_if_empty:NF \l_@@_affiliations_seq
  {
    \int_compare:nNnTF {\l_@@_participating_columns_int} > {0}
      { \@@_participating_institutions_columns: }
      {
        \exp_args:NV \@@_participating_institutions_raster:n
          \l_@@_participating_raster_options_tl
      }
  }
  \group_end:
}

%    \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~ valign=top,
  			raster~ columns=2,
  			raster~ equal~ height=rows,
            raster~ column~ skip=12pt,
  			raster~ row~ skip=10pt,
  			PIbox
  		]
  		\seq_map_inline:Nn \l_tmpa_seq
  		{%
  			\__getperson_one:n {##1}%
  		}%
  	\end{tcbraster}
  }%
}

\bool_new:N \l_@@_pi_academicdegree_below_bool

\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
  }%
  % Match the tallest title in this raster; equal-height groups settle over
  % successive LaTeX runs. Keep title text at the top of the reserved space.
  \begin{tcolorbox}[PIbox,title={
      \tcbox[blankest,tcbox~ width=forced~ left,
        equal~ height~ group={dfg-PI-titles-\thetcbraster}]{%
        \parbox[t]{\linewidth}{%
          \RaggedRight\bfseries
          \dfgShowTag{#1}{firstname}{\theFirstName}[\tmpLocalDB]\space
          \color{referencePI}
          \dfgShowTag{#1}{lastname}{\theLastName}[\tmpLocalDB]
          \normalfont\normalcolor
          \bool_if:NTF \l_@@_pi_academicdegree_below_bool
            {\newline}
            {,\space}
          \dfgShowTag{#1}{academicdegree}{\theAcademicDegree}[\tmpLocalDB]}}}]
  	\ifdefempty{\theORCiD}{\mbox{~}\\[.75\baselineskip]}{\getORCiD{#1}\\}
    \ifdefempty{\theInstitution}{}{\printList{{Institutions}{#1}}\newline}
    \ifdefempty{\thePhone}{}
      {\str_case:Vn \l_@@_custom_pi_contact_style_tl
        {
          {icons}
            {\mbox{\faPhone\space
             \dfgShowTag{#1}{phone}{\thePhone}[\tmpLocalDB]}\quad}
          {text}
            {\mbox{Phone:\space
             \dfgShowTag{#1}{phone}{\thePhone}[\tmpLocalDB]}\quad}
          {none}
            {\mbox{\dfgShowTag{#1}{phone}{\thePhone}[\tmpLocalDB]}\quad}
        }}
    \ifdefempty{\theEmail}{}
      {\str_case:Vn \l_@@_custom_pi_contact_style_tl
        {
          {icons}
            {\mbox{\faEnvelope\space
              \dfgShowTag{#1}{email}{\theEmail}[\tmpLocalDB]}}
          {text}
            {\mbox{E-Mail:\space
              \dfgShowTag{#1}{email}{\theEmail}[\tmpLocalDB]}}
          {none}
            {\mbox{\dfgShowTag{#1}{email}{\theEmail}[\tmpLocalDB]}}
        }}
  \end{tcolorbox}
}

% ============================================================
%  Precompute compact project-table data per person
% ============================================================

% --- Shared allocations outside each function ----------------------
\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
\prop_new:N \g_@@_proj_pi_institution_ids_prop
\prop_new:N \g_@@_projects_table_institution_abbreviation_prop
\prop_new:N \g_@@_projects_table_institution_name_prop
\prop_new:N \g_@@_projects_table_abbreviation_owner_id_prop
\prop_new:N \g_@@_projects_table_abbreviation_owner_name_prop
\prop_new:N \g_@@_projects_table_abbreviation_warned_prop
\tl_new:N \l_@@_projects_table_legend_tl
\seq_new:N \l_@@_projects_table_institution_ids_seq
\seq_new:N \l_@@_projects_table_sorted_institution_ids_seq
\clist_new:N \l_@@_projects_table_institution_ids_clist
\tl_new:N \l_@@_projects_table_institution_abbreviation_tl

\cs_new_protected:Npn \@@_projects_table_collect_person_institutions:n #1
{
  \prop_get:NnNT \g_@@_proj_pi_institution_ids_prop {#1} \l_tmpa_tl
  {
    \clist_set:NV \l_@@_projects_table_institution_ids_clist \l_tmpa_tl
    \clist_map_inline:Nn \l_@@_projects_table_institution_ids_clist
    {
      \seq_if_in:NnF \l_@@_projects_table_institution_ids_seq {##1}
        { \seq_put_right:Nn \l_@@_projects_table_institution_ids_seq {##1} }
    }
  }
}

\cs_new_protected:Npn \@@_projects_table_collect_institutions:n #1
{
  \bool_if:NT \l_@@_custom_projects_table_institution_abbreviations_bool
  {
    \clist_map_function:nN {#1}
      \@@_projects_table_collect_person_institutions:n
  }
}

\cs_new_protected:Npn \@@_projects_table_institution_legend:
{
  \bool_if:NT \l_@@_custom_projects_table_institution_abbreviations_bool
  {
    \tl_clear:N \l_@@_projects_table_legend_tl
    \seq_set_eq:NN \l_@@_projects_table_sorted_institution_ids_seq
      \l_@@_projects_table_institution_ids_seq
    \seq_sort:Nn \l_@@_projects_table_sorted_institution_ids_seq
    {
      \prop_get:NnN \g_@@_projects_table_institution_abbreviation_prop
        {##1} \l_tmpa_tl
      \prop_get:NnN \g_@@_projects_table_institution_abbreviation_prop
        {##2} \l_tmpb_tl
      \str_compare:eNeTF
        { \str_casefold:V \l_tmpa_tl }
        >
        { \str_casefold:V \l_tmpb_tl }
        { \sort_return_swapped: }
        { \sort_return_same: }
    }
    \seq_map_inline:Nn \l_@@_projects_table_sorted_institution_ids_seq
    {
      \prop_get:NnN \g_@@_projects_table_institution_abbreviation_prop
        {##1} \l_tmpa_tl
      \prop_get:NnN \g_@@_projects_table_institution_name_prop
        {##1} \l_tmpb_tl
      \DTLifnullorempty{\l_tmpa_tl}{}
      {
        \tl_if_blank:VF \l_@@_projects_table_legend_tl
          { \tl_put_right:Nn \l_@@_projects_table_legend_tl { ;~ } }
        \tl_put_right:Nx \l_@@_projects_table_legend_tl
        {
          \exp_not:N \textbf { \exp_not:V \l_tmpa_tl }
          \c_space_tl = \c_space_tl
          \exp_not:V \l_tmpb_tl
        }
      }
    }
    \tl_if_blank:VF \l_@@_projects_table_legend_tl
    {
      \par\vspace{.15\baselineskip}
      {\tiny\RaggedRight\setlength{\parskip}{0pt}\noindent
        \textit{Institution~abbreviations:}\space
        \tl_use:N \l_@@_projects_table_legend_tl
        \par
      }
    }
  }
}


% Helper for render-time formatting
\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
}

% Precompute once: store only the tokens, not \color & \bfseries directly
\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: precompute institution strings (as before)
  	\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,
      \l_@@_projects_table_institution_abbreviation_tl = abbreviation
  	}{%
		\prop_gput:NVV \g_@@_projects_table_institution_abbreviation_prop
      \l_tmpa_tl \l_@@_projects_table_institution_abbreviation_tl
		\prop_gput:NVV \g_@@_projects_table_institution_name_prop
      \l_tmpa_tl \l_tmpb_tl
		\DTLifnullorempty{\l_@@_projects_table_institution_abbreviation_tl}{}
    {
      \prop_get:NVNTF \g_@@_projects_table_abbreviation_owner_name_prop
        \l_@@_projects_table_institution_abbreviation_tl \l_tmpe_tl
      {
        \tl_if_eq:NNF \l_tmpe_tl \l_tmpb_tl
        {
          \prop_if_in:NVF \g_@@_projects_table_abbreviation_warned_prop
            \l_@@_projects_table_institution_abbreviation_tl
          {
            \prop_get:NVN \g_@@_projects_table_abbreviation_owner_id_prop
              \l_@@_projects_table_institution_abbreviation_tl \l_tmpf_tl
            \msg_warning:nneeee { dfg } { duplicate-institution-abbreviation }
              { \l_@@_projects_table_institution_abbreviation_tl }
              { \l_tmpe_tl }
              { \l_tmpb_tl }
              { \l_tmpf_tl,~\l_tmpa_tl }
            \prop_gput:NVn \g_@@_projects_table_abbreviation_warned_prop
              \l_@@_projects_table_institution_abbreviation_tl { 1 }
          }
        }
      }
      {
        \prop_gput:NVV \g_@@_projects_table_abbreviation_owner_id_prop
          \l_@@_projects_table_institution_abbreviation_tl \l_tmpa_tl
        \prop_gput:NVV \g_@@_projects_table_abbreviation_owner_name_prop
          \l_@@_projects_table_institution_abbreviation_tl \l_tmpb_tl
      }
    }
		\bool_if:NTF
		  \l_@@_custom_projects_table_institution_abbreviations_bool
		{
		  \@@_institution_abbreviation_or_name:nN
		    { \l_tmpa_tl } \l_tmpf_tl
		}
		{
		  \tl_set:Nn \l_@@_institution_label_field_tl { name }
		  \DTLgetvalueforkey{\l_tmpf_tl}{name}{institution}{id}{\l_tmpa_tl}
		}
  		\prop_get:NVNT \l_@@_aff_narrow_prop \l_tmpc_tl \l_tmpd_tl {
          \tl_if_blank:VTF \l_tmpf_tl
          {
            \tl_set:Nx \l_tmpe_tl
            {
              \exp_not:N \dfgShowTag
                {\exp_not:V \l_tmpc_tl}{name}
                {\exp_not:V \l_tmpd_tl}[affiliation]
            }
          }
          {
            \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
  	}{%
		\prop_gput:NVV \g_@@_proj_pi_institution_ids_prop
      \l_tmpa_tl \l_tmpd_tl
  		\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
  \printList[abbreviation,noaddress,nolocation,nozip,narrow]{{Institutions}{#1}}%
  \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
  \seq_clear:N   \l_@@_projects_table_institution_ids_seq
  \@@_proj_pi_build:

  \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
    \exp_args:NV \@@_projects_table_collect_institutions:n \pRefPersonId
  	% --- 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_type_service_bool ) && ! \l_@@_project_status_E_bool }
  	{%
    \clist_set:NV \l_tmpa_clist \l_tmpa_clist
  		\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}
      & \bool_if:NF \l_@@_project_status_C_bool
          { \noexpand\dfgShowTag{\pID}{project-status}{\pStatus}[project] }
      & \noexpand\dfgShowTag{\pID}{name}{\pName}[project]
  		&
  		\bool_if:nT
  		{ ( \l_@@_project_type_research_bool || \l_@@_project_type_service_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     = {m{1.1cm}@{}m{0.2cm}X[m]m{1.1cm}X[1.3,m]},
  		rowhead     = 1,
        rows        = {halign=l,font=\raggedright},
  		column{2,4} = {halign=c},
		% column{1}   = {fg=tableFirstColumn},
  		row{1}      = {
  			              bg     = tableHeadingsBG,
  			              fg     = tableHeadingsFont,
  			              font   = \bfseries,
  			              % halign = c,
  			              guard
  		              },
  	}
  	Project
  	 & %{Status}
  	 & Title
  	 & {\mbox{Research}                                               \\area}
  	 & Project\space leader(s),\space institute(s),\space location(s)         \\
	\tblrbody
  \end{tblr}
  \@@_projects_table_institution_legend:
  \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,valign=m, 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
  % Sort the fixed-width classification code numerically after removing
  % punctuation; treating `2.21-02` as an fp expression would parse the
  % hyphen as subtraction.
  \clist_sort:Nn \l_@@_research_area_clist
  {
    \tl_set:Nn \l_tmpa_tl {##1}
    \tl_set:Nn \l_tmpb_tl {##2}
    \regex_replace_all:nnN { [-.] } {} \l_tmpa_tl
    \regex_replace_all:nnN { [-.] } {} \l_tmpb_tl
    \exp_args:NnV \regex_match:nnTF { \A \d+ \Z } \l_tmpa_tl
      {
        \exp_args:NnV \regex_match:nnTF { \A \d+ \Z } \l_tmpb_tl
          {
            \int_compare:nNnTF { \l_tmpa_tl } < { \l_tmpb_tl }
              { \sort_return_same: }
              { \sort_return_swapped: }
          }
          { \sort_return_same: }
      }
      {
        \exp_args:NnV \regex_match:nnTF { \A \d+ \Z } \l_tmpb_tl
          { \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.
  }
}
%    \end{macrocode}
% \subsection{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.
%    \begin{macrocode}
\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}{
  \exp_args:Ne \@@_research_area_print:n { \tl_trim_spaces:n {#1} }
}
\cs_new_protected:Npn \@@_research_area_print:n #1
{
  % #1: a single code, with surrounding spaces removed
  \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}
    \@@_warn_unknown_name:nnN {position~in~\string\dfgPositionName} {#1}
      \g_@@_dfg_position_names_prop
  }
}
\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}
    \@@_warn_unknown_name:nnN {category~in~\string\dfgCategoryName} {#1}
      \g_@@_dfg_category_names_prop
  }
}
%    \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   \g_@@_count_phase_tl
\tl_new:N   \l_@@_count_db_tl
%    \end{macrocode}
% Keep the cache phase global, like the counts themselves: a nested group
% may switch periods, and subsequent calls must see the matching phase.
% 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 \g_@@_count_phase_tl
  {
    \tl_gset:Nx \g_@@_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}
    \@@_warn_unknown_name:nnN {staff~position~for~counts} {#3}
      \g_@@_dfg_position_names_prop
  }
}

% 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}
\bool_new:N \l_@@_gender_leaders_all_sexes_bool
\tl_new:N \l_@@_gender_leaders_database_tl
\tl_new:N \l_@@_gender_leaders_unknown_options_tl
\clist_new:N \l_@@_gender_leaders_unknown_options_clist
\keys_define:nn {dfg/gender-leaders}
{
  all-sexes .bool_set:N = \l_@@_gender_leaders_all_sexes_bool,
  all-sexes .default:n = true,
  database .tl_set:N = \l_@@_gender_leaders_database_tl,
}
\NewDocumentCommand{\GenderEqualityProjectLeadersTable}{ O{} }
{
  \group_begin:
  \bool_set_false:N \l_@@_gender_leaders_all_sexes_bool
  \tl_set:Nn \l_@@_gender_leaders_database_tl {GenderEqualityProjectLeaders}
  \keys_set_known:nnN {dfg/gender-leaders} {#1}
    \l_@@_gender_leaders_unknown_options_tl
  \tl_if_blank:VF \l_@@_gender_leaders_unknown_options_tl
  {
    % Preserve the old bare database argument, including when combined with
    % a new display flag. Unknown key=value pairs still receive key errors.
    \clist_set:NV \l_@@_gender_leaders_unknown_options_clist
      \l_@@_gender_leaders_unknown_options_tl
    \int_compare:nNnTF
      {\clist_count:N \l_@@_gender_leaders_unknown_options_clist} = {1}
    {
      \exp_args:NV \tl_if_in:nnTF \l_@@_gender_leaders_unknown_options_tl {=}
      {
        \exp_args:NnV \keys_set:nn {dfg/gender-leaders}
          \l_@@_gender_leaders_unknown_options_tl
      }
      {
        \tl_set:Ne \l_@@_gender_leaders_database_tl
          {\clist_item:Nn \l_@@_gender_leaders_unknown_options_clist {1}}
      }
    }
    {
      \exp_args:NnV \keys_set:nn {dfg/gender-leaders}
        \l_@@_gender_leaders_unknown_options_tl
    }
  }
  \bool_if:NTF \l_@@_gender_leaders_all_sexes_bool
    { \exp_args:NV \@@_gender_leaders_all:n \l_@@_gender_leaders_database_tl }
    { \exp_args:NV \@@_gender_leaders_female:n \l_@@_gender_leaders_database_tl }
  \group_end:
}
\cs_new_protected:Npn \@@_gender_leaders_all:n #1
{%
  \def\dfgLocalDB{#1}
  \DTLifdbexists{\dfgLocalDB}{%
    % Invalidate once per table. Both counts and their phase are global, so
    % cell groups and prose commands always agree on the cached period.
    \tl_gclear:N \g_@@_count_phase_tl
  	\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
      \int_compare:nNnT {\theFundingPeriodNumeral} = {3}
      {
      & \getPositionGenderPhaseAmount{\pPosition}{f}{1}
      & \getPositionGenderPhaseAmount{\pPosition}{m}{1}
      & \getPositionGenderPhaseAmount{\pPosition}{d}{1}
      & \getPositionGenderPhasePercentage{\pPosition}{f}{1}
      & \getPositionGenderPhasePercentage{\pPosition}{m}{1}
      & \getPositionGenderPhasePercentage{\pPosition}{d}{1}
      }
      & \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
      \int_compare:nNnT {\theFundingPeriodNumeral} = {3}
      {
        & \getPositionGenderPhaseAmount{\pPosition}{f}{3}
        & \getPositionGenderPhaseAmount{\pPosition}{m}{3}
        & \getPositionGenderPhaseAmount{\pPosition}{d}{3}
        & \getPositionGenderPhasePercentage{\pPosition}{f}{3}
        & \getPositionGenderPhasePercentage{\pPosition}{m}{3}
        & \getPositionGenderPhasePercentage{\pPosition}{d}{3}
      }
  			\\
  		}
  	}
    \tl_gput_right:Nx \l_tblr_body_tl
    {
      \exp_not:n {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}

      }}
      \int_compare:nNnT {\theFundingPeriodNumeral} = {3}
      {
      & \getGenderPhaseTotal{f}{1}
      & \getGenderPhaseTotal{m}{1}
      & \getGenderPhaseTotal{d}{1}
      & \getGenderPhasePercentage{f}{1}
      & \getGenderPhasePercentage{m}{1}
      & \getGenderPhasePercentage{d}{1}
      }
  		 &                                                                % 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
      & % current-period objective
      \int_compare:nNnT {\theFundingPeriodNumeral} = {3}
      {
        & \getGenderPhaseTotal{f}{3}
        & \getGenderPhaseTotal{m}{3}
        & \getGenderPhaseTotal{d}{3}
        & \getGenderPhasePercentage{f}{3}
        & \getGenderPhasePercentage{m}{3}
        & \getGenderPhasePercentage{d}{3}
      }
      \\
    }
    \int_compare:nNnTF {\theFundingPeriodNumeral} = {3}
    {
      \@@_gender_leaders_render:nn
      {
        vline{2,8,15}={1-4}{1pt,solid,tableLines},
        vline{5,12,19}={3-4}{1pt,solid,tableLines},
        vline{9,16}={3-4}{1pt,solid,tableLines},
        colspec={X[m] *{6}{m{0.5cm}} m{1.3cm}
                         *{6}{m{0.5cm}} m{1.3cm} *{6}{m{0.5cm}}},
        colsep=1pt,
        column{1}={halign=l},
        column{2-21}={halign=c},
        cell{2}{8,15}={font=\scriptsize\bfseries},
      }
      {
        \SetCell[r=4]{l} Position
        & \SetCell[c=6]{c} First~ funding~ period & & & & &
        & \SetCell[c=7]{c} Second~ funding~ period & & & & & &
        & \SetCell[c=7]{c} Third~ funding~ period & & & & & & \\
        & \SetCell[c=6]{c} Status~ Quo & & & & &
        & {Objective~ [\unit{\percent}]}
        & \SetCell[c=6]{c} Status~ Quo\TblrNote{a} & & & & &
        & {Objective~ [\unit{\percent}]}
        & \SetCell[c=6]{c} Status~ Quo\TblrNote{a} & & & & & \\
        & \SetCell[c=3]{c} Number & &
        & \SetCell[c=3]{c} [\unit{\percent}] & &
        &
        & \SetCell[c=3]{c} Number & &
        & \SetCell[c=3]{c} [\unit{\percent}] & &
        &
        & \SetCell[c=3]{c} Number & &
        & \SetCell[c=3]{c} [\unit{\percent}] & & \\
        & f & m & d & f & m & d
        &
        & f & m & d & f & m & d
        & f
        & f & m & d & f & m & d \\
      }
    }
    {
      \@@_gender_leaders_render:nn
      {
        vline{3}={3-4}{1pt,solid,tableLines},
        vline{6}={4-4}{1pt,solid,tableLines},
        vline{9}={1-4}{1pt,solid,tableLines},
        colspec={X[m] m{2cm} *{6}{m{0.5cm}} m{3cm}},
        column{2-9}={halign=c},
      }
      {
        \SetCell[r=4]{l} Position
        & \SetCell[c=7]{c}
          \int_case:nnF {\theFundingPeriodNumeralPrevious}
            {{1}{First}{2}{Second}} {Previous}~ funding~ period & & & & & &
        & \dfgFundingPeriodText\space funding~ period \\
        & {Objective~ [\unit{\percent}]}
        & \SetCell[c=6]{c} Status~ Quo\TblrNote{a} & & & & &
        & {Objective~ [\unit{\percent}]} \\
        &
        & \SetCell[c=3]{c} Number & &
        & \SetCell[c=3]{c} [\unit{\percent}] & &
        & \\
        & & f & m & d & f & m & d & f \\
      }
    }
  }
  {
    Database~ \texttt{#1}~ missing.
    \msg_warning:nne { dfg } { database-not-found }{ #1 }
  }
}
%    \end{macrocode}
% Female-only view: the third-period layout follows DFG form 60.200,
% including the current period's number/percentage next to its original target.
% The existing future-objective field supplies that target, preserving metadata.
%    \begin{macrocode}
\cs_new:Npn \@@_gender_leaders_female_cells:nn #1#2
{
  & \getPositionGenderPhaseAmount{#1}{f}{#2}
  & \getPositionGenderPhasePercentage{#1}{f}{#2}
}
\cs_new_protected:Npn \@@_gender_leaders_female:n #1
{
  \def\dfgLocalDB{#1}
  \DTLifdbexists{\dfgLocalDB}
  {
    \tl_gclear:N \g_@@_count_phase_tl
    \tl_clear:N \l_tblr_body_tl
    \DTLforeach*[
      \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]
        \int_compare:nNnTF {\theFundingPeriodNumeral} = {3}
        {
          \@@_gender_leaders_female_cells:nn {\pPosition}{1}
          \@@_gender_leaders_female_cells:nn {\pPosition}{2}
          & \dfgShowTag{\pPosition}{future-objective-percentage-female}
              {\pFutureObjPctFemale}[\dfgLocalDB]
          \@@_gender_leaders_female_cells:nn {\pPosition}{3}
        }
        {
          & \dfgShowTag{\pPosition}{previous-objective-percentage-female}
              {\pPrevObjPctFemale}[\dfgLocalDB]
          \@@_gender_leaders_female_cells:nn
            {\pPosition}{\theFundingPeriodNumeralPrevious}
          & \dfgShowTag{\pPosition}{future-objective-percentage-female}
              {\pFutureObjPctFemale}[\dfgLocalDB]
        }
        \\
      }
    }
    \tl_gput_right:Nx \l_tblr_body_tl
    {
      Total
      \int_compare:nNnTF {\theFundingPeriodNumeral} = {3}
      {
        & \getGenderPhaseTotal{f}{1} & \getGenderPhasePercentage{f}{1}
        & \getGenderPhaseTotal{f}{2} & \getGenderPhasePercentage{f}{2}
        &
        & \getGenderPhaseTotal{f}{3} & \getGenderPhasePercentage{f}{3}
      }
      {
        &
        & \getGenderPhaseTotal{f}{\theFundingPeriodNumeralPrevious}
        & \getGenderPhasePercentage{f}{\theFundingPeriodNumeralPrevious}
        &
      }
      \\
    }
    \int_compare:nNnTF {\theFundingPeriodNumeral} = {3}
    {
      \@@_gender_leaders_render:nnnn
      {
        colspec={X[m] m{1.2cm} m{.8cm} m{1.2cm} m{.8cm}
                 m{2cm} m{1.2cm} m{.8cm}},
        vline{2,4,6}={1-2}{1pt,solid,tableLines},
        column{2-8}={halign=c},
      }
      {
        \SetCell[r=2]{l} Position~(female)
        & \SetCell[c=2]{c} First~ funding~ period &
        & \SetCell[c=2]{c} Second~ funding~ period &
        & \SetCell[c=3]{c} {Status~ Quo\TblrNote{a}\\Third~ funding~ period} & & \\
        & Number & [\unit{\percent}]
        & Number & [\unit{\percent}]
        & {Original~ objective~[\unit{\percent}]} & Number & [\unit{\percent}] \\
      }
      {2}{3}
    }
    {
      \@@_gender_leaders_render:nnnn
      {
        colspec={X[m] m{2cm} m{1.5cm} m{1.5cm} m{3cm}},
        vline{3}={2-2}{1pt,solid,tableLines},
        vline{5}={1-2}{1pt,solid,tableLines},
        column{2-5}={halign=c},
      }
      {
        \SetCell[r=2]{l} Position~(female)
        & \SetCell[c=3]{c}
          \int_case:nnF {\theFundingPeriodNumeralPrevious}
            {{1}{First}{2}{Second}} {Previous}~ funding~ period & &
        & \dfgFundingPeriodText\space funding~ period \\
        & {Original~ objective~[\unit{\percent}]}
        & {Number\TblrNote{a}} & [\unit{\percent}]
        & {Objective~[\unit{\percent}]} \\
      }
      {2}{3}
    }
  }
  {
    Database~ \texttt{#1}~ missing.
    \msg_warning:nne {dfg}{database-not-found}{#1}
  }
}

%    \end{macrocode}
% Share the table styling between the two-period and three-period layouts.
% The complete four-row header repeats if the table crosses a page boundary.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_gender_leaders_render:nn #1#2
  { \@@_gender_leaders_render:nnnn {#1}{#2}{4}{5} }
\cs_new_protected:Npn \@@_gender_leaders_render:nnnn #1#2#3#4
{
  \begin{tblr}[
    theme=main,
    note{a}={Reference~ date:~ proposal~ for~ \dfgFundingPeriodText\space funding~ period},
    expand=\l_tblr_body_tl,
    long
  ]{
    vspan=even,
    hspan=minimal,
    row{Z}={font={\footnotesize\bfseries}},
    hline{#4}={1pt,solid,tableLines},
    hline{Y}={1pt,solid,fg={tableOuterLines}},
    hline{2}={wd=0pt},
    row{odd}={bg=white},
    row{even}={bg=tableRows},
    row{1-#3}={bg=tableHeadingsBG},
    rowhead=#3,
    row{2-#3}={guard,valign=t,font={\footnotesize\bfseries},
              fg={tableHeadingsFont},bg=white},
    #1
  }
    #2
    \l_tblr_body_tl
  \end{tblr}
}
%    \end{macrocode}
% We continue with the list of existing instrumentation
%    \begin{macrocode}
\NewDocumentCommand{\ExistingInstrumentationTable}{ O{existingInstrumentation} }{%
  \def\dfgLocalDB{#1}
  \def\tblrbody{}
  \DTLifdbexists{\dfgLocalDB}{%
    \DTLsort{ref-project-id}{\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{0}%
    \def\totalRatQuantity{0}%
  	\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[3,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_set:NV \tmpProjectResearchArea \tmpProjectResearchArea
  	\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*{1em}

  % --- 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}%
	{\footnotesize 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},
			cells     = {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} }
}

% The frame wrapper retains the configured bibliography font. Clear the
% local selector first so disabled emphasis cannot inherit an outer selector.
\NewDocumentCommand{\printFrameBibliography}{o}
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
  {
    \group_begin:
    \tl_clear:N \l_@@_bibentry_highlight_keyword_tl
    \bool_if:NT \l_@@_custom_emphasize_entries_bool
      { \tl_set:Nn \l_@@_bibentry_highlight_keyword_tl {frametext-highlight} }
    \IfNoValueTF{#1}
    { \printbibliography }
    { \printbibliography[#1] }
    \group_end:
  }
}

\NewDocumentCommand{\printProjectBibliography}{o}
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
  {
    \group_begin:
    % biblatex applies \bibfont when it starts the bibliography list.
    \renewcommand*{\bibfont}{\normalfont\footnotesize}%
    \bool_if:NT \l_@@_custom_emphasize_entries_bool
    {
      \tl_if_blank:VF \l__tmp_current_project_tl
      {
        \tl_set:Ne \l_@@_bibentry_highlight_keyword_tl
          {\l__tmp_current_project_tl-highlight}
      }
    }
    \IfNoValueTF{#1}
    { \printbibliography }
    { \printbibliography[#1] }
    \group_end:
  }
}

\NewDocumentEnvironment{projectReport}{}
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
  { \begin{refsegment} }
}
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_publications_bool
  {
    \printProjectBibliography[
      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 {,} }
        \printProjectBibliography[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}
  }
}

\cs_new_protected:Npn \@@_print_project_head:n #1
{ \printProjectHead{#1} }

\cs_new_protected:Npn \@@_print_project_error:n #1
{
  \PackageError{dfg-crc}
    {Invalid~project~part~'#1'}
    {Use~\string\printProject{{Head}{project-id}}~or~\string\printProject{{Tail}}.}
}

\cs_new_protected:Npn \@@_print_project_dispatch:w #1#2 \q_stop
{
  \str_case:nnF {#1}
  {
    {Head}
    {
      \tl_if_blank:nTF {#2}
        { \@@_print_project_error:n {Head} }
        { \@@_print_project_head:n {#2} }
    }
    {Tail}
    {
      \tl_if_blank:nTF {#2}
        { \printProjectTail }
        { \@@_print_project_error:n {Tail} }
    }
  }
  { \@@_print_project_error:n {#1} }
}

\NewDocumentCommand{\printProject}{m}
{ \@@_print_project_dispatch:w #1 \q_stop }
%    \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}{%
  % Older funding entries may omit positionText; keep it an optional column.
  \DTLifhaskey{\tmpLocalDB}{positionText}{}{\DTLaddcolumn{\tmpLocalDB}{positionText}}
  	\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 & \SetCell{c} Sum
		& Qty & \SetCell{c} Sum
		& Qty & \SetCell{c} Sum
		& Qty & \SetCell{c} Sum
		& Qty & \SetCell{c} Sum \\
  	}

  	\tl_put_right:Nn \l__tmp_body_costs_tl {
  		\SetHline{-}{tableOuterLines,0.5pt}
  		\SetRow{tableHeadingsBGalt}
  		\SetCell{font=\footnotesize\bfseries,halign=l}
		Direct~ Costs
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum  \\
  	}
  	\tl_put_right:Nn \l__tmp_body_fellowships_tl {
  		\SetHline{-}{tableOuterLines,0.5pt}
  		\SetRow{tableHeadingsBGalt}
  		\SetCell{font=\footnotesize\bfseries,halign=l}
		Fellowships
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum \\
  	}
  	\tl_put_right:Nn \l__tmp_body_globalfunds_tl {
  		\SetHline{-}{tableOuterLines,0.5pt}
  		\SetRow{tableHeadingsBGalt}
  		\SetCell{font=\footnotesize\bfseries,halign=l}
		Globalfunds
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum  \\
  	}
  	\tl_put_right:Nn \l__tmp_body_instrumentation_tl {
  		\SetHline{-}{tableOuterLines,0.5pt}
  		\SetRow{tableHeadingsBGalt}
  		\SetCell{font=\footnotesize\bfseries,halign=l}
		Instrumentation
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} Sum
		& & \SetCell{c} 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,
  			\pPositionText      =positionText,
  			\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} {
          % Use the category only when no custom position label is supplied.
          \DTLifnullorempty{\pPositionText}
            {
              \tl_set:Ne \l_tmpa_tl
                { \dfgShowTag{\pProject/\pCategory}{category}
                    {\dfgCategoryName{\pCategory}}[\tmpLocalDB] }
            }
            {
              \tl_set:Ne \l_tmpa_tl
                { \dfgShowTag{\pProject/\pCategory}{positionText}
                    {\exp_not:V \pPositionText}[\tmpLocalDB] }
            }
					\DTLaddall{\tmpHorizontalSum}{
  						\pSumYearOne,
  						\pSumYearTwo,
  						\pSumYearThree,
  						\pSumYearFour,
  						\pSumYearFive
  					}
  					\tl_put_right:Ne \l__tmp_body_staff_tl
  					{

            \exp_not:V \l_tmpa_tl
            ,~
            \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,l,t]}
					*{5}{
						@{}X[0.75,c,si={table-format=1}]
						@{}X[1.2,c,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_staff_type_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,
  staff-type .tl_set:N = \l_@@_rfs_staff_type_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:n #1
{
  \bool_if:NTF \l_@@_class_fastcompile_bool
    { \@@_rfs_error_text:n {#1} }
    { \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_staff_type_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 },
    staff-type = { \exp_not:V \pRFSStaffType },
    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:
{
  % Preserve the null marker for an omitted position until person lookup.
  \clist_map_inline:nn
  {
    \pRFSRefPerson, \pRFSFirstname, \pRFSLastname, \pRFSDegree,
    \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
        % Only a missing database value inherits; an explicit empty value wins.
        \DTLifnull{\l_@@_rfs_position_tl}
        {
          \DTLgetvalueforkey{\l_tmpa_tl}{positionText}{person}{id}
            {\l_@@_rfs_ref_person_tl}
          \tl_set:NV \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 }
    }
  }
  \DTLifnull{\l_@@_rfs_position_tl}
    { \tl_clear:N \l_@@_rfs_position_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:n {department} }
      }
      {
        \@@_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:n {#2} }
  }
  { \tl_set:NV #3 #1 }
}

\cs_new_protected:Npn \@@_rfs_make_field_cell:
{
  \bool_lazy_all:nTF
  {
    { \str_if_eq_p:Vn \l_@@_rfs_funding_status_tl { existing } }
    { \str_if_eq_p:Vn \l_@@_rfs_staff_type_tl { nonResearch } }
    { \tl_if_blank_p:V \l_@@_rfs_field_tl }
  }
  { \tl_set:Nn \l_@@_rfs_field_cell_tl { \SetCell{bg=tableNoValue} } }
  {
    \@@_rfs_make_cell:NnN \l_@@_rfs_field_tl
      { field-of-research } \l_@@_rfs_field_cell_tl
  }
}

\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_set:Nn \l_@@_rfs_plain_name_tl { TBA }
    \tl_set:Nn \l_@@_rfs_description_name_tl { TBA }
    \tl_set:Nn \l_tmpa_tl { TBA }
  }
  {
    \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
      {
        \bool_if:NTF \l_@@_class_fastcompile_bool
          { \@@_rfs_error_text:n {lastname} }
          { \@@_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:n {firstname} }
      \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 }
    }
    \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_if_blank:VF \l_@@_rfs_position_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_field_cell:
  \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:n {category} }
    }
    {
      \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
  {
    \exp_not:N \item
      [\exp_not:N \textbf
        { \int_use:N \l_@@_rfs_display_number_int. }]
    \exp_not:N \textbf
      { \exp_not:N \dfgShowCalculatedTag{RequestedFundingStaffTable}
          {RequestedFundingStaff,person}
          {\exp_not:V \l_@@_rfs_description_name_tl} }
    \space
    \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]
  }
}

\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}
          \begin{itemize}[
            label={},
            labelindent=0pt,
            labelwidth=1.5em,
            labelsep=.5em,
            leftmargin=2em,
            align=left,
            beginpenalty=10000]
            \tl_use:N \l_@@_rfs_existing_descriptions_tl
          \end{itemize}}
      }
      \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}
          \begin{itemize}[
            label={},
            labelindent=0pt,
            labelwidth=1.5em,
            labelsep=.5em,
            leftmargin=2em,
            align=left,
            beginpenalty=10000]
            \tl_use:N \l_@@_rfs_requested_descriptions_tl
          \end{itemize}}
      }
    }
  }
  { \@@_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}{abbreviation} : } ~
      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}
% \subsection{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~ title=\raggedright,
		before~ upper=\raggedright,
  		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}
% \subsection{New Commands}
% Providing further commands that can and will be used throughout the document
%    \begin{macrocode}
\providecommand{\crc}{Collaborative~ Research~ Centre\xspace}

% 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*{-1em}
}
%    \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 }

\keys_define:nn { @@ / institution-list }
{
  abbreviation .bool_set:N = \l_@@_institution_abbreviation_bool,
  narrow .bool_set:N = \l_@@_narrow_bool,
  noaddress .bool_set:N = \l_@@_noaddr_bool,
  nozip .bool_set:N = \l_@@_nozip_bool,
  nolocation .bool_set:N = \l_@@_noloc_bool,
}

\NewDocumentCommand{\InstitutionsList}{O{} m O{}}
{
  \group_begin:
    \@@_list_options:n {#1}
    \tl_put_left:Nn \l_@@_list_options_tl {#3,}
    \exp_args:NVnV \@@_institutions_list:nnn
      \l_@@_list_database_tl {#2} \l_@@_list_options_tl
  \group_end:
}

\cs_new_protected:Npn \@@_institutions_list:nnn #1#2#3
{
 \bool_if:NTF \l_@@_class_fastcompile_project_bool
 { \dfgFastReference{#2} }
 {
 \DTLifdbexists{#1}{
  % Parse key names rather than comparing tokens: options forwarded by
  % keys_set_known may have string catcodes. Boolean values also allow a
  % leading setting to override an older trailing flag.
  \bool_set_false:N \l_@@_institution_abbreviation_bool
  \bool_set_false:N \l_@@_narrow_bool
  \bool_set_false:N \l_@@_noaddr_bool
  \bool_set_false:N \l_@@_nozip_bool
  \bool_set_false:N \l_@@_noloc_bool
  \keys_set:nn { @@ / institution-list } {#3}
  \bool_if:NTF \l_@@_narrow_bool
  {
    \tl_set:Nn \l_@@_sep_tl {,~}
    \tl_set:Nn \l_@@_inst_sep_tl {;~}
  }
  {
    \tl_set:Nn \l_@@_sep_tl {\newline}
    \tl_set:Nn \l_@@_inst_sep_tl {\par\medskip}
  }
  \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 }
   }
 }
}

% Compatibility spelling for older proposal sources.
\cs_new_eq:NN \dfgInstitutionList \InstitutionsList

\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 leading options include
% database (person by default) and raster settings. Trailing raster options
% remain supported for older documents.
%    \begin{macrocode}
\keys_define:nn { @@ / pi-role-list }
{
  academicdegree-below .bool_set:N = \l_@@_pi_academicdegree_below_bool,
}

\NewDocumentCommand{\getPIsWithRole}{O{} m O{}}
{
  \group_begin:
    \bool_set_false:N \l_@@_pi_academicdegree_below_bool
    \@@_list_options:n {#1}
    \tl_put_left:Nn \l_@@_list_options_tl {#3,}
    \exp_args:NnV \keys_set_known:nnN { @@ / pi-role-list }
      \l_@@_list_options_tl \l_@@_list_options_tl
    \exp_args:NVnV \@@_get_pis_with_role:nnn
      \l_@@_list_database_tl {#2} \l_@@_list_options_tl
  \group_end:
}

\cs_new_protected:Npn \@@_get_pis_with_role:nnn #1#2#3
{%
  \bool_if:NTF \l_@@_class_fastcompile_bool
  { \dfgItemSkipped{dfgPIsWithRole:~#2} }
  {%
    \DTLifdbexists{#1}
    {
      \def\tmpLocalDB{#1}%
      \DTLsort*{lastname}{#1}%
      \begin{tcbraster}[
          raster~ valign=top,
          raster~ columns=3,
          raster~ equal~ height=rows,
          raster~ column~ skip=12pt,
          raster~ row~ skip=20pt,
          raster~ after~ skip=20pt,
          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}
\cs_new_protected:Npn \@@_pi_reference_seq_use:N #1
{
  \bool_if:NTF \g_@@_tblr_inside_bool
    { \seq_use:Nn #1 {\addnbthinspace/\addthinspace} }
    { \seq_use:Nnnn #1 {~and~} {,~} {,~and~} }
}

\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>}}
  		}
  		{
          \tl_if_eq:NnF \l_@@_custom_referencePI_tl {current}
            { \color{referencePI} }
          \bfseries
  			\IfNoValueTF{#3}%

              {\hyperlink{pi:##1}{\@@_pi_reference_name:nn {#1}{##1}}}
  			{\hyperlink{pi:##1}{#3}}}
  		\group_end:
  	}}
  \@@_pi_reference_seq_use:N \l_tmpb_seq
  }
}
%    \end{macrocode}
% Unstarred PI references disambiguate shared surnames across all PI records
% with the first given-name initial, for example K.~Schneider and C.~Schneider.
% If that initial is shared as well, use the full given name. Starred references
% and explicit display text retain their existing behavior, as do unique names.
% Project-first references inherit this formatting through \cs{getPI}.
% Recompute from the current metadata so additions are reflected immediately.
%    \begin{macrocode}
\tl_new:N \l_@@_pi_lastname_tl
\tl_new:N \l_@@_pi_firstname_tl
\tl_new:N \l_@@_pi_initial_tl
\tl_new:N \l_@@_pi_candidate_lastname_tl
\tl_new:N \l_@@_pi_candidate_firstname_tl
\tl_new:N \l_@@_pi_candidate_initial_tl
\clist_new:N \l_@@_pi_candidate_roles_clist
\bool_new:N \l_@@_pi_candidate_is_pi_bool
\int_new:N \l_@@_pi_same_lastname_int
\int_new:N \l_@@_pi_same_initial_int

% Count matching PI surnames and first initials across the current metadata.
\cs_new_protected:Npn \@@_pi_count_name_matches:
  {
    \int_zero:N \l_@@_pi_same_lastname_int
    \int_zero:N \l_@@_pi_same_initial_int
    \DTLforeach*{person}
      {
        \dfgDisambiguationName=lastname,
        \dfgDisambiguationFirstname=firstname,
        \dfgDisambiguationRoles=role
      }
      {
        \clist_set:Nx \l_@@_pi_candidate_roles_clist {\dfgDisambiguationRoles}
        \bool_set_false:N \l_@@_pi_candidate_is_pi_bool
        \clist_if_in:NnT \l_@@_pi_candidate_roles_clist {PI}
          {\bool_set_true:N \l_@@_pi_candidate_is_pi_bool}
        \clist_if_in:NnT \l_@@_pi_candidate_roles_clist {Co-PI}
          {\bool_set_true:N \l_@@_pi_candidate_is_pi_bool}
        \bool_if:NT \l_@@_pi_candidate_is_pi_bool
          {
            \tl_set:Nx \l_@@_pi_candidate_lastname_tl {\dfgDisambiguationName}
            \tl_if_eq:NNT \l_@@_pi_lastname_tl \l_@@_pi_candidate_lastname_tl
              {
                \int_incr:N \l_@@_pi_same_lastname_int
                \tl_set:Nx \l_@@_pi_candidate_firstname_tl {\dfgDisambiguationFirstname}
                \tl_trim_spaces:N \l_@@_pi_candidate_firstname_tl
                \tl_set:Nx \l_@@_pi_candidate_initial_tl
                  {\tl_head:V \l_@@_pi_candidate_firstname_tl}
                \tl_if_eq:NNT \l_@@_pi_initial_tl \l_@@_pi_candidate_initial_tl
                  {\int_incr:N \l_@@_pi_same_initial_int}
              }
          }
      }
  }

% Render the name inside the PI hyperlink. #1 is the star, #2 the person ID.
% The caller has already fetched and validated the name fields.
\cs_new_protected:Npn \@@_pi_reference_name:nn #1#2
  {
    \group_begin:
    \IfBooleanTF{#1}
      {\dfgShowTag{#2}{firstname}{\thePersonFirstName}[person]\space}
      {
        \tl_set:Nx \l_@@_pi_lastname_tl {\thePersonName}
        \tl_set:Nx \l_@@_pi_firstname_tl {\thePersonFirstName}
        \tl_trim_spaces:N \l_@@_pi_firstname_tl
        \tl_set:Nx \l_@@_pi_initial_tl {\tl_head:V \l_@@_pi_firstname_tl}
        \@@_pi_count_name_matches:
        \int_compare:nNnTF {\l_@@_pi_same_lastname_int} > {1}
          {
            \int_compare:nNnTF {\l_@@_pi_same_initial_int} > {1}
              {\dfgShowTag{#2}{firstname}{\thePersonFirstName}[person]}
              {\tl_use:N \l_@@_pi_initial_tl.}
            \nobreakspace
          }
          {
            \bool_if:NT \l_@@_custom_pi_reference_firstname_bool
              {\dfgShowTag{#2}{firstname}{\thePersonFirstName}[person]\space}
          }
      }
    \dfgShowTag{#2}{lastname}{\thePersonName}[person]
    \group_end:
  }
%    \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.
\bool_new:N \l_@@_project_newline_separator_bool
\bool_new:N \l_@@_project_custom_text_bool
\cs_new_protected:Npn \@@_project_reference_seq_use:N #1
{
  \bool_if:NTF \l_@@_project_newline_separator_bool
    { \seq_use:Nn #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, or \newline/\\ for a stacked project list
  \bool_set_false:N \l_@@_project_newline_separator_bool
  \bool_set_false:N \l_@@_project_custom_text_bool
  \IfNoValueF{#2}
    {
      \bool_set_true:N \l_@@_project_custom_text_bool
      \tl_if_eq:nnT {#2} {\newline}
        { \bool_set_false:N \l_@@_project_custom_text_bool
          \bool_set_true:N \l_@@_project_newline_separator_bool }
      \tl_if_eq:nnT {#2} {\\}
        { \bool_set_false:N \l_@@_project_custom_text_bool
          \bool_set_true:N \l_@@_project_newline_separator_bool }
    }
  \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
      {
        \bool_if:NTF \l_@@_project_custom_text_bool
          {#2}
          {
            \dfgShowTag {##1}{number}
              {\@@_fast_project_reference:n {##1}}[project]
          }
      }
    }
    \@@_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}
        {
          \bool_if:NTF \l_@@_project_custom_text_bool
            {#2}
            {\dfgShowTag{##1}{number}{\theProjectNumber}[project]}%
          \@@_project_reference_only_indicator:
        }
        {
          \bool_if:NTF \l_@@_project_custom_text_bool
          {
            \bool_if:NTF \l_@@_class_cv_bool
              { #2 }
              { \hyperlink{project:##1}{#2} }
          }
          {
            \bool_if:NTF \l_@@_class_cv_bool
              { \dfgShowTag{##1}{number}{\theProjectNumber}[project] }
              { \hyperlink{project:##1}
                  {\dfgShowTag{##1}{number}{\theProjectNumber}[project]} }
          }
        }
  		}
  		\group_end:
  	}}%
  \@@_project_reference_seq_use:N \l_tmpb_seq
  }
}

\NewDocumentCommand{\getProject}{s m o}
{
  \IfBooleanTF{#1}
    { \@@_get_project_compact:nn {#2} {#3} }
    {
      \bool_if:NTF \l_@@_custom_project_pi_once_per_section_bool
        { \@@_get_project_with_people:nnn {\BooleanFalse} {#2} {#3} }
        { \@@_get_project_compact:nn {#2} {#3} }
    }
}

\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
\bool_new:N \l_@@_suppress_deprecated_project_pi_warning_bool
% Global flags keep repeated calls and table measurement groups quiet.
\bool_new:N \g_@@_warned_get_pi_project_bool
\bool_new:N \g_@@_warned_get_project_pi_bool
\seq_new:N \l_@@_project_pi_with_project_seq
\msg_new:nnn {dfg} {deprecated-get-pi-project}
  {Command~\string\getPIProject~ ~is~deprecated;~use~\string\getPIWithProject.}
\msg_new:nnn {dfg} {deprecated-get-project-pi}
  {Command~\string\getProjectPI~ ~is~deprecated;~use~\string\getProjectWithPI.}

\NewDocumentCommand{\getPIProject}{s m}{
  \bool_if:NF \l_@@_suppress_deprecated_project_pi_warning_bool
    {
      \bool_if:NF \g_@@_warned_get_pi_project_bool
        {
          \bool_gset_true:N \g_@@_warned_get_pi_project_bool
          \msg_warning:nn {dfg}{deprecated-get-pi-project}
        }
    }
  \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.
        % Keep project references compact: the PI name is already printed.
  			\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} }
  {
  \group_begin:
  % Project-first references use lastnames by default regardless of the
  % global PIReferenceFirstName setting. The explicit star still selects full
  % names through the starred \getPI call below.
  \bool_set_false:N \l_@@_custom_pi_reference_firstname_bool
  %-----------------------------------------------------------------
  % 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
  \group_end:
  }
}

\NewDocumentCommand{\getPIWithProject}{s m}
{
  \group_begin:
  \bool_set_true:N \l_@@_suppress_deprecated_project_pi_warning_bool
  \IfBooleanTF{#1}{\getPIProject*{#2}}{\getPIProject{#2}}
  \group_end:
}

\NewDocumentCommand{\getProjectPI}{s m}
  {
    \bool_if:NF \l_@@_suppress_deprecated_project_pi_warning_bool
      {
        \bool_if:NF \g_@@_warned_get_project_pi_bool
          {
            \bool_gset_true:N \g_@@_warned_get_project_pi_bool
            \msg_warning:nn {dfg}{deprecated-get-project-pi}
          }
      }
    \exp_args:NnnV \@@_get_project_with_people:nnn
      {#1} {#2} \c_novalue_tl
  }
\NewDocumentCommand{\getProjectWithPI}{s m}
{
  \group_begin:
  \bool_set_true:N \l_@@_suppress_deprecated_project_pi_warning_bool
  \IfBooleanTF{#1}{\getProjectPI*{#2}}{\getProjectPI{#2}}
  \group_end:
}

\NewDocumentCommand{\getPIOfProjectWithProject}{s m}
{
  \seq_clear:N \l_@@_project_pi_with_project_seq
  \clist_map_inline:nn {#2}
  {
    \seq_put_right:Nn \l_@@_project_pi_with_project_seq
    {
      \IfBooleanTF{#1}
        {\getPIofProject*{##1}}
        {\getPIofProject{##1}}
      \space(\getProject*{##1})
    }
  }
  \@@_project_reference_seq_use:N \l_@@_project_pi_with_project_seq
}
%    \end{macrocode}
% We also need a way to extract all PIs of a project. 
%    \begin{macrocode}
% The star defaults to full names and a prose list; explicit properties still
% override the default. A starred delimiter overrides only the final join.
\clist_new:N \l_@@_project_pi_properties_clist
\tl_new:N \l_@@_project_pi_name_tl
\NewDocumentCommand{\getPIofProject}{s o m o}
{
  \group_begin:
  \IfNoValueTF{#2}
    {
      \bool_if:NTF \l_@@_custom_pi_reference_firstname_bool
        {\clist_set:Nn \l_@@_project_pi_properties_clist {firstname,lastname}}
        {
          \IfBooleanTF{#1}
            {\clist_set:Nn \l_@@_project_pi_properties_clist {firstname,lastname}}
            {\clist_set:Nn \l_@@_project_pi_properties_clist {lastname}}
        }
    }
    {\clist_set:Nn \l_@@_project_pi_properties_clist {#2}}
  \bool_if:NTF \l_@@_class_fastcompile_project_bool
    {\@@_fast_project_reference:n {#3}}
    {
      \clist_clear:N \l_@@_person_clist
      \DTLgetvalueforkey{\l_@@_person_id_clist}
        {ref-person-id}{project}{id}{#3}
      \DTLifnullorempty{\l_@@_person_id_clist}
        {\clist_clear:N \l_@@_person_id_clist}{}
      \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}
          \tl_clear:N \l_@@_project_pi_name_tl
          \clist_if_in:NnT \l_@@_project_pi_properties_clist {academicdegree}
            {
              \tl_put_right:Ne \l_@@_project_pi_name_tl
                {\dfgShowTag{\l_tmpa_clist}{academicdegree}{\tmpPIacademicdegree}[person]\addnbthinspace}
            }
          \clist_if_in:NnT \l_@@_project_pi_properties_clist {firstname}
            {
              \tl_put_right:Ne \l_@@_project_pi_name_tl
                {\dfgShowTag{\l_tmpa_clist}{firstname}{\tmpPIfirstname}[person]\space}
            }
          \clist_if_in:NnT \l_@@_project_pi_properties_clist {lastname}
            {
              \tl_put_right:Ne \l_@@_project_pi_name_tl
                {\dfgShowTag{\l_tmpa_clist}{lastname}{\tmpPIlastname}[person]}
            }
          % Reuse getPI's target, reference styling, and missing-person handling.
          % Freeze the ID and selected fields before advancing the metadata loop.
          \tl_if_empty:NF \l_@@_project_pi_name_tl
            {
              \clist_put_right:Ne \l_@@_person_clist
                {
                  \exp_not:N \getPI {\exp_not:V \l_tmpa_clist}
                    [\exp_not:V \l_@@_project_pi_name_tl]
                }
            }
        }
      \IfBooleanTF{#1}
        {
          \IfNoValueTF{#4}
            {\clist_use:Nnnn \l_@@_person_clist {~and~} {,~} {~and~}}
            {\clist_use:Nnnn \l_@@_person_clist {#4} {,~} {#4}}
        }
        {
          \IfNoValueTF{#4}
            {\clist_use:Nn \l_@@_person_clist {\,/\,}}
            {\clist_use:Nn \l_@@_person_clist {#4}}
        }
    }
  \group_end:
}
%    \end{macrocode}
% PI and project references also accept an all-lowercase command spelling.
% Copy the complete command so stars, optional arguments, and legacy warnings
% follow the canonical implementation without a separate argument parser.
%    \begin{macrocode}
\clist_map_inline:nn
  {
    getPI, getPIsWithRole, getProject, getProjectColor, getProjectCount,
    getPIWithProject, getProjectWithPI, getPIOfProjectWithProject,
    getPIofProject, getPIProject, getProjectPI
  }
  { \cs_new_eq:cc { \str_lowercase:n {#1} } {#1} }
% Common mixed-case spellings retained alongside the lowercase aliases.
\cs_new_eq:NN \getPIwithProject \getPIWithProject
\cs_new_eq:NN \getProjectwithPI \getProjectWithPI
\cs_new_eq:NN \getPIOfProject \getPIofProject
%    \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 work-package references, \cs{labelcref} keeps cleveref's sorting and
% ranges while we provide a narrow, unbreakable space after |WP| or |WPs|.
%    \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 } }
  \textcolor{referenceWP}
    {\textbf{WP\int_compare:nNnF
      { \clist_count:N \l_@@_wp_refs_clist } = { 1 } { s }}}
  \addnbthinspace
  \exp_args:NV \labelcref \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 }
}

% The visible sub-workpackage label contains its parent number, but enumitem's
% child counter restarts for every parent.  Cleveref otherwise sees, for
% example, both WP 1b and WP 2b as child counter 2 and can discard the latter
% while sorting or compress a range across two parents.  Store the parent
% counter as Cleveref's numeric prefix so sorting and range detection respect
% the work-package hierarchy.
\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}
    \bool_if:NT \l_@@_class_fastcompile_project_show_images_bool
      { \addEntry[gantt]{gantt-\l__tmp_current_project_tl}{id=#1,#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 unlabelled 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
\bool_new:N \l_@@_collaboration_plot_arcs_bool

\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 },
  arcs .bool_set:N = \l_@@_collaboration_plot_arcs_bool,
  arcs .default:n = true,
  no-arcs .meta:n = { arcs = false },
  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=\tl_use:N \l_@@_collaboration_plot_color_tl!78!black,
      fill=\tl_use:N \l_@@_collaboration_plot_color_tl,
      text=white,
      font=\footnotesize\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=\footnotesize\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=\footnotesize
      ] 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
      {
        ( \l_@@_collaboration_plot_width_dim - 6mm ) /
        \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
    {
      3mm + \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 % chktex 12
      ($ (dfg-collaboration-arc-\l_@@_collaboration_plot_focus_tl) % chktex 25
         + (0,\dim_use:N \l_@@_collaboration_plot_arc_height_dim) $) % chktex 25 chktex 35
      and
      ($ (dfg-collaboration-arc-\l_@@_collaboration_plot_target_tl) % chktex 25
         + (0,\dim_use:N \l_@@_collaboration_plot_arc_height_dim) $) % chktex 25 chktex 35
      ..
      (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=\tl_use:N \l_@@_collaboration_plot_color_tl!78!black,
      fill=\tl_use:N \l_@@_collaboration_plot_color_tl,
      text=white,
      font=\scriptsize\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=\scriptsize\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=\scriptsize
      ] at (dfg-collaboration-arc-#1) {#1};
    }
  }
}

\cs_new_protected:Npn \@@_collaboration_plot_arc_group:nn #1#2
{
  \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) $) % chktex 25
      --
      ($ (dfg-collaboration-arc-\l_tmpb_tl) + (3mm,-3.5mm) $); % chktex 25
  }
}
\cs_generate_variant:Nn \@@_collaboration_plot_arc_group:nn { V V }

\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 }
    \bool_if:NT \l_@@_collaboration_plot_arcs_bool
    {
      \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:VV
          \l_tmpa_tl \l_@@_collaboration_plot_color_tl
      }
  \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_arc_picture: }
}

% Keep both caption variants at the captured body-text width without scaling
% the TikZ plot, even when the surrounding \linewidth is temporarily narrower.
\cs_new_protected:Npn \@@_collaboration_plot_full_width_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 builds either bottom 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 = arc,
    arcs = false,
    #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[
          floatPos=h,
          capPos=bottom
        ]
        {figure}
        {\@@_collaboration_plot_full_width_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_full_width_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[
        floatPos=h,
        capPos=bottom
      ]
      {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:
}

% Lowercase plot names accept either an explicit project ID or the active
% project.  An explicit ID may carry a trailing caption; the current-project
% form uses the caption key instead.
\cs_new_protected:Npn \@@_typed_plot:nnnn #1#2#3#4
{
  \IfNoValueTF{#4}
    { #1[#2]{#3} }
    { #1[#2]{#3}[#4] }
}
\cs_new_protected:Npn \@@_typed_plot_current:nnnn #1#2#3#4
  { \@@_typed_plot:nnnn {#2}{#3}{#1}{#4} }

\NewDocumentCommand{\ganttPlot}{ O{} g o }
{
  \IfNoValueTF{#2}
    {
      \tl_if_blank:VTF \l__tmp_current_project_tl
        { \msg_warning:nnn { dfg } { plot-current-project-missing } { gantt } }
        { \exp_args:NV \@@_typed_plot_current:nnnn
            \l__tmp_current_project_tl {\GanttPlot}{#1}{#3} }
    }
    { \@@_typed_plot:nnnn {\GanttPlot}{#1}{#2}{#3} }
}
\NewDocumentCommand{\collaborationsPlot}{ O{} g o }
{
  \IfNoValueTF{#2}
    {
      \tl_if_blank:VTF \l__tmp_current_project_tl
        { \msg_warning:nnn { dfg } { plot-current-project-missing }
            { collaborations } }
        { \exp_args:NV \@@_typed_plot_current:nnnn
            \l__tmp_current_project_tl {\ProjectCollaborationPlot}{#1}{#3} }
    }
    { \@@_typed_plot:nnnn {\ProjectCollaborationPlot}{#1}{#2}{#3} }
}
% Preserve the earlier singular current-project shorthand.
\cs_new_eq:NN \collaborationPlot \collaborationsPlot

\NewDocumentCommand{\printGantt}{ m o }
{
  \IfNoValueTF{#2}
    { \printPlot{{Gantt}{#1}} }
    { \printPlot[caption={#2}]{{Gantt}{#1}} }
}
%    \end{macrocode}
% \subsection{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.  Row breaks precede each visible bar after
%         the first, so skipped rows and the last bar add no blank bottom row.
%         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}, using
%         an explicitly coloured PDF pattern for consistent viewer rendering;
%         |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.  A 0.9-row bar with no top shift leaves a
%         narrow gap between the final bar and the bottom rule.
% \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.  Both \cs{hvFloat} calls put the caption below the
% chart; the second one appends optional extra text.  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}
% Store the stripe colour inside the PDF pattern. Some renderers paint
% stroked, uncoloured patterns black even when their fill colour is set.
% Include the resolved model and components in the pattern cache key, so
% per-chart colour changes produce a new pattern instead of reusing one.
\tl_new:N \l_@@_gantt_stripe_color_model_tl
\tl_new:N \l_@@_gantt_stripe_color_spec_tl
\pgfdeclarepattern{
  name = dfg~gantt~stripes,
  type = colored,
  parameters = {
    \l_@@_gantt_stripe_color_model_tl,
    \l_@@_gantt_stripe_color_spec_tl
  },
  bottom~left = {\pgfpoint{-6pt}{-6pt}},
  top~right = {\pgfpoint{6pt}{6pt}},
  tile~size = {\pgfpoint{12pt}{12pt}},
  tile~transformation = {\pgftransformrotate{45}},
  code = {
    \pgfsetstrokecolor{dfgGanttStripeColor}
    \pgfsetlinewidth{6pt}
    \pgfpathmoveto{\pgfpoint{-6pt}{0pt}}
    \pgfpathlineto{\pgfpoint{6pt}{0pt}}
    \pgfusepath{stroke}
  },
}
\bool_new:N \l_@@_gantt_first_bar_bool
\NewDocumentCommand{\dfgGanttContent}{m}{%
  % Resolve the active colour model before extracting the cache parameters.
  \colorlet{dfgGanttStripeColor}{color@gantt@stripe-two}
  \extractcolorspecs{dfgGanttStripeColor}
    {\l_@@_gantt_stripe_color_model_tl}{\l_@@_gantt_stripe_color_spec_tl}
  \bool_set_true:N \l_@@_gantt_first_bar_bool
  \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.
		\bool_if:NTF \l_@@_gantt_first_bar_bool
		  { \bool_set_false:N \l_@@_gantt_first_bar_bool }
		  { \ganttnewline }
		\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={dfg~gantt~stripes}},
  							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}}%
  		}
		}%
  	\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{tableOuterLines,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~ top~ shift=0,
			bar~ height=.9,
  			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}
% \subsection{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} & {\printList{{Institutions}{#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_documentation_bool
{
\bool_if:NTF \l_@@_class_fastcompile_project_bool
{
  \bool_if:NT \l_@@_class_fastcompile_project_show_images_bool
    { \checkFile{metadata/dfg-metadata.tex} }
}
{
  \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
% \section{Generated files and examples}
% \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}
% Use |\frontmatter| before the title pages and table of contents. It selects
% lowercase Roman page numbers and unnumbered chapters. Use |\mainmatter|
% before General information: it clears the preliminary pages, restores
% numbered chapters, and restarts Arabic page numbering at 1.
% When updating an existing proposal, also copy the page-numbering setup below
% into its customized proposal drivers: the update targets preserve these files.
% 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}
% Preliminary pages use lowercase Roman page numbers.
\frontmatter
\dfgIfFastCompileProjectF{\input{content/00_titlepage}}
% Start numbered chapters on Arabic page 1.
\mainmatter
\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>
%<*doc-proposal>
% \fi
% \subsection{Complete proposal included in the manual}
% The documentation build uses the same main file and chapter inputs as the
% local proposal, including its shared consortium metadata and project files. Final mode removes drafting aids. The makefile compiles this generated wrapper
% before the manual and publishes its PDF beside the manual.
%    \begin{macrocode}
\PassOptionsToClass{final=true}{dfg-crc}
\input{crc-proposal.tex}
%    \end{macrocode}
% \iffalse
%</doc-proposal>
%<*research-example>
% \fi
% \subsection{Shared research-project example}
% Each compact project file supplies its own ID and status to this reusable
% example body. All project leaders and affiliations come from shared metadata.
%    \begin{macrocode}
\providecommand{\dfgExampleResearchProject}[2]{%
  \printProjectHead{#1}
  \section{Summary}
  This project investigates \getEntry[project]{#1}{name}. Its project leaders
  combine experimental and analytical approaches within the shared research
  programme of \thisCRC.
  \ifstrequal{#2}{C}{%
    \section{Project progress to date}
    The preceding funding period established the experimental models and
    shared datasets. The next phase tests causal mechanisms and validates
    their relevance across the participating projects.
  }{%
    \section{Research rationale}
    Preliminary observations motivate a new testable hypothesis. The project
    establishes its experimental framework and independent validation strategy
    during the requested funding period.
  }
  \projectPublicationsHeading
  \projectNocite{FAIR2016}
  \printProjectBibliography[heading=none]
  \section{Project plan}
  \begin{aims}
    \addAim{1} Establish reproducible experimental and analytical workflows.
    \addAim{2} Validate the findings in complementary models and datasets.
  \end{aims}
  \begin{workpackages}
    \addWP{wp1}{
      name = {Experimental framework},
      description = {Establish models, controls, and quality criteria},
      periodStart = {1}, periodEnd = {7}, style = {default}
    }
    Define the controls, sampling strategy, and analysis workflow for \getAim{1}.
    \addWP{wp2}{
      name = {Validation and integration},
      description = {Validate results and integrate consortium datasets},
      periodStart = {6}, periodEnd = {16}, style = {important}
    }
    Test robustness and share the validated results for \getAim{2}.
  \end{workpackages}
  \printPlot{{Gantt}{#1}}
  \section{Relevance of sex, gender and/or diversity in the research project}
  Include relevant biological variables in sampling and analysis; document
  the rationale for each model and the limits of generalisation.
  \section{Role within the Collaborative Research Centre}
  Share methods, data, and validation resources with the linked projects.
  \printPlot{{ProjectCollaboration}{#1}}
  \section{Differentiation from other funded projects}
  The proposed work addresses the CRC-specific hypothesis and does not
  duplicate personnel or experiments supported by other grants.
  \section{Project funding}
  \addEntry[funding]{RequestedFunding}{
    ref-project-id = {#1}, funding-type = {staff}, category = {PhD},
    percentage = {65},
    quantity = {year1=1,year2=1,year3=1,year4=1,year5=1}
  }
  \addEntry[funding]{RequestedFunding}{
    ref-project-id = {#1}, funding-type = {costs}, category = {consumables},
    sum = {year1=1000,year2=2000,year3=2000,year4=2000,year5=1000}
  }
  \printTable{{RequestedFunding}{#1}}
  The doctoral researcher performs the experiments and integrates the data.
  Consumables cover sample preparation, assays, and independent validation.
  \printProjectTail
}
%    \end{macrocode}
% \iffalse
%</research-example>
%<*doc-projects>
% \fi
% \subsection{Complete local project index}
%    \begin{macrocode}
\chapter{Project details}
\printThumbIndex{3}
\dfgTOCprojectPart{A}{Research Projects}
\input{content/03_project_A01}
\input{content/03_project_A02}
\input{content/03_project_A03}
\input{content/03_project_A04}
\input{content/03_project_A05}
\input{content/03_project_A06}
\dfgTOCprojectPart{B}{Research Projects}
\input{content/03_project_B01}
\input{content/03_project_B02}
\input{content/03_project_B03}
\input{content/03_project_B04}
\input{content/03_project_B05}
\input{content/03_project_B06}
\dfgTOCprojectPart{Q}{Central Projects}
\input{content/03_project_Q01}
\input{content/03_project_Q02}
\input{content/03_project_Q03}
\dfgTOCprojectPart{A}{Former project}
\input{content/03_project_A00}
%    \end{macrocode}
% \iffalse
%</doc-projects>
%<*03-project-a03>
% \fi
%    \begin{macrocode}
\input{content/03_project_research-example}
\dfgExampleResearchProject{A03}{C}
%    \end{macrocode}
% \iffalse
%</03-project-a03>
%<*03-project-a04>
% \fi
%    \begin{macrocode}
\input{content/03_project_research-example}
\dfgExampleResearchProject{A04}{N}
%    \end{macrocode}
% \iffalse
%</03-project-a04>
%<*03-project-a05>
% \fi
%    \begin{macrocode}
\input{content/03_project_research-example}
\dfgExampleResearchProject{A05}{C}
%    \end{macrocode}
% \iffalse
%</03-project-a05>
%<*03-project-a06>
% \fi
%    \begin{macrocode}
\input{content/03_project_research-example}
\dfgExampleResearchProject{A06}{N}
%    \end{macrocode}
% \iffalse
%</03-project-a06>
%<*03-project-b02-new>
% \fi
%    \begin{macrocode}
\input{content/03_project_research-example}
\dfgExampleResearchProject{B02}{N}
%    \end{macrocode}
% \iffalse
%</03-project-b02-new>
%<*03-project-b03>
% \fi
%    \begin{macrocode}
\input{content/03_project_research-example}
\dfgExampleResearchProject{B03}{C}
%    \end{macrocode}
% \iffalse
%</03-project-b03>
%<*03-project-b04>
% \fi
%    \begin{macrocode}
\input{content/03_project_research-example}
\dfgExampleResearchProject{B04}{N}
%    \end{macrocode}
% \iffalse
%</03-project-b04>
%<*03-project-b05>
% \fi
%    \begin{macrocode}
\input{content/03_project_research-example}
\dfgExampleResearchProject{B05}{C}
%    \end{macrocode}
% \iffalse
%</03-project-b05>
%<*03-project-b06>
% \fi
%    \begin{macrocode}
\input{content/03_project_research-example}
\dfgExampleResearchProject{B06}{N}
%    \end{macrocode}
% \iffalse
%</03-project-b06>
%<*doc-cv>
% \fi
% \subsection{Complete CV appendix included in the manual}
% Reuse the starter CV and its metadata, suppress drafting aids, and expose
% destinations for the manual's individual-CV previews. The header wrapper
% adds an invisible target after the original header has selected its page.
%    \begin{macrocode}
\PassOptionsToClass{final=true}{dfg-crc}
\AddToHook{class/dfg-crc/after}{%
  \NewCommandCopy{\dfgDocOriginalCVHeader}{\dfgCVheader}
  \RenewDocumentCommand{\dfgCVheader}{m}{%
    \dfgDocOriginalCVHeader{#1}%
    \hypertarget{doc-cv:#1}{}%
  }%
}
\input{crc-cv.tex}
%    \end{macrocode}
% \iffalse
%</doc-cv>
%<*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}
  }

@Comment{All ExampleCV records below are fictional template examples, not real research outputs.}

@Article{ExampleCVper1,
  Author       = {Sample, Kim},
  Title        = {Illustrative study of microbial metabolites and epithelial signalling},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per1-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper1Methods,
  Author       = {Sample, Kim},
  Title        = {Reproducible methods for microbial metabolites and epithelial signalling},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per1-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper1Data,
  Author       = {Sample, Kim},
  Title        = {Fictional demonstration dataset: microbial metabolites and epithelial signalling},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per1-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper2,
  Author       = {Example, Alex},
  Title        = {Illustrative study of multimodal data integration and reproducible analysis},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per2-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper2Methods,
  Author       = {Example, Alex},
  Title        = {Reproducible methods for multimodal data integration and reproducible analysis},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per2-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper2Data,
  Author       = {Example, Alex},
  Title        = {Fictional demonstration dataset: multimodal data integration and reproducible analysis},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per2-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper3,
  Author       = {Meier, Hansi},
  Title        = {Illustrative study of microbial sensing and innate immune memory},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per3-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper3Methods,
  Author       = {Meier, Hansi},
  Title        = {Reproducible methods for microbial sensing and innate immune memory},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per3-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper3Data,
  Author       = {Meier, Hansi},
  Title        = {Fictional demonstration dataset: microbial sensing and innate immune memory},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per3-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper4,
  Author       = {Miller, Kimmi},
  Title        = {Illustrative study of epithelial repair and tissue regeneration},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per4-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper4Methods,
  Author       = {Miller, Kimmi},
  Title        = {Reproducible methods for epithelial repair and tissue regeneration},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per4-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper4Data,
  Author       = {Miller, Kimmi},
  Title        = {Fictional demonstration dataset: epithelial repair and tissue regeneration},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per4-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper5,
  Author       = {Redata, Friedhelm},
  Title        = {Illustrative study of structured doctoral training and research integrity},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per5-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper5Methods,
  Author       = {Redata, Friedhelm},
  Title        = {Reproducible methods for structured doctoral training and research integrity},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per5-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper5Data,
  Author       = {Redata, Friedhelm},
  Title        = {Fictional demonstration dataset: structured doctoral training and research integrity},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per5-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper6,
  Author       = {Hartmann, Samira},
  Title        = {Illustrative study of microbial metabolic pathways and immune adaptation},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per6-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper6Methods,
  Author       = {Hartmann, Samira},
  Title        = {Reproducible methods for microbial metabolic pathways and immune adaptation},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per6-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper6Data,
  Author       = {Hartmann, Samira},
  Title        = {Fictional demonstration dataset: microbial metabolic pathways and immune adaptation},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per6-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper7,
  Author       = {Lindberg, Noah},
  Title        = {Illustrative study of spatial immune niches and quantitative imaging},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per7-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper7Methods,
  Author       = {Lindberg, Noah},
  Title        = {Reproducible methods for spatial immune niches and quantitative imaging},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per7-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper7Data,
  Author       = {Lindberg, Noah},
  Title        = {Fictional demonstration dataset: spatial immune niches and quantitative imaging},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per7-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper8,
  Author       = {Winters-Scholz, Alexis-Marie},
  Title        = {Illustrative study of dietary perturbations and mucosal microbial communities},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per8-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper8Methods,
  Author       = {Winters-Scholz, Alexis-Marie},
  Title        = {Reproducible methods for dietary perturbations and mucosal microbial communities},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per8-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper8Data,
  Author       = {Winters-Scholz, Alexis-Marie},
  Title        = {Fictional demonstration dataset: dietary perturbations and mucosal microbial communities},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per8-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper9,
  Author       = {Navarro, Leonie},
  Title        = {Illustrative study of nutrient sensing and predictive metabolic models},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per9-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper9Methods,
  Author       = {Navarro, Leonie},
  Title        = {Reproducible methods for nutrient sensing and predictive metabolic models},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per9-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper9Data,
  Author       = {Navarro, Leonie},
  Title        = {Fictional demonstration dataset: nutrient sensing and predictive metabolic models},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per9-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper10,
  Author       = {Okafor, Daniel},
  Title        = {Illustrative study of microbial biomarkers and clinical tissue responses},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per10-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper10Methods,
  Author       = {Okafor, Daniel},
  Title        = {Reproducible methods for microbial biomarkers and clinical tissue responses},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per10-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper10Data,
  Author       = {Okafor, Daniel},
  Title        = {Fictional demonstration dataset: microbial biomarkers and clinical tissue responses},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per10-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper11,
  Author       = {Sato, Mira},
  Title        = {Illustrative study of inflammatory circuits between intestine and liver},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per11-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper11Methods,
  Author       = {Sato, Mira},
  Title        = {Reproducible methods for inflammatory circuits between intestine and liver},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per11-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper11Data,
  Author       = {Sato, Mira},
  Title        = {Fictional demonstration dataset: inflammatory circuits between intestine and liver},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per11-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper12,
  Author       = {Keller, Robin},
  Title        = {Illustrative study of patient-derived models and biomarker translation},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2025},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per12-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Article{ExampleCVper12Methods,
  Author       = {Keller, Robin},
  Title        = {Reproducible methods for patient-derived models and biomarker translation},
  JournalTitle = {Fictional Journal of Consortium Research},
  Date         = {2024},
  Volume       = {1},
  Pages        = {1--8},
  Keywords     = {per12-A},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}

@Dataset{ExampleCVper12Data,
  Author       = {Keller, Robin},
  Title        = {Fictional demonstration dataset: patient-derived models and biomarker translation},
  Date         = {2025},
  Version      = {1.0},
  Publisher    = {Example Research Repository},
  Keywords     = {per12-B},
  Note         = {Fictional reference for template demonstration only},
  LangID       = {english}
}
%    \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{
%% dfgLocation                 ={<Location>},
%% dfgDate                     ={<date>},
%% dfgTitle                    ={<Proposal title>},
%% InfoTeX                     ={<Compiler information>},
%% font                        =<nn>,
%% crcLogoPath                 =<file path>,
%% affiliationLogoPath         =<file path>,
%% doiAPIMail                  =<contact email for optional DOI API lookup>,
%% projectPIOncePerSection     =true,
%% projectsTableInstitutionAbbreviations=false,
%% salary@prof                 =126600,
%% salary@groupLeader          =105000,
%% salary@postDoc              =90600,
%% salary@medDoc               =112200,
%% salary@PhD                  =83700,
%% salary@research             =69000,
%% salary@nonResearch          =61500,
%% salary@student              =1,
%% salary@assistant            =1,
%% animalHousing@mouse         =0.75,
%% animalHousing@mouseGnotobiotic=3.9,
%% animalHousing@rat           =1.4,
%% thumbindex                  =true,
%% thumbindex@pattern          =<int>,
%% thumbindex@orientation      =outwards, % or inwards
%% thumbindex@topmargin        =auto,
%% thumbindex@bottommargin     =auto,
%% emphasizeAuthors            =true,
%% emphasizeEntries            =false,
%% biblatexstyleCV             =<nn>,
%% biblatexstyleFeatureCV      ={<nn>,<nn>},
%% biblatexstyleProposal       =<nn>,
%% biblatexstyleFeatureProposal={<nn>,<nn>},
%%%%%   color section   %%%%%
%% color@reference@boldAuthor =<nn>,
%% color@reference@PI         =black, % or current / a named color
%% color@reference@WP         =<nn>,
%% color@reference@Aim        =<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. The salary defaults use the 2027 rates. 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/408716/60-12-2027-de.pdf}
% (DFG personnel rates for 2027, form 60.12, version 01/27).
%
% Use \cs{getValue} with the setting key, for example
% |\num{\getValue{animalHousing@mouse}}|, to read these rates in text.
% 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|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>
% \fi
% \subsection{Shared proposal and documentation metadata}
% The manual, local proposal, and CV use one fictional consortium: six active A projects,
% six active B projects, three Q projects, twelve PIs, and one former project.
% Person/project references are reciprocal; collaboration targets exist.
% The developer installer extracts these same records into local/metadata/.
%    \begin{macrocode}
%<*meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>
\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}
}
%</meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>
\addEntry{institution}{
  id                 = {ins1},
  name               = {Institute of Microbial Systems Medicine},
  abbreviation       = {IMSM},
  ref-affiliation-id = {aff1}
}
%</meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>
\addEntry{institution}{
  id                 = {ins2},
  name               = {Department of Translational Biosciences},
  abbreviation       = {DTB},
  ref-affiliation-id = {aff2}
}
%</meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>
\addEntry{affiliation}{
  id            = {aff1},
  name          = {Example University},
  abbreviation  = {EU},
  addressStreet = {University Avenue 1},
  addressZIP    = {12345},
  location      = {Example City},
  country       = {Germany}
}
%</meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>
\addEntry{affiliation}{
  id            = {aff2},
  name          = {Partner University},
  abbreviation  = {PU},
  addressStreet = {Research Road 2},
  addressZIP    = {54321},
  location      = {Partner City},
  country       = {Germany}
}
%</meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-pis>
\addEntry{person}{
  id                   = {per1},
  firstname            = {Kim},
  lastname             = {Sample},
  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 Sample},
    {Sample, 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-sample},
  phone                = {+49 000 100-1000},
  email                = {kim.sample@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}
  }
}
%</meta|doc-table-a|doc-table-pis>

%<*meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>
\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},
  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}
  }
}
%</meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-b|doc-table-q|doc-table-pis>
\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,B03,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}
  }
}
%</meta|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-b|doc-table-pis>
\addEntry{person}{
  id                   = {per4},
  period               = {2,3},
  firstname            = {Kimmi},
  lastname             = {Miller},
  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,B04},
  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}
  }
}
%</meta|doc-table-b|doc-table-pis>

%<*meta|doc-table-b|doc-table-q|doc-table-pis>
\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       = {B05,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}
  }
}
%</meta|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-pis>
\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,A04,A06,B01,B03,B06,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
    }
}
%</meta|doc-table-a|doc-table-pis>

%<*meta|doc-table-a|doc-table-pis>
\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,per6},
  collaborations     = {A01,A03,B02,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
  }
}
%</meta|doc-table-a|doc-table-pis>

%<*meta>
\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      = {per4,per10},
  collaborations     = {}
}
%</meta>

%<*meta|doc-table-b|doc-table-pis>
\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,B02,B03,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
  }
}
%</meta|doc-table-b|doc-table-pis>

%<*meta|doc-table-b|doc-table-pis>
\addEntry{project}{
  id                 = {B02},
  project-area       = {B},
  number             = {B02},
  project-status     = {N},
  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,per10},
  collaborations     = {A02,B01,B04,Q01},
  legal-issues       = {
      L1  = yes,
      L1a = no,
      L2  = yes,
      L2a = yes,
      L3  = yes,
      L4  = yes,
      L5  = yes,
      L5a = no,
      L6  = yes,
      L7  = yes,
      L7a = no
    }
}
%</meta|doc-table-b|doc-table-pis>

%<*meta|doc-table-q|doc-table-pis>
\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,per7},
  collaborations     = {A01,A03,A04,A06,B02,B03,B05},
  legal-issues       = {
    L1  = no,
    L1a = no,
    L2  = no,
    L2a = no,
    L3  = no,
    L4  = no,
    L5  = no,
    L5a = no,
    L6  = no,
    L7  = no,
    L7a = no
  }
}
%</meta|doc-table-q|doc-table-pis>

%<*meta|doc-table-q|doc-table-pis>
\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,per9},
  collaborations     = {A02,A05,B01,B04,B06}
}
%</meta|doc-table-q|doc-table-pis>

%<*meta|doc-table-q|doc-table-pis>
\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,per12},
  collaborations     = {A01,A02,A03,A04,A05,A06,B01,B02,B03,B04,B05,B06,Q01,Q02}
}
%</meta|doc-table-q|doc-table-pis>

%<*meta>
\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}
}
%</meta>

%<*meta>
\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}
}
%</meta>

%<*meta>
\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}
}
%</meta>

%<*meta>
\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}
}
%</meta>

%<*meta|doc-table-a|doc-table-q|doc-table-pis>
\addEntry{affiliation}{
  id                  = {aff3},
  name                = {Northbridge University},
  abbreviation        = {NU},
  addressStreet       = {Science Avenue 3},
  addressZIP          = {34567},
  location            = {Northbridge},
  country             = {Germany}
}
%</meta|doc-table-a|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>
\addEntry{affiliation}{
  id                  = {aff4},
  name                = {Westhaven Research Centre},
  abbreviation        = {WRC},
  addressStreet       = {Science Avenue 3},
  addressZIP          = {34567},
  location            = {Westhaven},
  country             = {Germany}
}
%</meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-q|doc-table-pis>
\addEntry{institution}{
  id                  = {ins3},
  name                = {Centre for Computational Microbiology},
  abbreviation        = {CCM},
  ref-affiliation-id  = {aff3}
}
%</meta|doc-table-a|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-q|doc-table-pis>
\addEntry{institution}{
  id                  = {ins4},
  name                = {Department of Experimental Immunology},
  abbreviation        = {DEI},
  ref-affiliation-id  = {aff3}
}
%</meta|doc-table-a|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>
\addEntry{institution}{
  id                  = {ins5},
  name                = {Institute of Metabolic Medicine},
  abbreviation        = {IMM},
  ref-affiliation-id  = {aff4}
}
%</meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>
\addEntry{institution}{
  id                  = {ins6},
  name                = {Centre for Clinical Translation},
  abbreviation        = {CCT},
  ref-affiliation-id  = {aff4}
}
%</meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-pis>
\addEntry{person}{
  id                  = {per6},
  orcid               = {0000-0000-0000-0016},
  firstname           = {Samira},
  lastname            = {Hartmann},
  academicdegree      = {Prof. Dr. rer. nat.},
  period              = {3},
  role                = {PI,steering-committee-member},
  gender              = {f},
  ref-institution-id  = {ins3},
  ref-project-id      = {A02,A03},
  position            = {prof-W2},
  positionText        = {Professor of Systems Medicine},
  doctorateYear       = {2010},
  doctorate           = {Dr. rer. nat., Example University},
  degree-programme    = {Life Sciences, Example University},
  phone               = {+49 000 300-0006},
  email               = {samira@example.org}
}
%</meta|doc-table-a|doc-table-pis>

%<*meta|doc-table-a|doc-table-q|doc-table-pis>
\addEntry{person}{
  id                  = {per7},
  firstname           = {Noah},
  lastname            = {Lindberg},
  academicdegree      = {Prof. Dr. rer. nat.},
  period              = {3},
  role                = {PI},
  gender              = {m},
  ref-institution-id  = {ins3,ins4},
  ref-project-id      = {A03,A04,Q01},
  position            = {prof-W2},
  positionText        = {Professor of Systems Medicine},
  doctorateYear       = {2010},
  doctorate           = {Dr. rer. nat., Example University},
  degree-programme    = {Life Sciences, Example University},
  phone               = {+49 000 300-0007},
  email               = {noah@example.org}
}
%</meta|doc-table-a|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-pis>
\addEntry{person}{
  id                  = {per8},
  firstname           = {Alexis-Marie},
  lastname            = {Winters-Scholz},
  academicdegree      = {Prof. Dr. rer. nat.},
  period              = {3},
  role                = {PI},
  gender              = {d},
  ref-institution-id  = {ins4},
  ref-project-id      = {A04,A05},
  position            = {prof-W2},
  positionText        = {Professor of Systems Medicine},
  doctorateYear       = {2010},
  doctorate           = {Dr. rer. nat., Example University},
  degree-programme    = {Life Sciences, Example University},
  phone               = {+49 000 300-0008},
  email               = {alexis-marie@example.org}
}
%</meta|doc-table-a|doc-table-pis>

%<*meta|doc-table-a|doc-table-q|doc-table-pis>
\addEntry{person}{
  id                  = {per9},
  firstname           = {Leonie},
  lastname            = {Navarro},
  academicdegree      = {Prof. Dr. rer. nat.},
  period              = {3},
  role                = {PI},
  gender              = {f},
  ref-institution-id  = {ins5},
  ref-project-id      = {A05,A06,Q02},
  position            = {prof-W2},
  positionText        = {Professor of Systems Medicine},
  doctorateYear       = {2010},
  doctorate           = {Dr. rer. nat., Example University},
  degree-programme    = {Life Sciences, Example University},
  phone               = {+49 000 300-0009},
  email               = {leonie@example.org}
}
%</meta|doc-table-a|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-b|doc-table-pis>
\addEntry{person}{
  id                  = {per10},
  firstname           = {Daniel},
  lastname            = {Okafor},
  academicdegree      = {Prof. Dr. rer. nat.},
  period              = {3},
  role                = {PI},
  gender              = {m},
  ref-institution-id  = {ins5,ins6},
  ref-project-id      = {A06,B02,B06},
  position            = {prof-W2},
  positionText        = {Professor of Systems Medicine},
  doctorateYear       = {2010},
  doctorate           = {Dr. rer. nat., Example University},
  degree-programme    = {Life Sciences, Example University},
  phone               = {+49 000 300-0010},
  email               = {daniel@example.org}
}
%</meta|doc-table-a|doc-table-b|doc-table-pis>

%<*meta|doc-table-b|doc-table-pis>
\addEntry{person}{
  id                  = {per11},
  firstname           = {Mira},
  lastname            = {Sato},
  academicdegree      = {Prof. Dr. rer. nat.},
  period              = {3},
  role                = {PI},
  gender              = {f},
  ref-institution-id  = {ins6},
  ref-project-id      = {B03,B04},
  position            = {prof-W2},
  positionText        = {Professor of Systems Medicine},
  doctorateYear       = {2010},
  doctorate           = {Dr. rer. nat., Example University},
  degree-programme    = {Life Sciences, Example University},
  phone               = {+49 000 300-0011},
  email               = {mira@example.org}
}
%</meta|doc-table-b|doc-table-pis>

%<*meta|doc-table-b|doc-table-q|doc-table-pis>
\addEntry{person}{
  id                  = {per12},
  firstname           = {Robin},
  lastname            = {Keller},
  academicdegree      = {Prof. Dr. rer. nat.},
  period              = {3},
  role                = {PI},
  gender              = {d},
  ref-institution-id  = {ins1,ins6},
  ref-project-id      = {B05,B06,Q03},
  position            = {prof-W2},
  positionText        = {Professor of Systems Medicine},
  doctorateYear       = {2010},
  doctorate           = {Dr. rer. nat., Example University},
  degree-programme    = {Life Sciences, Example University},
  phone               = {+49 000 300-0012},
  email               = {robin@example.org}
}
%</meta|doc-table-b|doc-table-q|doc-table-pis>

%<*meta|doc-table-a|doc-table-pis>
\addEntry{project}{
  id                  = {A03},
  project-area        = {A},
  number              = {A03},
  project-status      = {C},
  consider-for-lists  = {true},
  reference-only      = {false},
  name                = {Microbiome-derived metabolites and immune memory},
  project-type        = {research},
  research-area       = {2.21-02},
  ref-person-id       = {per6,per7},
  collaborations      = {A02,A04,B03,Q01}
}
%</meta|doc-table-a|doc-table-pis>

%<*meta|doc-table-a|doc-table-pis>
\addEntry{project}{
  id                  = {A04},
  project-area        = {A},
  number              = {A04},
  project-status      = {N},
  consider-for-lists  = {true},
  reference-only      = {false},
  name                = {Spatial niches of host--microbe interactions},
  project-type        = {research},
  research-area       = {2.21-02},
  ref-person-id       = {per7,per8},
  collaborations      = {A01,A03,A05,B04,Q01}
}
%</meta|doc-table-a|doc-table-pis>

%<*meta|doc-table-a|doc-table-pis>
\addEntry{project}{
  id                  = {A05},
  project-area        = {A},
  number              = {A05},
  project-status      = {C},
  consider-for-lists  = {true},
  reference-only      = {false},
  name                = {Dietary control of microbial community dynamics},
  project-type        = {research},
  research-area       = {2.21-02},
  ref-person-id       = {per8,per9},
  collaborations      = {A04,A06,B05,Q02}
}
%</meta|doc-table-a|doc-table-pis>

%<*meta|doc-table-a|doc-table-pis>
\addEntry{project}{
  id                  = {A06},
  project-area        = {A},
  number              = {A06},
  project-status      = {N},
  consider-for-lists  = {true},
  reference-only      = {false},
  name                = {Modelling microbial resilience and recovery},
  project-type        = {research},
  research-area       = {2.21-02},
  ref-person-id       = {per9,per10},
  collaborations      = {A01,A05,B06,Q01}
}
%</meta|doc-table-a|doc-table-pis>

%<*meta|doc-table-b|doc-table-pis>
\addEntry{project}{
  id                  = {B03},
  project-area        = {B},
  number              = {B03},
  project-status      = {C},
  consider-for-lists  = {true},
  reference-only      = {false},
  name                = {Immune circuits linking intestine and liver},
  project-type        = {research},
  research-area       = {2.21-02},
  ref-person-id       = {per3,per11},
  collaborations      = {A01,A03,B01,B05,Q01}
}
%</meta|doc-table-b|doc-table-pis>

%<*meta|doc-table-b|doc-table-pis>
\addEntry{project}{
  id                  = {B04},
  project-area        = {B},
  number              = {B04},
  project-status      = {N},
  consider-for-lists  = {true},
  reference-only      = {false},
  name                = {Cross-organ consequences of inflammatory stress},
  project-type        = {research},
  research-area       = {2.21-02},
  ref-person-id       = {per4,per11},
  collaborations      = {A04,B02,B06,Q02}
}
%</meta|doc-table-b|doc-table-pis>

%<*meta|doc-table-b|doc-table-pis>
\addEntry{project}{
  id                  = {B05},
  project-area        = {B},
  number              = {B05},
  project-status      = {C},
  consider-for-lists  = {true},
  reference-only      = {false},
  name                = {Patient-derived models of metabolic disease},
  project-type        = {research},
  research-area       = {2.21-02},
  ref-person-id       = {per5,per12},
  collaborations      = {A05,B03,B06,Q01}
}
%</meta|doc-table-b|doc-table-pis>

%<*meta|doc-table-b|doc-table-pis>
\addEntry{project}{
  id                  = {B06},
  project-area        = {B},
  number              = {B06},
  project-status      = {N},
  consider-for-lists  = {true},
  reference-only      = {false},
  name                = {Translating microbial biomarkers into interventions},
  project-type        = {research},
  research-area       = {2.21-02},
  ref-person-id       = {per10,per12},
  collaborations      = {A01,A06,B04,B05,Q02}
}
%</meta|doc-table-b|doc-table-pis>

%<*!example-data>
%<*meta>
\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}
}
%</meta>
%<*meta>
\addEntry[funding]{RequestedFunding}{
  ref-project-id={A02}, funding-type={costs}, category={consumables},
  sum={year1=1000,year2=2000,year3=2000,year4=2000,year5=1000}
}
%</meta>
%<*meta>
\addEntry[staff]{RequestedFundingStaff}{
  ref-project-id={A02}, ref-person-id={per6},
  funding-status={existing}, staff-type={research},
  field-of-research={Microbiology}, commitment={8}, funding-source={State funds},
  description={Supervises experiments and analysis.}
}
%</meta>
%</!example-data>
%    \end{macrocode}
% \iffalse

%<doc-table-a>\printTable{{Projects}{A}{Microbiota and metabolic pathways}}
%<doc-table-b>\printTable{{Projects}{B}{Immune mechanisms and clinical translation}}
%<doc-table-q>\printTable{{Projects}{Q}{Shared services, training, and coordination}}
%<doc-table-pis>\printTable{ProjectLeaders}
%</meta|doc-table-a|doc-table-b|doc-table-q|doc-table-pis>
%<*meta-cv>
% \fi
%    \begin{macrocode}

%% Fictional CV fixtures shared by the local CV and the embedded manual PDF.

%% Each PI demonstrates three career stages and all five optional categories.


%% Kim Sample: Microbial systems medicine.

\addEntry[cv]{cv-per1}{
  ref-person-id      = {per1},
  cv-type            = {mandatory},
  periodStart        = {2013},
  periodEnd          = {},
  positionText       = {Professor and Director},
  position           = {Current appointment},
  description        = {Leads the mechanistic microbiome programme and
    coordinates the shared experimental strategy.},
  ref-institution-id = {ins1}
}

\addEntry[cv]{cv-per1}{
  ref-person-id      = {per1},
  cv-type            = {mandatory},
  periodStart        = {2005},
  periodEnd          = {2012},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on microbial metabolites
    and epithelial signalling and developed collaborative
    methods.},
  ref-institution-id = {ins1}
}

\addEntry[cv]{cv-per1}{
  ref-person-id      = {per1},
  cv-type            = {mandatory},
  periodStart        = {2001},
  periodEnd          = {2004},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    microbial metabolites and epithelial signalling.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per1}{
  ref-person-id      = {per1},
  cv-type            = {supplement},
  description        = {Research focus: microbial metabolites and epithelial
    signalling. A visiting fellowship at the Example
    Centre for Interdisciplinary Research supported new
    collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per1}{
  ref-person-id      = {per1},
  cv-type            = {activities},
  description        = {Chairs the consortium steering committee and an
    annual host--microbiome symposium. Contributes to
    peer review and open teaching materials.}
}

\addEntry[cv]{cv-per1}{
  ref-person-id      = {per1},
  cv-type            = {supervision},
  description        = {Mentors laboratory and clinical doctoral researchers
    through joint thesis committees. Regular progress
    reviews include research integrity and publication
    planning.}
}

\addEntry[cv]{cv-per1}{
  ref-person-id      = {per1},
  cv-type            = {distinction},
  description        = {2024: Example Academy fellowship for
    interdisciplinary microbiome research. 2021:
    consortium mentoring recognition for support of
    early-career researchers.}
}

\addEntry[cv]{cv-per1}{
  ref-person-id      = {per1},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}


%% Alex Example: Computational systems biology.

\addEntry[cv]{cv-per2}{
  ref-person-id      = {per2},
  cv-type            = {mandatory},
  periodStart        = {2016},
  periodEnd          = {},
  positionText       = {Research group leader},
  position           = {Current appointment},
  description        = {Develops statistical models linking molecular
    measurements with clinical phenotypes.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per2}{
  ref-person-id      = {per2},
  cv-type            = {mandatory},
  periodStart        = {2004},
  periodEnd          = {2015},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on multimodal data
    integration and reproducible analysis and developed
    collaborative methods.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per2}{
  ref-person-id      = {per2},
  cv-type            = {mandatory},
  periodStart        = {2000},
  periodEnd          = {2003},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    multimodal data integration and reproducible
    analysis.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per2}{
  ref-person-id      = {per2},
  cv-type            = {supplement},
  description        = {Research focus: multimodal data integration and
    reproducible analysis. A visiting fellowship at the
    Example Centre for Interdisciplinary Research
    supported new collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per2}{
  ref-person-id      = {per2},
  cv-type            = {activities},
  description        = {Leads the data standards working group and maintains
    the consortium code-review programme. Contributes to
    peer review and open teaching materials.}
}

\addEntry[cv]{cv-per2}{
  ref-person-id      = {per2},
  cv-type            = {supervision},
  description        = {Supervises doctoral projects in statistics and
    biology, with paired computational and experimental
    mentors. Regular progress reviews include research
    integrity and publication planning.}
}

\addEntry[cv]{cv-per2}{
  ref-person-id      = {per2},
  cv-type            = {distinction},
  description        = {2024: Partner University award for open research
    software. 2021: consortium mentoring recognition for
    support of early-career researchers.}
}

\addEntry[cv]{cv-per2}{
  ref-person-id      = {per2},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}


%% Hansi Meier: Microbiology and host defence.

\addEntry[cv]{cv-per3}{
  ref-person-id      = {per3},
  cv-type            = {mandatory},
  periodStart        = {2018},
  periodEnd          = {},
  positionText       = {Senior research scientist},
  position           = {Current appointment},
  description        = {Coordinates experimental infection models and
    validation of immune mechanisms.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per3}{
  ref-person-id      = {per3},
  cv-type            = {mandatory},
  periodStart        = {2004},
  periodEnd          = {2017},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on microbial sensing and
    innate immune memory and developed collaborative
    methods.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per3}{
  ref-person-id      = {per3},
  cv-type            = {mandatory},
  periodStart        = {2000},
  periodEnd          = {2003},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    microbial sensing and innate immune memory.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per3}{
  ref-person-id      = {per3},
  cv-type            = {supplement},
  description        = {Research focus: microbial sensing and innate immune
    memory. A visiting fellowship at the Example Centre
    for Interdisciplinary Research supported new
    collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per3}{
  ref-person-id      = {per3},
  cv-type            = {activities},
  description        = {Organises a practical course on host defence and
    serves on the laboratory methods committee.
    Contributes to peer review and open teaching
    materials.}
}

\addEntry[cv]{cv-per3}{
  ref-person-id      = {per3},
  cv-type            = {supervision},
  description        = {Mentors early-career scientists in experimental
    design, biosafety and reproducible laboratory
    practice. Regular progress reviews include research
    integrity and publication planning.}
}

\addEntry[cv]{cv-per3}{
  ref-person-id      = {per3},
  cv-type            = {distinction},
  description        = {2024: Example Society prize for translational
    infection research. 2021: consortium mentoring
    recognition for support of early-career researchers.}
}

\addEntry[cv]{cv-per3}{
  ref-person-id      = {per3},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}


%% Kimmi Miller: Molecular tissue regeneration.

\addEntry[cv]{cv-per4}{
  ref-person-id      = {per4},
  cv-type            = {mandatory},
  periodStart        = {2015},
  periodEnd          = {},
  positionText       = {Professor of Molecular Medicine},
  position           = {Current appointment},
  description        = {Connects organoid perturbation experiments with
    molecular measurements of tissue recovery.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per4}{
  ref-person-id      = {per4},
  cv-type            = {mandatory},
  periodStart        = {2004},
  periodEnd          = {2014},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on epithelial repair and
    tissue regeneration and developed collaborative
    methods.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per4}{
  ref-person-id      = {per4},
  cv-type            = {mandatory},
  periodStart        = {2000},
  periodEnd          = {2003},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    epithelial repair and tissue regeneration.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per4}{
  ref-person-id      = {per4},
  cv-type            = {supplement},
  description        = {Research focus: epithelial repair and tissue
    regeneration. A visiting fellowship at the Example
    Centre for Interdisciplinary Research supported new
    collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per4}{
  ref-person-id      = {per4},
  cv-type            = {activities},
  description        = {Coordinates the organoid methods network and an
    interdisciplinary regeneration seminar. Contributes
    to peer review and open teaching materials.}
}

\addEntry[cv]{cv-per4}{
  ref-person-id      = {per4},
  cv-type            = {supervision},
  description        = {Supervises doctoral researchers in molecular medicine
    and provides mentoring for clinician scientists.
    Regular progress reviews include research integrity
    and publication planning.}
}

\addEntry[cv]{cv-per4}{
  ref-person-id      = {per4},
  cv-type            = {distinction},
  description        = {2024: Partner University award for collaborative
    tissue research. 2021: consortium mentoring
    recognition for support of early-career researchers.}
}

\addEntry[cv]{cv-per4}{
  ref-person-id      = {per4},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}


%% Friedhelm Redata: Biomedical research training.

\addEntry[cv]{cv-per5}{
  ref-person-id      = {per5},
  cv-type            = {mandatory},
  periodStart        = {2014},
  periodEnd          = {},
  positionText       = {Professor of Research Training},
  position           = {Current appointment},
  description        = {Directs the graduate programme and evaluates
    interdisciplinary training formats.},
  ref-institution-id = {ins1}
}

\addEntry[cv]{cv-per5}{
  ref-person-id      = {per5},
  cv-type            = {mandatory},
  periodStart        = {2003},
  periodEnd          = {2013},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on structured doctoral
    training and research integrity and developed
    collaborative methods.},
  ref-institution-id = {ins1}
}

\addEntry[cv]{cv-per5}{
  ref-person-id      = {per5},
  cv-type            = {mandatory},
  periodStart        = {1999},
  periodEnd          = {2002},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    structured doctoral training and research integrity.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per5}{
  ref-person-id      = {per5},
  cv-type            = {supplement},
  description        = {Research focus: structured doctoral training and
    research integrity. A visiting fellowship at the
    Example Centre for Interdisciplinary Research
    supported new collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per5}{
  ref-person-id      = {per5},
  cv-type            = {activities},
  description        = {Chairs the graduate curriculum committee and
    coordinates the annual doctoral retreat. Contributes
    to peer review and open teaching materials.}
}

\addEntry[cv]{cv-per5}{
  ref-person-id      = {per5},
  cv-type            = {supervision},
  description        = {Supports thesis committees, individual development
    plans and peer mentoring across all research areas.
    Regular progress reviews include research integrity
    and publication planning.}
}

\addEntry[cv]{cv-per5}{
  ref-person-id      = {per5},
  cv-type            = {distinction},
  description        = {2024: Example University prize for doctoral
    education. 2021: consortium mentoring recognition for
    support of early-career researchers.}
}

\addEntry[cv]{cv-per5}{
  ref-person-id      = {per5},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}


%% Samira Hartmann: Microbial systems medicine.

\addEntry[cv]{cv-per6}{
  ref-person-id      = {per6},
  cv-type            = {mandatory},
  periodStart        = {2018},
  periodEnd          = {},
  positionText       = {Professor of Systems Medicine},
  position           = {Current appointment},
  description        = {Combines microbial genetics with functional assays of
    host metabolic responses.},
  ref-institution-id = {ins3}
}

\addEntry[cv]{cv-per6}{
  ref-person-id      = {per6},
  cv-type            = {mandatory},
  periodStart        = {2015},
  periodEnd          = {2017},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on microbial metabolic
    pathways and immune adaptation and developed
    collaborative methods.},
  ref-institution-id = {ins3}
}

\addEntry[cv]{cv-per6}{
  ref-person-id      = {per6},
  cv-type            = {mandatory},
  periodStart        = {2011},
  periodEnd          = {2014},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    microbial metabolic pathways and immune adaptation.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per6}{
  ref-person-id      = {per6},
  cv-type            = {supplement},
  description        = {Research focus: microbial metabolic pathways and
    immune adaptation. A visiting fellowship at the
    Example Centre for Interdisciplinary Research
    supported new collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per6}{
  ref-person-id      = {per6},
  cv-type            = {activities},
  description        = {Coordinates the pathway-discovery workshop and joint
    protocol reviews across the consortium. Contributes
    to peer review and open teaching materials.}
}

\addEntry[cv]{cv-per6}{
  ref-person-id      = {per6},
  cv-type            = {supervision},
  description        = {Supervises paired microbiology and immunology
    projects, including laboratory exchanges for doctoral
    researchers. Regular progress reviews include
    research integrity and publication planning.}
}

\addEntry[cv]{cv-per6}{
  ref-person-id      = {per6},
  cv-type            = {distinction},
  description        = {2024: Example Foundation award for microbial systems
    research. 2021: consortium mentoring recognition for
    support of early-career researchers.}
}

\addEntry[cv]{cv-per6}{
  ref-person-id      = {per6},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}


%% Noah Lindberg: Spatial immunology.

\addEntry[cv]{cv-per7}{
  ref-person-id      = {per7},
  cv-type            = {mandatory},
  periodStart        = {2018},
  periodEnd          = {},
  positionText       = {Professor of Systems Medicine},
  position           = {Current appointment},
  description        = {Links spatial profiling to microscopy and
    quantitative descriptions of immune-cell
    neighbourhoods.},
  ref-institution-id = {ins3}
}

\addEntry[cv]{cv-per7}{
  ref-person-id      = {per7},
  cv-type            = {mandatory},
  periodStart        = {2015},
  periodEnd          = {2017},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on spatial immune niches
    and quantitative imaging and developed collaborative
    methods.},
  ref-institution-id = {ins3}
}

\addEntry[cv]{cv-per7}{
  ref-person-id      = {per7},
  cv-type            = {mandatory},
  periodStart        = {2011},
  periodEnd          = {2014},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    spatial immune niches and quantitative imaging.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per7}{
  ref-person-id      = {per7},
  cv-type            = {supplement},
  description        = {Research focus: spatial immune niches and
    quantitative imaging. A visiting fellowship at the
    Example Centre for Interdisciplinary Research
    supported new collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per7}{
  ref-person-id      = {per7},
  cv-type            = {activities},
  description        = {Leads the imaging quality-control forum and teaches
    the annual spatial-analysis course. Contributes to
    peer review and open teaching materials.}
}

\addEntry[cv]{cv-per7}{
  ref-person-id      = {per7},
  cv-type            = {supervision},
  description        = {Mentors doctoral researchers in image analysis, with
    shared supervision across experimental and
    computational groups. Regular progress reviews
    include research integrity and publication planning.}
}

\addEntry[cv]{cv-per7}{
  ref-person-id      = {per7},
  cv-type            = {distinction},
  description        = {2024: Example Imaging Society early-career research
    prize. 2021: consortium mentoring recognition for
    support of early-career researchers.}
}

\addEntry[cv]{cv-per7}{
  ref-person-id      = {per7},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}


%% Alexis-Marie Winters-Scholz: Host--microbe interactions.

\addEntry[cv]{cv-per8}{
  ref-person-id      = {per8},
  cv-type            = {mandatory},
  periodStart        = {2018},
  periodEnd          = {},
  positionText       = {Professor of Systems Medicine},
  position           = {Current appointment},
  description        = {Develops experimental models of diet-dependent
    microbial colonisation and mucosal responses.},
  ref-institution-id = {ins4}
}

\addEntry[cv]{cv-per8}{
  ref-person-id      = {per8},
  cv-type            = {mandatory},
  periodStart        = {2015},
  periodEnd          = {2017},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on dietary perturbations
    and mucosal microbial communities and developed
    collaborative methods.},
  ref-institution-id = {ins4}
}

\addEntry[cv]{cv-per8}{
  ref-person-id      = {per8},
  cv-type            = {mandatory},
  periodStart        = {2011},
  periodEnd          = {2014},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    dietary perturbations and mucosal microbial
    communities.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per8}{
  ref-person-id      = {per8},
  cv-type            = {supplement},
  description        = {Research focus: dietary perturbations and mucosal
    microbial communities. A visiting fellowship at the
    Example Centre for Interdisciplinary Research
    supported new collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per8}{
  ref-person-id      = {per8},
  cv-type            = {activities},
  description        = {Coordinates the experimental-models working group and
    a public seminar series on microbiome science.
    Contributes to peer review and open teaching
    materials.}
}

\addEntry[cv]{cv-per8}{
  ref-person-id      = {per8},
  cv-type            = {supervision},
  description        = {Supervises doctoral projects in microbial ecology and
    supports exchange placements between partner
    laboratories. Regular progress reviews include
    research integrity and publication planning.}
}

\addEntry[cv]{cv-per8}{
  ref-person-id      = {per8},
  cv-type            = {distinction},
  description        = {2024: Example University award for experimental
    microbiome research. 2021: consortium mentoring
    recognition for support of early-career researchers.}
}

\addEntry[cv]{cv-per8}{
  ref-person-id      = {per8},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}


%% Leonie Navarro: Metabolic systems biology.

\addEntry[cv]{cv-per9}{
  ref-person-id      = {per9},
  cv-type            = {mandatory},
  periodStart        = {2018},
  periodEnd          = {},
  positionText       = {Professor of Systems Medicine},
  position           = {Current appointment},
  description        = {Integrates dietary interventions with metabolic
    profiling and predictive modelling.},
  ref-institution-id = {ins5}
}

\addEntry[cv]{cv-per9}{
  ref-person-id      = {per9},
  cv-type            = {mandatory},
  periodStart        = {2015},
  periodEnd          = {2017},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on nutrient sensing and
    predictive metabolic models and developed
    collaborative methods.},
  ref-institution-id = {ins5}
}

\addEntry[cv]{cv-per9}{
  ref-person-id      = {per9},
  cv-type            = {mandatory},
  periodStart        = {2011},
  periodEnd          = {2014},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    nutrient sensing and predictive metabolic models.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per9}{
  ref-person-id      = {per9},
  cv-type            = {supplement},
  description        = {Research focus: nutrient sensing and predictive
    metabolic models. A visiting fellowship at the
    Example Centre for Interdisciplinary Research
    supported new collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per9}{
  ref-person-id      = {per9},
  cv-type            = {activities},
  description        = {Organises the metabolic modelling summer school and
    contributes to graduate admissions panels.
    Contributes to peer review and open teaching
    materials.}
}

\addEntry[cv]{cv-per9}{
  ref-person-id      = {per9},
  cv-type            = {supervision},
  description        = {Mentors doctoral researchers in model validation,
    interdisciplinary communication and career planning.
    Regular progress reviews include research integrity
    and publication planning.}
}

\addEntry[cv]{cv-per9}{
  ref-person-id      = {per9},
  cv-type            = {distinction},
  description        = {2024: Example Society distinction for integrative
    metabolic research. 2021: consortium mentoring
    recognition for support of early-career researchers.}
}

\addEntry[cv]{cv-per9}{
  ref-person-id      = {per9},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}


%% Daniel Okafor: Translational systems medicine.

\addEntry[cv]{cv-per10}{
  ref-person-id      = {per10},
  cv-type            = {mandatory},
  periodStart        = {2018},
  periodEnd          = {},
  positionText       = {Professor of Systems Medicine},
  position           = {Current appointment},
  description        = {Connects patient-derived measurements with biomarker
    validation and experimental tissue models.},
  ref-institution-id = {ins5}
}

\addEntry[cv]{cv-per10}{
  ref-person-id      = {per10},
  cv-type            = {mandatory},
  periodStart        = {2015},
  periodEnd          = {2017},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on microbial biomarkers
    and clinical tissue responses and developed
    collaborative methods.},
  ref-institution-id = {ins5}
}

\addEntry[cv]{cv-per10}{
  ref-person-id      = {per10},
  cv-type            = {mandatory},
  periodStart        = {2011},
  periodEnd          = {2014},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    microbial biomarkers and clinical tissue responses.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per10}{
  ref-person-id      = {per10},
  cv-type            = {supplement},
  description        = {Research focus: microbial biomarkers and clinical
    tissue responses. A visiting fellowship at the
    Example Centre for Interdisciplinary Research
    supported new collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per10}{
  ref-person-id      = {per10},
  cv-type            = {activities},
  description        = {Coordinates the translational data-analysis workshop
    and the clinical assay harmonisation group.
    Contributes to peer review and open teaching
    materials.}
}

\addEntry[cv]{cv-per10}{
  ref-person-id      = {per10},
  cv-type            = {supervision},
  description        = {Supervises clinician scientists and laboratory
    researchers in joint translational thesis projects.
    Regular progress reviews include research integrity
    and publication planning.}
}

\addEntry[cv]{cv-per10}{
  ref-person-id      = {per10},
  cv-type            = {distinction},
  description        = {2024: Westhaven Research Centre translational science
    award. 2021: consortium mentoring recognition for
    support of early-career researchers.}
}

\addEntry[cv]{cv-per10}{
  ref-person-id      = {per10},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}


%% Mira Sato: Cross-organ immunology.

\addEntry[cv]{cv-per11}{
  ref-person-id      = {per11},
  cv-type            = {mandatory},
  periodStart        = {2018},
  periodEnd          = {},
  positionText       = {Professor of Systems Medicine},
  position           = {Current appointment},
  description        = {Coordinates tissue sampling and comparative analyses
    of inflammatory responses across organs.},
  ref-institution-id = {ins6}
}

\addEntry[cv]{cv-per11}{
  ref-person-id      = {per11},
  cv-type            = {mandatory},
  periodStart        = {2015},
  periodEnd          = {2017},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on inflammatory circuits
    between intestine and liver and developed
    collaborative methods.},
  ref-institution-id = {ins6}
}

\addEntry[cv]{cv-per11}{
  ref-person-id      = {per11},
  cv-type            = {mandatory},
  periodStart        = {2011},
  periodEnd          = {2014},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    inflammatory circuits between intestine and liver.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per11}{
  ref-person-id      = {per11},
  cv-type            = {supplement},
  description        = {Research focus: inflammatory circuits between
    intestine and liver. A visiting fellowship at the
    Example Centre for Interdisciplinary Research
    supported new collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per11}{
  ref-person-id      = {per11},
  cv-type            = {activities},
  description        = {Leads the clinical sample-coordination group and
    teaches a course on cross-organ immunology.
    Contributes to peer review and open teaching
    materials.}
}

\addEntry[cv]{cv-per11}{
  ref-person-id      = {per11},
  cv-type            = {supervision},
  description        = {Mentors doctoral researchers in clinical cohort
    design, sample governance and mechanistic validation.
    Regular progress reviews include research integrity
    and publication planning.}
}

\addEntry[cv]{cv-per11}{
  ref-person-id      = {per11},
  cv-type            = {distinction},
  description        = {2024: Example Clinical Research Society award for
    collaborative immunology. 2021: consortium mentoring
    recognition for support of early-career researchers.}
}

\addEntry[cv]{cv-per11}{
  ref-person-id      = {per11},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}


%% Robin Keller: Integrative systems medicine.

\addEntry[cv]{cv-per12}{
  ref-person-id      = {per12},
  cv-type            = {mandatory},
  periodStart        = {2018},
  periodEnd          = {},
  positionText       = {Professor of Systems Medicine},
  position           = {Current appointment},
  description        = {Combines patient-derived models with biomarker
    translation and stewardship of shared research data.},
  ref-institution-id = {ins1}
}

\addEntry[cv]{cv-per12}{
  ref-person-id      = {per12},
  cv-type            = {mandatory},
  periodStart        = {2015},
  periodEnd          = {2017},
  positionText       = {Independent research group leader},
  position           = {Independent research},
  description        = {Established a research team on patient-derived models
    and biomarker translation and developed collaborative
    methods.},
  ref-institution-id = {ins1}
}

\addEntry[cv]{cv-per12}{
  ref-person-id      = {per12},
  cv-type            = {mandatory},
  periodStart        = {2011},
  periodEnd          = {2014},
  positionText       = {Postdoctoral researcher},
  position           = {Postdoctoral training},
  description        = {Developed experimental and analytical approaches to
    patient-derived models and biomarker translation.},
  ref-institution-id = {ins2}
}

\addEntry[cv]{cv-per12}{
  ref-person-id      = {per12},
  cv-type            = {supplement},
  description        = {Research focus: patient-derived models and biomarker
    translation. A visiting fellowship at the Example
    Centre for Interdisciplinary Research supported new
    collaborations and exchange of methods.}
}

\addEntry[cv]{cv-per12}{
  ref-person-id      = {per12},
  cv-type            = {activities},
  description        = {Chairs the consortium reproducibility forum and
    coordinates workshops on reusable clinical research
    data. Contributes to peer review and open teaching
    materials.}
}

\addEntry[cv]{cv-per12}{
  ref-person-id      = {per12},
  cv-type            = {supervision},
  description        = {Co-supervises doctoral researchers across clinical
    and computational projects, with individual
    career-development plans. Regular progress reviews
    include research integrity and publication planning.}
}

\addEntry[cv]{cv-per12}{
  ref-person-id      = {per12},
  cv-type            = {distinction},
  description        = {2024: Example University award for reproducible
    translational medicine. 2021: consortium mentoring
    recognition for support of early-career researchers.}
}

\addEntry[cv]{cv-per12}{
  ref-person-id      = {per12},
  cv-type            = {other},
  description        = {Makes analysis protocols and training resources
    available for reuse. No commercial interests related
    to the proposed research. All career details and
    distinctions in this CV are fictional examples.}
}

% \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[raster columns=1]{spokesperson}
  \end{minipage}\hfill%
  \begin{minipage}[t]{.49\linewidth}
  	\textbf{Management or office of\\the \crc:}\\[1\baselineskip]
    \getPIsWithRole[raster columns=1]{manager}
  \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.
\defbibheading{frame-references}[References]{\subsection*{#1}}
\printFrameBibliography[heading=frame-references]


\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      = {Sample},
  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-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 default full-width arc layout shows nodes and area rules without edges.
\printPlot{{ProjectCollaboration}{A01}}
%% To draw the connecting arcs, replace the call above with:
%% \printPlot[arcs=true,caption={Optional additional caption text.}]
%%   {{collaborations}{A01}}
%% Use [layout=heatmap] for the alternative heatmap layout.


\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-ending>
% \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{A00}

\section{Project history}
\label{A00:project-history}

\subsection{Report}
\label{A00: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{A00: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{A00: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{A00: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     = {A00},
  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     = {A00},
  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}{A00}}

\printProjectTail
%    \end{macrocode}
% \iffalse
%</03-project-ending>
%<*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{known as 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 image switch is initially
%% false so the fast project option prevents the proposal metadata from loading.
%% Immediately after \begin{document} the image switch is enabled so dummy
%% project entries are retained and the plots below exercise their focused-mode
%% dispatch without disabling the other fast-mode reductions.
\documentclass[
  fastcompile-project = true,
  fastcompile-project-show-images = false,
  english
]{dfg-crc}

\begin{document}

\ExplSyntaxOn
\bool_set_true:N \l_@@_class_fastcompile_project_show_images_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}

%% Focused image mode must retain Gantt rows created through the same data path
%% as ordinary project work packages.
\addEntry[gantt]{gantt-B06}{
  id = {wp1},
  name = {Dummy work package},
  description = {Dummy Gantt bar},
  periodStart = {1},
  periodEnd = {4},
  style = {default}
}

\printPlot{{Gantt}{B06}}

%% The first plot is deliberately called before any project-area key has been
%% entered.  It exercises the missing-column and ID-prefix fallbacks.
\printPlot[layout=heatmap,caption={Many collaborations are shown here.}]
  {{collaborations}{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[
  layout=heatmap,
  area-colors={C=cyan!70!black,Shared services=orange!80!black}
]{{collaborations}{B07}}

\clearpage

%% Select the low arc layout with arcs explicitly. Every displayed arc reaches the
%% same vertical peak, IDs should sit inside the boxes, and each area rule should
%% span its boxes; additional caption text uses the leading options.
\printPlot[
  layout=arc,
  arcs=true,
  area-palette={orange!80!black,violet!75!black,teal!70!black},
  caption={Dummy metadata; A04 and A00 are intentionally omitted.}
]{{collaborations}{B06}}

\clearpage

%% The same full-width node strip can be shown without connecting arcs.
\printPlot[arcs=false]{{collaborations}{B06}}

\clearpage

%% Turning the image switch off again must restore the fast-mode plot skip.
\ExplSyntaxOn
\bool_set_false:N \l_@@_class_fastcompile_project_show_images_bool
\ExplSyntaxOff
\printPlot{{ProjectCollaboration}{B06}}

\end{document}
%    \end{macrocode}
% \iffalse
%</test-project-collaboration>
%<*test-reference-lookups>
% \fi
% \subsection{Reference-path lookup regression test}
% Exercise the public command against real databases, including fan-out,
% shared destinations, arbitrary database names, missing data and fast mode.
% The tag hook records the originating row and protected value of every result.
%    \begin{macrocode}
\documentclass[english,final=true]{dfg-crc}
\ExplSyntaxOn
\tl_new:N \g_@@_get_test_seen_tl
\int_new:N \g_@@_get_test_count_int
\NewDocumentCommand{\CheckGet}{m m +m}
{
  \tl_gclear:N \g_@@_get_test_seen_tl
  \par\noindent #1:~#3\par
  \str_if_eq:eeF {\tl_to_str:V \g_@@_get_test_seen_tl}{\tl_to_str:n {#2}}
    {\PackageError{get-test}{Failed~#1:~\tl_to_str:V \g_@@_get_test_seen_tl}
      {Expected~\tl_to_str:n {#2}}}
  \int_gincr:N \g_@@_get_test_count_int
  \typeout{GET~TEST~PASS:~#1}
}
% A custom keyset verifies that traversal does not hard-code the four
% built-in relation types or require the source database to match its keyset.
\keys_define:nn {get-test}
{
  id .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{id}{#1},
  name .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{name}{#1},
  code .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{code}{#1},
  ref-person-id .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-person-id}{#1},
  ref-other-unit-id .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-other-unit-id}{#1},
  ref-absent-db-id .code:n = \DTLnewdbentry{\l_@@_database_name_tl}{ref-absent-db-id}{#1},
}
\ExplSyntaxOff
\begin{document}
\DTLcleardb{person}
\DTLcleardb{institution}
\DTLcleardb{affiliation}
\DTLcleardb{project}
\addEntry{affiliation}{id={a1},name={University One},country={Germany}}
\addEntry{affiliation}{id={a2},name={University Two},country={France}}
\addEntry{institution}{id={i1},name={\textbf{Alpha Institute}},ref-affiliation-id={a1}}
\addEntry{institution}{id={i2},name={Beta Institute},ref-affiliation-id={a1}}
\addEntry{institution}{id={i3},name={Gamma Institute},ref-affiliation-id={a2}}
\addEntry{person}{id={p1},lastname={Example},ref-institution-id={i1},ref-project-id={P1}}
\addEntry{person}{id={p2},lastname={Other},ref-institution-id={i2,i3,i1,i2}}
\addEntry{person}{id={empty},lastname={Empty},ref-institution-id={}}
\addEntry{person}{id={broken},ref-institution-id={unknown,i3}}
\addEntry{project}{id={P1},name={Project One},ref-person-id={p1,p2}}
\addEntry[get-test]{lookup-source}{id={r1},code={alternate},ref-person-id={p1,p2},ref-other-unit-id={u1}}
\addEntry[get-test]{other-unit}{id={u1},name={Custom Unit},ref-person-id={p1}}
\addEntry[get-test]{lookup-source}{id={r2},ref-absent-db-id={nowhere}}

\ExplSyntaxOn
\RenewDocumentCommand{\dfgShowTag}{m m m o}
{
  \tl_gput_right:Nn \g_@@_get_test_seen_tl {[#4/#1/#2]=#3;}
  #3
}
\ExplSyntaxOff
\CheckGet{direct}{[person/p1/lastname]=Example;}{\get[person]{p1}{lastname}}
\CheckGet{one-hop}{[institution/i1/name]=\textbf{Alpha Institute};}
  {\get[person]{p1}{institution}{name}}
\CheckGet{explicit-key}{[institution/i1/name]=\textbf{Alpha Institute};}
  {\get[person]{p1}{ref-institution-id}{name}}
\CheckGet{two-hops}{[affiliation/a1/name]=University One;}
  {\get[person]{p1}{institution}{affiliation}{name}}
\CheckGet{explicit-chain}{[affiliation/a1/country]=Germany;}
  {\get[person]{p1}{ref-institution-id}{ref-affiliation-id}{country}}
\CheckGet{institution-root}{[affiliation/a1/name]=University One;}
  {\get[institution]{i2}{affiliation}{name}}
\CheckGet{project-reference}{[project/P1/name]=Project One;}
  {\get[person]{p1}{project}{name}}
\CheckGet{person-reference}{[person/p1/lastname]=Example;[person/p2/lastname]=Other;}
  {\get[project]{P1}{person}{lastname}}
\CheckGet{multiple-ids}{[institution/i2/name]=Beta Institute;[institution/i3/name]=Gamma Institute;[institution/i1/name]=\textbf{Alpha Institute};}
  {\get[person]{p2}{institution}{name}}
\CheckGet{shared-affiliation}{[affiliation/a1/name]=University One;[affiliation/a2/name]=University Two;}
  {\get[person]{p2}{institution}{affiliation}{name}}
\CheckGet{three-hops}{[affiliation/a1/name]=University One;[affiliation/a2/name]=University Two;}
  {\get[project]{P1}{person}{institution}{affiliation}{name}}
\CheckGet{named-source}{[person/p1/lastname]=Example;[person/p2/lastname]=Other;}
  {\get[lookup-source]{r1}{person}{lastname}}
\CheckGet{custom-target}{[other-unit/u1/name]=Custom Unit;}
  {\get[lookup-source]{r1}{other-unit}{name}}
\CheckGet{custom-explicit}{[person/p1/lastname]=Example;}
  {\get[lookup-source]{r1}{ref-other-unit-id}{ref-person-id}{lastname}}
\CheckGet{alternative-id}{[person/p1/lastname]=Example;[person/p2/lastname]=Other;}
  {\get[lookup-source]{alternate}{person}[code]{lastname}}
\def\tmpLocalDB{person}
\CheckGet{default-database}{[institution/i1/name]=\textbf{Alpha Institute};}
  {\get{p1}{institution}{name}}
\CheckGet{raw-reference}{[person/p1/ref-institution-id]=i1;}
  {\get[person]{p1}{ref-institution-id}}
\CheckGet{following-group}{[person/p1/lastname]=Example;}
  {\get[person]{p1}{lastname}{\textbf{Following prose.}}}
\CheckGet{field-reference-cycle}{[person/p1/lastname]=Example;[person/p2/lastname]=Other;}
  {\get[person]{p1}{project}{person}{lastname}}
\CheckGet{starred}{}{
  \get*[person]{p1}{\TestLastname=lastname}
  \ifdefstring{\TestLastname}{Example}{}{\PackageError{get-test}{Starred lookup failed}{}}
}
\CheckGet{empty-reference}{}{\get[person]{empty}{institution}{name}}
\CheckGet{missing-root}{}{\get[person]{missing}{institution}{name}}
\CheckGet{missing-leaf}{}{\get[person]{p1}{institution}{absent-field}}
\CheckGet{missing-relation}{}{\get[institution]{i1}{person}{lastname}}
\CheckGet{missing-target-db}{}{\get[lookup-source]{r2}{ref-absent-db-id}{name}}
\CheckGet{missing-source-db}{}{\get[absent-db]{r1}{person}{lastname}}
\CheckGet{broken-branch}{[institution/i3/name]=Gamma Institute;}
  {\get[person]{broken}{institution}{name}}
\CheckGet{after-missing-reset}{[affiliation/a1/name]=University One;}
  {\get[person]{p1}{institution}{affiliation}{name}}
\begingroup
\ExplSyntaxOn
\bool_set_true:N \l_@@_class_fastcompile_project_bool
\RenewDocumentCommand{\dfgFastReference}{m}
  {\tl_gput_right:Ne \g_@@_get_test_seen_tl {fast:#1;}}
\RenewDocumentCommand{\dfgShowTag}{m m m o}
{
  \tl_gput_right:Ne \g_@@_get_test_seen_tl
    {tag:\IfNoValueTF{#4}{}{#4}/#1/#2;}
  #3
}
\ExplSyntaxOff
\CheckGet{fast-chain}{tag:person/p1/institution/affiliation/name;fast:p1;}
  {\get[person]{p1}{institution}{affiliation}{name}}
\addEntry[get-test]{skipped-source}{id={skip},ref-other-unit-id={u1}}
\CheckGet{fast-skipped-custom}
  {tag:skipped-source/skip/other-unit/person/lastname;fast:skip;}
  {\get[skipped-source]{skip}{other-unit}{person}{lastname}}
\CheckGet{fast-skipped-scalar}{tag:skipped-source/skip/name;fast:skip;}
  {\get[skipped-source]{skip}{name}{\textbf{Following prose.}}}
\CheckGet{fast-star}{}{
  \def\TestLastname{stale}
  \get*[person]{p1}{\TestLastname=lastname}
  \ifdefempty{\TestLastname}{}{\PackageError{get-test}{Fast starred lookup failed}{}}
}
\endgroup
\CheckGet{after-fast-reset}{[person/p1/lastname]=Example;}{\get[person]{p1}{lastname}}
\ExplSyntaxOn
\int_compare:nNnF {\g_@@_get_test_count_int} = {33}
  {\PackageError{get-test}{Not~all~33~cases~ran}{}}
\ExplSyntaxOff
\typeout{REFERENCE LOOKUP TEST PASS: 33 cases}
\end{document}
%    \end{macrocode}
% \iffalse
%</test-reference-lookups>
%<*test-command-options>
% \fi
% \subsection{Public-command option regression tests}
% Small probe renderers check the public dispatchers without depending on a
% particular table or plot. Database-aware lists retain their real lookup and
% filtering; only their final cells are replaced with assertions.
%    \begin{macrocode}
% The customization file is loaded during class initialization. Probe both
% interfaces there, then verify that later class setup preserves the values.
\AddToHook{file/dfg-customization.tex/before}{%
  \let\DefaultDateBeforeCustomization\dfgDate
  \renewcommand{\dfgLocation}{Direct early location\xspace}%
  \renewcommand{\dfgDate}{Direct early date\xspace}%
  \renewcommand{\dfgTitle}{Direct early title\xspace}%
  \renewcommand{\InfoTeX}{Direct early compiler}%
  \changeSettings{
    dfgLocation={Early location}, dfgDate={Early date},
    dfgTitle={Early title}, InfoTeX={Early compiler}}
}
\documentclass[english,final=true]{dfg-crc}
\ExplSyntaxOn
\int_new:N \g_@@_document_settings_test_count_int
\NewDocumentCommand{\CheckDocumentSetting}{m m m}
{
  \tl_set:No \l_tmpa_tl {#2}
  \tl_if_eq:NnF \l_tmpa_tl {#3}
    {\PackageError{settings-test}{Failed~#1}{Unexpected~document~text.}}
  \int_gincr:N \g_@@_document_settings_test_count_int
}
\ExplSyntaxOff
% Resolve the default date's fast-mode conditional, preserving its spacing
% command. Other checks below deliberately retain deferred metadata lookups.
\ExplSyntaxOn
\group_begin:
\cs_set_eq:NN \xspace \scan_stop:
\cs_set:Npe \ExpandedDefaultDateBeforeCustomization
  {\DefaultDateBeforeCustomization}
\CheckDocumentSetting{generic-date}
  {\ExpandedDefaultDateBeforeCustomization}{<date>\xspace}
\group_end:
\ExplSyntaxOff
\CheckDocumentSetting{early-location}{\dfgLocation}{Early location\xspace}
\CheckDocumentSetting{early-date}{\dfgDate}{Early date\xspace}
\CheckDocumentSetting{early-title}{\dfgTitle}{Early title\xspace}
\CheckDocumentSetting{early-compiler}{\InfoTeX}{Early compiler}
\begingroup
\changeSettings{
  dfgLocation={Runtime location}, dfgDate={Runtime date},
  dfgTitle={\get[meta]{crc}{name}}, InfoTeX={Runtime compiler}}
\CheckDocumentSetting{runtime-location}{\dfgLocation}{Runtime location\xspace}
\CheckDocumentSetting{runtime-date}{\dfgDate}{Runtime date\xspace}
\CheckDocumentSetting{deferred-title}{\dfgTitle}{\get[meta]{crc}{name}\xspace}
\CheckDocumentSetting{runtime-compiler}{\InfoTeX}{Runtime compiler}
\renewcommand{\dfgLocation}{Direct location\xspace}
\renewcommand{\dfgDate}{Direct date\xspace}
\renewcommand{\dfgTitle}{Direct title\xspace}
\renewcommand{\InfoTeX}{Direct compiler}
\CheckDocumentSetting{direct-location}{\dfgLocation}{Direct location\xspace}
\CheckDocumentSetting{direct-date}{\dfgDate}{Direct date\xspace}
\CheckDocumentSetting{direct-title}{\dfgTitle}{Direct title\xspace}
\CheckDocumentSetting{direct-compiler}{\InfoTeX}{Direct compiler}
\endgroup
\CheckDocumentSetting{local-settings-scope}{\dfgDate}{Early date\xspace}
\ExplSyntaxOn
\int_compare:nNnF {\g_@@_document_settings_test_count_int} = {14}
  {\PackageError{settings-test}{Not~all~14~cases~ran}{}}
\typeout{DOCUMENT~SETTINGS~TEST~PASS:~14~cases}

% Exercise the public customization getter through real key assignments.
% All rates below are synthetic, group-local test inputs, not proposal defaults.
\int_new:N \g_@@_get_value_test_count_int
\cs_new_protected:Npn \@@_test_custom_value:nn #1#2
  {
    \tl_set:Ne \l_tmpa_tl {\getValue{#1}}
    \str_if_eq:VnF \l_tmpa_tl {#2}
      {\PackageError{settings-test}{Unexpected~getValue~result~for~#1}{}}
    \int_gincr:N \g_@@_get_value_test_count_int
  }
\clist_map_inline:nn
  {font,fontspec,sansfont,sansfontspec,crcLogoPath,affiliationLogoPath,PIcontactStyle,collaborationAreaColors,thumbindex@font,doiAPIMail,biblatexstyleCV,biblatexstyleFeatureCV,biblatexstyleProposal,biblatexstyleFeatureProposal,color@reference@boldAuthor,color@reference@PI,color@reference@WP,color@reference@Aim,color@gantt@frame,color@gantt@default,color@gantt@alternative,color@gantt@crosshatch,color@gantt@important,color@gantt@stripe-one,color@gantt@stripe-two,color@table@headingsBG,color@table@headingsBGalt,color@table@headingsFont,color@table@rows,color@table@lines,color@table@outerLines,color@table@noValue,color@table@firstColumn,color@table@link,color@table@contFootHead,color@table@caption,color@thumbindex@bg,color@thumbindex@font,color@tags@font,color@tags@line,color@font@alternative,color@item@i}
  {
    \group_begin:
    \changeSettings{#1={Getter~probe}}
    \@@_test_custom_value:nn {#1}{Getter~probe}
    \changeSettings{#1={Second~probe}}
    \@@_test_custom_value:nn {#1}{Second~probe}
    \group_end:
  }
\clist_map_inline:nn
  {projectPIOncePerSection,PIReferenceFirstName,projectsTableInstitutionAbbreviations,thumbindex,emphasizeAuthors,emphasizeEntries}
  {
    \group_begin:
    \changeSettings{#1={false}}
    \@@_test_custom_value:nn {#1}{false}
    \changeSettings{#1={true}}
    \@@_test_custom_value:nn {#1}{true}
    \group_end:
  }
\clist_map_inline:nn
  {salary@prof,salary@groupLeader,salary@postDoc,salary@medDoc,salary@PhD,salary@research,salary@nonResearch,salary@student,salary@assistant,animalHousing@mouse,animalHousing@mouseGnotobiotic,animalHousing@rat}
  {
    \group_begin:
    \changeSettings{#1={17.25}}
    \@@_test_custom_value:nn {#1}{17.25}
    \changeSettings{#1={23.5}}
    \@@_test_custom_value:nn {#1}{23.5}
    \group_end:
  }
\clist_map_inline:nn
  {thumbindex@pattern}
  {
    \group_begin:
    \changeSettings{#1={17}}
    \@@_test_custom_value:nn {#1}{17}
    \changeSettings{#1={23}}
    \@@_test_custom_value:nn {#1}{23}
    \group_end:
  }
\clist_map_inline:nn
  {thumbindex@width}
  {
    \group_begin:
    \changeSettings{#1={17pt}}
    \@@_test_custom_value:nn {#1}{17.0pt}
    \changeSettings{#1={23pt}}
    \@@_test_custom_value:nn {#1}{23.0pt}
    \group_end:
  }

\group_begin:
\cs_set:Npn \xspace {}
\changeSettings{dfgLocation=Here,dfgDate=Today,dfgTitle=Title,InfoTeX=Compiler,
  collaborationAreaPalette={red,blue},thumbindex@topmargin=17pt,
  thumbindex@bottommargin=23pt,thumbindex@orientation=inwards,
  animalHousing@mouse=0.85,salary@postDoc=90000}
\@@_test_custom_value:nn {dfgLocation}{Here}
\@@_test_custom_value:nn {dfgDate}{Today}
\@@_test_custom_value:nn {dfgTitle}{Title}
\@@_test_custom_value:nn {InfoTeX}{Compiler}
\@@_test_custom_value:nn {collaborationAreaPalette}{red,blue}
\changeSettings{collaborationAreaPalette={}}
\@@_test_custom_value:nn {collaborationAreaPalette}{red,blue}
\@@_test_custom_value:nn {thumbindex@topmargin}{17.0pt}
\@@_test_custom_value:nn {thumbindex@bottommargin}{23.0pt}
\@@_test_custom_value:nn {thumbindex@orientation}{inwards}
\changeSettings{thumbindex@topmargin=auto,thumbindex@bottommargin=auto,
  thumbindex@orientation=outwards}
\@@_test_custom_value:nn {thumbindex@topmargin}{auto}
\@@_test_custom_value:nn {thumbindex@bottommargin}{auto}
\@@_test_custom_value:nn {thumbindex@orientation}{outwards}
\@@_test_custom_value:nn {~animalHousing@mouse~}{0.85}
\fp_compare:nNnF {2 * \getValue{animalHousing@mouse}} = {1.7}
  {\PackageError{settings-test}{getValue~failed~in~arithmetic}{}}
\group_begin:
\changeSettings{animalHousing@mouse=1.25}
\@@_test_custom_value:nn {animalHousing@mouse}{1.25}
\group_end:
\@@_test_custom_value:nn {animalHousing@mouse}{0.85}
\changeSettings{biblatexstyle=shared,biblatexstyleFeature=shared-feature}
\@@_test_custom_value:nn {biblatexstyleCV}{shared}
\@@_test_custom_value:nn {biblatexstyleProposal}{shared}
\changeSettings{biblatexstyleCV=cv-style,biblatexstyleProposal=proposal-style,
  biblatexstyleFeatureCV=cv-feature,biblatexstyleFeatureProposal=proposal-feature}
\bool_set_false:N \l_@@_class_cv_bool
\@@_test_custom_value:nn {biblatexstyle}{proposal-style}
\@@_test_custom_value:nn {biblatexstyleFeature}{proposal-feature}
\bool_set_true:N \l_@@_class_cv_bool
\@@_test_custom_value:nn {biblatexstyle}{cv-style}
\@@_test_custom_value:nn {biblatexstyleFeature}{cv-feature}
\group_end:
\typeout{CUSTOMIZATION~GETTER~TEST~PASS:~\int_use:N\g_@@_get_value_test_count_int~checks}


\tl_new:N \g_@@_options_test_result_tl
\tl_new:N \l_@@_options_test_mode_tl
\tl_new:N \l_@@_options_test_caption_tl
\dim_new:N \l_@@_options_test_width_dim
\int_new:N \g_@@_options_test_count_int
\keys_define:nn {dfg-options-test}
{
  mode .tl_set:N = \l_@@_options_test_mode_tl,
  caption .tl_set:N = \l_@@_options_test_caption_tl,
}
\cs_new_protected:Npn \@@_options_test_probe:nnn #1#2#3
{
  \tl_set:Nn \l_@@_options_test_mode_tl {empty}
  \tl_clear:N \l_@@_options_test_caption_tl
  \keys_set:nn {dfg-options-test} {#2}
  \tl_gput_right:Ne \g_@@_options_test_result_tl
    {#1|\l_@@_options_test_mode_tl|\l_@@_options_test_caption_tl|#3}
}
\NewDocumentCommand{\OptionProbeList}{O{mode=default}}
  {\@@_options_test_probe:nnn {list}{#1}{}}
\NewDocumentCommand{\OptionProbePlot}{O{mode=default}}
  {\@@_options_test_probe:nnn {plot}{#1}{}}
\NewDocumentCommand{\OptionProbeTable}{O{mode=default}}
{
  \int_compare:nNnF {\value{rowNumber}} = {0}
    {\PackageError{options-test}{Table~row~counter~was~not~reset}{}}
  \@@_options_test_probe:nnn {table}{#1}{}
}
\NewDocumentCommand{\OptionArgumentsList}{O{mode=default} m m}
  {\@@_options_test_probe:nnn {list}{#1}{#2/#3}}
\NewDocumentCommand{\OptionArgumentsPlot}{O{mode=default} m m}
  {\@@_options_test_probe:nnn {plot}{#1}{#2/#3}}
\NewDocumentCommand{\OptionArgumentsTable}{O{mode=default} m m}
  {\@@_options_test_probe:nnn {table}{#1}{#2/#3}}
\NewDocumentCommand{\CheckOptions}{m m +m}
{
  \tl_gclear:N \g_@@_options_test_result_tl
  #3
  \str_if_eq:eeF {\g_@@_options_test_result_tl} {#2}
  {
    \PackageError{options-test}{Failed~#1:~\g_@@_options_test_result_tl}
      {Expected~#2.}
  }
  \int_gincr:N \g_@@_options_test_count_int
  \typeout{OPTIONS~TEST~PASS:~#1}
}
% Keep the real database lookup and option parsing; inspect the resulting
% institution ID and boolean settings at the final formatting boundary.
\cs_set_protected:Npn \_@@_one_institution:n #1
{
  \tl_gput_right:Ne \g_@@_options_test_result_tl
  {
    #1|
    \bool_if:NTF \l_@@_institution_abbreviation_bool {1}{0}
    \bool_if:NTF \l_@@_narrow_bool {1}{0}
    \bool_if:NTF \l_@@_noaddr_bool {1}{0}
    \bool_if:NTF \l_@@_nozip_bool {1}{0}
    \bool_if:NTF \l_@@_noloc_bool {1}{0}
  }
}
% Keep the real PI filtering and raster, but use a minimal box to measure
% the available column width independently of the card's text/padding.
\cs_set_protected:Npn \__getperson_one:n #1
{
  \begin{tcolorbox}[blankest]
    \dim_compare:nNnT
      {\dim_abs:n{\linewidth-\l_@@_options_test_width_dim}} > {.1pt}
      {\PackageError{options-test}{PI~raster~column~width~is~wrong}{}}
    \tl_gput_right:Ne \g_@@_options_test_result_tl
      {#1\bool_if:NT \l_@@_pi_academicdegree_below_bool {|below}}
    PI~#1
  \end{tcolorbox}
}
\NewDocumentCommand{\CheckPIOptions}{m m m +m}
{
  \dim_set:Nn \l_@@_options_test_width_dim
    {(\linewidth-12pt*\int_eval:n{#2-1})/#2}
  \CheckOptions{#1}{#3}{#4}
}
\ExplSyntaxOff

\begin{document}
\begingroup
\changeSettings{animalHousing@mouse=0.85,salary@postDoc=90000}
Test-only mouse housing: \num{\getValue{animalHousing@mouse}}\,EUR per week.\par
Test-only postdoctoral salary: \num{\getValue{salary@postDoc}}\,EUR per year.\par
\endgroup

\section*{Command option regression checks}
\CheckOptions{list-omitted}{list|default||}{\printList{OptionProbe}}
\CheckOptions{list-empty}{list|empty||}{\printList[]{OptionProbe}}
\CheckOptions{list-grouped}{list|default||}{\printList{{OptionProbe}}}
\CheckOptions{list-leading}{list|leading||}{\printList[mode=leading]{OptionProbe}}
\CheckOptions{list-legacy}{list|legacy||}{\printList{OptionProbe}[mode=legacy]}
\CheckOptions{list-precedence}{list|leading||}
  {\printList[mode=leading]{{OptionProbe}}[mode=legacy]}
\CheckOptions{list-arguments}{list|leading|left,right|A01/two words}
  {\printList[mode=leading,caption={left,right}]{{OptionArguments}{A01}{two words}}}
\CheckOptions{plot-omitted}{plot|default||}{\printPlot{OptionProbe}}
\CheckOptions{plot-empty}{plot|empty||}{\printPlot[]{OptionProbe}}
\CheckOptions{plot-grouped}{plot|default||}{\printPlot{{OptionProbe}}}
\CheckOptions{plot-arguments}{plot|leading|left,right|A01/two words}
  {\printPlot[mode=leading,caption={left,right}]{{OptionArguments}{A01}{two words}}}
\CheckOptions{plot-embedded-legacy}{plot|legacy||A01/second}
  {\printPlot{{OptionArguments}[mode=legacy]{A01}{second}}}
\setcounter{rowNumber}{99}
\CheckOptions{table-omitted-and-counter}{table|default||}{\printTable{OptionProbe}}
\CheckOptions{table-empty}{table|empty||}{\printTable[]{OptionProbe}}
\CheckOptions{table-grouped}{table|default||}{\printTable{{OptionProbe}}}
\CheckOptions{table-arguments}{table|leading|left,right|A01/two words}
  {\printTable[mode=leading,caption={left,right}]{{OptionArguments}{A01}{two words}}}

\DTLcleardb{person}
\addEntry{person}{id={default-person},lastname={Default},role={PI},
  period={1,2,3},ref-institution-id={default-institute}}
\DTLnewdb{option-people}
\DTLnewrow{option-people}
\DTLnewdbentry{option-people}{id}{other-person}
\DTLnewdbentry{option-people}{lastname}{Other}
\DTLnewdbentry{option-people}{role}{PI,spokesperson}
\DTLnewdbentry{option-people}{period}{1,2,3}
\DTLnewdbentry{option-people}{ref-institution-id}{other-institute}

\CheckOptions{institutions-default}{default-institute|00000}
  {\printList{{Institutions}{default-person}}}
\CheckOptions{institutions-flags}{other-institute|11111}
  {\printList[database=option-people,abbreviation,narrow,noaddress,nozip,nolocation]
    {{Institutions}{other-person}}}
\CheckOptions{institutions-legacy-database}{other-institute|11000}
  {\InstitutionsList[option-people]{other-person}[abbreviation,narrow]}
\CheckOptions{institutions-precedence}{other-institute|01000}
  {\InstitutionsList[database=option-people,abbreviation=false,narrow]
    {other-person}[abbreviation]}
\CheckOptions{institutions-dispatch-precedence}{other-institute|01000}
  {\printList[database=option-people,abbreviation=false,narrow]
    {{Institutions}{other-person}}[abbreviation]}
\CheckOptions{institutions-empty}{default-institute|00000}
  {\InstitutionsList[]{default-person}}
\CheckOptions{institutions-reset}{default-institute|00000}
  {\InstitutionsList{default-person}}

\CheckPIOptions{pi-default}{3}{default-person}{\getPIsWithRole{PI}}
\CheckPIOptions{pi-leading}{2}{other-person}
  {\getPIsWithRole[database=option-people,raster columns=2]{spokesperson}}
\CheckPIOptions{pi-legacy}{1}{other-person}
  {\getPIsWithRole[option-people]{PI}[raster columns=1]}
\CheckPIOptions{pi-precedence}{2}{other-person}
  {\getPIsWithRole[database=option-people,raster columns=2]{PI}[raster columns=1]}
\CheckPIOptions{pi-degree-below}{3}{default-person|below}
  {\getPIsWithRole[academicdegree-below]{PI}}
\CheckPIOptions{pi-degree-legacy}{1}{other-person|below}
  {\getPIsWithRole[option-people]{PI}[academicdegree-below,raster columns=1]}
\CheckPIOptions{pi-degree-precedence}{3}{default-person}
  {\getPIsWithRole[academicdegree-below=false]{PI}[academicdegree-below]}
\CheckPIOptions{pi-degree-reset}{3}{default-person}{\getPIsWithRole{PI}}
\CheckPIOptions{pi-empty}{3}{default-person}{\getPIsWithRole[]{PI}}
\CheckPIOptions{pi-reset}{3}{default-person}{\getPIsWithRole{PI}}
\CheckPIOptions{pi-role-filter}{3}{}{\getPIsWithRole{spokesperson}}

\ExplSyntaxOn
\int_compare:nNnF {\g_@@_options_test_count_int} = {34}
  {\PackageError{options-test}{Not~all~34~cases~ran}{}}
\ExplSyntaxOff
\typeout{COMMAND OPTIONS TEST PASS: 34 cases}

% Render real metadata lookups to check punctuation and option defaults.
\clearpage
\section*{Project PI prose lists}
\addEntry{person}{id={pi-test-a},firstname={Alice},lastname={Able},academicdegree={Dr.}}
\addEntry{person}{id={pi-test-b},firstname={Bob},lastname={Baker},academicdegree={Dr.}}
\addEntry{person}{id={pi-test-c},firstname={Carol},lastname={Clark},academicdegree={Dr.}}
\addEntry{person}{id={pi-test-d},firstname={Dan},lastname={Dover},academicdegree={Dr.}}
\addEntry{project}{id={PI0},ref-person-id={}}
\addEntry{project}{id={PI1},ref-person-id={pi-test-a}}
\addEntry{project}{id={PI2},ref-person-id={pi-test-a,pi-test-b}}
\addEntry{project}{id={PI3},ref-person-id={pi-test-a,pi-test-b,pi-test-c}}
\addEntry{project}{id={PI4},ref-person-id={pi-test-a,pi-test-b,pi-test-c,pi-test-d}}
Zero: [\getPIofProject*{PI0}].\par
One: \getPIofProject*{PI1}.\par
Two: \getPIofProject*{PI2}.\par
Three: \getPIofProject*{PI3}.\par
Four: \getPIofProject*{PI4}.\par
Properties: \getPIofProject*[lastname]{PI3}.\par
Final separator: \getPIofProject*{PI3}[\space und \space].\par
Legacy: \getPIofProject[firstname,lastname]{PI3}[; ].\par
Reset: \getPIofProject{PI2}.\par
Empty properties: [\getPIofProject*[]{PI1}].\par
Following group: \getPIofProject*{PI1}{ followed}.\par
\begingroup
\ExplSyntaxOn
\bool_set_true:N \l_@@_class_fastcompile_project_bool
\ExplSyntaxOff
Fast: \getPIofProject*{PI3}.\par
\endgroup

% Use the same destination helper as the PI table. Keep targets on a separate
% page so a PDF check can distinguish working links from fallback destinations.
\clearpage
\section*{PI table link targets}
\ExplSyntaxOn
\clist_map_inline:nn {pi-test-a,pi-test-b,pi-test-c,pi-test-d}
  {\@@_pi_target:n {#1} PI~target~#1\par}
\ExplSyntaxOff
\end{document}
%    \end{macrocode}
% \iffalse
%</test-command-options>
%<*test-participating-institutions>
% \fi
% \subsection{Participating-institution layout regression test}
% Assert the width and complete, ordered content of the rendered institution
% groups. Shared PI institutions must appear once, inactive/non-PI institutions
% must be absent, and options must not leak into the next list.
%    \begin{macrocode}
\documentclass[english,final=true]{dfg-crc}

\ExplSyntaxOn
\seq_new:N \g_@@_institutions_test_seen_seq
\dim_new:N \l_@@_institutions_test_width_dim
\NewDocumentCommand{\TestInstitutionName}{m}
{
  \dim_compare:nNnT
    {\dim_abs:n {\linewidth-\l_@@_institutions_test_width_dim}} > {.1pt}
  {
    \PackageError{institutions-test}
      {Wrong~column~width~for~#1:~\the\linewidth}
      {The~list~did~not~honour~its~column~count~or~column~gap.}
  }
  \seq_gput_right:Nn \g_@@_institutions_test_seen_seq {#1}
  Institute~#1
}
\AddToHook{env/multicols/before}
{
  \dim_compare:nNnT {\lastskip} < {\medskipamount}
    {\PackageError{institutions-test}{Missing~space~above~columns}{}}
}
\NewDocumentCommand{\TestInstitutionList}{m m m m +m}
{
  \clearpage
  \section*{#1}
  \seq_gclear:N \g_@@_institutions_test_seen_seq
  \dim_set:Nn \l_@@_institutions_test_width_dim
    {(\linewidth-\dim_eval:n{#3}*\int_eval:n{#2-1})/#2}
  #5
  \tl_set:Ne \l_tmpa_tl
    {\seq_use:Nn \g_@@_institutions_test_seen_seq {,}}
  \tl_if_eq:NnF \l_tmpa_tl {#4}
  {
    \PackageError{institutions-test}
      {Unexpected~institutions~in~#1:~\l_tmpa_tl}
      {Check~filtering,~duplicate~removal,~sorting,~and~option~scoping.}
  }
  \typeout{INSTITUTIONS~TEST~PASS:~#1}
}
\ExplSyntaxOff

\newcommand{\TestInstitution}[2]{%
  \addEntry{institution}{
    id={#1},name={\TestInstitutionName{#1}},ref-affiliation-id={#2}
  }%
}

\begin{document}
\DTLcleardb{affiliation}
\DTLcleardb{institution}
\DTLcleardb{person}

\addEntry{affiliation}{id={z},name={Zeta University},location={Zeta City}}
\addEntry{affiliation}{id={a},name={Alpha University},location={Alpha City}}
\addEntry{affiliation}{id={b},name={Beta University},location={Beta City}}
\addEntry{affiliation}{id={unused},name={Unused University},location={Unused City}}
\TestInstitution{Z1}{z}
\TestInstitution{Z2}{z}
\TestInstitution{Z3}{z}
\TestInstitution{Z4}{z}
\TestInstitution{Z5}{z}
\TestInstitution{Z6}{z}
\TestInstitution{A1}{a}
\TestInstitution{B1}{b}
\TestInstitution{INACTIVE}{unused}
\TestInstitution{NONPI}{unused}
\addEntry{person}{
  id={active},role={PI},period={1,2,3},
  ref-institution-id={Z1,Z2,Z3,Z4,Z5,Z6,A1,B1,Z1}
}
\addEntry{person}{
  id={shared},role={PI},period={1,2,3},ref-institution-id={Z1,A1}
}
\addEntry{person}{
  id={inactive},role={PI},period={1},ref-institution-id={INACTIVE}
}
\addEntry{person}{
  id={manager},role={manager},period={1,2,3},ref-institution-id={NONPI}
}

\TestInstitutionList{flow-two}{2}{12pt}{Z1,Z2,Z3,Z4,Z5,Z6,A1,B1}
  {\printList[columns=2]{ParticipatingInstitutions}}
\TestInstitutionList{flow-three-alpha}{3}{16pt}{A1,B1,Z1,Z2,Z3,Z4,Z5,Z6}
  {\printList[columns=3,column sep=16pt,order=alpha]{ParticipatingInstitutions}}
\TestInstitutionList{raster-two}{2}{12pt}{Z1,Z2,Z3,Z4,Z5,Z6,A1,B1}
  {\printList[raster columns=2]{ParticipatingInstitutions}}
\TestInstitutionList{raster-three}{3}{16pt}{Z1,Z2,Z3,Z4,Z5,Z6,A1,B1}
  {\printList[raster columns=3,raster column skip=16pt]{ParticipatingInstitutions}}
\TestInstitutionList{legacy-alpha}{2}{12pt}{A1,B1,Z1,Z2,Z3,Z4,Z5,Z6}
  {\printList[columns=2]{{ParticipatingInstitutions}}[alpha]}
\TestInstitutionList{leading-order-wins}{2}{12pt}{Z1,Z2,Z3,Z4,Z5,Z6,A1,B1}
  {\printList[columns=2,order=count]{{ParticipatingInstitutions}}[alpha]}
\TestInstitutionList{default-reset}{1}{12pt}{Z1,Z2,Z3,Z4,Z5,Z6,A1,B1}
  {\printList{ParticipatingInstitutions}}
\TestInstitutionList{flow-after-text}{2}{12pt}{Z1,Z2,Z3,Z4,Z5,Z6,A1,B1}
  {Introductory text.\printList[columns=2]{ParticipatingInstitutions}}
\TestInstitutionList{flow-one}{1}{12pt}{Z1,Z2,Z3,Z4,Z5,Z6,A1,B1}
  {\printList[columns=1]{ParticipatingInstitutions}}
\DTLcleardb{person}
\TestInstitutionList{empty-list}{2}{12pt}{}
  {\printList[columns=2]{ParticipatingInstitutions}}

\end{document}
%    \end{macrocode}
% \iffalse
%</test-participating-institutions>
%<*test-workpackage-references>
% \fi
% \subsection{Nested work-package reference test}
% This focused test creates repeated child-counter values under three parent
% work packages.  It catches both loss of later references during sorting and
% ranges that incorrectly cross a parent boundary.
%    \begin{macrocode}
%% Compile from the generated local directory with:
%%   latexmk -lualatex -g -halt-on-error test-workpackage-references.tex
\documentclass[
  fastcompile-project = true,
  fastcompile-project-show-images = false,
  english
]{dfg-crc}

\begin{document}

\ExplSyntaxOn
\tl_set:Nn \l__tmp_current_project_tl {WPTEST}
\ExplSyntaxOff

\begin{workpackages}
  \addWP{wp1}{name={Parent one}}
  Parent one.
  \begin{workpackages}
    \addWP{wp1a}{} Child 1a.
    \addWP{wp1b}{} Child 1b.
    \addWP{wp1c}{} Child 1c.
    \addWP{wp1d}{} Child 1d.
  \end{workpackages}

  \addWP{wp2}{name={Parent two}}
  Parent two.
  \begin{workpackages}
    \addWP{wp2a}{} Child 2a.
    \addWP{wp2b}{} Child 2b.
  \end{workpackages}

  \addWP{wp3}{name={Parent three}}
  Parent three.
  \begin{workpackages}
    \addWP{wp3a}{} Child 3a.
    \addWP{wp3b}{} Child 3b.
    \addWP{wp3c}{} Child 3c.
  \end{workpackages}
\end{workpackages}

\noindent Range result:
\getWP{wp1b,wp1c,wp1d,wp2b,wp3c}.

\noindent Unordered result:
\getWP{wp2b,wp3c,wp1d}.


\noindent Mixed result:
\getWP{wp1a,wp1b,wp2,wp3a,wp3b}.

\noindent Reversed mixed:
\getWP{wp3b,wp2,wp1a,wp3a,wp1b}.

\noindent Parent and children:
\getWP{wp1,wp1a,wp1b,wp1c,wp2,wp2a,wp2b,wp3}.

\noindent Parent range:
\getWP{wp1,wp2,wp3}.

\end{document}
%    \end{macrocode}
% \iffalse
%</test-workpackage-references>
%<*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}
  }
}

%% Project fast mode must update existing-funds totals as well as the rows.
%% Keep this local so the normal-mode auxiliary overview remains unchanged.
\ExplSyntaxOn
\group_begin:
\cs_set_protected:Npn \@@_direct_costs_fast_expect:nnn #1#2#3
{
  \@@_funding_sum_set:Nnnnn \l_tmpa_tl
    {RequestedAndExistingFundingDirectCosts}{#1}{__ALL__}{#2}
  \fp_compare:nNnF {\l_tmpa_tl} = {#3}
  {
    \PackageError{direct-costs-test}
      {Expected~#1/#2~sum~#3,~got~\l_tmpa_tl}
      {Existing~direct-cost~totals~must~match~the~project~rows.}
  }
}
%% Normal-mode rows above must still be counted exactly once.
\@@_direct_costs_fast_expect:nnn {A01}{sum-year1}{5000}
\bool_set_true:N \l_@@_class_fastcompile_project_bool
\bool_set_true:N \l_@@_class_fastcompile_project_show_funding_tables_bool
\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id={FASTTEST}, ref-affiliation-id={aff1}, financed-by={Test},
  sum={year1=1000,year2=1000,year3=1000,year4=1000,year5=1000}
}
\clist_map_inline:nn {sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}
  { \@@_direct_costs_fast_expect:nnn {FASTTEST}{#1}{1000} }
\@@_direct_costs_fast_expect:nnn {FASTTEST}
  {sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}{5000}
%% A second entry adds to the same project without affecting other projects.
\addEntry[funding]{RequestedAndExistingFundingDirectCosts}{
  ref-project-id={FASTTEST}, ref-affiliation-id={aff1}, financed-by={Test},
  sum={year1=200,year2=200,year3=200,year4=200,year5=200}
}
\@@_direct_costs_fast_expect:nnn {FASTTEST}{sum-year1}{1200}
\@@_direct_costs_fast_expect:nnn {FASTTEST}
  {sum-year1,sum-year2,sum-year3,sum-year4,sum-year5}{6000}
\@@_direct_costs_fast_expect:nnn {A01}{sum-year1}{5000}
\iow_term:n {FAST~DIRECT~COSTS~TEST~PASS:~yearly~and~combined~totals}
\group_end:
\ExplSyntaxOff

\makeatletter
\protected@write\@auxout{}{%
  \string\gdef\string\dfgDirectCostsAuxReady{1}}
\makeatother

\end{document}
%    \end{macrocode}
% \iffalse
%</test-existing-funds-direct-costs>
%<*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
