% \iffalse meta-comment
%
%% File: latex-lab-title.dtx (C) Copyright 2023-2026 LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
%
% The latex-lab bundle is developed in the LaTeX2e GitHub.
% Issues may be reported at
%
%    https://github.com/latex3/latex2e/issues
%
\def\ltlabtitledate{2026-10-11}
\def\ltlabtitleversion{0.85i}

%<*driver>
\documentclass{l3in2edoc}
\EnableCrossrefs
\CodelineIndex
\begin{document}
  \DocInput{latex-lab-title.dtx}
\end{document}
%</driver>
%
% \fi
%
% \title{The \textsf{latex-lab-title} package\\
% Changes related to the tagging of the title}
% \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}}
% \date{v\ltlabtitleversion\ \ltlabtitledate}
%
% \maketitle
%
% \newcommand{\xt}[1]{\textsl{\textsf{#1}}}
% \newcommand{\TODO}[1]{\textbf{[TODO:} #1\textbf{]}}
% \newcommand{\docclass}{document class \marginpar{\raggedright document class
% customizations}}
%
% 
% \newcommand\tagname[1]{\textbf{#1}}
% \newcommand\key[1]{\texttt{#1}}
% \newcommand\keyvalue[1]{\texttt{#1}}
% \begin{abstract}
% \end{abstract}
%
% \section{Introduction}
%
% This module contains changes to improve the tagging (in the standard classes) of
% the title created with the \cs{maketitle} command. It also improves the
% setting of the metadata related to the title and the author.
%
% \subsection{Tagging of the title}
% For basic tagging of the printed title there are basically three things to do:
%
% \begin{itemize}
% \item The actual title should be tagged with a suitable tag.
% \item The tabular used to format the author list should \emph{not} be tagged as a tabular.
% \item \cs{maketitle} redefines footnote internals. These must be made tagging aware.
% \item There should be some structure that surrounds the whole title block.
% \end{itemize}
%
% \subsection{New control over the tagging of title and headings}
% HTML pages and accessibility API typically do not distinguish titles
% as distinct from section headings. Titles are marked up as \verb|<h1>|, following
% heading commands are marked up as \verb|<h2>| etc. This allows the title
% to be announced by screen readers and take part in navigation.
%
% For PDF 1.7 the PDF association recommends to tag a title like a normal
% paragraph (\url{https://pdfa.org/how-to-tag-titles-in-pdf-documents/}) and to start
% the tagging of the heading commands with \verb|<h1>|. Such titles are not announced
% and do not take part in the navigation.
%
% PDF 2.0 introduced a new \tagname{Title} structure element which should
% in principle allow titles to be distinguished, however at the present
% time it has no defined mapping to the System Accessibility API, and
% the \href{https://pdfa.org/deriving-pdf-to-html-version-1-2/}{derivation to
% HTML} maps it to \verb|<div>|. As such, tagging with \tagname{Title} is
% equivalent to tagging with \tagname{Div} or \tagname{NonStruct} and does
% not produce accessible titles. Title are simply read as the underlying
% text.
%
% Given that the standard mappings to the Accessibility API and to HTML
% may change, it is not always clear what is the best tagging to use at
% the present time.  The code therefore introduces some options to allow
% document authors some control here.
%
% \LaTeX{} uses the tag \tagname{title-block} to surround the title, author and date.
% This tag is role mapped to a \tagname{Div}.
%
% Author and date are surround by the tags \tagname{title-author} and \tagname{title-date}.
% These tags are role mapped to \tagname{P}
%
% The title is surrounded by the tag \tagname{title-text}. 
% 
% In PDF 2.0 \tagname{title-text} is by default role mapped to \tagname{Title}, in PDF 1.7
% and in the global Rolemap in PDF 2.0, \tagname{Title} it is in turn role mapped to \tagname{P}.
% \tagname{part-heading} is mapped to \tagname{Title}.
%
% The following options allow to change the tagging. They also affect how headings are tagged.
% 
% The options can be set by setting the \tagname{title} key either in the preamble with
% \cs{tagpdfsetup} or in the \key{tagging-setup} key of \cs{DocumentMetadata}.
% 
% The key \key{title} knows the values
% \begin{description}
% \item[Title] This is the default already described above: 
% \tagname{title-text} is role mapped to \tagname{Title},
% The tagging of heading commands starts
% with \tagname{H1}. The heading of a \cs{part} is tagged with 
% \tagname{part-heading} and role mapped to \tagname{Title}.
% \item[H1] \tagname{title-text} is role mapped to \tagname{H1}. The tagging of heading commands starts
% with \tagname{H2}. \tagname{part-heading} is mapped to \tagname{H1}.
% In current systems this produces the most accessible
% behavior. Documents tagged in this way will pass all mechanically
% checkable requirements of PDF/UA-2. There is a ``human check'' that
% titles should be tagged using \tagname{Title} but it seems reasonable
% to assert that titles in \LaTeX\ documents are structural elements
% that should be reported to AT and that as currently specified they are
% not suitable for \tagname{Title} which is an anonymous container with
% no defined accessibility properties.
%
% \item[html] In PDF 1.7 this behaves like the \keyvalue{H1} value. In PDF 2.0
% \tagname{title-text} is role mapped  to \tagname{h1} in the html namespace, which in turn is role
% mapped to \tagname{Title}. The first heading command is role mapped to
% \tagname{h2} in the HTML namespace, which in turn is role
% mapped to \tagname{H1} in the PDF name space. The global Rolemap is the same as the default case.
% This mapping can improve derivation to html as derivation can (but doesn't have to)
% stop when it encounters a tag in the HTML namespace.
% 
% \item[aria] This additionally adds an Aria-role \texttt{heading} with level 1
% to the \tagname{title-text} structure and Aria-roles \texttt{heading}
% with level 2--7 to the heading
% commands. \tagname{part-heading} gets an Aria-role \texttt{heading} with level 1. 
% It doesn't change the role mapping, and can in theory be combined with the
% other \key{title} options.
% \end{description}
% 
% \subsection{Metadata}
% A second task related to title is to store the authors and the title text
% (or a shorter version) inside the  XMP-metadata and (in PDF 1.7 or lower) in
% the Info dictionary. Currently this can only be set if hyperref
% is loaded and requires the use of the \key{pdftitle} and \key{pdfauthor} keys.
% The new code therefore extends the \cs{title} and \cs{author} commands: They
% stores their argument and use them at the end of the document
% for the PDF metadata if the data hasn't been given in another way.
% The code also gives \cs{title} and \cs{author}
% an optional argument where the PDF title or author can be given with
% in a key-value syntax. As with hyperref it is possible to store titles
% in more than one language:
%
% \begin{verbatim}
% \title
%   [pdftitle =
%      {[en]English Title,[de] Deutscher Titel,[fr]{titre français, avec comma}}]
%   {Document title}
% \end{verbatim}
%
% It is also possible to set a subtitle which is then stored in the XMP-metadata:
%
% \begin{verbatim}
% \title
%   [pdfsubtitle =
%      {[en]English Subtitle,[de] Deutscher Subtitel,[fr]{subtitre français, avec comma}}]
%   {Document title}
% \end{verbatim}
%
% If using the \key{pdfauthor} key authors should be separated
% by commas, and to hide commas in a name inside braces if needed:
%
%  \begin{verbatim}
%  \author[pdfauthor = {Bär, Peter Anteater, {Riley, the sloth}}]{\ldots}
%  \end{verbatim}
%
% If hyperref is loaded there is no difference to the \key{pdftitle} and
% \key{pdfauthor} key used in \cs{hypersetup}. Both can be used (and the last
% key used will win).
%
% \subsection{Open questions and TODOs}
%
% \begin{itemize}
% \item Writing into the Info dictionary needs to convert the input into a PDF string.
% This is here done with a simple version of hyperref's \cs{pdfstringdef}, similar code
% exist also in the generic hyperref driver. This should be moved into a better place
% module.
%
% \item Is it sensible to enhance \cs{author} and \cs{title} with an optional argument as done here?
% An advantage is that it is rather light-weight and
% doesn't require to decide how this values should be set in \cs{DocumentMetadata} (and would also work
% without \cs{DocumentMetadata}. But a problem could be that various classes and packages already
% extend this commands with other optional arguments.
%
% \item Some of the definitions related to metadata should perhaps be moved into l3pdfmeta.
%
% \item Are the names \key{pdftitle} and \key{pdfauthor} ok?
%
% \item The patch for \cs{thanks} to get a rlap-footnotemarker looks wrong. This
% probably means that some configuration option is missing in the footnote code.
% \end{itemize}
%
%
%
% \section{Implementation}
%    \begin{macrocode}
%<*package>
%<@@=tag>
%    \end{macrocode}
%    \begin{macrocode}
\ProvidesExplPackage {latex-lab-testphase-title} {\ltlabtitledate} {\ltlabtitleversion}
  {Changes related to the tagging of the title}
%    \end{macrocode}
% \subsection{Separating the authors}
% We redefined \cs{and} to separate authors in individual structures
% \changes{0.85i}{2026-10-11}{redefine \cs{and} for tagging}
%    \begin{macrocode}
\DeclareRobustCommand\and{%   % \begin{tabular}
  \end{tabular}\UseTaggingSocket{inline/end}{}%
  \hskip 1em \@plus.17fil%
  \UseTaggingSocket{inline/begin}{tag=title-author,attribute-class=center}%
  \begin{tabular}[t]{c}}%     % \end{tabular}
%    \end{macrocode}
% \subsection{\cs{maketitle} in article class}
%
%    \begin{macrocode}
\cs_new_protected:Npn \@@_patch_thanks:n #1
  {
    \rlap{\footnotemark}
    \protected@xdef\@thanks{\@thanks
      \protect\footnotetext[\the\c@footnote]{#1}}
  }
%    \end{macrocode}
% The no-titlepage version of article, report and book
%    \begin{macrocode}
\cs_new_protected:Npn \@@_patch_maketitle:
  {
    \par
    \begingroup
%    \end{macrocode}
% Disable table tagging
%    \begin{macrocode}
      \tagpdfsetup{table/tagging=false}%
      \renewcommand\thefootnote{\@fnsymbol\c@footnote}%
%    \end{macrocode}
% the original definition redefines \cs{@makefnmark} and
% \cs{@makefntext} to get an rlap-mark in the text without
% affecting the mark in the note (which gives by the way
% a wrong link area with hyperref). There seem to be currently
% no good way in the footnote to configure this, so we redefine
% \cs{thanks} instead
%    \begin{macrocode}
      \cs_set_eq:NN \thanks \@@_patch_thanks:n
      \if@twocolumn
        \ifnum \col@number=\@ne
          \@maketitle
        \else
          \twocolumn[\@maketitle]%
        \fi
      \else
      \newpage
        \global\@topnum\z@   % Prevents figures from going at top of page.
        \@maketitle
      \fi
      \thispagestyle{plain}\@thanks
    \endgroup
    \setcounter{footnote}{0}%
    \global\let\thanks\relax
    \global\let\maketitle\relax
    \global\let\@maketitle\relax
    \global\let\@thanks\@empty
    \global\let\@author\@empty
    \global\let\@date\@empty
    \global\let\@title\@empty
    \global\let\title\relax
    \global\let\author\relax
    \global\let\date\relax
    \global\let\and\relax
  }
%    \end{macrocode}
% We must also change \cs{@maketitle} to insert a \tagname{Title} tag.
% We have here two options: We can surround the whole block with a \tagname{Title}
% or only the title text (but not both).
% As default the title text has the \tagname{Title} tag and the block is a \tagname{Part} (from
% the symbolic name \tagname{para/semantic}),
% but this can be changed by reassigning the symbolic name \tagname{title/block}
% and changing the plug of the tagging socket to the transparent plug, e.g.,
% \begin{verbatim}
% \AssignStructureRole{title/block}{Title}
% \AssignTaggingSocketPlug{title}{transparent}
% \end{verbatim}
% Note that in PDF 1.7 the \tagname{Title} tag is not a standard tag, it is a user defined
% and by default rolemapped to \tagname{P}. If \tagname{Title} should be used for the
% title block the rolemapping must be adjusted, e.g., to \tagname{Part} or \tagname{Sect}.
% \changes{0.85i}{2026-10-11}{Add center attribute}
%    \begin{macrocode}
\IfSocketExistsF{tagsupport/title}
 {
  \NewTaggingSocket{title}{2}
 }
\NewTaggingSocketPlug{title}{kernel}
 {
   \par
   \group_begin:
     \tagpdfparaOff
     \tag_struct_begin:n{tag=\UseStructureName{title/text},attribute-class=center}
     \tagmcbegin{}#2\tagmcend
     \tag_struct_end:
     \par
   \group_end:
 }
%    \end{macrocode}
% An aria attribute to mark up the title-block: 
% \changes{0.85i}{2026-10-11}{Add an ARIA attribute}
%    \begin{macrocode}
\tagpdfsetup{role/new-attribute={aria-banner}{/O/ARIA-1.1/role (banner)}}
\AssignTaggingSocketPlug{title}{kernel}
\cs_new_protected:Npn \@@_patch_@maketitle:
 {
  \newpage
  \null
  \vskip 2em%
  \begin{center}%
   [tagging-suppress-paras=true,
    tagging-recipe=standalone,
    tag-name=\UseStructureName{title/block},
    tag-attr-class=aria-banner]
  \let \footnote \thanks
%    \end{macrocode}
% By default this socket adds \tagname{Title} around the title text.
% In PDF 1.7 \tagname{Title} is rolemapped to P and the socket
% adapts the \tagname{para/textblock} to avoid
% that we get an \tagname{P} inside a \tagname{P}.
% One can assign the \plug{transparent} plug to the socket if
% \tagname{Title} should be used for the title block instead.
%    \begin{macrocode}
  {\LARGE\UseTaggingSocket{title}{}{\@title}\par}
   \vskip 1.5em%
    {\large
     \AssignStructureRole{para/textblock}{title-author}%
      \lineskip .5em%
      \begin{tabular}[t]{c}%
        \@author
      \end{tabular}\par}%
    \vskip 1em%
    {\large
     \AssignStructureRole{para/textblock}{title-date}%
     \@date}%
  \end{center}%
  \par
  \vskip 1.5em
  }

%    \end{macrocode}
% The titlepage variant:
% \changes{0.85f}{2026-05-07}{Added support for title/block tag}
% \changes{0.85i}{2026-10-11}{add aria attribute}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_patch_maketitle_page:
  {\begin{titlepage}%
%    \end{macrocode}
% disable table tagging
%    \begin{macrocode}
  \tagpdfsetup{table/tagging=false}%
  \let\footnotesize\small
  \let\footnoterule\relax
  \let \footnote \thanks
  \null\vfil
  \vskip 60\p@
%    \end{macrocode}
%    \begin{macrocode}
  \begin{center}%
   [tagging-suppress-paras=true,
    tagging-recipe=standalone,
    tag-name=\UseStructureName{title/block},
    tag-attr-class=aria-banner]
%    \end{macrocode}
% By default this socket adds \tagname{Title} around the title text.
% In PDF 1.7 \tagname{Title} is rolemapped to P and the socket
% adapts the \tagname{para/textblock} to avoid
% that we get an \tagname{P} inside a \tagname{P}.
% One can assign the \plug{transparent} plug to the socket if
% \tagname{Title} should be used for the title block instead.
%    \begin{macrocode}
   {\LARGE\UseTaggingSocket{title}{}{\@title}\par}
   \vskip 3em%
    {\large
     \AssignStructureRole{para/textblock}{title-author}%
     \lineskip .75em%
      \begin{tabular}[t]{c}%
        \@author
      \end{tabular}\par}%
      \vskip 1.5em%
    {\large
     \AssignStructureRole{para/textblock}{title-date}%
     \@date
     \par}%       % Set date in \large size.
  \end{center}\par
  \@thanks
  \vfil\null
  \end{titlepage}%
  \setcounter{footnote}{0}%
  \global\let\thanks\relax
  \global\let\maketitle\relax
  \global\let\@thanks\@empty
  \global\let\@author\@empty
  \global\let\@date\@empty
  \global\let\@title\@empty
  \global\let\title\relax
  \global\let\author\relax
  \global\let\date\relax
  \global\let\and\relax
  }

%    \end{macrocode}
% Map the new commands onto \cs{maketitle}:
%    \begin{macrocode}
\AddToHook{class/article/after}
  {
    \if@titlepage
     \cs_set_eq:NN \maketitle \@@_patch_maketitle_page:
    \else
     \cs_set_eq:NN \maketitle \@@_patch_maketitle:
     \cs_set_eq:NN \@maketitle \@@_patch_@maketitle:
    \fi
  }
\AddToHook{class/report/after}
  {
    \if@titlepage
     \cs_set_eq:NN \maketitle \@@_patch_maketitle_page:
    \else
    \cs_set_eq:NN \maketitle \@@_patch_maketitle:
    \cs_set_eq:NN \@maketitle \@@_patch_@maketitle:
    \fi
  }
\AddToHook{class/book/after}
  {
    \if@titlepage
     \cs_set_eq:NN \maketitle \@@_patch_maketitle_page:
    \else
    \cs_set_eq:NN \maketitle \@@_patch_maketitle:
    \cs_set_eq:NN \@maketitle \@@_patch_@maketitle:
    \fi
  }
%    \end{macrocode}
%
% \subsection{Title options} 
% Depending on if there are chapters or not, we have a different offset for the headings
% from their level.   
% \changes{0.85i}{2026-10-11}{Add tagging options for title}
%    \begin{macrocode} 
\AddToHook{begindocument}
 {
   \@ifundefined{chapter}
    {\tl_const:Nn \c_@@_title_offset_tl {1}}
    {\tl_const:Nn \c_@@_title_offset_tl {2}}
 }         
%    \end{macrocode}   
% \subsubsection{Title (default)}
%    \begin{macrocode}
\keys_define:nn {__tag/setup}
  {
    title .choice: ,    
    title/Title .code:n = 
     {
       \AddToHook{begindocument}
          {      
            \@ifundefined{chapter}          
             {   
               \AssignStructureRole{title/text}{title-text/latex} 
               \AssignStructureRole{sec/-1/title}{part-heading/latex}               
               \AssignStructureRole{sec/1/title}{section-heading/latex}  
               \AssignStructureRole{sec/2/title}{subsection-heading/latex}  
               \AssignStructureRole{sec/3/title}{subsubsection-heading/latex}  
               \AssignStructureRole{sec/4/title}{paragraph-heading/latex}  
               \AssignStructureRole{sec/5/title}{subparagraph-heading/latex}
%    \end{macrocode}
% Reassign the default mapping for the global rolemap. 
% TODO: create a simpler interface in tagpdf
%    \begin{macrocode}
               \tagpdfsetup
                {                                   
                  role/new-tag={title-text/Title},
                  role/new-tag={part-heading/Title},    
                  role/new-tag={section-heading/H1},
                  role/new-tag={subsection-heading/H2},
                  role/new-tag={subsubsection-heading/H3},
                  role/new-tag={paragraph-heading/H4},
                  role/new-tag={subparagraph-heading/H5}
                }                          
             }
             {    
               \AssignStructureRole{title/text}{title-text/latex} 
               \AssignStructureRole{sec/-1/title}{part-heading/latex}    
               \AssignStructureRole{sec/0/title}{chapter-heading/latex-book}             
               \AssignStructureRole{sec/1/title}{section-heading/latex-book}  
               \AssignStructureRole{sec/2/title}{subsection-heading/latex-book}  
               \AssignStructureRole{sec/3/title}{subsubsection-heading/latex-book}  
               \AssignStructureRole{sec/4/title}{paragraph-heading/latex-book}  
               \AssignStructureRole{sec/5/title}{subparagraph-heading/latex-book}   
               \tagpdfsetup
                {                                   
                  role/new-tag={title-text/Title},
                  role/new-tag={part-heading/Title},     
                  role/new-tag={chapter-heading/H1},
                  role/new-tag={section-heading/H2},
                  role/new-tag={subsection-heading/H3},
                  role/new-tag={subsubsection-heading/H4},
                  role/new-tag={paragraph-heading/H5},
                  role/new-tag={subparagraph-heading/H6}
                }                         
             }
         }    
     }
  }     
%    \end{macrocode}
% \subsubsection{Aria}
% The aria option adds aria attributes to \tagname{title-text} and the headings. 
% Currently it cannot be disabled again. 
%    \begin{macrocode}
\keys_define:nn {__tag/setup}
  {
    title/aria .code:n =
      {
%    \end{macrocode}
% Set up the attributes and plugs if they do not exist yet.
%    \begin{macrocode}
        \IfSocketPlugExistsF {sec/title/begin}{aria}
         {
%    \end{macrocode}
%    Set up the heading level attributes: 
%    \cs{part} and \cs{chapter} have always the same attribute. For the
%    other sectioning commands it depends on the class.
%    \begin{macrocode}  
            \int_step_inline:nn {7}
             {
               \keys_set:nn {__tag/setup}
                {
                  role/new-attribute*=
                    {aria-heading-##1}{/O/ARIA-1.1/role (heading)/aria-level~##1}
                }
             }               
%    \end{macrocode}
% The plug to add an aria attribute to the title text:
%    \begin{macrocode}
         \NewTaggingSocketPlug{title}{aria}
          {
            \par
            \group_begin:
              \tagpdfparaOff
              \tag_struct_begin:n
               {
                tag=\UseStructureName{title/text},
                attribute-class={aria-heading-1,center}
               }
              \tagmcbegin{}##2\tagmcend
              \tag_struct_end:%
              \par
            \group_end:
          }
%    \end{macrocode}
%  We add the attribute class to the display headings:
%    \begin{macrocode}
         \NewTaggingSocketPlug{sec/title/begin}{aria}
          {  
            \int_compare:nNnTF { \int_eval:n {\use_i:nn ##1} }<{1}  
%    \end{macrocode}
%      \cs{part} (level -1) and \cs{chapter} (level 0) should 
%      use aria-heading-1 and aria-heading-2
%    \begin{macrocode}
             {
               \__tag_sec_title_begin:nnn ##1
                {attribute-class={aria-heading-\int_eval:n{\use_i:nn ##1 + 2}}}
             } 
%    \end{macrocode}
%  \cs{section} (level 1) should be mapped to aria-heading 3 in a book class and
%  aria-heading 2 in article. 
%    \begin{macrocode}
             { 
               \__tag_sec_title_begin:nnn ##1
                {attribute-class={aria-heading-\int_eval:n{\use_i:nn ##1 + \c_@@_title_offset_tl}}}                          
             }   
          }
%    \end{macrocode}
% And now the run-in headings. We assume that 
% \cs{part} and \cs{chapter} are not a run-in heading. 
% TODO pass the level in a better way
%    \begin{macrocode}
         \NewTaggingSocketPlug{sec/title/split}{aria}
          {
           \tag_struct_gput:nnn
             {\tag_get:n{struct_num}}
             {C}
             {/aria-heading-\int_eval:n{ \l__head_level_int +\c_@@_title_offset_tl }}
           \__tag_sec_title_split:
          }
        }
%    \end{macrocode}
% And now activate the plugs
%    \begin{macrocode}
     \AssignTaggingSocketPlug{title}{aria}
     \AssignTaggingSocketPlug{sec/title/begin}{aria}
     \AssignTaggingSocketPlug{sec/title/split}{aria}
     }
  }
%    \end{macrocode}      
% 
% \subsubsection{H1}
% The \keyvalue{H1} option role maps \tagname{title-text} to H1 and headings one level down.
% We need different versions depending on the PDF version.
% As tagpdf resets the name space of the heading commands 
% in the begindocument hook, we have to use that too.
%    \begin{macrocode}   
\pdf_version_compare:NnTF < {2.0}
 { 
  \keys_define:nn {__tag/setup}
    {
      title/H1 .code:n = 
       {                        
         \AddToHook{begindocument}
           {      
            \@ifundefined{chapter}   
             {     
               \tagpdfsetup
                {                                   
                  role/new-tag={title-text/H1},   
                  role/new-tag={part-heading/H1},
                  role/new-tag={section-heading/H2},
                  role/new-tag={subsection-heading/H3},
                  role/new-tag={subsubsection-heading/H4},
                  role/new-tag={paragraph-heading/H5},
                  role/new-tag={subparagraph-heading/H6}
                }
             }
             {
               \tagpdfsetup
                {                                   
                  role/new-tag={title-text/H1},
                  role/new-tag={part-heading/H1},     
                  role/new-tag={chapter-heading/H2},
                  role/new-tag={section-heading/H3},
                  role/new-tag={subsection-heading/H4},
                  role/new-tag={subsubsection-heading/H5},
                  role/new-tag={paragraph-heading/H6},
                  role/new-tag={subparagraph-heading/P}
                }             
             }       
           }
       }
    }       
 }   
%    \end{macrocode}
% PDF 2.0.
%    \begin{macrocode}
 {
   \keys_define:nn {__tag/setup}
    {
      title/H1 .code:n = 
       {       
         \AddToHook{begindocument}
          {      
            \@ifundefined{chapter}          
             {
               \tag_if_tag_known:nnF {title-text}{latex-title-H1}
                {
                 \tagpdfsetup
                  {               
                    role/new-NS={latex-title-H1}{https://www.latex-project.org/ns/title-H1}{},
                    role/new-tag={tag=title-text,tag-namespace=latex-title-H1,role=H1},     
                    role/new-tag={tag=part-heading,tag-namespace=latex-title-H1,role=H1},
                    role/new-tag={tag=section-heading,tag-namespace=latex-title-H1,role=H2},
                    role/new-tag={tag=subsection-heading,tag-namespace=latex-title-H1,role=H3},
                    role/new-tag={tag=subsubsection-heading,tag-namespace=latex-title-H1,role=H4},
                    role/new-tag={tag=paragraph-heading,tag-namespace=latex-title-H1,role=H5},
                    role/new-tag={tag=subparagraph-heading,tag-namespace=latex-title-H1,role=H6}, 
                  }
                }                
              \AssignStructureRole{title/text}{title-text/latex-title-H1} 
              \AssignStructureRole{sec/-1/title}{part-heading/latex-title-H1}               
              \AssignStructureRole{sec/1/title}{section-heading/latex-title-H1}  
              \AssignStructureRole{sec/2/title}{subsection-heading/latex-title-H1}  
              \AssignStructureRole{sec/3/title}{subsubsection-heading/latex-title-H1}  
              \AssignStructureRole{sec/4/title}{paragraph-heading/latex-title-H1}  
              \AssignStructureRole{sec/5/title}{subparagraph-heading/latex-title-H1}   
             } 
%    \end{macrocode}
%     for book classes
%    \begin{macrocode}  
            { 
              \tag_if_tag_known:nnF {title-text}{latex-title-H1-book}
                {  
                  \tagpdfsetup
                   {               
                     role/new-NS={latex-title-H1-book}{https://www.latex-project.org/ns/title-H1-book}{},
                     role/new-tag={tag=title-text,tag-namespace=latex-title-H1-book,role=H1},
                     role/new-tag={tag=part-heading,tag-namespace=latex-title-H1-book,role=H1},                    
                     role/new-tag={tag=chapter-heading,tag-namespace=latex-title-H1-book,role=H2},
                     role/new-tag={tag=section-heading,tag-namespace=latex-title-H1-book,role=H3},
                     role/new-tag={tag=subsection-heading,tag-namespace=latex-title-H1-book,role=H4},
                     role/new-tag={tag=subsubsection-heading,tag-namespace=latex-title-H1-book,role=H5},
                     role/new-tag={tag=paragraph-heading,tag-namespace=latex-title-H1-book,role=H6},
                     role/new-tag={tag=subparagraph-heading,tag-namespace=latex-title-H1-book,role=H7}
                   }
                }                                                  
              \AssignStructureRole{title/text}{title-text/latex-title-H1-book}  
              \AssignStructureRole{sec/-1/title}{part-heading/latex-title-H1-book}                             
              \AssignStructureRole{sec/0/title}{chapter-heading/latex-title-H1-book}
              \AssignStructureRole{sec/1/title}{section-heading/latex-title-H1-book}  
              \AssignStructureRole{sec/2/title}{subsection-heading/latex-title-H1-book}  
              \AssignStructureRole{sec/3/title}{subsubsection-heading/latex-title-H1-book}  
              \AssignStructureRole{sec/4/title}{paragraph-heading/latex-title-H1-book}  
              \AssignStructureRole{sec/5/title}{subparagraph-heading/latex-title-H1-book}    
            }                      
          }   
       }
    }
 }   
%    \end{macrocode}
%  
% \subsubsection{html}
% In PDF 1.7 this behaves like the \keyvalue{H1} value. In PDF 2.0
% \tagname{title-text} is role mapped  to \tagname{h1} in the html namespace, 
% which in turn is role
% mapped to \tagname{Title}. The first heading command is role mapped to
% \tagname{h2} in the HTML namespace, which in turn is role
% mapped to \tagname{H1} in the PDF name space. The global Rolemap is the same as the default case.
% This mapping can improve derivation to html as derivation can (but doesn't have to)
% stop when it encounters a tag in the HTML namespace. 
% 
%    \begin{macrocode}
\pdf_version_compare:NnTF < {2.0}
 { 
  \keys_define:nn {__tag/setup}
    {
      title/html .code:n = 
       {  
        \keys_set:nn {__tag/setup}{title=H1}  
       } 
    }                       
 }   
 {
   \keys_define:nn {__tag/setup}
    {
      title/html .code:n = 
       { 
        \tag_if_tag_known:nnF { h1 }{ html } 
         { 
          \keys_set:nn {__tag/setup}
            {
             role/new-NS={html}{http://www.w3.org/1999/xhtml}{},
             role/new-tag={tag=h1,tag-namespace=html,role=Title},
             role/new-tag={tag=h2,tag-namespace=html,role=H1},
             role/new-tag={tag=h3,tag-namespace=html,role=H2},
             role/new-tag={tag=h4,tag-namespace=html,role=H3},
             role/new-tag={tag=h5,tag-namespace=html,role=H4},
             role/new-tag={tag=h6,tag-namespace=html,role=H5}
            }         
         }
        \AddToHook{begindocument}
         { 
          \@ifundefined{chapter}
           {
            \AssignStructureRole{title/text}{h1} 
            \AssignStructureRole{sec/-1/title}{h1} 
            \AssignStructureRole{sec/1/title}{h2} %section role mapped to H1  
            \AssignStructureRole{sec/2/title}{h3} 
            \AssignStructureRole{sec/3/title}{h4} 
            \AssignStructureRole{sec/4/title}{h5} 
            \AssignStructureRole{sec/5/title}{h6} 
           }
           {
            \AssignStructureRole{title/text}{h1}
            \AssignStructureRole{sec/-1/title}{h1} 
            \AssignStructureRole{sec/0/title}{h2}  
            \AssignStructureRole{sec/1/title}{h3} %section role mapped to H1  
            \AssignStructureRole{sec/2/title}{h4} 
            \AssignStructureRole{sec/3/title}{h5} 
            \AssignStructureRole{sec/4/title}{h6} 
           }        
         }
       } 
    }
 }
%    \end{macrocode}
% \subsection{Helper commands to set metadata}
%
% Some temp variables
%    \begin{macrocode}
\str_new:N \g_@@_title_tmpa_str
\str_new:N \l_@@_title_tmpa_str
\tl_new:N  \l_@@_title_tmpa_tl
\seq_new:N \l_@@_title_tmpa_seq
%    \end{macrocode}
%
% We ensure that the default definitions
% of \cs{@title} and \cs{@author} are robust:
%    \begin{macrocode}
\protected\def\@title{\@latex@error{No~\noexpand\title given}\@ehc}
\protected\def\@author{\@latex@warning@no@line{No~\noexpand\author given}}
%    \end{macrocode}
% A helper command to convert the title into a pdfstring similar to
% \cs{pdfstringdef}.
%\changes{0.85e}{2026-04-29}{The command makes now use of \cs{pdf_purify:nN}}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_title_pdfstring:nnN #1 #2 #3 % #1 text, #2 e.g. utf16/hex
  {
    \group_begin:
    \pdf_purify:nN {#1}\l_@@_title_tmpa_tl
    \pdf_string_from_unicode:nVN { #2 } \l_@@_title_tmpa_tl \l_@@_title_tmpa_str
    \str_gset_eq:NN \g_@@_title_tmpa_str\l_@@_title_tmpa_str
    \group_end:
    \str_set_eq:NN #3 \g_@@_title_tmpa_str
  }
\cs_generate_variant:Nn\@@_title_pdfstring:nnN {e}
%    \end{macrocode}

% \subsection{Extend title to set metadata}
% At first a variable to store the title, as \cs{@title} is emptied by \LaTeX.
%    \begin{macrocode}
\tl_new:N \g_@@_title_title_tl
%    \end{macrocode}
% Now we redefine \cs{title} so that it stores the title, and processes
% keys in the optional argument. We use \texttt{hyp} as module
% name for the key as this means that if hyperref is loaded its definition
% of \key{pdftitle} will be used -- at some time probably this
% should be moved out of hyperref so that we have only one definition.
%
%    \begin{macrocode}
\RenewDocumentCommand\title{O{}m}
 {
    \gdef\@title{#2}
    \tl_gset_eq:NN\g_@@_title_title_tl\@title
    \keys_set:nn {hyp}{#1}
 }
%    \end{macrocode}
% Now we define the \key{pdftitle} key. This is more or less
% the same definition as in the generic hyperref driver.
%    \begin{macrocode}
\regex_new:N\l_@@_title_optlang_regex
\regex_set:Nn\l_@@_title_optlang_regex {\A\[([A-Za-z\-]+)\](.*)}
\cs_generate_variant:Nn \clist_item:nn {on}
%    \end{macrocode}
% and now the keys.
%    \begin{macrocode}
\keys_define:nn { hyp }
   {
     pdftitle  .code:n =
       {
         \tl_if_blank:nTF {#1}
           {
             \pdfmanagement_remove:nn {Info}{Title}
           }
           {
             \tl_set:Ne\l_@@_title_tmpa_tl {\clist_item:on{#1}{1}}
             \regex_extract_once:NVN
                \l_@@_title_optlang_regex
                \l_@@_title_tmpa_tl
                \l_@@_title_tmpa_seq
             \seq_if_empty:NTF\l_@@_title_tmpa_seq
              {
                \@@_title_pdfstring:nnN {#1}{utf16/hex}\l_@@_title_tmpa_str
              }
              {
                \@@_title_pdfstring:enN
                   {\seq_item:Nn \l_@@_title_tmpa_seq{3}}{utf16/hex}\l_@@_title_tmpa_str
              }
             \str_if_eq:VnF\l_@@_title_tmpa_str{<FEFF>}
               {
                 \pdfmanagement_add:nne {Info}{Title}{\l_@@_title_tmpa_str}
               }
           }
          \AddToDocumentProperties[hyperref]{pdftitle}{#1}
       }
   ,pdfsubtitle .code:n = { \AddToDocumentProperties[hyperref]{pdfsubtitle}{#1} }
   }
%    \end{macrocode}
%
% \subsection{Extend \cs{author} to set metadata}
%
% At first a variable to store the authors, as \cs{@author} is emptied by \LaTeX.
%    \begin{macrocode}
\tl_new:N \g_@@_title_author_tl
%    \end{macrocode}
% Now we redefine \cs{author} so that it stores the authors, and processes
% keys in the optional argument. We use \texttt{hyp} as module
% name for the key as this means that if hyperref is loaded its definition
% of \key{pdfauthor} will be used -- at some time probably this
% should be moved out of hyperref so that we have only one definition.
%
%    \begin{macrocode}
\RenewDocumentCommand\author{O{}m}
 {
    \gdef\@author{#2}
    \tl_gset_eq:NN\g_@@_title_author_tl\@author
    \keys_set:nn {hyp}{#1}
 }
%    \end{macrocode}
%
% Now we define the \key{pdfauthor} key. This is more or less
% the same definition as in the generic hyperref driver.

%    \begin{macrocode}
\keys_define:nn { hyp }
   {
     pdfauthor  .code:n =
       {
         \tl_if_blank:nTF {#1}
           {
             \pdfmanagement_remove:nn {Info}{Author}
           }
           {
             \tl_set:Ne\l_@@_title_tmpa_tl {\clist_item:on{#1}{1}}
             \regex_extract_once:NVN
                \l_@@_title_optlang_regex
                \l_@@_title_tmpa_tl
                \l_@@_title_tmpa_seq
             \seq_if_empty:NTF\l_@@_title_tmpa_seq
              {
                \@@_title_pdfstring:nnN {#1}{utf16/hex}\l_@@_title_tmpa_str
              }
              {
                \@@_title_pdfstring:enN
                   {\seq_item:Nn \l_@@_title_tmpa_seq{3}}{utf16/hex}\l_@@_title_tmpa_str
              }
             \str_if_eq:VnF\l_@@_title_tmpa_str{<FEFF>}
               {
                 \pdfmanagement_add:nne {Info}{Author}{\l_@@_title_tmpa_str}
               }
           }
          \AddToDocumentProperties[hyperref]{pdfauthor}{#1}
       }
   }
%    \end{macrocode}
% \subsection{Fallback for classes and packages that redefine \cs{title} or \cs{author}}
% If a class redefines \cs{author} and \cs{title} again, we try to retrieve at
% least the values.
%    \begin{macrocode}
\AddToHook{cmd/maketitle/before}
  {
   \tl_gset_eq:NN \g_@@_title_author_tl\@author
   \tl_gset_eq:NN \g_@@_title_title_tl\@title
  }
%    \end{macrocode}
%
% \subsection{Finalize document}
% At last we set the title and the author at the end of document
% if that hasn't happened yet:
% \changes{0.85h}{2026-09-14}{Correct title processing, tagging/1594}
%    \begin{macrocode}
\AddToHook{shipout/lastpage}
 {
   \tl_if_empty:eT{\GetDocumentProperty{hyperref/pdftitle}}
      {
        \group_begin:
        \cs_set_eq:NN\thanks \use_none:n
        \pdf_purify:nN { \g_@@_title_title_tl }\l_@@_title_tmpa_tl
        \tl_if_blank:oF { \l_@@_title_tmpa_tl }
         { \keys_set:ne{hyp}{pdftitle={{\exp_not:V\l_@@_title_tmpa_tl}}} }
        \group_end:
      }
   \tl_if_empty:eT{\GetDocumentProperty{hyperref/pdfauthor}}
      {
        \group_begin:
        \cs_set_eq:NN\thanks \use_none:n
        \cs_set:Npn \and {,}
        \pdf_purify:nN { \g_@@_title_author_tl }\l_@@_title_tmpa_tl
        \tl_if_blank:oF { \l_@@_title_tmpa_tl }
          { \keys_set:ne{hyp}{pdfauthor={\exp_not:V\l_@@_title_tmpa_tl}} }
        \group_end:
      }
%    \end{macrocode}
% force display title, if an UA-standard is detected.
%    \begin{macrocode}
   \tl_if_empty:eF{\GetDocumentProperty{document/pdfstandard-UA}}
     {
       \pdfmanagement_add:nnn {Catalog / ViewerPreferences } { DisplayDocTitle } { true }
     }
 }
\DeclareHookRule{shipout/lastpage}{latex-lab-testphase-title}{before}{pdfmanagement-testphase}
%</package>
%    \end{macrocode}

%    \begin{macrocode}
%<*latex-lab>
\ProvidesFile{title-latex-lab-testphase.ltx}
        [\ltlabtitledate\space v\ltlabtitleversion\space
         Changes related to the tagging of the title]

\RequirePackage{latex-lab-testphase-title}

%</latex-lab>
%    \end{macrocode}
