% \iffalse meta-comment
%
%% File: latex-lab-sec.dtx (C) Copyright 2022-2025 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 development version of the bundle can be found below
%
%    https://github.com/latex3/latex2e/required/latex-lab
%
% for those people who are interested or want to report an issue.
%
\def\ltlabsecdate{2025-10-20}
\def\ltlabsecversion{0.84k}
%    \end{macrocode}
%<*driver>
\DocumentMetadata{tagging=on,pdfstandard=ua-2}
\documentclass[kernel]{l3doc}
\usepackage{latex-lab-testphase-l3doc}
\EnableCrossrefs
\CodelineIndex
\begin{document}
  \DocInput{latex-lab-sec.dtx}
\end{document}
%</driver>
%
% \fi
%
%
% \title{The \textsf{latex-lab-sec} package\\
% Changes related to the tagging of sectioning commands}
% \author{\LaTeX{} Project\thanks{Initial implementation done by Ulrike Fischer}}
% \date{v\ltlabsecversion\ \ltlabsecdate}
%
% \maketitle
%
% \newcommand{\xt}[1]{\textsl{\textsf{#1}}}
% \newcommand{\TODO}[1]{\textbf{[TODO:} #1\textbf{]}}
% \newcommand{\docclass}{document class \marginpar{\raggedright document class
% customizations}}
%
% \providecommand\hook[1]{\texttt{#1}}
%
% \begin{abstract}
% The following code implements a first draft for the tagging of sectioning commands.
% \end{abstract}
%
% \section{Limitations}
%
% Sectioning commands are in general not defined by the format but by the classes.
% Their implementation vary: some are defined with the help of \cs{@startsection},
% some are like \cs{chapter} handcrafted,
% some build with the help of extension packages or as in the KOMA classes
% with class code that extends the \cs{@startsection} functionality.
%
% The following code can therefore currently be used \emph{only} with the standard classes
% or with classes which do not overwrite the changed definitions.
%
%
%
% \section{Introduction}
%
%  Tagging of sectioning commands consist of two parts:
%
% \begin{itemize}
%  \item The heading/title text of the section should be surrounded by a
%  heading tag, typically \texttt{Hn} with some value of \texttt{n}.
%  In theory, one could put the number of the section command in an \texttt{Lbl}.
%  However, current AT doesn't handle this well, so
%  we use a tag \texttt{section-number} that is mapped to \texttt{Span}.
%  The number of the \texttt{Hn} tag should reflect the \enquote{natural} level.
%  So in an article \cs{section} will use  \texttt{H1}, in a book \cs{chapter} will use
%  \texttt{H1} and \cs{section} \texttt{H2}.
%  Titles of \cs{part} are a bit out of this system as they are normally
%  not part of the hierarchy: often only some chapters are grouped under a part.
%  Their title is therefore tagged as \texttt{Title}.
%  \item
%  The whole section should normally be surrounded by
%  a \texttt{Sect} tag. Parts should be surrounded by \texttt{Part}.
%  It is a bit unclear if the headings should be inside or outside of these
%  structures---the best practice guide puts them outside---but on the whole
%  it sounds more logical to group the heading with the text inside the \texttt{Sect}.
%  For the part this is actually required, as there can be only one \texttt{Title}
%  in a structure, so the part title can't be at the same level as the
%  document \texttt{Title}.
%
%  Starting such an enclosing \texttt{Sect} structure is rather easy,
%  but closing it requires code in various place,
%  for example the commands \cs{mainmatter}, \cs{backmatter},
%  \cs{frontmatter} and \cs{appendix} should typically close everything.
%  Following sectioning commands should close all previous structures
%  with a level equal or higher than their own level.
%  \end{itemize}
%
%  \section{Technical details and problems}
%
%  The implementation has to take care of various details.
%
%  \begin{itemize}
%
%  \item As sections in \LaTeX{} are not environments, the
%  \texttt{<Sect>} structures can be wrongly nested with other structures. For example
%  if a document puts a sectioning command into a list or a trivlist or
%  a minipage then it can no longer close previous \texttt{<Sect>} structures correctly.
%  The problem can be detected by checking the structure stack
%  and a warning can be issued, but the author then has to close the structures
%  manually before the list or minipage.
%
%  Thus there have to be user interfaces to handle such cases.
%  It should also be possible not to create all the \texttt{<Sect>} structures
%  automatically but to tag only the headings so that the author can handle special
%  cases manually.
%
%  \item If hyperref is used, targets for links should be inserted, either with
%  \cs{refstepcounter} or manually with \cs{MakeLinkTarget}. These targets must be
%  in the correct structure for the structure destinations. They replace some
%  of the current patches in hyperref.
%
%  \end{itemize}
%
%  \subsection{Functions and keys}
%
% \begin{function}{\tag_tool:n,\tagtool}
% \emph{deprecated}, use tagging sockets instead.
% \end{function}
%
%  \subsection{TODO}
%
%  \begin{itemize}
%   \item A dedicated command to close a sectioning unit should be provided.
%
%   \item A dedicated command to open a sectioning unit should be provided too.
%
%   \item It should also be possible to suppress the sectioning unit in sectioning commands
%     to allow e.g. to put an epigraph or similar in front.
%
%  \item The number in \cs{part} and  \cs{chapter} is currently not correctly
%  tagged as a \texttt{section-number} as this requires to redefine the internal (class dependent)
%  commands too.
%
%  \end{itemize}
%
%    \begin{macrocode}
%<*package>
%    \end{macrocode}
%
% \section{Implementation}
%    \begin{macrocode}
\ProvidesExplPackage {latex-lab-testphase-sec} {\ltlabsecdate} {\ltlabsecversion}
  {Code related to the tagging of sectioning commands}
%    \end{macrocode}
% \changes{0.84k}{2025-10-20}{Switched to tagging sockets and various corrections}.
% \subsection{Temporary fix}
% Until tagpdf correctly sets the symbolic name (2025-10-06)
%    \begin{macrocode}
\tl_set:Nn  \l__tag_para_tag_default_tl { \UseStructureName {para/textblock} }
\tl_set:Nn  \l__tag_para_main_tag_tl    { \UseStructureName {para/semantic} }
%    \end{macrocode}
%
% \subsection{Surrounding by \texttt{Sect} structures}
%  We use a stack to record the levels of the open \texttt{Sect}. The first item
%  has level -100. A sectioning command will take a record from the stack. If its level is
%  greater or equal it closes this structure and takes the next record from the stack.
%  If the record has a smaller level then it puts it back and stops.
%  The stack is compared with the main structure stack, if they don't match
%  it means we can't safely close the \texttt{Sect} and so we issue a warning
%  and do nothing.
%
%    \begin{macrocode}
%</package>
%    \end{macrocode}
% \subsubsection{Glyphtounicode improvements}
%
% As lualatex runs with legacy encodings in the test files, we enable and
% load glyphtounicode. For the math we load additional definitions.
%
%    \begin{macrocode}
%<*kernelchange>
\ifdefined\directlua
 \ifnum\outputmode > 0
   \pdfvariable gentounicode =1
   \protected\def\pdfglyphtounicode {\pdfextension glyphtounicode }
   \protected\edef\pdfgentounicode  {\pdfvariable gentounicode}
   \input{glyphtounicode}
 \fi
\fi
\ifdefined\pdfglyphtounicode
 \input{glyphtounicode-cmex}
\fi
%</kernelchange>
%    \end{macrocode}
%
%    \begin{macrocode}
%<*package>
%<@@=tag>
%    \end{macrocode}
%
% \subsubsection{Tagging commands}
%
%
% \begin{variable}{\g_@@_sec_stack_seq}
% The stack holds the tag, the level and the structure number.
%    \begin{macrocode}
\seq_new:N   \g_@@_sec_stack_seq
\seq_gpush:Nn\g_@@_sec_stack_seq {{Document}{-100}{2}}
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_get_data_current_Sect:}
% This allows to retrieve the number of the current Sect structure (or
% Document if we are outside any Sect) with |\tag_get:n{current_Sect}|
%    \begin{macrocode}
\cs_new:Npn \@@_get_data_current_Sect:
 {
   \exp_last_unbraced:Ne\use_iii:nnn{\seq_item:Nn\g_@@_sec_stack_seq{1}}
 }
%    \end{macrocode}
% \end{macro}
% \begin{variable}{\l_@@_sec_Sect_bool}
% This boolean controls if a Sect structure is opened.
%    \begin{macrocode}
\bool_new:N     \l_@@_sec_Sect_bool
\bool_set_true:N\l_@@_sec_Sect_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_sec_begin:nn}
% This starts a sectioning structure (the „Sect environment“).
% Currently the default tag is either Sect or Part, depending on the level,
% but this can be changed by adapting the symbolic structure names which are
% built from the level.
% The second argument allows to add more options but is currently unused.
%    \begin{macrocode}
\cs_new_protected:Npn\@@_sec_begin:nn #1 #2 %#1 level #2 keyval
  {
    \tag_struct_begin:n
      {
         tag= \UseStructureName{sec/#1}
        ,#2
      }
    \seq_gpush:Ne \g_@@_sec_stack_seq
      {{\g_@@_struct_tag_tl}{\int_eval:n{#1}}{\g_@@_struct_stack_current_tl}}
  }
\cs_generate_variant:Nn \@@_sec_begin:nn {en}
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_sec_end:n}
%    \begin{macrocode}
\msg_new:nnn { tag } {wrong-sect-nesting}
  {
    The~structure~#1~can~not~be~closed.\\
    It~is~not~equal~to~the~current~structure~#2~on~the~main~stack
  }

\cs_new_protected:Npn\@@_sec_end:n #1 % #1 level
  {
    \seq_get:NN \g_@@_sec_stack_seq \l_@@_tmpa_tl
    \int_compare:nNnT {#1}<{\exp_last_unbraced:NV\use_ii:nnn\l_@@_tmpa_tl+1}
      {
        \seq_get:NN\g_@@_struct_tag_stack_seq \l_@@_tmpb_tl
        \exp_args:Nee
          \tl_if_eq:nnTF
            {\exp_last_unbraced:NV\use_i:nnn\l_@@_tmpa_tl}
            {\exp_last_unbraced:NV\use_i:nn\l_@@_tmpb_tl}
            {
              \seq_gpop:NN \g_@@_sec_stack_seq \l_@@_tmpa_tl
              \tag_struct_end:
              \@@_sec_end:n {#1}
            }
            {
              \msg_warning:nnee {tag}{wrong-sect-nesting}
               { \exp_last_unbraced:NV\use_i:nnn \l_@@_tmpa_tl }
               { \exp_last_unbraced:NV\use_i:nn \l_@@_tmpb_tl }
            }
      }
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\@@_sec_title_split:,\@@_sec_restore_para:}
% Runin-sectioning command must separate the heading from the following text.
% The code is in an \cs{everypar} which is perhaps executed in a group (e.g. when
% a list follows), we have to ensure that the restoring of the para can escape.
%    \begin{macrocode}
\cs_new_protected:Npn\@@_sec_restore_para:
 {
   \UseTaggingSocket {para/restore}
   \if_int_compare:w \tex_currentgrouptype:D =14        % semi-simple group
     \group_insert_after:N \@@_sec_restore_para:
   \else:
       \if_int_compare:w \tex_currentgrouptype:D =\c_one_int  % simple group
         \group_insert_after:N \@@_sec_restore_para:
       \fi:
   \fi:
 }
\cs_new_protected:Npn \@@_sec_title_split:
  {
%    \end{macrocode}
% This ends the title structure. As the begin is from the
% automatic (flattened) para-tagging we have to increase the counter.
%    \begin{macrocode}
    \tag_mc_end:
    \tag_struct_end:
    \@@_gincr_para_end_int:
%    \end{macrocode}
% In case something (e.g. a list) did reset the boolean we need to close also a semantic
% paragraph.
%    \begin{macrocode}
    \bool_if:NF\l__tag_para_flattened_bool
      {\UseTaggingSocket{para/semantic/end}{}}
%    \end{macrocode}
% Now restore the para-tagging and start a normal paragraph:
%    \begin{macrocode}
    \@@_sec_restore_para:
    \UseTaggingSocket{para/begin}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_sec_title_begin:nn}
% This command is used in the socket at the begin of display sectioning commands
% like part and chapter. It takes two arguments: the level and the title.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_sec_title_begin:nn #1 #2 %level, title
  {
    \tag_struct_begin:n{tag=\UseStructureName{sec/#1/title},title={#2}}
    \bool_set_true:N\l_@@_para_flattened_bool
    \tl_set:Nn\l_@@_para_tag_tl {\UseStructureName{sec/#1/titleline}}
  }
%    \end{macrocode}
% \end{macro}

% \begin{macro}{\@@_sec_title_end:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_sec_title_end:
  {
    \tag_struct_end: %P = Hn
    \UseTaggingSocket{para/restore}
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}{\@@_set_title_hang:nnn}
% To be able to correctly tag the number and insert the link target in the
% title of a sectioning command created with \cs{@startsection}
% we need a special\cs{@hangfrom} variant. This is a bit tricky:
% The argument contains the link target and for a correct structure
% destination it should be typeset \emph{after} the structure has been opened.
% But to measure the hangindent it must be typeset \emph{before} the paragraph is started.
% This means that we have to open the title structure manually
% and then have to suppress the para-tagging.
% Additionally there is an engine difference: with pdftex the literals for the mc are inserted
% with the box after the paragraph has started but luatex sets the attributes before
% and we have to reset them. Hiding all this in a tagging socket is non-trivial.
% The code assumes that we are in vmode!
% Attention: The code opens a structure that it doesn't close (it is closed by the \cs{par}).
% It therefore does not handle the full tagging of the title. In a new implementation
% of the sectioning command this will perhaps have to change.
%
%    \begin{macrocode}
\cs_new_protected:Npn \@@_set_title_hang:nNnn #1 #2 #3 #4
  %#1 level,
  %#2 boolean: nonumber? (will be later \l__head_nonumber_bool)
  %#3 formated number /hang space
  %#4 title
%    \end{macrocode}
% The handling of the title is not perfect. It would be better to pass it through
% something like \cs{GetTitleString}. TODO.
%    \begin{macrocode}
  {   
    \tagstructbegin{tag=\UseStructureName{sec/#1/title},title-o={#4}}
    \cs_if_exist_use:N \@@_gincr_para_begin_int:
    \bool_if:NF #2
     { \tagstructbegin{tag=\UseStructureName{sec/#1/number}} }
    \setbox\@tempboxa\hbox{{#3}}
%    \end{macrocode}
% We stop paratagging now, to avoid that the \cs{noindent} creates a structure.
%    \begin{macrocode}
    \bool_set_false:N \l_@@_para_bool
    \hangindent \wd\@tempboxa\noindent
%    \end{macrocode}
% Restart paratagging and insert the box. If the box has a real content (if there is a
% number) we have to add mc-chunks and reset the attribute of the box.
%    \begin{macrocode}
    \bool_set_true:N \l_@@_para_bool
    \bool_if:NTF #2
     {
       \box\@tempboxa
     }
     {
       \tagmcbegin{}
%    \end{macrocode}
% In lua mode we have to reset the attributes inside the box!
%    \begin{macrocode}
       \tag_mc_reset_box:N\@tempboxa
       \box\@tempboxa
       \tagmcend
       \tagstructend
     }
   \tagmcbegin{}
  }
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_sec_title_runin_number:nn}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_sec_title_runin_number:nNn #1 #2 #3 %#1 level, #2 boolean no number, #3 content
  {
    \bool_if:NTF #2
    { #3 }
    {
      \tag_mc_end_push:
      \tag_struct_begin:n{tag=\UseStructureName{sec/#1/number}}
      \tag_mc_begin:n{}
      #3
      \tag_mc_end:
      \tag_struct_end:
      \tag_mc_begin_pop:n{}
    }
  }
%    \end{macrocode}
% \end{macro}
% Open sec structures should be closed at the end of the document. This should
% be done before tagpdf closes the Document structure.
%    \begin{macrocode}
\hook_gput_code:nnn
  {tagpdf/finish/before}
  {tagpdf/sec}
  {\AssignTaggingSocketPlug{sec/end}{kernel}\UseTaggingSocket{sec/end}{-10}}
\hook_gset_rule:nnnn {tagpdf/finish/before}{tagpdf/sec}{before}{tagpdf}
%    \end{macrocode}
%
% The commands \cs{mainmatter}, \cs{backmatter}, \cs{frontmatter} and
% \cs{appendix} close all \texttt{Sect} and \texttt{Part} structures.
% \changes{v0.84g}{2025/01/05}{ensure that paragraph is ended (tagging/777)}
%    \begin{macrocode}
\AddToHook{cmd/frontmatter/before}{\par\UseTaggingSocket{sec/end}{-10}}
\AddToHook{cmd/mainmatter/before} {\par\UseTaggingSocket{sec/end}{-10}}
\AddToHook{cmd/backmatter/before} {\par\UseTaggingSocket{sec/end}{-10}}
\AddToHook{cmd/appendix/before}   {\par\UseTaggingSocket{sec/end}{-10}}
%    \end{macrocode}
%
% \subsection{Tagging Sockets}
% First the sockets that handle the Sect structures. 
% 
% The argument of the begin socket consists of two brace groups,
% in the first brace is the level, in the second the keys for the structure.
%    \begin{macrocode}
\NewTaggingSocketPlug{sec/begin}{kernel}
  {
     \@@_sec_begin:en #1
  }
\AssignTaggingSocketPlug{sec/begin}{kernel}
%    \end{macrocode}
% The end socket takes as argument only the level to close.
%    \begin{macrocode}
\NewTaggingSocketPlug{sec/end}{kernel}
  {
     \@@_sec_end:n {#1}
  }
\AssignTaggingSocketPlug{sec/end}{kernel}
%    \end{macrocode}
%
% These two sockets handle the tagging of headings with special formatting
% like part and chapter.
% The argument of the begin socket is two brace groups containing the level and
% the title.
%    \begin{macrocode}
\NewTaggingSocketPlug{sec/title/begin}{kernel}
 {
   \@@_sec_title_begin:nn #1 
 }
\AssignTaggingSocketPlug{sec/title/begin}{kernel}
%    \end{macrocode}
% The end socket does not take an argument. It only closes the structures
% and restores the para settings.
%    \begin{macrocode}

\NewTaggingSocketPlug{sec/title/end}{kernel}
 {
   \@@_sec_title_end:
 }
\AssignTaggingSocketPlug{sec/title/end}{kernel}
%    \end{macrocode}
%
%
% The \texttt{sec/title/hang} socket is used to typeset the heading of a title using \cs{@hangfrom}.
% It is the most tricky one. It takes two argument.
% The second argument of this socket will pass the normal \cs{@hangfrom} command
% if tagging is not active. It is not used with tagging.
% The first argument passes four brace groups:
% the level, a boolean for \enquote{nonumber}, 
% the actual content of the number and the title.
%
% Attention: The socket opens a structure that it doesn't close (it is closed by the \cs{par}).
% It therefore does not handle the full tagging of the title. In a new implementation
% of the sectioning command this will perhaps have to change.
%    \begin{macrocode}
\NewTaggingSocketPlug{sec/title/hang}{kernel}
  {
    \@@_set_title_hang:nNnn #1
  }
\AssignTaggingSocketPlug{sec/title/hang}{kernel}
%    \end{macrocode}
%
% The \texttt{sec/title/init} socket is used to do some initialization 
% for sectioning commands that are setup with \cs{@startsection}. It sets
% the tag name and flattens the para-tagging. It is mostly needed for run-in
% headings which set the heading inside \cs{everypar}. 
% It takes 1 argument, the level.
%    \begin{macrocode}
\NewTaggingSocketPlug{sec/title/init}{kernel}
 {
   \tl_set:Ne\l_@@_para_tag_tl{\UseStructureName{sec/#1/title}}
   \bool_set_true:N \l_@@_para_flattened_bool
 }
\AssignTaggingSocketPlug{sec/title/init}{kernel}
%    \end{macrocode}
%
% This socket handles the tagging between a run-in heading and the following text.
% It takes no argument.
%    \begin{macrocode}
\NewTaggingSocketPlug{sec/title/split}{kernel}
 {
   \@@_sec_title_split:
 }
\AssignTaggingSocketPlug{sec/title/split}{kernel}
%    \end{macrocode}
%
% The following tagging socket command is used to handle the tagging
% of the number in the title of run-in headings. Similar to the hang variant it does not
% handle the full structure but relies in part on the paragraph
% tagging. This again can change if sectioning commands are reimplemented.
% It takes as first argument the level and a boolean for the numbering.
% The second argument contains the formatted number (if numbered) and the destination.
%    \begin{macrocode}
\NewTaggingSocketPlug{sec/title/runin/number}{kernel}
 {
   \@@_sec_title_runin_number:nNn #1 {#2}
 }
\AssignTaggingSocketPlug{sec/title/runin/number}{kernel}
%    \end{macrocode}
%
% The following tagging socket command simply tags a number.
% It is not used here, as the legacy code needs a more complicated setup.
% 
% It takes the level as first argument.
% The second argument contains the formatted number.
%    \begin{macrocode}
\NewTaggingSocketPlug{sec/title/number}{kernel}
 {
   \tag_mc_end_push:
   \tag_struct_begin:n{tag=\UseStructureName{sec/#1/number}}
   \tag_mc_begin:n{}
     #2
   \tag_mc_end:
   \tag_struct_end:
   \tag_mc_begin_pop:n{}
 }
\AssignTaggingSocketPlug{sec/title/number}{kernel}
%    \end{macrocode}
%
% \section{Sectioning commands}
%
% \subsection{\cs{part} and \cs{chapter}}
%
% \cs{part} and \cs{chapter} are defined by the classes.
% To tag them we redefine the user commands.
% This will probably break with various classes and with titlesec.
% The tagging inside relies on the para tagging.
% We do not yet use keyval in the optional argument, as this requires latex-dev
% and the naming of the keys and their key family is unclear.
% \changes{v0.84f}{2024/10/04}{Added braces around optional arg (tagging/725)}
%    \begin{macrocode}
\AddToHook{class/after}
 {
  \@ifundefined{chapter}
    {
%    \end{macrocode}
% This redefines \cs{part} in article class.
%    \begin{macrocode}
     \@ifundefined{part}{}
      {
        \RenewDocumentCommand\part{ s O{#3} m }
         {
           \if@noskipsec \leavevmode \fi
           \par
           \addvspace{4ex}%
           \@afterindentfalse
%    \end{macrocode}
% This are the tagging commands needed at the begin. They open a Part structure
% and the structure for the title of the heading.
%    \begin{macrocode}
        % tagging start commands
          \UseTaggingSocket{sec/end}{-1}
          \UseTaggingSocket{sec/begin}{{-1}{tag=\UseStructureName{sec/-1}}}
          \UseTaggingSocket{sec/title/begin}{{-1}{#2}}
        % end tagging start commands
%    \end{macrocode}
% This adds a  manual target if the part is unnumbered or starred.
% It replaces the hyperref patches.
%    \begin{macrocode}
           \bool_lazy_any:nT
            {
              { #1 }
              {
                \int_compare_p:nNn {\c@secnumdepth}<{-1}
              }
            }
            {
              \MakeLinkTarget[part]{}
            }
%    \end{macrocode}
% The main call to the underlying commands.
%    \begin{macrocode}
          \IfBooleanTF
            {#1}
            { \@spart {#3} }
            { \@part [{#2}]{#3} }
%    \end{macrocode}
% and now the closing command for the tagging of the title.
%    \begin{macrocode}
         \UseTaggingSocket{sec/title/end}
         }
       }
    }
%    \end{macrocode}
% Redefinitions for book and report
%    \begin{macrocode}
    {
     \RenewDocumentCommand\chapter{ s O{#3} m }
      {
        \if@openright\cleardoublepage\else\clearpage\fi
        \thispagestyle{plain}%
        \global\@topnum\z@
        \@afterindentfalse
%    \end{macrocode}
% This are the tagging commands needed at the begin. They open a Sect structure
% and the structure for the title of the heading.
%    \begin{macrocode}
        \UseTaggingSocket{sec/end}{0}
        \UseTaggingSocket{sec/begin}{{0}{tag=\UseStructureName{sec/0}}}
        \UseTaggingSocket{sec/title/begin}{{0}{#2}}
%    \end{macrocode}
% This adds a  manual target if the chapter is unnumbered or starred.
% It replaces the hyperref patches.
%    \begin{macrocode}
        \bool_lazy_any:nT
          {
            { #1 }
            {
              \int_compare_p:nNn {\c@secnumdepth}<{0}
            }
            {
              %in book target also needed in frontmatter
              \bool_lazy_and_p:nn
                { \cs_if_exist_p:c { @mainmattertrue } }
                { ! \legacy_if_p:n { @mainmatter } }
            }
          }
          {
%    \end{macrocode}
% The relation target-struct is stored internally by the MakeLinkTarget commands
%    \begin{macrocode}
            \MakeLinkTarget[chapter]{}
          }
%    \end{macrocode}
% The main call to the underlying commands.
%    \begin{macrocode}
        \IfBooleanTF
          {#1}
          { \@schapter {#3} }
          { \@chapter [{#2}]{#3} }
%    \end{macrocode}
% and now the closing command for the tagging of the title.
%    \begin{macrocode}
        \UseTaggingSocket{sec/title/end}
      }
%    \end{macrocode}
% and similar for \cs{part}
%    \begin{macrocode}
     \RenewDocumentCommand\part{ s O{#3} m }
      {
        \if@openright
          \cleardoublepage
        \else
          \clearpage
        \fi
        \thispagestyle{plain}%
        \if@twocolumn
          \onecolumn
          \@tempswatrue
        \else
          \@tempswafalse
        \fi
        \null\vfil
%    \end{macrocode}
% These are the tagging commands needed at the begin. They open a Part structure
% and the structure for the title of the heading.
%    \begin{macrocode}
       \UseTaggingSocket{sec/end}{-1}
       \UseTaggingSocket{sec/begin}{{-1}{tag=\UseStructureName{sec/-1}}}
       \UseTaggingSocket{sec/title/begin}{{-1}{#2}}
%    \end{macrocode}
% This adds a  manual target if the part is unnumbered or starred.
% It replaces the hyperref patches.
%    \begin{macrocode}
        \bool_lazy_any:nT
          {
            { #1 }
            {
              \int_compare_p:nNn {\c@secnumdepth}<{-1}
            }
            {
              %in book target also needed in frontmatter
              \bool_lazy_and_p:nn
                { \cs_if_exist_p:c { @mainmattertrue } }
                { ! \legacy_if_p:n { @mainmatter } }
            }
          }
          {
            \MakeLinkTarget[part]{}
          }
%    \end{macrocode}
% The main call to the underlying commands.
%    \begin{macrocode}
        \IfBooleanTF
          {#1}
          { \@spart {#3} }
          { \@part [{#2}]{#3} }
%    \end{macrocode}
% and now the closing command for the tagging of the title.
%    \begin{macrocode}
        \UseTaggingSocket{sec/title/end}
      }
    }
 }
%    \end{macrocode}
%
% \subsection{Sectioning commands based on \cs{@startsection}}
%
% The tagging relies again on the para tagging:
% we simply exchange the tag name by the one given as \#1.
% This assumes that a tag with the name of the sectioning type is defined.
% We don't try to pass the title, this will be done together with
% the new keyval handling in the user command.
%
% \subsubsection{Hyperref code}
% hyperref has to insert anchors. If the sectioning is numbered this is done by
% \cs{refstepcounter} (and so in vmode). For unnumbered section hyperref
% injects the anchor in hmode before the text, it also inserts a
% kern to compensate the indent.
%
% This means that the target of numbered and unnumbered sectioning commands
% differ, both regarding the location and in relation to the
% tagging structure: The anchor from the \cs{refstepcounter} is outside of
% the structure created by the heading title if the para tags are used,
% while the other anchors are inside and so the structure destinations are different.
%
% We unify this by suppressing the anchor from the refstepcounter.
% Also we only go back if the indent is positive.
%
% At first suppress all hyperref patches related to sectioning:
%    \begin{macrocode}
\def\hyper@nopatch@sectioning{}
%    \end{macrocode}
%
% \begin{variable}{\l__kernel_sec_nonumber_bool}
% A boolean to keep track if a sectioning command should be numbered or not. 
%    \begin{macrocode}
\bool_new:N\l__kernel_sec_nonumber_bool
%    \end{macrocode}
% \end{variable}
% 
% \begin{macro}[no-user-doc]{\@hyp@section@target@nnn}
% A simple internal command. There is no need for something public,
% as packages defining their own version of \cs{@startsection} will
% probably need something slightly different based on \cs{MakeLinkTarget}.
% \changes{v0.84i}{2025/02/13}{Wrapped all use inside \cs{NoCaseChange},
% tagging-project issue \#787}
%    \begin{macrocode}
\cs_new_protected:Npn \@hyp@section@target@nnn #1 #2 #3 %#1 optarg #2 name/counter, #3 indent
  {
    \makebox[0pt][l]
     {
       \skip_set:Nn \@tempskipa {#3}
       \dim_compare:nNnF {\@tempskipa}<{0pt}{\kern-\@tempskipa}
       \MakeLinkTarget#1{#2}
     }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{macro}[no-user-doc]{\@@_makecurrentHref:n}
% In run-in heading we have to set the name of the anchor before it is actually
% created in a everypar. If hyperref is loaded we could use \cs{Hy@MakeCurrentHrefAuto}
% but without it we need a similar command.
%    \begin{macrocode}
\cs_new_protected:Npn \@kernel@makecurrentHref #1 %#1 prefix
  {
    \int_gincr:N\g__kernel_target_int
    \tl_gset:Ne \@currentHref {#1.\int_use:N\g__kernel_target_int}
  }
%    \end{macrocode}
% hyperref uses a different counter so we need to use a different command,
% TODO: merge that.
%
%    \begin{macrocode}
\AddToHook{package/hyperref/after}
 {
  \cs_set_eq:NN \@kernel@makecurrentHref \Hy@MakeCurrentHrefAuto
 }
%    \end{macrocode}
% \end{macro}

% \subsection{Adaption of the heading commands}
% We add to \cs{@startsection} the commands to open the \texttt{Sect}
% structure and to change the para tag.
%
% We save the current level so that unnumbered sections can use it too.
% \begin{macro}{\@currentseclevel}
%    \begin{macrocode}
\newcommand\@currentseclevel{-2}
%    \end{macrocode}
% \end{macro}
%    \begin{macrocode}
\def\@startsection#1#2#3#4#5#6{%
  \def\@currentseclevel{#2}
  \if@noskipsec \leavevmode \fi
  \par
  \@tempskipa #4\relax
  \@afterindenttrue
  \ifdim \@tempskipa <\z@
    \@tempskipa -\@tempskipa \@afterindentfalse
  \fi
  \if@nobreak
    \everypar{}%
  \else
    \addpenalty\@secpenalty\addvspace\@tempskipa
  \fi
  \UseTaggingSocket{sec/end}
      {#2}
  \UseTaggingSocket{sec/begin}
      {
        {#2}
        {tag=\cs_if_exist_use:cF{g_tag_role_#1_tl}{Sect}}
      }
%    \end{macrocode}
% \changes{0.84j}{2025-10-07}{Moved para-flattened setting}
% This tagging sockets changes the para-tagging: it is flattened and
% the tag is changed. This is actually used only by runin headings,
% but nevertheless this looks like the best place to use it as we can
% not make the changes inside some \cs{everypar} command.
%    \begin{macrocode}
  \UseTaggingSocket{sec/title/init}{#2}
  \@ifstar
    {\@ssect{#3}{#4}{#5}{#6}}%
    {\@dblarg{\@sect{#1}{#2}{#3}{#4}{#5}{#6}}}}
%    \end{macrocode}
%
% \cs{@sect} is only changed to replace the hyperref patches
% and to use the new \cs{@kernel@tag@hangfrom}.
%    \begin{macrocode}
%<@@=>
\def\@sect#1#2#3#4#5#6[#7]#8{%
% #1= name, #2= level, #3= indent #4 unused #5 after vspace #6 formatting #7=short title, #8=title
  \ifnum #2>\c@secnumdepth
    \bool_set_true:N\l__kernel_sec_nonumber_bool
    \@kernel@makecurrentHref {#1*}
    \def\@svsec{\NoCaseChange{\@hyp@section@target@nnn{*}{\@currentHref}{#3}}}
  \else
    \bool_set_false:N\l__kernel_sec_nonumber_bool
    \LinkTargetOff
    \refstepcounter{#1}%
    \tl_gset:Ne\@currentHref{#1.\use:c{theH#1}}
    \LinkTargetOn
    \protected@edef\@svsec{\NoCaseChange{\@hyp@section@target@nnn{}{#1}{#3}}\@seccntformat{#1}\relax}%
  \fi
  \@tempskipa #5\relax
  \ifdim \@tempskipa>\z@
    \begingroup
      #6{%
%    \end{macrocode}
% The formatting can contain a \cs{MakeUppercase} 
% so we must protect the name of the socket:
%    \begin{macrocode}
         \NoCaseChange
          {\UseTaggingSocket{sec/title/hang}
             {{#2}\l__kernel_sec_nonumber_bool{\hskip #3\relax\@svsec}{#7}}
             {\@hangfrom {\hskip #3\relax\@svsec}}}
          \interlinepenalty \@M #8\@@par}%
    \endgroup
    \csname #1mark\endcsname{#7}%
    \addcontentsline{toc}{#1}{%
      \ifnum #2>\c@secnumdepth \else
        \protect\numberline{\csname the#1\endcsname}%
      \fi
      #7}%
  \else
    \def\@svsechd{%
      #6{\hskip #3\relax
         \NoCaseChange{
           \UseTaggingSocket{sec/title/runin/number}{{#2}\l__kernel_sec_nonumber_bool}{\@svsec}}
        #8}%
      \csname #1mark\endcsname{#7}%
      \addcontentsline{toc}{#1}{%
        \ifnum #2>\c@secnumdepth \else
          \protect\numberline{\csname the#1\endcsname}%
        \fi
        #7}}%
  \fi
  \@xsect{#5}}
%    \end{macrocode}
% similar for \cs{@ssect}
%    \begin{macrocode}
\def\@ssect#1#2#3#4#5{%
  \@tempskipa #3\relax
  \ifdim \@tempskipa>\z@
    \begingroup
      #4{
         \NoCaseChange
          {
            \UseTaggingSocket{sec/title/hang}
             {
               {\@currentseclevel}
               \c_true_bool
               {\hskip #1\relax\NoCaseChange{\@hyp@section@target@nnn{[section]}{}{#1}}}
               {#5}
             }
             {\@hangfrom{\hskip #1\relax\NoCaseChange{\@hyp@section@target@nnn{[section]}{}{#1}}}}
          }
         \interlinepenalty \@M #5\@@par}%
    \endgroup
  \else
    \@kernel@makecurrentHref{section*}
    \def\@svsechd{#4{\hskip #1\relax\NoCaseChange{\@hyp@section@target@nnn{*}{\@currentHref}{#3}}\relax #5}}%
  \fi
  \@xsect{#3}}
%    \end{macrocode}
% At last \cs{@xsect} needs code in two places. For display headings it has to
% restore the default para code, for run in headings it has to separated the
% heading from the following text.
%    \begin{macrocode}
\def\@xsect#1{%
  \@tempskipa #1\relax
  \ifdim \@tempskipa>\z@
    \par \nobreak
    \vskip \@tempskipa
    \UseTaggingSocket {para/restore}
    \@afterheading
  \else
    \@nobreakfalse
    \global\@noskipsectrue
    \everypar{%
      \if@noskipsec
        \global\@noskipsecfalse
       {\setbox\z@\lastbox}%
        \clubpenalty\@M
        \begingroup \@svsechd \endgroup
        \unskip
        \UseTaggingSocket{sec/title/split}
        \@tempskipa #1\relax
        \hskip -\@tempskipa
      \else
        \clubpenalty \@clubpenalty
        \everypar{}%
      \fi}%
  \fi
  \ignorespaces}
%    \end{macrocode}
%
% \subsection{Keys for \cs{tagpdfsetup}}
% We need to provide user and package level commands
% \changes{0.84k}{2025/04/09}{Add braces around key values, tagging issue \#830}
% \changes{0.84j}{2025-10-11}{add \cs{tagpdfsetup} keys for two user facing keys}
%
%    \begin{macrocode}
\keys_define:nn{__tag / setup}
 {
   ,sec/end .code:n =
      {
        \par
        \UseTaggingSocket{sec/end}{\int_eval:n{\cs_if_exist_use:c{toclevel@#1}+0}}
      }
   ,sec/end .value_required:n = true
   ,sec/grouping .choice:,
   ,sec/grouping / true .code:n =
     {
       \AssignTaggingSocketPlug{sec/begin}{kernel}
       \AssignTaggingSocketPlug{sec/end}{kernel}
     }
   ,sec/grouping / false .code:n =
     {
       \AssignTaggingSocketPlug{sec/begin}{noop}
       \AssignTaggingSocketPlug{sec/end}{noop}
     }
   ,sec/grouping .default:n = true
 }
%    \end{macrocode}
%
% \subsubsection{Tagging tools (deprecated)}
% \cs{tag_tool:n} is deprecated.
%    \begin{macrocode}
\cs_if_free:NT \tag_tool:n
 {
   \cs_new_protected:Npn \tag_tool:n #1
    {
      \tag_if_active:T { \keys_set:nn {tag / tool}{#1} }
    }
   \cs_set_eq:NN\tagtool\tag_tool:n
 }
\keys_define:nn { tag / tool}
  {
    ,sec-start-part .code:n =
      {
        \UseTaggingSocket{sec/end}{-1}
        \UseTaggingSocket{sec/begin}{{-1}{tag=\UseStructureName{sec/-1}}}
        \UseTaggingSocket{sec/title/begin}{{-1}{#1}}
%    \end{macrocode}
% We remap here the text-unit from the paragraph to NonStruct.
% It would be better to suppress it completely as with the other
% sectioning commands, but this would require to redefine \cs{@spart}
% and \cs{@part}, as there is the grouping, and these commands are
% all slightly different in the standard classes. So this is delayed
% to the time when sectioning commands are redefined with templates.
%    \begin{macrocode}
      }
    ,sec-stop-part .code:n = {\UseTaggingSocket{sec/title/end}}
    ,sec-start-chapter .code:n =
     {
        \UseTaggingSocket{sec/end}{0}
        \UseTaggingSocket{sec/begin}{{0}{tag=\UseStructureName{sec/0}}}
        \UseTaggingSocket{sec/title/begin}{{0}{#1}}
     }
    ,sec-stop-chapter .meta:n = { sec-stop-part}
    ,sec-start .code:n = % #1 is a name like "section"
      {
        \UseTaggingSocket{sec/end}  {\int_eval:n{\cs_if_exist_use:c{toclevel@#1}+0}}
        \UseTaggingSocket{sec/begin}
          {
            {\int_eval:n{\cs_if_exist_use:c{toclevel@#1}+0}}
            {tag=\cs_if_exist_use:cF{g_tag_role_#1_tl}{Sect}}
          }
        \tl_set:Nn\l_@@_para_tag_tl{#1}
      }
    ,sec-start .value_required:n = true
    ,sec-split-para .code:n = {\UseTaggingsocket{sec/title/split}}
    ,restore-para .code:n = {\UseTaggingSocket{para/restore}}%
    ,sec-stop .code:n =
      {
        \par
        \UseTaggingSocket{sec/end}{\int_eval:n{\cs_if_exist_use:c{toclevel@#1}+0}}
      }
    ,sec-stop .value_required:n = true
    ,sec-add-grouping .choice:,
    ,sec-add-grouping / true .code:n =
     {
       \AssignTaggingSocketPlug{sec/begin}{kernel}
       \AssignTaggingSocketPlug{sec/end}{kernel}
     }
    ,sec-add-grouping / false .code:n =
     {
       \AssignTaggingSocketPlug{sec/begin}{noop}
       \AssignTaggingSocketPlug{sec/end}{noop}
     }
    ,sec-add-grouping .default:n = true
  }
%</package>
%    \end{macrocode}

%    \begin{macrocode}
%<*latex-lab>
\ProvidesFile{sec-latex-lab-testphase.ltx}
        [\ltlabsecdate\space v\ltlabsecversion\space latex-lab wrapper sec]
\RequirePackage{latex-lab-testphase-sec}
%</latex-lab>
%    \end{macrocode}