<html><head><meta name="color-scheme" content="light dark"></head><body><pre style="word-wrap: break-word; white-space: pre-wrap;">% \iffalse meta-comment
%
%% File: latex-lab-block.dtx (C) Copyright 2021-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
%
\def\ltlabblockdate{2025-01-20}
\def\ltlabblockversion{0.9a}

%&lt;*driver&gt;
\documentclass[kernel]{l3doc}
\usepackage{amstext}
\EnableCrossrefs
\CodelineIndex

\setcounter{secnumdepth}{4}
\setcounter{tocdepth}{4}

\usepackage{todonotes}

\begin{document}
  \DocInput{latex-lab-block.dtx}
\end{document}
%&lt;/driver&gt;
%
% \fi
%
% \providecommand\hook[1]{\texttt{#1\DescribeHook[noprint]{#1}}}
% \providecommand\socket[1]{\texttt{#1\DescribeSocket[noprint]{#1}}}
% \providecommand\plug[1]{\texttt{#1\DescribePlug[noprint]{#1}}}
%
% \NewDocElement[printtype=\textit{socket},idxtype=socket,idxgroup=Sockets]{Socket}{socketdecl}
% \NewDocElement[printtype=\textit{hook},idxtype=hook,idxgroup=Hooks]{Hook}{hookdecl}
% \NewDocElement[printtype=\textit{plug},idxtype=plug,idxgroup=Plugs]{Plug}{plugdecl}
%
%
% \title{Prototype reimplementation of \LaTeXe{}'s block environments using templates}
% \author{\LaTeX{} Project\thanks{Initial reimplementation of lists done by Bruno
%    Le Floch, generalized second version with tagging support by Frank Mittelbach.}}
% \date{v\ltlabblockversion\ \ltlabblockdate}
%
% \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}}
% \providecommand\struct[1]{\texttt{&lt;#1&gt;}}
%
% \NewDocElement[envlike, idxtype=objecttype, idxgroup=object types,
%    printtype=\textit{objecttype}] {ObjectType}{objecttype}
%
% \NewDocElement[envlike, idxtype=template, idxgroup=templates,
%    printtype=\textit{templ.}] {Template}{template}
%
% \NewDocElement[envlike, idxtype=instance, idxgroup=instances,
%    printtype=\textit{inst.}] {Instance}{instance}
%
% 
% \newcommand\key[1]{\texttt{#1}}
% \newcommand\keyvalue[1]{\texttt{#1}}
% \newcommand\valuefrom[1]{\textrm{value from }\key{#1}}
% 
% 
% \NewDocumentCommand\fmi{sO{}m}
%   {\IfBooleanTF{#1}{\todo[inline,#2]{#3}}^^A
%                    {\todo[#2]{#3}}}
%                    
% \NewDocumentCommand\ufi{sO{}m}
%   {\IfBooleanTF{#1}{\todo[inline,#2]{UFi:#3}}^^A
%                    {\todo[#2]{UFi:#3}}}
% \makeatletter
% \renewenvironment{TemplateInterfaceDescription}[1]
%   {
%     \subsubsection{The~object~type~`#1'}
%     \begingroup
%     \@beginparpenalty\@M
%     \description
%     \def\TemplateArgument##1##2{\item[Arg:~##1]##2\par}
%     \def\TemplateSemantics
%       {
%         \enddescription\endgroup
%         \subsubsection*{Semantics:}
%       }
%   }
%   {
%     \par\bigskip
%   }
% \renewenvironment{TemplateDescription}[2]
%   {\subsubsection{The \texttt{#1} template `#2'}^^A
%     \paragraph*{Attributes:}^^A
%     \begingroup
%     \@beginparpenalty\@M
%     \description
%     \def\TemplateKey##1##2##3##4{^^A
%         \item[\texttt{##1}~(\textit{\mdseries##2})]##3^^A
%         \ifx\TemplateKey##4\TemplateKey\else
%           \hfill\penalty500\hbox{}\hfill Default:~\keyvalue{##4}^^A
%           \nobreak\hskip-\parfillskip\hskip0pt\relax
%         \fi
%         \par
%       }^^A
%     \def\TemplateSemantics{^^A
%         \enddescription\endgroup
%         \paragraph*{Semantics~\&amp;~Comments:}^^A
%       }^^A
%   }
%   { \par \bigskip }
% \makeatother
%
% 
% \begin{abstract}
% \end{abstract}
%
%
% \tableofcontents
% \medskip
%
%
% \begin{documentation}
%
%
%
% \section{Introduction}
%
% The list implementation in \LaTeXe{} serves a dual purpose: it
% implements real lists such as \env{itemize} or \env{enumerate},
% but it is also used as the basis for vertical blocks, i.e., to specify
% the vertical spacing and paragraph handling after such block, e.g.,
% in environments like \env{center}, \env{quote}, \env{verbatim}, or in
% the theorem environments. They are all implemented as
% \enquote{trivial} lists with a single (hidden) item.
%
% While this was convenient to get a consistent layout using a single
% implementation it is not adequate if it comes to interpreting the
% structure of a document, because environments based on \env{trivlist}
% should not advertise themselves as being a \enquote{list} --- after all,
% from a semantic point of view they aren't lists.
%
% The approach taking here is therefore to offer separate object
% types: \xt{block} (horizontally or vertically oriented data that
% needs some handling at the start and the end), \xt{para} (that deals
% with different paragraph layouts), \xt{list} (that handles list
% related parameters, and \xt{item} (for item layouts and handling), to address
% the independent aspects and also offer the object type \xt{blockenv}
% that ties them together as necessary.
%
% For example, a \env{quote} environment would make use of a (display)
% \xt{block} and some \xt{para} handling while an standard
% \env{enumerate} would make use of a display \xt{block}, a \xt{list},
% and  an \xt{item} and \xt{para} instance.
% An inline list (like \env{enumerate*} from the \pkg{enumitem}
% package) would be using the same \xt{list} instance but a different
% (horizontally oriented) \xt{block}.
%
% 
% \section{Object types and templates for blocks and lists}
%
% \subsection{Object types}
% 
% \begin{TemplateInterfaceDescription}{block}
%    \TemplateArgument{1}{key/value list to alter the default block parameters}
%    \TemplateSemantics
%    Handle the layout aspects of a block of data. In case of a
%    \enquote{display} block (i.e., vertically oriented) the spacing
%    and page breaking as well as the handling if the block starts a
%    paragraph or ends one, that is, if text is immediately following
%    the block without being separated by an empty line, then this
%    text is considered to be in the same paragraph as the block.
%
%    In case of a horizontally oriented block it covers any special
%    handling at the start and end of the block, e.g, extra spacing,
%    prohibitying or encuraging line breaks, and so forth.
% \end{TemplateInterfaceDescription}
% 
% \begin{TemplateInterfaceDescription}{para}
%    \TemplateArgument{1}{key/value list to alter the default item parameters}
%    \TemplateSemantics
%    Sets up paragraph-specific parameters for H\&amp;J, e.g., to
%    implement justification variations, the behavior of \verb=\\=
%    etc. The instances are used in higher-level templates, e.g., in a
%    \xt{block}.
% \end{TemplateInterfaceDescription}
% 
% \begin{TemplateInterfaceDescription}{list}
%    \TemplateArgument{1}{key/value list to alter the default item parameters}
%    \TemplateSemantics
%    Handle the aspects related to list design, e.g., the use and
%    formatting of counters, etc.
%
%    Note that this does not cover block-related aspects, i.e., a list
%    instance could be used both for a display list or for an inline line.
% \end{TemplateInterfaceDescription}
% 
% \begin{TemplateInterfaceDescription}{item}
%    \TemplateArgument{1}{key/value list to alter the default item parameters}
%    \TemplateSemantics
%    A sub-type used as part of \xt{list} to easily cover alternative layout
%    for list items.
% \end{TemplateInterfaceDescription}
%
%
% \begin{TemplateInterfaceDescription}{blockenv}
%    \TemplateArgument{1}{key/value list to alter the default item parameters}
%    \TemplateSemantics
%    This object type is used to implement document-level
%    environments. It defines a \xt{block} instance to handle the
%    layout at the \enquote{edge} of the environment data, possibly
%    some paragraph setup through a \xt{para} instance, potentially an
%    \enquote{inner} instance for more complicated environments (such
%    as lists), and possibly some additional setup code for certain
%    environments.
%
%    It also defines how the \xt{blockenv} behaves with respect to
%    nesting, e.g., does it change when nested and if so how many
%    levels of nesting are supported, etc.
%
%    Finally, the object type defines how it appears in a tagged PDF
%    document, what tag names are used, how they are rolemapped and
%    whether it adds additional attributes, etc. 
% \end{TemplateInterfaceDescription}
%
%
%
% \subsection{Templates}
% 
% 
% \begin{TemplateDescription}{blockenv}{display}
%
%  \TemplateKey{env-name}{tokenlist}
%              {Name of the environment used in tracing and error messages}{}
%  \TemplateKey{tag-name}{tokenlist}
%              {Name of the tag in the PDF. If not explicitly given
%               the name is defined by the \key{tagging-recipe}}{}
%  \TemplateKey{tag-class}{tokenlist}
%              {An explicit tag class attribute}{}
%  \TemplateKey{tagging-recipe}{tokenlist}
%              {Defines the way tagging is done. Currently the values
%               \keyvalue{basic}, \keyvalue{standard}, and \keyvalue{list}
%               are supported}{standard}
%  \TemplateKey{level-increase}{boolean}{Does this \xt{blockenv}
%               increase the block level if it is nested in an outer block?}{true}
%  \TemplateKey{setup-code}{tokenlist}
%              {Initial setup code. This is
%               executed after legacy defaults (from \tn{@listi},
%               \tn{@listii}, etc.) are used but before the block instance is called}{}
%  \TemplateKey{block-instance}{tokenlist}{Part of the name of the
%               \xt{block} instance that is called. The full name has
%               a \texttt{-}\meta{level} appended}{displayblock}
%  \TemplateKey{para-instance}{tokenlist}{}{}
%  \TemplateKey{inner-level-counter}{tokenlist}{Name of an existing (!) counter
%               that is incremented and used to determine final name
%               of the \key{inner-instance} or empty if always the
%               same inner instance should be used}{}
%  \TemplateKey{max-inner-levels}{tokenlist}{Maximum number of nested
%               environments of this kind. Only relevant if there is a
%               \key{inner-level-counter} specified}{4}
%  \TemplateKey{inner-instance-type}{tokenlist}{Object type of the
%    inner instance}{list}
%  \TemplateKey{inner-instance}{tokenlist}{Name of the inner instance
%               (if any).}{}
%  \TemplateKey{para-flattened}{boolean}{\emph{describe}}{false}
%  \TemplateKey{final-code}{tokenlist}{Final setup code}{\tn{ignorespaces}}
%
%    \TemplateSemantics
%
%    This \xt{blockenv} template supports the legacy list setting that
%    are found in many document classes in the macros \tn{@listi},
%    \tn{@listii}, up to \tn{@listvi}. It also uses the counter
%    \tn{@listdepth} to track nesting of block, again mainly to
%    support legacy setups (internally it gives it a more appropriate
%    name but it remains accessible through the \LaTeXe{} name).
%
%
%    It first checks that nothing is too deeply nested.
%    If the level should increase then the increments the
%    \tn{@listdepth} counter and
%    calls the corresponding \tn{@list...} macro to update the legacy
%    defaults. If \key{level-increase} is set to false this is bypassed.
%
%    It then sets up the
%    tagging via the \key{tagging-recipe} setting and executes any
%    code in \key{setup-code}.
%
%    Afterwards it calls the appropriate \xt{block} instance based on
%    \key{block-instance} and current level, e.g.,
%    \texttt{displayblock-1}.  Then it sets up paragraph parameters if
%    a \key{para-instance} was specified (otherwise they stay as
%    they are).
%
%    If a \key{inner-instance} was specified this is called next,
%    or more precisely: if no \key{inner-level-counter} was
%    specified the instance \key{inner-instance} is
%    called.
%
%    Otherwise, the \key{inner-level-counter} is incremented and the
%    instance with the name
%    \key{inner-instance}\texttt{-}\key{inner-level-counter} is
%    called.
%
%    Finally, the \key{final-code} is executed (by default
%    \tn{ignorespaces}).
%
%
% \end{TemplateDescription}
%
% The maximum number of \xt{blockenv}s that can be nested into each
% other is restricted by the \LaTeX{} counter
% \texttt{maxblocklevels} with a default value of \keyvalue{6}. If this
% value is increased then it is necessary to provide additional
% instances, e.g., \texttt{displayblock-7}, etc. Decreasing is, of
% course, always possible, then some of the instances defined are not
% used and instead the user gets an error that there is too much
% nesting going on.
%
% If the key \key{level-increase} is set to \keyvalue{false} then such
% an environment doesn't alter the nesting level and therefore you can
% nest those environments as often as you like (a typical example
% would be \env{flushleft} anywhere in the nesting hierarchy, that
% would have no effect on hitting the boundary).
%  
% 
% \begin{TemplateDescription}{block}{display}
%
%  \TemplateKey{heading}{tokenlist}{\emph{not really used yet}}{}
%  \TemplateKey{beginsep}{skip}{}{\tn{topsep}}
%  \TemplateKey{begin-par-skip}{skip}{}{\tn{partopsep}}
%  \TemplateKey{par-skip}{skip}{}{\tn{parsep}}
%  \TemplateKey{end-skip}{skip}{}{\valuefrom{beginsep}}
%  \TemplateKey{end-par-skip}{skip}{}{\valuefrom{begin-par-skip}}
%  \TemplateKey{item-skip}{skip}{The space in front of an item if the
%    block is a list; if not the setting has no effect}{\tn{itemsep}}
%  \TemplateKey{beginpenalty}{integer}{}{\tn{@beginparpenalty}}
%  \TemplateKey{endpenalty}{integer}{}{\tn{@endparpenalty}}
%  \TemplateKey{leftmargin}{length}{}{\tn{leftmargin}}
%  \TemplateKey{rightmargin}{length}{}{\tn{rightmargin}}
%  \TemplateKey{parindent}{length}{}{0pt}
%
%    \TemplateSemantics
%
%    The idea of a \key{heading} key needs some further
%    thoughts. Maybe instead the object type should accept a second
%    argument and receive input for such a heading from the document
%    level instead.
%
%    The names of the keys need further thoughts and some
%    decision. Right now it is a mixture of those with hyphens and
%    those that match legacy register names (the way \pkg{enumitem}
%    did its keys).
%
%    Also \key{parindent} conflicts with \key{indent-width}!
% 
% \end{TemplateDescription}
%
%  
% \begin{TemplateDescription}{para}{std}
%
%  \TemplateKey{indent-width}{length}{}{\tn{parindent}}
%  \TemplateKey{start-skip}{skip}{}{0pt}
%  \TemplateKey{left-skip}{skip}{}{0pt}
%  \TemplateKey{right-skip}{skip}{}{0pt}
%  \TemplateKey{end-skip}{skip}{}{\tn{@flushglue}}
%  \TemplateKey{fixed-word-spaces}{boolean}{}{false}
%  \TemplateKey{final-hyphen-demerits}{integer}{}{5000}
%  \TemplateKey{cr-cmd}{tokenlist}{}{\tn{@normalcr}}
%  \TemplateKey{para-class}{tokenlist}{}{justify}
%
%    \TemplateSemantics
% 
% 
% \end{TemplateDescription}
%
%  
% 
% \begin{TemplateDescription}{list}{std}
%
%  \TemplateKey{counter}{tokenlist}
%              {Counter name to be used in a numbered list or empty,
%               if the list is unnumbered}{}
%  \TemplateKey{item-label}{tokenlist}
%              {Label \enquote{string} for a fixed label or as
%               generated from the current \key{counter} value}{}
%  \TemplateKey{start}{integer}
%              {Start value for the counter if the list is numbered,
%               otherwise irrelevant}{1}
%  \TemplateKey{resume}{boolean}
%              {Should a numbered list be resumed from the last instance?}{false}
%  \TemplateKey{item-instance}{instance}
%              {Instance of type \texttt{item} to be used to format
%               the label string}{basic}
%  \TemplateKey{item-skip}{skip}{The space in front of an item in the
%               list. If not specified the value specified in the block template instance is used}{}
%  \TemplateKey{item-indent}{length}{Horizontal displacement of the item.}{0pt}
%  \TemplateKey{item-penalty}{integer}
%              {Penalty for breaking before an
%               item (except the first)}{\tn{@itempenalty}}
%  \TemplateKey{label-width}{length}
%              {Width reserved for the formatted item label}{\tn{labelwidth}}
%  \TemplateKey{label-sep}{length}
%              {Horizontal separation between label and following text}{\tn{labelsep}}
%  \TemplateKey{legacy-support}{boolean}
%              {Is formatting the label via \tn{makelabel} supported?}{false}
%
%    \TemplateSemantics
% 
% 
% \end{TemplateDescription}
%
%  
% \begin{TemplateDescription}{item}{std}
%
%  \TemplateKey{counter-label}{function{1}}{\emph{unused}}{\tn{arabic}\{\#1\}}
%  \TemplateKey{counter-ref}{function{1}}{\emph{unused}}{\valuefrom{counter-label}}
%  \TemplateKey{label-ref}{function{1}}{\emph{unused}}{\#1}
%  \TemplateKey{label-autoref}{function{1}}{\emph{unused}}{item~\#1}
%  \TemplateKey{label-format}{function{1}}
%       {Formatting of the label, questionable the way it is used}{\#1}
%  \TemplateKey{label-strut}{boolean}{Add a \tn{strut} to the label?}{false}
%  \TemplateKey{label-align}{choice}
%              {Supported values \keyvalue{left},\keyvalue{center},
%               \keyvalue{right}, and \keyvalue{parleft}. \emph{Only partly implemented}}{right}
%  \TemplateKey{label-boxed}{boolean}
%              {Should the label be boxed?}{true}
%  \TemplateKey{next-line}{boolean}{}{false}
%  \TemplateKey{text-font}{tokenlist}{\emph{unused}}{}
%  \TemplateKey{compatibility}{boolean}{}{true}
%
%    \TemplateSemantics
%
%    This template is only rudimentary implemented at the moment. It
%    probably needs other keys and the existing ones need a proper
%    implementation.
% 
% \end{TemplateDescription}
%
%
% \section{Tagging support}
%
% \subsection{Paragraph tags}
%
%  Paragraphs in \LaTeX{} can be nested, e.g., you can have a paragraph
%  containing a display quote, which in turn consists of more than one
%  (sub)paragraph, followed by some more text which all belongs to the
%  same outer paragraph.
%
%  In the PDF model and in the HTML model that is not supported --- a
%  limitation that conflicts with real live, given that such
%  constructs are quite normal in spoken and written language.
%
%  The approach we take to resolve this is to model such \enquote{big}
%  paragraphs with a structure named \struct{text-unit} and use \struct{text} (rollmapped to \struct{P})
%  only for (portions of) the actual paragraph text in a way that the
%  \struct{text}s are not nested. As a result we have for a simple
%  paragraph the structures
% \begin{tabbing}
% \hspace*{1em}\=\hspace*{1em}\=\hspace*{1em}\=\hspace*{1em}\= \kill
%    \&gt;    \struct{text-unit}\\
%    \&gt;\&gt;  \struct{text}\\
%    \&gt;\&gt;\&gt; The paragraph text \ldots\\
%    \&gt;\&gt;  \struct{/text}\\
%    \&gt;    \struct{/text-unit}
% \end{tabbing}
% The \struct{text-unit} structure is rollmapped to \struct{Part} or possibly to
% \struct{Div} so we get a valid PDF, but processors who care can identify
% the complete paragraphs by looking for \struct{text-unit} tags.
%
% In the case of an element, such as a display quote or a display list
%  inside the paragraph, we then have
% \begin{tabbing}
% \hspace*{1em}\=\hspace*{1em}\=\hspace*{1em}\=\hspace*{1em}\= \kill
%    \&gt;     \struct{text-unit}\\
%    \&gt;\&gt;   \struct{text}\\
%    \&gt;\&gt;\&gt; The paragraph text before the display element \ldots\\
%    \&gt;\&gt;   \struct{/text}\\
%    \&gt;\&gt;   \struct{display element structure}\\
%    \&gt;\&gt;\&gt;  Content of the display structure possibly involving inner \struct{text-unit} tags\\
%    \&gt;\&gt;   \struct{/display element structure}\\
%    \&gt;\&gt;   \struct{text}\\
%    \&gt;\&gt;\&gt; \ldots{} continuing the outer paragraph text\\
%    \&gt;\&gt;   \struct{/text}\\
%    \&gt;     \struct{/text-unit}
% \end{tabbing}
% In other words such a display block is always embedded in a
% \struct{text-unit} structure, possibly preceded by a \struct{text}\ldots\struct{/text} block
% and possibly followed by one, though both such blocks are optional.
%
% Thus an \env{itemize} environment that has some introductory text
% but no text immediately following the list
% would be tagged as follows:
% \begin{tabbing}
% \hspace*{1em}\=\hspace*{1em}\=\hspace*{1em}\=\hspace*{1em}\=\hspace*{1em}\= \kill
%    \&gt;          \struct{text-unit}\\
%    \&gt;\&gt;        \struct{text}\\
%    \&gt;\&gt;\&gt;      The intro text for the \env{itemize} environment \ldots\\
%    \&gt;\&gt;        \struct{/text}\\
%    \&gt;\&gt;        \struct{itemize}\\
%    \&gt;\&gt;\&gt;      \struct{LI}\\
%    \&gt;\&gt;\&gt;\&gt;    \struct{Lbl} label \struct{/Lbl}\\
%    \&gt;\&gt;\&gt;\&gt;    \struct{LBody}\\
%    \&gt;\&gt;\&gt;\&gt;\&gt;  The text of the first item involving \struct{text-unit} as necessary \ldots\\
%    \&gt;\&gt;\&gt;\&gt;    \struct{/LBody}\\
%    \&gt;\&gt;\&gt;      \struct{/LI}\\
%    \&gt;\&gt;\&gt;      \struct{LI}\\
%    \&gt;\&gt;\&gt;\&gt;    The second item \ldots{}\\
%    \&gt;\&gt;\&gt;      \struct{/LI}\\
%    \&gt;\&gt;\&gt;      \ldots{} further items \ldots\\
%    \&gt;\&gt;        \struct{/itemize}\\
%    \&gt;          \struct{/text-unit}
% \end{tabbing}
% The \struct{itemize} is rollmapped to \struct{L}.
%
% For some display blocks, such as centered text, we use a simpler
% strategy. Such blocks still ensure that they are inside a \struct{text-unit}
% structure but their body  uses simple \struct{text} blocks and not
% \struct{text-unit}\struct{text} inside, e.g., the input
% \begin{verbatim}
% This is a paragraph with some
% \begin{center}
%    centered lines
%
%    with a paragraph break between them
% \end{center}
% followed by some more text.
% \end{verbatim}
%  will be tagged as follows:
% \begin{tabbing}
% \hspace*{1em}\=\hspace*{1em}\=\hspace*{1em}\=\hspace*{1em}\=\hspace*{1em}\= \kill
%    \&gt;          \struct{text-unit}\\
%    \&gt;\&gt;        \struct{text}\\
%    \&gt;\&gt;\&gt;      This is a paragraph with some\\
%    \&gt;\&gt;        \struct{/text}\\
%    \&gt;\&gt;        \struct{text /O /Layout /TextAlign/Center}\\
%    \&gt;\&gt;\&gt;      centered lines\\
%    \&gt;\&gt;        \struct{/text}\\
%    \&gt;\&gt;        \struct{text /O /Layout /TextAlign/Center}\\
%    \&gt;\&gt;\&gt;      with a paragraph break between them\\
%    \&gt;\&gt;        \struct{/text}\\
%    \&gt;\&gt;        \struct{text}\\
%    \&gt;\&gt;\&gt;      followed by some more text.\\
%    \&gt;          \struct{/text-unit}
% \end{tabbing}
% 
%
% \subsection{Tagging recipes}
%
% There are a number of different tagging recipes that implement
% different tagging approaches. They are selected through the
% \key{tagging-recipe} of the \xt{blockenv} template. Currently the
% following values are implemented:
% \begin{description}
% \raggedright
% \item[\keyvalue{standalone}]
%   This recipe does the following:
%   \begin{itemize}
%   \item
%     Ensure that the \xt{blockenv} is not inside a \struct{text-unit}
%     structure. If necessary, close the open one (and any open
%     \struct{text} structure). 
%
%   \item
%     Text inside the body of the environment start with
%     \struct{text-unit}\struct{text} unless the key
%     \key{para-flattened} is set to \keyvalue{true} 
%     (which is most likely the wrong thing to do because we then get just
%     \struct{text} as the structure).
%
%   \item
%     At the end of the environment close \struct{/text} and possibly an
%     inner \struct{/text-unit} if open.
%
%   \item
%    Finally, ensure that after the environment a new
%     \struct{text-unit} is started, if appropriate, e.g., if text is following.
%   \end{itemize}
%
% \item[\keyvalue{basic}]
%   This recipe does the following:
%   \begin{itemize}
%   \item
%     Ensure that the \xt{blockenv} is inside a \struct{text-unit}
%     structure, if necessary, start one. 
%   \item
%     If inside a \struct{text-unit}\struct{text}, then close the \struct{/text} but
%     leave the \struct{text-unit} open.
%
%   \item
%     Text inside the body of the environment start with
%     \struct{text-unit}\struct{text} if \key{para-flattened} is set to \keyvalue{false},
%     otherwise just with \struct{text}.
%
%   \item
%     At the end of the environment close \struct{/text} and possibly an
%     inner \struct{/text-unit} if open.
%
%   \item
%     Then look if the environment is followed by an empty line
%     (\tn{par}). If so, close the outer \struct{/text-unit} and start any
%     following text with \struct{text-unit}\struct{text}. Otherwise,
%     don't and following text restarts with a just a \struct{text} (and no
%     paragraph indentation)
%   \end{itemize}
%
% \item[\keyvalue{standard}]
%  This recipe is like the \keyvalue{basic} one as far as handling
%  \struct{text-unit} and \struct{text} is concerned. In addition
%   \begin{itemize}
%   \item
%     it starts an inner tagging structure (i.e., which is therefore a
%     child of the outer \struct{text-unit}).
%   \item
%     By default this structure is a \struct{Figure} unless overwritten
%     by the key \key{tag-name}. If that key is used, a suitable
%     rollmap needs to be provided for the name given.
%   \item
%     At the end of the environment that inner structure is closed
%     again so that we are back on the \struct{text-unit} level from the outside.
%   \item
%     Then the lookahead for an empty line is done as described previously.
%   \end{itemize}
%
%
%
% \item[\keyvalue{list}]
%  This recipe is like the \keyvalue{standard} one except that
%   \begin{itemize}
%   \item
%     the inner structure is a list (\struct{L}).
%   \item
%     Furthermore everything is set up so that we have list items
%     (\struct{LI}) with suitable substructures (\struct{Lbl} for the item
%     labels and \struct{LBody} for the item bodies).
%   \item
%     If the key \key{tag-name} is specified, this is used as the tag
%     name for the whole list instead of \struct{L}. Of course, it
%     should then have a suitable rollmap.
%   \item
%     If the key \key{tag-class} is specified then this is used as the
%     class attribute. Again, this requires a suitable setup on the outside.
%   \item
%     At the end of the environment the \struct{/LBody}, \struct{/LI}, and
%     \struct{/L} (or the tag name used) are closed.
%   \item
%     Then the lookahead for an empty line is done as described previously.
%   \end{itemize}
%
%
% \end{description}
%
% \section{Debugging}
% 
% \begin{function}{\DebugBlocksOn,\DebugBlocksOff, \block_debug_on:, \block_debug_off:}
% 
% These commands enable/disable debugging messages.
% 
% \end{function}
%
% \section{New and redefined kernel command}
% 
% \begin{function}{\@doendpe}
%   The original \LaTeXe{} command is augmented to allow for tagging.
% \end{function}
%
% \begin{function}{\legacyverbatimsetup,\legacylistsetupcode}
% \emph{to be documented}
% \end{function}
% 
% \begin{function}{\@setupverbinvisiblespace}
% A counterpart definition to the kernel command \tn{@setupverbinvisiblespace},
% needed as we need to handle real space chars in verbatim.
% \end{function}
%
% \begin{function}{endblockenv,\g_block_nesting_depth_int}
% \emph{to be documented}
% \end{function}
% 
% \begin{function}{\newtheorem,\@thm,\@begintheorem}
% Redefined to make theorems tagging aware.
% \end{function}
%
% \begin{function}{\item,\@itemlabel}
% The \tn{item} is redefined.
% \end{function}
%
% \begin{function}{\c@maxblocklevels}
%    A counter to increase or decrease the number of supported
%    level. If increased, one needs to supply additional level instances.
% \end{function}
% 
% \begin{function}{\begin}
% The \tn{begin} is slightly redefine to handle \tn{@doendpe} better.
% TODO: move to kernel
% \end{function}
%
% \begin{function}{\para_end:}
% TODO: consider name, document 
% \end{function}
% 
% \begin{function}{para/begin}
% The para/begin hook is enhanced to support list ends
% \end{function} 
%   
% \end{documentation}
%
% \StopEventually{\setlength\IndexMin{200pt}  \PrintIndex  }
%
%
%
% \begin{implementation}
%
% \section{The Implementation}
%
%
%    \begin{macrocode}
%&lt;*package&gt;
%&lt;@@=block&gt;
%    \end{macrocode}
%
%
%    \begin{macrocode}
\ProvidesPackage {latex-lab-testphase-block}
                 [\ltlabblockdate\space v\ltlabblockversion\space
                            blockenv implementation]
%    \end{macrocode}
%
%   General kernel changes, also loaded by the sec and toc code.
%    \begin{macrocode}
\RequirePackage{latex-lab-kernel-changes}
%    \end{macrocode}
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
%
% \subsection{Handling \tn{par} after the end of the list}
%
% An empty line (or a \tn{par}) after a list has semantic meaning as
% it defines whether then following text is logically within the same
% paragraph as the list (no empty line) or whether it starts a new
% paragraph and the paragraph containing the list ends at the end of
% the list (empty line after the list).
% This is handled by \LaTeX{} using a legacy flag called
% \texttt{@endpe} and set of commands inside the
% generic \tn{end} (calling \tn{@doendpe}) and as part of the list
% environments identifying themselves as \enquote{paragraph ending
% environments} (by setting this flag).
%
% For the reimplementation of the list environments including support
% of tagging we need to augment that mechanism slightly and add some
% kernel hook(s) to add the tagging code if needed.
%
%
%
%
%  \begin{macro}{\@doendpe,\__kernel_displayblock_doendpe:}
%    The original \LaTeXe{} command is augmented to allow for tagging.
%    TODO: use sockets for this and move to the kernel eventually.
%    \begin{macrocode}
\def\@doendpe{\@endpetrue
  \def\par
    {
%    \end{macrocode}
%    If we are processing a \verb=$$= math display and we encounter a real
%    \cs{par} after it, we need to add a \cs{parskip} when tagging is
%    done, because the one
%    added by \TeX{} is always canceled by the processing in
%    \cs{__math_tag_dollardollar_display_end:} in that case. This is
%    signaled by the global legacy switch \texttt{@domathendpe} which is set
%    to true in that case. Once the skip is applied we set it to
%    false. If there is no \cs{par} at all, it will be reset in
%    \cs{everypar} when the next paragraph starts.
%  \changes{v0.8x}{2024/12/01}{Handle \cs{parskip} after \texttt{\$\$}
%    display (tagging/762)}
%    \begin{macrocode}
      \if@domathendpe
%        \typeout{-------&gt;~ add~ another~ parskip~ that~ is~
%                           not~ canceled:~ \the\parskip }
        \skip_vertical:n { \tex_parskip:D }
        \@domathendpefalse
      \fi
      \@restorepar
      \clubpenalty\@clubpenalty
%    \end{macrocode}
%    At this point we add the tagging code that closes an open
%    \struct{text-unit}, \struct{text} tag combination,
%    if necessary:
%    \begin{macrocode}
      \__kernel_displayblock_doendpe:
%    \end{macrocode}
%
%    The standard \tn{par} command (\cs{par_end:}) acts on
%    \texttt{@endpe} and attempts to close a still open \struct{text-unit}s
%    and this would be wrong if it was already closed above. So we
%    have to reset the switch to false first.      
%    \begin{macrocode}
      \@endpefalse
      \everypar{}
      \par
    }
  \everypar{{\setbox\z@\lastbox}
            \everypar{}
            \@endpefalse
%    \end{macrocode}
%    Not sure what is faster: testing for the status of the switch or
%    setting it unconditionally to false (globally), probably roughly the same,
%    so we set it always:
%    \begin{macrocode}
%           \if@domathendpe
            \@domathendpefalse
%           \fi
  }
}
%    \end{macrocode}
%
%    By default we don't do any tagging:
%    \begin{macrocode}
\cs_new_eq:NN \__kernel_displayblock_doendpe: \prg_do_nothing:
%    \end{macrocode}
%
%
% \end{macro}
%
%
%  \begin{macro}{\if@domathendpe,\@domathendpefalse,\@domathendpetrue}
%    Signal that special paragraph handling after a math display is required.
%  \changes{v0.8x}{2024/12/01}{Handle \cs{parskip} after \texttt{\$\$}
%    display (tagging/762)}
%    \begin{macrocode}
\newif\if@domathendpe
\def\@domathendpefalse{\global\let\if@domathendpe\iffalse}
\def\@domathendpetrue {\global\let\if@domathendpe\iftrue}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
% \subsection{Object and template interfaces}
%
%
% \begin{objecttype}{blockenv, block, para, list, item}
%   All object types expect a single
%   key--value argument used to tweak template parameters specific to a
%   given use in the document.  This section is devoted to template
%   interfaces, and the template code is covered later.
%    \begin{macrocode}
\NewTemplateType{blockenv}{1}
\NewTemplateType{block}{1}
\NewTemplateType{para}{1}
\NewTemplateType{list}{1}
\NewTemplateType{item}{1}
%    \end{macrocode}
% \end{objecttype}
%
%
%
%  \begin{template}{blockenv display}
%    
%    \begin{macrocode}
\DeclareTemplateInterface{blockenv}{display}{1}
{
  env-name       : tokenlist ,
  tag-name       : tokenlist ,
  tag-class      : tokenlist ,
  tagging-recipe : tokenlist = standard,
  level-increase : boolean = true ,
  setup-code     : tokenlist , 
  block-instance : tokenlist = displayblock ,
  para-instance  : tokenlist ,
  inner-level-counter : tokenlist,
  max-inner-levels    : tokenlist = 4,
  inner-instance-type : tokenlist = list ,
  inner-instance      : tokenlist ,
  para-flattened : boolean = false ,
  final-code     : tokenlist = \ignorespaces ,
}
%    \end{macrocode}
%  \end{template}
%
%
%  \begin{template}{block display}
%    
%  \changes{v0.8s}{2024/10/03}{Offer item-skip key also on block templates}
%    \begin{macrocode}
\DeclareTemplateInterface{block}{display}{1}    
{
  heading        : tokenlist = ,                % ??
  beginsep       : skip = \topsep ,
  begin-par-skip : skip = \partopsep ,
  par-skip       : skip = \parsep ,
  end-skip       : skip = \KeyValue{beginsep} , % conflict with name below
  end-par-skip   : skip = \KeyValue{begin-par-skip} ,
  item-skip      : skip = \itemsep ,
  beginpenalty   : integer = \UseName{@beginparpenalty} ,
  endpenalty     : integer = \UseName{@endparpenalty} ,
  leftmargin     : length = \leftmargin ,
  rightmargin    : length = \rightmargin ,
  parindent      : length = 0pt ,
% maybe add? (or more general for fonts and color)
%  font            : tokenlist
}
%    \end{macrocode}
%  \end{template}
%
%
%  \begin{template}{para std}
%    
%    \begin{macrocode}
\DeclareTemplateInterface{para}{std}{1}    
{
  para-class            : tokenlist = justify ,                          
  indent-width          : length = \parindent ,
  start-skip            : skip = 0pt  ,
  left-skip             : skip = 0pt ,
  right-skip            : skip = 0pt ,
  end-skip              : skip = \@flushglue ,
  fixed-word-spaces     : boolean = false ,
  final-hyphen-demerits : integer = 5000 ,
  cr-cmd                : tokenlist = \@normalcr ,
}
%    \end{macrocode}
%  \end{template}
%
%
%  \begin{template}{list std}
%    
%    \begin{macrocode}
\DeclareTemplateInterface{list}{std}{1}     % optional
{
  counter         : tokenlist = ,
  item-label      : tokenlist = ,
  start           : integer = 1 ,
  resume          : boolean = false ,
  item-instance   : instance{item} = basic ,
  item-skip       : skip = \itemsep ,
  item-penalty    : integer = \UseName{@itempenalty} ,
  item-indent     : length = \itemindent ,
  label-width     : length = \labelwidth ,
  label-sep       : length = \labelsep ,
  legacy-support   : boolean = false ,
}
%    \end{macrocode}
%  \end{template}
%
%
% \begin{template}{item std}
%
%    \begin{macrocode}
\DeclareTemplateInterface{item}{std}{1}
  {
    counter-label : function{1} = \arabic{#1} ,
    counter-ref   : function{1} = \KeyValue{counter-label} ,
    label-ref     : function{1} = #1 ,
    label-autoref : function{1} = item~#1 ,
    label-format  : function{1} = #1 ,
    label-strut   : boolean = false ,
    label-align   : choice {left,center,right,parleft} = right ,
    label-boxed   : boolean = true ,
    next-line     : boolean = false ,
    text-font     : tokenlist ,
    compatibility : boolean = true ,
  }
%    \end{macrocode}
% \end{template}
%
%
%
%
%
%
% \subsection{Useful helper commands}
%
% This section collects \pkg{expl3} commands that will be useful.
%
%  \begin{macro}{\@@_skip_set_to_last:N,\@@_skip_remove_last:}
%    Set a skip register to  the value of an immediately preceding
%    skip or zero if there was none.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_skip_set_to_last:N #1 {
  \skip_set:Nn #1 { \tex_lastskip:D }
}
%    \end{macrocode}
%    Remove a skip previous skip if it is directly in front (not
%    allowed in unrestricted vertical mode).
%    \begin{macrocode}
\cs_new_eq:NN \@@_skip_remove_last: \tex_unskip:D
%    \end{macrocode}
%  \end{macro}
%    
%    \begin{macrocode}
\cs_generate_variant:Nn \tl_if_novalue:nTF { o }
%    \end{macrocode}
%    
%
% \subsubsection{Debugging}
%
%    
%  \begin{variable}{\g_@@_debug_bool}
%    
%    \begin{macrocode}
\bool_new:N \g_@@_debug_bool
%    \end{macrocode}
%  \end{variable}
%
%
%  \begin{macro}{\@@_debug:n,\@@_debug_typeout:n}
%    
%    \begin{macrocode}
\cs_new_eq:NN \@@_debug:n \use_none:n
\cs_new_eq:NN \@@_debug_typeout:n \use_none:n
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\block_debug_on:,\block_debug_off:,
%                \@@_debug_gset:}
%    \begin{macrocode}
\cs_new_protected:Npn \block_debug_on:
  {
    \bool_gset_true:N \g_@@_debug_bool
    \@@_debug_gset:
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_new_protected:Npn \block_debug_off:
  {
    \bool_gset_false:N \g_@@_debug_bool
    \@@_debug_gset:
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_new_protected:Npn \@@_debug_gset:
  {
    \cs_gset_protected:Npx \@@_debug:n ##1
      { \bool_if:NT \g_@@_debug_bool {##1} }
    \cs_gset_protected:Npx \@@_debug_typeout:n ##1
      { \bool_if:NT \g_@@_debug_bool { \typeout{==&gt;~ ##1} } }
  }
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\DebugBlocksOn,\DebugBlocksOff}
%    
%    \begin{macrocode}
\cs_new_protected:Npn \DebugBlocksOn  { \block_debug_on:  }
\cs_new_protected:Npn \DebugBlocksOff { \block_debug_off: }
%    \end{macrocode}
%    
%    \begin{macrocode}
\DebugBlocksOff
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
% \subsection{Implementation of templates}
%
%
% \subsubsection{Implementation of blockenv templates \ldots}
%
%
%
%  \begin{macro}{\g_block_nesting_depth_int}
%    \LaTeXe{} already has a counter to record the nesting depth of
%    blocks, but  we want our own name because it isn't really tied to
%    \enquote{lists} any more. However, \tn{@listdepth} is really part
%    of the legacy interface (for example \env{minipage} alters it to
%    point to a different counter) so that we are stuck with using at
%    least indirectly for now and the following line makes this look
%    like an L3 integer variable but internally expands to \tn{@listdepth}:
%    \begin{macrocode}
\cs_new:Npn \g_block_nesting_depth_int { \@listdepth }  % a fake int
                                                        % for now
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{template}{blockenv display}
%    
%    \begin{macrocode}
\DeclareTemplateCode{blockenv}{display}{1}
{
  env-name       = \l_@@_env_name_tl ,
  tag-name       = \l_@@_tag_name_tl ,
  tag-class      = \l_@@_tag_class_tl ,
  tagging-recipe = \l_@@_tagging_recipe_tl ,
  level-increase = \l_@@_level_incr_bool ,
  setup-code     = \l_@@_setup_code_tl , 
  block-instance = \l_@@_block_instance_tl ,
  para-instance  = \l_@@_para_instance_tl ,
  para-flattened = \l__tag_para_flattened_bool ,
  inner-level-counter = \l_@@_inner_level_counter_tl ,
  max-inner-levels    = \l_@@_max_inner_levels_tl ,
  inner-instance-type = \l_@@_inner_instance_type_tl ,
  inner-instance      = \l_@@_inner_instance_tl ,
  final-code     = \l_@@_final_code_tl , 
}
{
  \@@_debug_typeout:n{\l_@@_env_name_tl -env-start}
%  
  \SetKnownTemplateKeys{blockenv}{display}{#1}
%    \end{macrocode}
%    We need to know later if we have nested blockenvs inside
%    a flattened environment. Whenever we  start a new blockenv we
%    increment \cs{l__tag_block_flattened_level_int} if it is already
%    different from zero. If it is zero we increment it if flattening
%    is requested.
%    Thus a value of \texttt{0} means no flattening requested so far
%    and \texttt{1} means this is the first blockenv requesting
%    flattening. In either case we have to make sure that the blockenv
%    is surrounded by a \struct{text-unit} tag, while for any value above
%    \texttt{1} we have to omit the \struct{text-unit}.
  %    \begin{macrocode}
  \int_compare:nNnTF \l__tag_block_flattened_level_int &gt; 0
      {
        \int_incr:N \l__tag_block_flattened_level_int
      }
      {
        \bool_if:NT \l__tag_para_flattened_bool
             {
               \int_incr:N \l__tag_block_flattened_level_int
             }
      }
%
  \tl_if_empty:NF \l_@@_inner_level_counter_tl
     {
       \int_compare:nNnTF  \l_@@_inner_level_counter_tl &gt;
                           { \l_@@_max_inner_levels_tl - 1 }
           { \@toodeep }
           { \int_incr:N \l_@@_inner_level_counter_tl }  % not clean "o"?
     }
%    \end{macrocode}
%    Legacy defaults are only roped in if the list level changes. For
%    display blocks that remain on the same level the current values
%    are kept.
%    \begin{macrocode}
  \bool_if:NT \l_@@_level_incr_bool
     {
       \int_compare:nNnTF  \g_block_nesting_depth_int &gt;
                           { \c@maxblocklevels - 1 } 
           { \@toodeep }
           {
             \int_gincr:N \g_block_nesting_depth_int
%    \end{macrocode}
%    If there are no legacy defaults for that level then the next line
%    does nothing, i.e., the current values (from the last level
%    become the defaults for the next.
%    \begin{macrocode}
             \use:c { @list \int_to_roman:n
                             { \g_block_nesting_depth_int } }
           }
     }
%    \end{macrocode}
%    If we are doing tagging we load one of the available recipes for
%    tagging, which alters various kernel hooks to add appropriate
%    tagging structures.
%    \begin{macrocode}
  \tag_if_active:T 
      { \use:c { @@_recipe_ \l_@@_tagging_recipe_tl : } }
%    \end{macrocode}
%    The default for \env{list} environments is that they have an
%    empty label and are not numbered (something that is then
%    overwritting by the setup of a specific list). We ensure
%    this here even for non-lists, because we need a defined state
%    that then can be overwritting by the legacy setup code for
%    the \env{list} environment in \cs{l_@@_setup_code_tl}.
%    This is needed in case lists are nested as they otherwise would
%    inherit outer values (and suddenly an \env{itemize} would start
%    incrementing an outer \env{enumerate} counter, etc. 
%  \changes{v0.8v}{2024/10/11}{Set the defaults for \tn{@itemlabel},
%    \tn{@listctr} and \texttt{@nmbrlist} early in the block code
%    before the setup code gets executed (tagging/730)}
%    \begin{macrocode}
  \tl_clear:N \@itemlabel
  \tl_clear:N \@listctr
  \legacy_if_set_false:n { @nmbrlist } 
%    \end{macrocode}
%    Then run the setup code if any is given in the instance.
%    \begin{macrocode}
  \l_@@_setup_code_tl
%    \end{macrocode}
%    Next call a block instance at the appropriate level passing it
%    any key/value list provided in the optional argument (keys that
%    are not recognized are ignored---currently with an
%    error).
%    \begin{macrocode}
  \@@_debug_typeout:n{use~ instance:~
           \l_@@_block_instance_tl - \int_use:N \g_block_nesting_depth_int }
  \UseInstance{block}
              { \l_@@_block_instance_tl - \int_use:N
                \g_block_nesting_depth_int }
              \UnusedTemplateKeys
%    \end{macrocode}
%    After this instance has been processed, any remaining unused keys
%    are stored in \cs{UnusedTemplateKeys} and we can make use of this
%    data later as
%    long as we do not call another instance that also does unused key
%    processing and overwrites it. This is what happens below, so we better save its
%    current value for now.
%    \begin{macrocode}
  \tl_set_eq:NN \l_@@_unused_blockenv_keys_tl \UnusedTemplateKeys
%    \end{macrocode}
%    After the block instance call the para and then inner (list)
%    instance if either or both are
%    specified (which may not be the case).
%    \begin{macrocode}
  \tl_if_empty:NF \l_@@_para_instance_tl 
    {
      \@@_debug_typeout:n{ use~ para~ instance:~
                           \l_@@_para_instance_tl }
%    \end{macrocode}
%    For now we don't offer to alter instance parameters here so we
%    pass an empty argument.
%    \begin{macrocode}
      \UseInstance{para}{ \l_@@_para_instance_tl } {}
    }
%    \end{macrocode}
%    The inner instance may have its own levels or none depending
%    on which the instance name differs. Again we pass it the optional
%    key/value list.
%    \begin{macrocode}
  \tl_if_empty:NF \l_@@_inner_instance_tl
    {
      \@@_debug_typeout:n{use~ instance:~ \l_@@_inner_instance_tl
               \tl_if_empty:NF \l_@@_inner_level_counter_tl
                       { - \int_use:N \l_@@_inner_level_counter_tl }}
      \UseInstance{ \l_@@_inner_instance_type_tl }
                  { \l_@@_inner_instance_tl
                    \tl_if_empty:NF \l_@@_inner_level_counter_tl
                       %   not clean use "o"?
                       { - \int_use:N \l_@@_inner_level_counter_tl }
                  }
                  \l_@@_unused_blockenv_keys_tl
%    \end{macrocode}
%    Again the instance may has processed a few keys from the sofar
%    unused keys, so we update \cs{l_@@_unused_blockenv_keys_tl} to
%    match the new reality.
%    \begin{macrocode}
      \tl_set_eq:NN \l_@@_unused_blockenv_keys_tl \UnusedTemplateKeys
    }
%    \end{macrocode}
%    At this point, the \cs{l_@@_unused_blockenv_keys_tl} token list
%    should either be empty or it should contain only keys that are suitable for
%    the item template, but right now there is no code to test that
%    can test
%    the latter; it would help probably if we have an interface for
%    this.
%
%    For now we handle that when the first item is encountered, but
%    that isn't realy clean.\fmi{fix}
%    \begin{macrocode}
  \tl_if_empty:NF \l_@@_unused_blockenv_keys_tl
    {
       % check if only item template keys remain
    }
%    \end{macrocode}
%    We finish off with \cs{l_@@_final_code_tl} which defaults to
%    \tn{ignorespaces} so that spaces between \verb=\begin{...}= and
%    the start of the text are ignored.
%    \begin{macrocode}
  \l_@@_final_code_tl
}
%    \end{macrocode}
%  \end{template}
%
%
%  \begin{macro}{\l_@@_unused_blockenv_keys_tl}
%    
%    \begin{macrocode}
\tl_new:N \l_@@_unused_blockenv_keys_tl
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\l__tag_block_flattened_level_int}
%    Count the levels of nested blockenvs starting with the first that
%    is \enquote{flattened}. The counter is defined in lttagging.dtx,
%    but until the next release 11/24 we set it up here too
%    \begin{macrocode}
\int_if_exist:NF \l__tag_block_flattened_level_int
  {
    \int_new:N \l__tag_block_flattened_level_int
  }
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\c@maxblocklevels}
%    A counter to increase or decrease the number of supported
%    level. If increased, one needs to supply additional level instances.
%    \begin{macrocode}
\newcounter{maxblocklevels}
\setcounter{maxblocklevels}{6}
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\endblockenv}
%    The code executed when a blockenv ends is 99\% the same for all
%    blockenvs (at least up to now). Small differences exist, though. They 
%    are  accounted for first in the conditionals.
%
%    We make this a public command so that new block environments can
%    be set up without the need to resort to L3 layer
%    programming.\fmi{name is bad}
%    \begin{macrocode}
\cs_new:Npn \endblockenv {
  \@@_debug_typeout:n{blockenv~ common~ ending \on@line}
%    \end{macrocode}
%    If this block was incrementing the level we have to decrement it
%    now again:
%    \begin{macrocode}
  \bool_if:NT \l_@@_level_incr_bool
    { \int_gdecr:N \g_block_nesting_depth_int }
%    \end{macrocode}
%    If this block was a list and there are still \tn{item} labels to
%    be placed we move to horizontal mode to get them typeset.
%    \begin{macrocode}
  \legacy_if:nT { @inlabel }
    {
      \mode_leave_vertical: 
      \legacy_if_gset_false:n { @inlabel }
    }
%    \end{macrocode}
%    If we are ending a list environment and we have not seen any
%    \tn{item}, i.e., \texttt{@newlist} is still true, we raise an
%    error. In basic a ``displayblock'' scenario \texttt{@newlist} will
%    always be false, but if such an environment appears inside an outer
%    list then \tn{noitemerr} could still be triggered and that is undesirable
%    (as the missing item will be detected at the wrong point and again later,
%    during the outer list processing). We
%    therefore run it only if the current environment is a list.
%  \changes{v0.8q}{2024/09/03}{Raise a \tn{@noitemerr} if appropriate}
%    \begin{macrocode}
  \@@_if_list:T { \legacy_if:nT { @newlist } { \@noitemerr } }
%    \end{macrocode}
%    \begin{macrocode}
  \mode_if_horizontal:TF
       { \@@_skip_remove_last: \@@_skip_remove_last: \par }
       { \@inmatherr{\end{\@currenvir}} }
%    \end{macrocode}
%    Once we are back in vertical mode we can add the appropriate
%    closing tagging structure(s), if we are doing tagging.
%    \begin{macrocode}
  \__kernel_displayblock_end:
%    \end{macrocode}
%    Resetting the \texttt{@newlist} switch is also only done if the
%    current enviornment is a list and not unconditionally.
%  \changes{v0.8q}{2024/09/03}{Setting \texttt{@newlist} to false
%    moved after tagging code if in a list}
%    \begin{macrocode}
  \@@_if_list:T { \legacy_if_gset_false:n { @newlist } }
%    \end{macrocode}
%    What to do in terms of vertical spacing  in different situations
%    is still somewhat open to debate, right now this is more or less
%    implementing what \LaTeXe{} list environment have been
%    doing.\fmi{some redesign/extensions here?}
%    \begin{macrocode}
%    \@@_debug_typeout:n{@noparlist =
%                       \legacy_if:nTF { @noparlist }{true}{false}}
  \legacy_if:nF { @noparlist }
    {
      \@@_skip_set_to_last:N \l_tmpa_skip
      \dim_compare:nNnT \l_tmpa_skip &gt; \c_zero_dim
        {
          \skip_vertical:n { - \l_tmpa_skip }
          \skip_vertical:n { \l_tmpa_skip + \parskip - \@outerparskip }
        }
      \addpenalty \@endparpenalty
      \addvspace \l_@@_topsepadd_skip
%    \end{macrocode}
%    \LaTeXe{} triggered the paragraph handling after a list at this
%    point here, i.e., only if the list didn't start a paragraph. One
%    can make a case for that, but it can be somewhat surprising to
%    the user and there is a good argument that even such a list could
%    be followed explanatory text that is part of the same paragraph
%    and doesn't start a new one.\fmi{decide which logic we want to
%    use! If the old logic is used we need to close the text-unit
%    ourselves in the true branch}
%    \begin{macrocode}
%        \legacy_if_gset_true:n { @endpe }
    }
%    \end{macrocode}
%    So this is for now always done. Probably \cs{l_@@_topsepadd_skip} above
%    should be added only if the paragraph ends here and not if it
%    continues, so this need some further cleanup.\fmi{decide}
%    
%    Finally, we have a socket that handles the \tn{par} handling
%    after the block. Normally, we use it with the \plug{on} plug (check for a
%    following \tn{par}) but in the case of standalone environments we
%    assign it the \plug{off} plug.
%    \begin{macrocode}
  \socket_use:n {tagsupport/block-endpe}
}
%    \end{macrocode}
%
%  \end{macro}
%
%
%  \begin{macro}{\@@_if_list:T}
%    The following code may need some redesigning, as there is no good test for \enquote{is
%    this environment a \enquote{list} that has \tn{item}s}. For now
%    this here does the trick well enough.\fmi{revisit}
%  \changes{v0.8q}{2024/09/03}{Provide a test for: Am I in a list?}
%    \begin{macrocode}
\cs_new:Npn \@@_if_list:T
   { \tl_if_eq:NnT \l_@@_block_instance_tl {list} }
%    \end{macrocode}
%  \end{macro}
%
%
%      
%  \begin{macro}{\__kernel_displayblock_end:}
%    The kernel hook for tagging at the end of the block.
%    \begin{macrocode}
\cs_new:Npn \__kernel_displayblock_end: {
  \@@_debug_typeout:n{\detokenize{__kernel_displayblock_end:}}
}
%    \end{macrocode}
%  \end{macro}
%
%
%
% \begin{socketdecl}{tagsupport/block-endpe}
%    This socket is responsible for the end environment \tn{par}
%    handling. We define two plugs for it (\plug{on} and \plug{off}).
%    \begin{macrocode}
\socket_new:nn      {tagsupport/block-endpe}{0}
%    \end{macrocode}
% \end{socketdecl}
%
% \begin{plugdecl}{on,off}
%    The plugs set the legacy \texttt{@endpe} switch. This must always
%    happen because block environments with different settings can be nested
%    and should not inherit the setting from the outer environment.
%    \begin{macrocode}
\socket_new_plug:nnn{tagsupport/block-endpe}{on}
%    \end{macrocode}
%    We can't use \cs{legacy_if_gset_true:n} because this is now doing
%    more than setting the legacy switch
%    \begin{macrocode}
                    { \@endpetrue }
\socket_new_plug:nnn{tagsupport/block-endpe}{off}
                    { \@endpefalse }
%    \end{macrocode}
%
%    \begin{macrocode}
\socket_assign_plug:nn{tagsupport/block-endpe}{on}
%    \end{macrocode}
% \end{plugdecl}
%
%
%
%
%
% \subsubsection{Implementation of para templates \ldots}
%
%  \begin{template}{para std}
%    
%    \begin{macrocode}
\DeclareTemplateCode{para}{std}{1}
{
  indent-width      = \parindent ,
  start-skip        = \l__par_start_skip ,              % name??
  left-skip         = \leftskip  ,
  right-skip        = \rightskip  ,
  end-skip          = \parfillskip ,
  fixed-word-spaces = \l__par_fixed_word_spaces_bool ,  % name??
  final-hyphen-demerits = \finalhyphendemerits ,
  cr-cmd                = \\ ,
  para-class            = \l__tag_para_attr_class_tl ,                          
}
{
  \SetTemplateKeys{para}{std}{#1}
  \skip_set:Nn \@rightskip \rightskip
}
%    \end{macrocode}
%  \end{template}
%
%
%
%
%
% \subsubsection{Implementation of block templates \ldots}
%
%
%
%
%
% \begin{template}{block display}
%    
%    In contrast to the \LaTeXe{} implementation we do not directly
%    use \tn{listparindent} here but a private register of the
%    template. The reason is that block template instances are also
%    used outside of lists.
%  \changes{v0.8s}{2024/10/03}{Offer item-skip key also on block templates}
%  \changes{v0.8w}{2024/11/23}{Use private storage bin for parindent
%    and not \tn{listparindent} to decouple block and list templates (tagging/767)}
%    \begin{macrocode}
\DeclareTemplateCode{block}{display}{1}
{
  heading         = \l_@@_heading_tl ,
  beginsep        = \topsep ,
  begin-par-skip  = \partopsep ,
  par-skip        = \parsep ,
  end-skip        = \l_@@_botsep_skip ,
  end-par-skip    = \l_@@_parbotsep_skip ,
  item-skip       = \itemsep ,
  beginpenalty    = \@beginparpenalty ,
  endpenalty      = \@endparpenalty ,
  rightmargin     = \rightmargin ,
  leftmargin      = \leftmargin ,
  parindent       = \l_@@_parindent_dim ,
}
{
    \SetKnownTemplateKeys{block}{display}{#1}
%    \end{macrocode}
%  \fmi{generalize heading usage (or drop?)}
%    \begin{macrocode}
    \tl_if_blank:oF \l_@@_heading_tl
       { \mode_leave_vertical:
         \textbf{\l_@@_heading_tl} } % TODO customize
%    \end{macrocode}
%    The code largely follows the logic of \LaTeXe{}'s \env{trivlist}
%    implementation as far as it applicable for the \enquote{display
%    block} but coded using the L3 programming layer. However, we keep
%    all the legacy variables (e.g., \texttt{@noskipsec}) if there is
%    some chance that they are set in classes or packages.
%    \begin{macrocode}
    \legacy_if:nT { @noskipsec } { \mode_leave_vertical: }
    \skip_set:Nn \l_@@_topsepadd_skip { \topsep }
    \mode_if_vertical:TF
      {
        \skip_add:Nn \l_@@_topsepadd_skip { \partopsep }
%    \end{macrocode}
%    At this point it is safe to add tagging structure(s) so we have
%    a kernel-owned hook here for tagging. This is used to possibly
%    start a paragraph structure (to surround the block, for example,
%    in case of lists) and possibly do some other preparation for
%    tagging the block.
%    \begin{macrocode}
        \__kernel_displayblock_beginpar_vmode:
      }
      {
%    \end{macrocode}
%    If we are in horizontal mode then the displayblock has to return
%    to vertical mode now (after removing any immediately preceding
%    skip or kern. But before we actually issue the\tn{par} we execute
%    a kernel hook in which we can add tagging code. This hook is
%    \enquote{weird} because by default it does nothing, but if
%    tagging is wanted it takes an argument and grabs the following
%    \tn{par} in order to put tagging code before and after the \tn{par}.
%    \begin{macrocode}
        \@@_skip_remove_last: \@@_skip_remove_last:
        \__kernel_displayblock_beginpar_hmode:w \par 
      }
%    \end{macrocode}
%    Now we are back to legacy list implementation \ldots
%    \begin{macrocode}
    \legacy_if:nTF { @inlabel }
      {
        \legacy_if_set_true:n { @noparitem }
        \legacy_if_set_true:n { @noparlist }
      }
      {
        \legacy_if:nT { @newlist } { \@noitemerr }
        \legacy_if_set_false:n { @noparlist }
        \skip_set_eq:NN \l_@@_effective_top_skip \l_@@_topsepadd_skip
      }
    \skip_add:Nn \l_@@_effective_top_skip { \parskip }
%    \end{macrocode}
%    Next lines set some paragraph defaults, any of them may get overwritten
%    if there is a \key{para-instance} specified on the \xt{blockenv}
%    instance.
%    \begin{macrocode}
    \skip_zero:N \leftskip
    \skip_set_eq:NN \rightskip \@rightskip
    \skip_set_eq:NN \parfillskip \@flushglue
%    \end{macrocode}
%    The next lines establish a parshape which is retained across
%    paragraphs be executing \cs{para_end:} within a group and thus
%    reestablishing the parshape for the next paragraph again. In case
%    a list got started \tn{par} is ignored until we have seen an
%    \tn{item} (or we have executed \tn{par} one thousand times.
%    \begin{macrocode}
    \int_zero:N \par@deathcycles
    \@setpar
      {
        \legacy_if:nTF { @newlist }
          {
            \int_incr:N \par@deathcycles
            \int_compare:nNnTF \par@deathcycles &gt; { 1000 }
                { \@noitemerr
                  { \para_end: }
                }
          }
          {
            { \para_end: }
          }
      }
    \skip_set_eq:NN \@outerparskip \parskip
    \skip_set_eq:NN \parskip \parsep
%    \end{macrocode}
%  \changes{v0.8w}{2024/11/23}{Use private storage bin for parindent
%    and not \tn{listparindent} to decouple block and list templates (tagging/767)}
%    \begin{macrocode}
    \dim_set_eq:NN \parindent \l_@@_parindent_dim
    \dim_add:Nn \linewidth { - \rightmargin - \leftmargin }
    \dim_add:Nn \@totalleftmargin { \leftmargin }
    \tex_parshape:D 1 ~ \@totalleftmargin \linewidth
%    \end{macrocode}
%    This is the point where we are ready to add the tagging structure
%    for the block, e.g., an \verb=&lt;L&gt;=, a \verb=&lt;Figure&gt;= or some
%    other structure.
%    \begin{macrocode}
    \__kernel_displayblock_begin:
%    \end{macrocode}
%    Finally, we have to output the vertical separation and penalty at
%    the start of the block  and make corrections for a change in
%    \tn{parskip} and some other housekeeping, unless this block is inside a list and the list
%    \tn{item} has not yet placed. In that case the vertical
%    space and penalty us suppressed. This
%    is controlled through the legacy switches \texttt{@noparitem},
%    \texttt{minipage}, and \texttt{@nobreak}.
%    \begin{macrocode}
    \legacy_if:nTF { @noparitem }
      {
        \legacy_if_set_false:n { @noparitem }
        \hbox_gset:Nn \g_@@_labels_box
          {
            \skip_horizontal:n { - \leftmargin }
            \hbox_unpack_drop:N \g_@@_labels_box
            \skip_horizontal:n { \leftmargin }
          }
%    \end{macrocode}
%    \fmi{document 2e logic used here}
%    \begin{macrocode}
        \legacy_if:nF { @minipage } % Why this chunk of code?
          {
            \@@_skip_set_to_last:N \l_@@_tmpa_skip
            \skip_vertical:n { - \l_@@_tmpa_skip }
            \skip_vertical:n { \l_@@_tmpa_skip +
                               \@outerparskip - \parskip }
          }
      }
      {
        \legacy_if:nTF { @nobreak }
          { \addvspace{\skip_eval:n{\@outerparskip-\parskip}} }
          {
            \addpenalty \@beginparpenalty
            \addvspace \l_@@_effective_top_skip
            \addvspace{-\parskip}
          }
      }
}
%    \end{macrocode}
%
%
%    Extra keys to support enumitem conventions:
%    \begin{macrocode}
\keys_define:nn { template/block/display }
{
  ,topsep        .skip_set:N = \topsep
  ,partopsep     .skip_set:N = \partopsep
  ,listparindent .skip_set:N = \listparindent
}
%    \end{macrocode}
% \end{template}
%
%
%  \begin{macro}{\__kernel_displayblock_begin:,
%                \__kernel_displayblock_beginpar_hmode:w,
%                \__kernel_displayblock_beginpar_vmode:}
%    The internal kernel hooks for tagging.
%    \begin{macrocode}
\cs_new:Npn \__kernel_displayblock_begin: {
  \@@_debug_typeout:n
     {\detokenize{__kernel_displayblock_begin:}}
}
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_new:Npn \__kernel_displayblock_beginpar_hmode:w {
  \@@_debug_typeout:n
     {\detokenize{__kernel_displayblock_beginpar_hmode:w}}
}
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_new:Npn \__kernel_displayblock_beginpar_vmode: {
  \@@_debug_typeout:n
     {\detokenize{__kernel_displayblock_beginpar_vmode:}}
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
% \subsubsection{Implementation of list templates \ldots}
%
%
%
%  \begin{macro}{\@itemlabel,\@listctr}
%    Both \tn{@itemlabel} and \tn{@listctr} from the \LaTeXe{} list
%    implementation are used (or set) by various packages. We
%    therefore use them too, so that these packages have a fighting
%    chance to work with the new tagging-aware implementation for
%    \env{list}.
%    \begin{macrocode}
\tl_new:N \@itemlabel         % should have a top-level definition
\tl_new:N \@listctr           % should have a top-level definition
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\@@_evaluate_saved_user_keys:nn}
%    Keys set on individual list environments may be intended to alter
%    the behavior of the template instance that defines the \tn{item}
%    command. If meant to alter only a single \tn{item} command one
%    would specify them in the optional argument of the \tn{item}, but
%    if they should alter all items the right place would be the list
%    environment. For this reason we need to store the values and then
%    set them inside the \tn{item} template code using
%    \tn{SetKnownTemplateKeys} in the appropriate context (template type
%    and template name). This is done in
%    \cs{@@_evaluate_saved_user_keys:nn}. The context is provided in
%    the two arguments (because different list environments may use
%    different \tn{item} instances based on different templates. By
%    default the command does
%    nothing because most environments do not have user key settings.
%  \changes{v0.8s}{2024/10/03}{Pass user keys on list to \tn{item} for
%    evaluation}
%    \begin{macrocode}
\cs_new_eq:NN \@@_evaluate_saved_user_keys:nn \use_none:nn
%    \end{macrocode}
%    Maybe something like this should become a public function, but
%    for now this is a one-off for the \tn{item} command and therefore
%    coded inline and internal to the block code.
%    \begin{macrocode}
%\cs_new:Npn \@@_save_user_keys:n #1 {
%  \tl_if_empty:nTF {#1}
%     { \cs_set_eq:NN \@@_evaluate_saved_user_keys:nn \use_none:nn }
%     { \cs_set:Npe \@@_evaluate_saved_user_keys:nn ##1##2
%          { \SetKnownTemplateKeys{##1}{##2}{ \exp_not:n{#1} }    }
%}
%    \end{macrocode}
%  \end{macro}
%
%
% \begin{template}{list std}
%    
%    This template implements numbered and unnumbered lists  and can
%    be combined with display blocks or with inline blocks.
%    \begin{macrocode}
\DeclareTemplateCode{list}{std}{1}
{
  counter         = \l_@@_counter_tl,
  item-label      = \l_@@_item_label_tl,
  start           = \l_@@_counter_start_int ,
  resume          = \l_@@_resume_bool ,
  item-instance   = \@@_item_instance:n ,
  item-skip       = \itemsep ,
%  item-par-skip   = \parsep ,
  item-penalty    = \@itempenalty ,
  item-indent     = \itemindent ,
  label-width     = \labelwidth ,
  label-sep       = \labelsep ,
  legacy-support  = \l_@@_legacy_support_bool , % FMi questionable
}
{
  \@@_debug_typeout:n{template:list:std}
%
%    \end{macrocode}
%    We start by looking at the user supplied keys in \texttt{\#1}. If
%    there aren't any we reset \cs{@@_evaluate_saved_user_keys:nn} to
%    do nothing. Otherwise we evaluate and set the keys in the context
%    of the current list template. In addition we prepare
%    \cs{@@_evaluate_saved_user_keys:nn} for execution in the
%    template for \tn{item}.
%  \changes{v0.8s}{2024/10/03}{Prepare \cs{@@_evaluate_saved_user_keys:nn}
%            for use in \tn{item}}
%    \begin{macrocode}
  \tl_if_empty:oTF {#1}
     { \cs_set_eq:NN \@@_evaluate_saved_user_keys:nn \use_none:nn }
     {
       \SetKnownTemplateKeys{list}{std}{#1}
%    \end{macrocode}
%    The setup for \cs{@@_evaluate_saved_user_keys:nn} is a bit trcky
%    and has to be done with \cs{cs_set:Npe} even though we don't want
%    to expand anything and therefore use \cs{exp_not:n} inside. All
%    this does is that any \texttt{\#} passed in via \texttt{\#1} is
%    doubled (e.g., from \verb/label-format=\fbox{#1}/ which is
%    represented as \verb/...\fbox{##1}/). Otherwise, we would end up
%    with a replacement text like
%\begin{verbatim}
%  \SetTemplateKeys {#1}{#2}{label-format=\fbox {#1}}
%\end{verbatim}
%   instead of
%\begin{verbatim}
%  \SetTemplateKeys {#1}{#2}{label-format=\fbox {##1}}
%\end{verbatim}
%  resulting in very odd and puzzling behavior. 
%    \begin{macrocode}
       \cs_set:Npe \@@_evaluate_saved_user_keys:nn ##1##2
          { \SetKnownTemplateKeys{##1}{##2}{
              \exp_not:o { \UnusedTemplateKeys }
            }
%    \end{macrocode}
%    
%    \begin{macrocode}
            \exp_not:n {
              \tl_if_empty:NF \UnusedTemplateKeys
                 {
                   \msg_error:nnee { block } { unknown-keys }
                       { \l_@@_env_name_tl \space environment}
                       \UnusedTemplateKeys
                 }
            }
          }
     }
%    \end{macrocode}
%    Has this list a counter name defined in the instance?
%    \begin{macrocode}
  \tl_if_empty:NTF \l_@@_counter_tl
    {                                
%    \end{macrocode}
%    If not we check if \tn{@nmbrlist} is true which may be the case
%    in legacy environments that used \tn{usecounter} in the argument
%    to the \env{list} environment.
%  \changes{v0.8v}{2024/10/11}{Correct logic for setting up the list
%    counter  (tagging/730)}
%    \begin{macrocode}
    \legacy_if:nT { @nmbrlist }
        {
%    \end{macrocode}
%    In that case we only check if we should resume a previous list
%    (\tn{@listctr} should be set in that case through the legacy
%    method as well so we should be able to use it).
%    \begin{macrocode}
         \bool_if:NF \l_@@_resume_bool
           {
             \int_gset:cn{ c@ \@listctr }
                 { \l_@@_counter_start_int - 1 }
           } 
        }
    }
%    \end{macrocode}
%    If a counter is set in the list instance we use that
%    one. This should be the name of a \LaTeX{} counter that is
%    already allocated externally---no runtime check is made for this:
%    if it is not declared one will get \enquote{no such counter}
%    error when the list is used.
%    \begin{macrocode}
    {
     \@nmbrlisttrue
     \tl_set_eq:NN \@listctr \l_@@_counter_tl
     \bool_if:NF \l_@@_resume_bool
       {
         \int_gset:cn{ c@ \@listctr }
             { \l_@@_counter_start_int - 1 }
       } 
    }
%    \end{macrocode}
%    Does the current instance has an item label representation? This
%    would be possible whether or not we have a numbered list. If yes,
%    then we use this for \tn{@itemlabel}, otherwise we expect that
%    \tn{@itemlabel} is provided from the outside, e.g., as part of
%    the \env{list} environment argument.
%    \begin{macrocode}
  \tl_if_empty:NF \l_@@_item_label_tl
    {
      \tl_set_eq:NN \@itemlabel \l_@@_item_label_tl
    }
%    \end{macrocode}
%    Finally, we signal that we are at the start of a new list (which
%    affects how the first \tn{item} is handled and how \tn{par}
%    commands are interpreted.
%    \begin{macrocode}
    \legacy_if_gset_true:n { @newlist }
%    \end{macrocode}
%    If we encounter horizontal material before the first \tn{item} we
%    do want a \tn{@noitemerr} straight away, because afterwards we
%    end up with tagging structure faults whose cause is the
%    missing \tn{item}. So we setup up \cs{@@_item_everypar:} to test
%    for this; when the first \tn{item} is encountered this will get
%    reset. This is only relevant for vertical lists, when dealing with
%    inline lists one would need to test for something else to
%    identify that there is horizontal material between the start of the list and
%    the first \tn{item} (maybe some \tn{spacefactor} trick could be
%    used then, or the material is boxed first and the width is
%    inspected as suggested by Joseph).\fmi{Think about a better
%    implementation at some point.}
%  \changes{v0.8q}{2024/09/02}{}
%    \begin{macrocode}
    \cs_set_eq:NN \@@_item_everypar: \@@_item_everypar_first:
%    \end{macrocode}
%    
%    \begin{macrocode}
  \@@_debug_typeout:n{template:list:std~end}
}
%    \end{macrocode}
%
%    The message that is used above when we are left with keys that
%    are unknown:
%    \begin{macrocode}
\msg_new:nnnn { block } { unknown-keys }
  { Some~ keys~ specified~ on~ the~ #1~ are~ unknown. }
  {
    The~ following~ keys~ are~ unknown~ and~ their~
    values~ are~ ignored:\\
    \space\space #2\\
    Perhaps~ a~ misspelling~ or~ the~ current~ template~
    instance~ uses~ special~ keys.
  }
%    \end{macrocode}
%    
%
%    Extra keys to support enumitem conventions:
%    \begin{macrocode}
\keys_define:nn { template/list/std }
{
  ,nosep .code:n =
    \dim_zero:N \itemsep
    \dim_zero:N \parsep
    \dim_zero:N \topsep
    \dim_zero:N \l_@@_botsep_skip
    \dim_zero:N \l_@@_parbotsep_skip
  ,midsep    .skip_set:N = \topsep 
}
%    \end{macrocode}
%
%  \end{template}
%
%
% \subsubsection{Implementation of \tn{item} template(s)}
%
%
%
% \begin{template}{item std}
%   The item template has one hidden key \key{label} which is not available on the
%    template for setting because it is only used to receive any
%    optional data passed to the \tn{item} command. We therefore
%    declare it with \cs{keys_define:nn} and ensure that the optional
%    argument data to \tn{item} (if it is not a key/value list
%    already) is passed to this \key{label} key.
%    \begin{macrocode}
\keys_define:nn { template/item/std }
                { label .tl_set:N = \l_@@_label_given_tl }
%    \end{macrocode}
%
% \fmi{alignment is mostly wrong (test short medium and multiline
% labels)}
%    \begin{macrocode}
\DeclareTemplateCode{item}{std}{1}
  {
    counter-label   = \@@_counter_label:n ,
    counter-ref     = \@@_counter_ref:n ,
%    \end{macrocode}
%    \fmi{next set of key not yet used}
%    \begin{macrocode}
    label-ref       = \@@_label_ref:n ,
    label-autoref   = \@@_label_autoref:n ,
    label-format    = \@@_label_format:n ,
    label-strut     = \l_@@_label_strut_bool ,
    label-boxed     = \l_@@_label_boxed_bool ,
    next-line       = \l_@@_next_line_bool ,
    text-font       = \l_@@_text_font_tl ,
    compatibility   = \l_@@_item_compatibility_bool ,
%    \end{macrocode}
%    This probably needs a different implementation (and needs completing)\fmi{complete}
%    \begin{macrocode}
    label-align     = {
      left    = \tl_set:Nn \l_@@_item_align_tl { \relax \hss } ,
      center  = \tl_set:Nn \l_@@_item_align_tl { \hss \hss } ,
      right   = \tl_set:Nn \l_@@_item_align_tl { \hss \relax } ,
      parleft = \NOT_IMPLEMENTED ,
    } ,
  }
%    \end{macrocode}
% Then typeset the label at its natural width by applying
% \cs{@@_make_label_box:n} to the label given or to a label constructed
% from the counter.  If it is boxed and reasonably short, add padding to
% make it at least of size \tn{labelwidth}, then add another layer of
% box.  This way, when we unpack it in \cs{g_@@_labels_box} it correctly
% remains boxed in those cases.  Afterwards, in the \keyvalue{nextline}
% case add \tn{newline} if the label did not fit in the allotted space.
%    \begin{macrocode}
  {
    \@@_debug_typeout:n{template:item:std}
%    \end{macrocode}
%    
%    First deal with the key--value input, which in particular may
%    provide a value for the label (the usual optional argument of
%    \tn{item}). For this we set \cs{l_@@_label_given_tl} to
%    \cs{c_novalue_tl} so that we can identify if an optional argument
%    was given.
%    \begin{macrocode}
    \tl_set_eq:NN \l_@@_label_given_tl \c_novalue_tl
%    \end{macrocode}
%    First we evaluate and set any keys specified on the list
%    environment by calling
%    \cs{@@_evaluate_saved_user_keys:nn}. Then we do the same
%    with all keys specified on this \tn{item} command (which may
%    overwrite one or the other setting just made).
%  \changes{v0.8s}{2024/10/03}{Use \cs{@@_evaluate_saved_user_keys:nn}
%            to make use of user keys on the list level}
%    \begin{macrocode}
    \@@_evaluate_saved_user_keys:nn {item}{std} 
%    \end{macrocode}
%    We don't care whether all of the user keys from the list level have
%    been applied, but those explicitly set on the \cs{item} command
%    should be aplicable, so we generate an error if that isn't the case:
    %    \begin{macrocode}
    \SetKnownTemplateKeys{item}{std}{#1}
    \tl_if_empty:NF \UnusedTemplateKeys
       {
         \msg_error:nnee { block } { unknown-keys }
             { \noexpand\item command }
             \UnusedTemplateKeys
       }
%    \end{macrocode}
%    
%    If no optional argument was given then \cs{l_@@_label_given_tl}
%    is still equal to \cs{c_novalue_tl} and so we can distinuish
%    that from \verb=\item[]=.
%
%    \begin{macrocode}
    \tl_if_novalue:oTF \l_@@_label_given_tl
      {
%    \end{macrocode}
%    The rest of the code for this template needs work and is both
%    incomplete and partly wrong.\fmi{fix}
%    \begin{macrocode}
        \tl_if_blank:oF \@listctr { \@kernel@refstepcounter \@listctr }
        \bool_if:NTF \l_@@_item_compatibility_bool   % not sure that
                                                     %  conditional
                                                     %  makes sense
          { \@@_make_label_box:n { \MakeLinkTarget[\@listctr]{}%
                                   \@itemlabel } } % TODO ?
          { \@@_make_label_box:n { \MakeLinkTarget[\@listctr]{}%
                                   \@@_counter_label:n { \@listctr } } }
      }
      {
        \@@_debug_typeout:n{item~ with~ optional}
        \@@_make_label_box:n { \l_@@_label_given_tl } }
    \bool_if:nT
      {
        \l_@@_label_boxed_bool
%   TODO: is \linewidth correct?
        &amp;&amp; \dim_compare_p:n
               { \box_wd:N \l_@@_one_label_box &lt;= \linewidth }
      }
      {
        \dim_compare:nNnT
          { \box_wd:N \l_@@_one_label_box } &lt; \labelwidth
          {
            \hbox_set_to_wd:Nnn \l_@@_one_label_box { \labelwidth }
              {
                \exp_after:wN \use_i:nn \l_@@_item_align_tl
%    \end{macrocode}
%    FMi: \LaTeXe{} keeps the label boxed inside (not unboxed). This
%    means that the content stays rigid and does not vary based on
%    glue setting in the line with the label.
%    There are cases where we do want the unboxed version (I think
%    enumitem offers that in some cases too) but it should probably
%    not the default.
%    \begin{macrocode}
%                TODO: customize?
%                \hbox_unpack_drop:N \l_@@_one_label_box
                \box_use_drop:N \l_@@_one_label_box
%    \end{macrocode}
%
%    \begin{macrocode}
                \exp_after:wN \use_ii:nn \l_@@_item_align_tl
              }
          }
%    \end{macrocode}
%    Add another box level to the label box:
%    \begin{macrocode}
       \hbox_set:Nn \l_@@_one_label_box
                    { \box_use_drop:N \l_@@_one_label_box }
      }
    \dim_compare:nNnTF { \box_wd:N \l_@@_one_label_box } &gt; \labelwidth
      { \bool_set_true:N \l_@@_long_label_bool }
      { \bool_set_false:N \l_@@_long_label_bool }
    \hbox_gset:Nn \g_@@_labels_box
      {
        \hbox_unpack_drop:N \g_@@_labels_box
        \skip_horizontal:n { \itemindent - \labelsep - \labelwidth }
        \hbox_unpack_drop:N \l_@@_one_label_box
        \skip_horizontal:n { \labelsep }
        \bool_if:NT \l_@@_next_line_bool
          { \bool_if:NT \l_@@_long_label_bool { \nobreak \hfil \break } }
        % version of \newline inside an hbox that will be unpacked
      }
    % TODO??? FMi what's that?  
    % \skip_set_eq:NN \parsep \l_@@_item_parsep_skip 
%    \end{macrocode}
%    The next setting is for compatibility: The list template sets
%    \tn{listparindent} to zero and otherwise doesn't use it any
%    more. However, in the second argument of a legacy \env{list}
%    envrironment the user may have set it explicitly to some other
%    value and whatever value it had was then used for \tn{parindent}
%    within the list. Now we use its value only if it differs from
%    zero but otherwise use whatever the template instances
%    specify. This gives 99.9\% compatibility for legacy
%    documents. 100\% for definitions using the \env{list} environment
%    and a setting inside, but if the user used \tn{listparindent}
%    within the document, e.g., inside a \env{verse} environment there
%    there is one case in which the setting is ignored, i.e., when it
%    was set back to zero. That's a rather unlikely scenario, but it
%    is not impossible. However, I couldn't think of an approach that
%    circumvents such boundary cases.
%
%  \changes{v0.8w}{2024/11/24}{Only use \tn{listparindent} if it was changed
%    from its default (tagging/767)}
%    \begin{macrocode}
    \dim_compare:nNnF \listparindent = {0pt}
      { \dim_set_eq:NN \parindent \listparindent }
%    \end{macrocode}
%    Placing the list label(s) is done when the paragraph for the
%    \tn{item} is started, which executes \cs{@@_item_everypar:}
%    inside \hook{para/begin}. By default this command does nothing, now we
%    change it to attach the pending label or labels.
%    \begin{macrocode}
    \cs_set_eq:NN \@@_item_everypar: \@@_item_everypar_std:
  }
%    \end{macrocode}
% \end{template}
%
%
%
%  \begin{macro}{\l_@@_item_align_tl}
%    
%    \begin{macrocode}
\tl_new:N \l_@@_item_align_tl
%    \end{macrocode}
%  \end{macro}
%
% \begin{variable}{\l_@@_one_label_box, \g_@@_labels_box}
%   Each label is typeset in \cs{l_@@_one_label_box} to be measured.
%   Once this is ready, it is put (boxed or unboxed) in
%   \cs{g_@@_labels_box}, together with any pending labels (for the case
%   where a list begins just after \tn{item}).  This is an analogue of
%   \LaTeXe{}'s \tn{@labels}, but it is always unboxed before use, to
%   support both boxed and unboxed labels.
%    \begin{macrocode}
\box_new:N \l_@@_one_label_box
\box_new:N \g_@@_labels_box
%    \end{macrocode}
% \end{variable}
%
% \begin{variable}{\l_@@_long_label_bool}
%   Track whether the \cs{l_@@_one_label_box} is larger than
%   \tn{labelwidth}.
%    \begin{macrocode}
\bool_new:N \l_@@_long_label_bool
%    \end{macrocode}
% \end{variable}
%
% \begin{macro}{\@@_make_label_box:n, \@@_label_format:e}
%   Make one label, wrapped in \cs{@@_label_format:n}, with an
%   appropriate \tn{strut} and possibly \tn{makelabel} in compatibility
%   mode (used for the \env{list} environment).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_make_label_box:n #1
  {
    \hbox_set:Nn \l_@@_one_label_box
      {
%    \end{macrocode}
%    If we do tagging then the contents of this box may need to be
%    wrapped into a structure, e.g., \verb=&lt;Lbl&gt;=.
%    \begin{macrocode}
        \__kernel_list_label_begin:
%    \end{macrocode}
%
%    \begin{macrocode}
        \@@_label_format:n
          {
            \bool_if:NT \l_@@_label_strut_bool { \strut }
            \bool_if:NTF \l_@@_legacy_support_bool
                         \makelabel
                         \use:n 
                 {#1}
          }
%    \end{macrocode}
%    And what gets opened also needs closing:
%    \begin{macrocode}
        \__kernel_list_label_end:
      }
  }
%    \end{macrocode}
% \end{macro}
%
%  
%  \begin{macro}{\__kernel_list_label_begin:,
%                \__kernel_list_label_end:}
%    If we aren't doing tagging the kernel hooks do nothing.
%    \begin{macrocode}
\cs_new_eq:NN \__kernel_list_label_begin: \prg_do_nothing:
\cs_new_eq:NN \__kernel_list_label_end:   \prg_do_nothing:
%    \end{macrocode}
%  \end{macro}
%
%
%
% \begin{macro}{\@@_item_everypar:, \@@_item_everypar_std:, \@@_item_everypar_first:}
%    The \cs{@@_item_everypar:} command is executed as part of \hook{para/begin}
%    but most of the time does nothing, i.e., it has the following
%    default definition outside of lists (and most of the time within lists).
%    \begin{macrocode}
\cs_new_eq:NN \@@_item_everypar: \prg_do_nothing:
%    \end{macrocode}
%    
%    \begin{macrocode}
\AddToHook{para/begin}[items]{\@@_item_everypar:}
%    \end{macrocode}
%
%    Note that we have to make sure that the above code is executed
%    after the hook chunk from \pkg{tagpdf} because the latter uses
%    \texttt{@inlabel} to make a decision.
%
%    By the end of the day both should probably move into the kernel
%    hook instead or, better, into sockets.
%    \begin{macrocode}
\DeclareHookRule{para/begin}{items}{after}{tagpdf}
%    \end{macrocode}
%
%
%    What follows is the version that resets various legacy booleans and puts
%    the label box in the right place and finally resets itself to do
%    nothing next time. \cs{@@_item_everypar:} is set to this by the
%    item template so that the next paragraph start runs the code below.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_item_everypar_std: {
    \@@_debug_typeout:n{item~ everypar \on@line }
    \legacy_if_set_false:n { @minipage }
    \legacy_if_gset_false:n { @newlist }
    \legacy_if:nT { @inlabel }
       {
         \legacy_if_gset_false:n { @inlabel }
%    \end{macrocode}
%
%    \begin{macrocode}
         \box_if_empty:NT \g_para_indent_box { \kern - \itemindent }
         \para_omit_indent:
%    \end{macrocode}
%
%    \begin{macrocode}
         \box_use_drop:N \g_@@_labels_box
%    \end{macrocode}
%    After the labels are placed we start a paragraph structure (if
%    appropriate). This is handled in the following kernel hook:
%    \begin{macrocode}
         \__kernel_list_label_after:
%    \end{macrocode}
%
%    \begin{macrocode}
         \penalty \c_zero_int
       }
   \legacy_if:nTF { @nobreak }
       {
         \legacy_if_gset_false:n { @nobreak }
         \int_set:Nn \clubpenalty { 10000 }
       }
       {
         \int_set_eq:NN \clubpenalty \@clubpenalty
%    \end{macrocode}
%    Once the label(s) are typeset and we are past any special
%    \texttt{@nobreak} handling we reset \cs{@@_item_everypar:} to do
%    nothing.
%    \begin{macrocode}
         \cs_set_eq:NN \@@_item_everypar: \prg_do_nothing:
       }
}
%    \end{macrocode}
%
%    This is the definition of \cs{@@_item_everypar:} before the first
%    \tn{item} is encountered.
%  \changes{v0.8q}{2024/09/02}{Call \tn{@noitemerr} if hmode is
%    started before the first item}
%    \begin{macrocode}
\cs_new:Npn \@@_item_everypar_first: {
  \legacy_if:nT { @newlist }  { \@noitemerr }
}
%    \end{macrocode}
%
% \end{macro}
%
%
%  \begin{macro}{\__kernel_list_label_after:}
%    
%    \begin{macrocode}
\cs_new_eq:NN \__kernel_list_label_after: \prg_do_nothing:
%    \end{macrocode}
%  \end{macro}
%
% \begin{variable}{\l_@@_tmpa_skip}
%    \begin{macrocode}
\skip_new:N \l_@@_tmpa_skip
%    \end{macrocode}
% \end{variable}
%
%
%
%
%
%
%
% \begin{variable}{\l_@@_topsepadd_skip, \l_@@_effective_top_skip}
%   Variables equivalent to \LaTeXe{}'s \tn{@topsepadd} and \tn{@topsep}.
%   Roughly equal to a mixture of \texttt{topsep}, \texttt{partopsep},
%   and various \texttt{parskip} at different nesting levels in lists.
%   The code is really elaborate when \texttt{@inlabel} is true.
%    \begin{macrocode}
\skip_new:N \l_@@_topsepadd_skip
\skip_new:N \l_@@_effective_top_skip
%    \end{macrocode}
% \end{variable}
%
%
%
%
%
%
%
%
%
%
%
% \begin{macro}{\item}
%   Here we already have all the building blocks.  Complain in math
%   mode.  Distinguish between first item (do necessary tagging) and
%    later items \cs{@@_inter_item:} to
%   cleanly close what's before, then call \cs{@@_item_instance:n} (which
%   calls \tn{UseInstance}\{item\}\marg{instance}) to prepare the
%   upcoming item: it will be actually inserted only once some later
%   material triggers \tn{everypar}.
%    \begin{macrocode}
\AddToHook{begindocument/before}{
  \RenewDocumentCommand{\item}{ ={label}o }
    {
      \@inmatherr \item
%    \end{macrocode}
%    TODO: Check if test for being outside of a list is sensible
%    \begin{macrocode}
      \cs_if_free:NTF \@@_item_instance:n
        {
          \@latex@error{Lonely~\string\item--perhaps~a~missing~
          list~environment}\@ehc
        }
        {
          \legacy_if:nTF { @newlist }
            {
              \__kernel_list_item_begin:
%    \end{macrocode}
%    The first item of a list also has to change the \texttt{@newlist} switch.
%  \changes{v0.8q}{2024/09/02}{Set \texttt{@newlist} to false after
%    the first \tn{item}}
%    \begin{macrocode}
              \legacy_if_gset_false:n { @newlist }
            }
            { \@@_inter_item: }
%    \end{macrocode}
%    To avoid unnecessary key/val processing we make a quick check if
%    there was an optional argument.
%    \begin{macrocode}
          \tl_if_novalue:nTF {#1}          % avoids reparsing label={}
            { \@@_item_instance:n { } }
            { \@@_item_instance:n {#1} }
%    \end{macrocode}
%    Set the legacy switch that signals that we have a pending item label:
%    \begin{macrocode}
          \legacy_if_gset_true:n { @inlabel }
          \ignorespaces
        }
    }
}
%    \end{macrocode}
% \end{macro}
%
%
% \begin{macro}{\@@_inter_item:}
%   Between items.  If the previous item had no content then we need to
%   trigger \tn{everypar}. Otherwise we simply close the previous item
%   with \tn{par} after removing some horizontal space.  Between items,
%   there is a penalty and some space.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_inter_item: {
  \legacy_if:nT { @inlabel }
                { \indent \par } % case of \item\item
%    \end{macrocode}
%    \tn{par} may have a strange definition and may not get us back to
%    vertical mode in one go, so we better do not treat the next line
%    as an else case to the above conditional (for now).
%    \begin{macrocode}
   \mode_if_horizontal:T { \@@_skip_remove_last:
                           \@@_skip_remove_last: \par }
%    \end{macrocode}
%    End any LI-tag, then start the next LI-tag (if doing tagging):
%    \begin{macrocode}
  \__kernel_list_item_end:
  \__kernel_list_item_begin:
%    \end{macrocode}
%
%    \begin{macrocode}
  \addpenalty \@itempenalty 
  \addvspace \itemsep
}
%    \end{macrocode}
% \end{macro}
%
%
%  \begin{macro}{\__kernel_list_item_begin:,
%                \__kernel_list_item_end:}
%    
%    \begin{macrocode}
\cs_new_eq:NN \__kernel_list_item_begin: \prg_do_nothing:
\cs_new_eq:NN \__kernel_list_item_end:   \prg_do_nothing:
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
%
% \subsection{Tagging support commands}
%
% In this section we provide code to the various kernel hooks to support
% the tagging of different displayblock environments. 
% 
%    All of the following definitions should only be made if tagging
%    is active!
%    \begin{macrocode}
\tag_if_active:TF {
%    \end{macrocode}
%
%  \begin{macro}{\@@_beginpar_vmode:}
%    When a block starts out in vertical mode, i.e., is not yet part of
%    a paragraph, we have to start a paragraph
%    structure. However, this is not the case if we are already
%    flattening paragraphs, thus in this case we do nothing.
%    We also do nothing if \texttt{@endpe} is currently true, because
%    that means we are right now just after the end of a
%    \texttt{blockenv} and in the process of looking if we have to end
%    the current \struct{text-unit}, i.e., it is already open.  
%    \begin{macrocode}
  \cs_set:Npn \@@_beginpar_vmode: {
           \@@_debug_typeout:n
              { @endpe = \legacy_if:nTF { @endpe }{true}{false}
                \on@line }
   \legacy_if:nTF { @endpe }
      {
        \legacy_if_gset_false:n { @endpe }
      }
%    \end{macrocode}
%    We test for \texttt{&lt;2} because  the first flattened environment
%    has to surround itself with a \struct{text-unit}. Only any inner ones
%    then have to avoid adding another \struct{text-unit}.
%    \begin{macrocode}
      {
        \int_compare:nNnT \l__tag_block_flattened_level_int &lt; 2
            {
              \__tag_gincr_para_main_begin_int:
              \tag_struct_begin:n
                {
                  tag=\l__tag_para_main_tag_tl,
                  attribute-class=\l__tag_para_main_attr_class_tl,
                }
              \__tag_para_main_store_struct:  
            }
      }
  }
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\@@_beginpar_hmode:N}
%    If the block is already part of a part  of a paragraph, i.e., when it has
%    some text directly in front, then the first thing  to
%    do is to return to vertical mode. However, that should be done
%    without inserting a paragraph end tag, so before calling \tn{par}
%    to do its normal work, we disable paragraph tagging and
%    restarting afterwards again. The argument to this config point
%    simply gobbles the \tn{par} following it in the code above (which
%    is used when there is no tagging going on.
%    \begin{macrocode}
  \cs_set:Npn \@@_beginpar_hmode:N #1
     {
        \tag_mc_end:
        \__tag_gincr_para_end_int:
        \@@_debug_typeout:n{increment~ /P \on@line }
        \bool_if:NT \l__tag_para_show_bool
          { \tag_mc_begin:n{artifact}
            \rlap{\color_select:n{red}\tiny\ \int_use:N\g__tag_para_end_int}
            \tag_mc_end:
          }
        \tag_struct_end:
        \tagpdfparaOff \par \tagpdfparaOn
     }
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\__kernel_displayblock_doendpe:}
%    If a display block ends and is followed by a blank line we have to end the
%    enclosing paragraph tagging structure.
%    \begin{macrocode}
\cs_set:Npn \__kernel_displayblock_doendpe: {
     \bool_if:NT \l__tag_para_bool
       {
%    \end{macrocode}
%    Given that restoring \tn{par} through the legacy \LaTeXe{} method
%    can take a few iterations (for example, in case of nested lists,
%    e.g., \verb=...\end{itemize} \item ...\par= it can happen that
%    \cs{__kernel_displayblock_doendpe:} is called while
%    \texttt{@endpe} is already handled and then we should not attempt
%    to close a \struct{text-unit} structure). So we need to check for this.
%    \begin{macrocode}
         \legacy_if:nT { @endpe }
           {
%    \end{macrocode}
%    If the display block currently ending was \enquote{flattened}
%    (i.e., uses simplified paragraphs that are not tagged by a
%    combination of \struct{text-unit} followed by \struct{text}, but simply
%    with a \struct{text}),
%    then we don't have to do anything, because the \struct{text} is already closed.
%    \begin{macrocode}
             \@@_debug_typeout:n
                { flattened= \bool_if:NTF
                               \l__tag_para_flattened_bool
                               {true}{false}
                  \on@line }
             \bool_if:NF \l__tag_para_flattened_bool
               {
                 \@@_debug_typeout:n{Structure-end~
                   \l__tag_para_main_tag_tl\space
                   after~ displayblock \on@line     }
                 \__tag_gincr_para_main_end_int:      
                 \tag_struct_end: %text-unit
               }
           }
      }
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{para/begin}
%
%    Paragraph tagging is mainly done using the paragraph hooks (will
%    get moved eventually). The default hook setting is not good
%    enough when lists get supported: we need to delay starting the
%    paragraph tagging if we still have to place the list label.
%    We therefore remove the existing hook data and replace it with an
%    augmented version (this will get combined eventually).
%    \begin{macrocode}
\RemoveFromHook{para/begin}[tagpdf]
%    \end{macrocode}
%
%    \begin{macrocode}
\AddToHook{para/begin}[tagpdf]{
  \bool_if:NT \l__tag_para_bool {
%    \end{macrocode}
%    if we are still waiting to typeset the list label we do nothing
%    (the paragraph tagging then happens when the list is finally
%    typeset).
%    \begin{macrocode}
       \legacy_if:nF { @inlabel }
         {
%    \end{macrocode}
%    Otherwise, we start a \struct{text} tag structure but only if we are not
%    starting a paragraph immediately \emph{after} a list, in which
%    case we only start a new MC (because the \struct{text} tag is still open from
%    before the list --- one of the reasons why lists are always put
%    \enquote{inside} paragraphs.
%
%    We do this in a separate command, because it is needed elsewhere too.
%    \begin{macrocode}
           \@@_start_para_structure:n { \PARALABEL }
         }
     }
}
%    \end{macrocode}
%    
%    
%  \begin{macro}{\@@_start_para_structure:n}
%    
%    \begin{macrocode}
\cs_new_protected:Npn \@@_start_para_structure:n #1 {
   \@@_debug_typeout:n
      { @endpe = \legacy_if:nTF { @endpe }{true}{false}
        \on@line }
   \legacy_if:nF { @endpe }
     {
       \bool_if:NF \l__tag_para_flattened_bool
          {
            \__tag_gincr_para_main_begin_int:
            \tag_struct_begin:n
              {
                tag=\l__tag_para_main_tag_tl,
                attribute-class=\l__tag_para_main_attr_class_tl,
              }
            \__tag_para_main_store_struct:  
          }
      }
   \__tag_gincr_para_begin_int:
   \@@_debug_typeout:n{increment~ P \on@line }
   \tag_struct_begin:n
       {
          tag=\l__tag_para_tag_tl
         ,attribute-class=\l__tag_para_attr_class_tl
       }
   \__tag_check_para_begin_show:nn {green}{#1}    
   \tag_mc_begin:n {}
}
%    \end{macrocode}
%    The same code, but without testing \texttt{@endpe}. This is not
%    needed in the standalone  case and wrong inside lists.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_start_para_structure_unconditionally:n #1 {
   \bool_if:NF \l__tag_para_flattened_bool
       {
         \__tag_gincr_para_main_begin_int:
         \tag_struct_begin:n
           {
             tag=\l__tag_para_main_tag_tl,
             attribute-class=\l__tag_para_main_attr_class_tl,
           }
         \__tag_para_main_store_struct:  
       }
   \__tag_gincr_para_begin_int:
   \@@_debug_typeout:n{increment~ P \on@line }
   \tag_struct_begin:n
       {
          tag=\l__tag_para_tag_tl
         ,attribute-class=\l__tag_para_attr_class_tl
       }
   \__tag_check_para_begin_show:nn {green}{#1}    
   \tag_mc_begin:n {}
}
%    \end{macrocode}
%  \end{macro}
%    
%    \begin{macrocode}
\RemoveFromHook{para/end}[tagpdf]
\AddToHook{para/end}
  {
    \bool_if:NT \l__tag_para_bool
      {
        \__tag_gincr_para_end_int:
        \@@_debug_typeout:n{increment~ /P \on@line }
        \tag_mc_end:
        \__tag_check_para_end_show:nn {red}{}
        \tag_struct_end:
        \bool_if:NF \l__tag_para_flattened_bool
         {
           \__tag_gincr_para_main_end_int:
           \tag_struct_end:
         }
      }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\def\PARALABEL{NP-}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\para_end:}
%    If we see a \tn{par} in vmode and a \struct{text-unit} is still open
%    we need to close that. For this we check if a request for
%    \text{@endpe} was made (but the \tn{par} redefinition got lost
%    due to (bad?) coding).
%    \begin{macrocode}
\cs_set_protected:Npn \para_end: {
  \scan_stop:
  \mode_if_horizontal:TF {
    \mode_if_inner:F {
         \tex_unskip:D
         \hook_use:n{para/end}
         \@kernel@after@para@end
         \mode_if_horizontal:TF {
           \if_int_compare:w 11 = \tex_lastnodetype:D
             \tex_hskip:D \c_zero_dim
           \fi:
           \tex_par:D
           \hook_use:n{para/after}
           \@kernel@after@para@after
         }
         { \msg_error:nnnn { hooks }{ para-mode }{end}{horizontal} }
    }
  }
  {
    \__kernel_endpe_vmode:       % should do nothing if no tagging
    \tex_par:D
  }
}
\cs_set_eq:NN \par     \para_end:
\cs_set_eq:NN \@@par   \para_end:
\cs_set_eq:NN \endgraf \para_end:
%    \end{macrocode}
%
%  \end{macro}
%
%
%  \begin{macro}{\begin}
%    We need to do a little more than canceling \texttt{@endpe} now.
%    \begin{macrocode}
\DeclareRobustCommand*\begin[1]{%
  \UseHook{env/#1/before}%
  \@ifundefined{#1}%
    {\def\reserved@a{\@latex@error{Environment~#1~undefined}\@eha}}%
    {\def\reserved@a{\def\@currenvir{#1}%
        \edef\@currenvline{\on@line}%
        \@execute@begin@hook{#1}%
        \csname #1\endcsname}}%
  \@ignorefalse
  \begingroup
    \__kernel_endpe_vmode:
    \reserved@a}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\__kernel_endpe_vmode:}
%    Close an open \struct{text-unit} if \texttt{@endpe} is true and we
%    are in vmode. Used in \cs{para_end:} and \tn{begin}.
%    \begin{macrocode}
\cs_new:Npn \__kernel_endpe_vmode: {
    \if@endpe \ifvmode
      \bool_if:NT \l__tag_para_bool
	{
	  \bool_if:NF \l__tag_para_flattened_bool
	   {
	     \__tag_gincr_para_main_end_int:
	     \tag_struct_end:
	   }
	   \@endpefalse
	}
    \fi \fi
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\__kernel_list_label_after:}
%    If starting the text-unit/text tags got delayed because of a pending label we
%    have to do it after the label got typeset
%    \begin{macrocode}
\cs_set:Npn \__kernel_list_label_after: {
   \bool_if:NT \l__tag_para_bool
     {
       \@@_start_para_structure_unconditionally:n { LI- }
     }
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\@@_inner_begin:}
%    Start a block that has an inner structure if it isn't also a list.
%    \begin{macrocode}
\cs_new:Npn \@@_inner_begin: {
  \tagstructbegin{tag=\l_@@_tag_inner_tag_tl}
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\@@_inner_end:}
%    End a block (which isn't also a list).
%    \begin{macrocode}
\cs_new:Npn \@@_inner_end: {
  \@@_debug_typeout:n{block-end \on@line}
  \legacy_if:nT { @endpe }
    {
      \__tag_gincr_para_main_end_int:
      \@@_debug_typeout:n{close~ /text-unit \on@line}
      \tagstructend
    }
  \tagstructend        % end inner structure
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
%
% \subsubsection{List tags}
%
%
%    \begin{macrocode}
\tl_new:N  \l__tag_L_tag_tl
\tl_set:Nn \l__tag_L_tag_tl {L}

\tl_new:N\l__tag_L_attr_class_tl
\tl_set:Nn \l__tag_L_attr_class_tl {list}
%    \end{macrocode}
%    
%    \begin{macrocode}
\tag_if_active:T
{
  \tagpdfsetup
      {
        role/new-attribute = {itemize}
                             {/O /List /ListNumbering/Unordered},
        role/new-attribute = {enumerate}
                             {/O /List /ListNumbering/Ordered},        
        role/new-attribute = {description}
                             {/O /List /ListNumbering/Description},
%    \end{macrocode}
%    Initially, we had \texttt{/None} for the basic \env{list}
%    environment, but that is not allowed in PDF/UA-2 if the list
%    contains any Lbl tags. So now we default to
%    \texttt{Unordered}.
%    \begin{macrocode}
        % default if unknown
        role/new-attribute = {list}{/O /List /ListNumbering/Unordered},    
      }
}
%    \end{macrocode}
%    
%    \begin{macrocode}
\def\LItag{LI}
%    \end{macrocode}
%
%  \begin{macro}{\@@_list_begin:}
%    Start a list \ldots
%    \begin{macrocode}
\cs_set:Npn \@@_list_begin: {
  \tagstructbegin
      {
         tag=\l__tag_L_tag_tl
        ,attribute-class=\l__tag_L_attr_class_tl
      }
}
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\@@_list_item_begin:}
%    Start tagging a list item.
%    \begin{macrocode}
\cs_set:Npn \@@_list_item_begin: { \tagstructbegin{tag=\LItag} }
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\__kernel_list_label_begin:}
%    A list label needs a \struct{Lbl} structure tag and an MC.
%    \begin{macrocode}
\cs_set:Npn \__kernel_list_label_begin: {
%
% FMi: this needs a different logic to decide when to make the label
%    an artifact (after cleaning up the \item code  ), therefore
%    disabled for now
%  \tl_if_empty:oTF \@itemlabel
%     {
%       \tag_mc_begin:n {artifact}
%     }
%     {
       \tagstructbegin{tag=Lbl}
       \tagmcbegin{tag=Lbl}
%     }
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\__kernel_list_label_end:}
%    And when we are done with the label we have to close the MC and
%    the \struct{Lbl} structure. We then start the \struct{LBody}. The
%    material inside will be \enquote{paragraph} text and the tagging
%    for that is handled by the normal para tagging. 
%    \begin{macrocode}
\cs_set:Npn \__kernel_list_label_end: {
  \tagmcend                                    % end mc-Lbl or artifact
% FMi: unconditionally for now
%  \tl_if_empty:oF \@itemlabel
         \tagstructend   % end   Lbl
  \tagstructbegin{tag=\LBody}
}
\def\LBody{LBody}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\@@_list_item_end:}
%    When a list item ends we have to close \struct{LBody} and
%    \struct{LI} but also a \struct{text} in the special case that the
%    item material ends in a list (identifiable via \texttt{@endpe}).
%    \begin{macrocode}
\cs_set:Npn \@@_list_item_end: {
  \legacy_if:nT { @endpe }
    {
      \__tag_gincr_para_main_end_int:
      \tagstructend                           % text-unit
%      \@@_debug_typeout:n{Structure-end~ P~ at~ item-end \on@line }
    }
  \tagstructend \tagstructend   % end LBody, LI
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\@@_list_end:}
%    Finally, at the list end we have to close the open
%    \struct{LBody}, \struct{LI}, \struct{L}, and possibly a
%    \struct{text} if the last item ends with a list.
%    However, if the user forgot to add an \tn{item} then there will be no
%    \struct{LI} and \struct{LBody} open, so we check for the status
%    of \texttt{@newlist}. The corresponding no-item error was
%    generated earlier outside the tagging code.
%
%    One could argue that it doesn't matter if the tagging is wrong
%    after a \tn{@noitemerr} was issued. However, there is one case
%    where it isn't an error: In the \env{thebibliography}
%    environment (which is internally a list) it is often the case
%    that documents start out with an empty environment, not
%    containing any \tn{bibitem}s. For that reason \tn{@noitemerr} is
%    redefined inside that environment to only produce a warning;
%    hence we have to produce correct tag structures in that case.
%  \changes{v0.8q}{2024/09/02}{Do not close LI and LBody if they
%    never were opened.}
%    \begin{macrocode}
\cs_set:Npn \@@_list_end: {
%    \end{macrocode}
%    If \texttt{@newlist} is true (i.e., when we have an error or warning
%    situation) there is not much to close.
%    \begin{macrocode}
  \legacy_if:nF { @newlist }
    {
      \legacy_if:nT { @endpe }
        {
          \__tag_gincr_para_main_end_int:
          \tagstructend                       % text-unit
          \@@_debug_typeout:n{Structure-end~ P~ at~ list-end \on@line }
        }
      \tagstructend\tagstructend  % end LBody, LI
    }
  \tagstructend               % end L
}
%    \end{macrocode}
%  \end{macro}
%    End of tagging related declarations.
%    \begin{macrocode}
}
%    \end{macrocode}
% These command should have a dummy declaration if tagging is not active
%    \begin{macrocode}
{
  \cs_new:Npn \@@_start_para_structure_unconditionally:n #1 {}
}
%    \end{macrocode}
%
%
%
%  
%
%  
%
%
%
%
%
% \subsection{Tagging recipes}
%
%  \begin{macro}{\@@_recipe_basic:}
%    The \keyvalue{basic} recipe simply ensures that the block is inside
%    a \struct{text-unit} structure and if necessary starts one. When the
%    block ends and is followed by a blank line the \struct{text-unit}
%    structure is closed too, otherwise it remains open and further
%    text starts with just a \struct{text} structure.
%
%    There is otherwise no inner structure so
%    \cs{__kernel_displayblock_begin:} and
%    \cs{__kernel_displayblock_end:} do nothing---blockenvs with inner
%    structure use the \keyvalue{standard} or \keyvalue{list} recipe instead.
%    \begin{macrocode}
\cs_new:Npn \@@_recipe_basic: {
  \cs_set_eq:NN \__kernel_displayblock_beginpar_hmode:w
                                              \@@_beginpar_hmode:N
  \cs_set_eq:NN \__kernel_displayblock_beginpar_vmode:
                                              \@@_beginpar_vmode:
  \let \__kernel_displayblock_begin:          \prg_do_nothing:
  \let \__kernel_displayblock_end:            \prg_do_nothing:
%    \end{macrocode}
%    End environment \tn{par} handling:
%    \begin{macrocode}
  \socket_assign_plug:nn{tagsupport/block-endpe}{on}
}
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\@@_recipe_standalone:}
%    
%    The \keyvalue{standalone} recipe produces a block that ensures that
%    a previous \struct{text-unit} ends and that after the block a new
%    \struct{text-unit} starts.
%    \begin{macrocode}
\cs_new:Npn \@@_recipe_standalone: {
  \cs_set_eq:NN \__kernel_displayblock_beginpar_hmode:w
                                              \prg_do_nothing:
  \cs_set_eq:NN \__kernel_displayblock_beginpar_vmode:
                                              \prg_do_nothing:
  \cs_set_eq:NN \__kernel_displayblock_begin: \@@_inner_begin:
  \cs_set_eq:NN \__kernel_displayblock_end:   \@@_inner_end:
%    \end{macrocode}
%    End environment \tn{par} handling:
%    \begin{macrocode}
  \socket_assign_plug:nn{tagsupport/block-endpe}{off}
%    \end{macrocode}
%    
%    \begin{macrocode}
  \tl_if_empty:NTF \l_@@_tag_name_tl
     { \tl_set:Nn    \l_@@_tag_inner_tag_tl {Sect}            }
     { \tl_set_eq:NN \l_@@_tag_inner_tag_tl \l_@@_tag_name_tl }
}
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\@@_recipe_standard:}
%    The \keyvalue{standard} recipe does the following:
%    \begin{itemize}
%    \item surround the block with a \struct{text-unit} structure if not already in a
%       a \struct{text-unit}. In the latter case end the
%    MC and the \struct{text} but leave the \struct{text-unit} open.
%
%    If we are producing flattened paragraphs, just close any
%    \struct{text} but do not open a \struct{text-unit}.
%
%    \item Then open an new (inner) structure (by default
%    \struct{Figure} but typically the one specified on the instance).
%    \item At the end of the block close the inner structure
%    (\struct{Figure} or explicit one)
%    but leave the \struct{text-unit} open to be either continued or closed due to a
%    following \tn{par}.
%    \end{itemize}
%    \begin{macrocode}
\cs_new:Npn \@@_recipe_standard:
{
  \cs_set_eq:NN \__kernel_displayblock_beginpar_hmode:w
                                              \@@_beginpar_hmode:N
  \cs_set_eq:NN \__kernel_displayblock_beginpar_vmode:
                                              \@@_beginpar_vmode:
  \cs_set_eq:NN \__kernel_displayblock_begin: \@@_inner_begin:
  \cs_set_eq:NN \__kernel_displayblock_end:   \@@_inner_end:
%    \end{macrocode}
%    End environment \tn{par} handling:
%    \begin{macrocode}
  \socket_assign_plug:nn{tagsupport/block-endpe}{on}
%    \end{macrocode}
%    
%    \begin{macrocode}
  \tl_if_empty:NTF \l_@@_tag_name_tl
     { \tl_set:Nn    \l_@@_tag_inner_tag_tl {Figure}          }
     { \tl_set_eq:NN \l_@@_tag_inner_tag_tl \l_@@_tag_name_tl }
} 
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\l_@@_tag_inner_tag_tl}
%    \begin{macrocode}
\tl_new:N \l_@@_tag_inner_tag_tl
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\@@_recipe_list:}
%    The \keyvalue{list} recipe does the following.
%    \begin{itemize}
%    \item It opens a \struct{text-unit}-structure or keeps the current one open (only
%      closing the MC).
%    \item  It then starts a new structure rolemapped to  L-structure
%      and arranges for handling list items, e.g., Li, Lbl and LBody
%      structures.
%    \item At the end it closes open list structures as needed but
%      keeps the \struct{text-unit}-structure open to continue the paragraph after the
%      list, if necessary.
%    \end{itemize}
%    \begin{macrocode}
\cs_new:Npn \@@_recipe_list:
{
  \cs_set_eq:NN \__kernel_displayblock_beginpar_hmode:w
                                              \@@_beginpar_hmode:N
  \cs_set_eq:NN \__kernel_displayblock_beginpar_vmode:
                                              \@@_beginpar_vmode:
  \cs_set_eq:NN \__kernel_displayblock_begin: \@@_list_begin:
  \cs_set_eq:NN \__kernel_displayblock_end:   \@@_list_end:
%    \end{macrocode}
%    The next two lines could be done globally, because they are only
%    called if we do have \tn{item}s, i.e., if we are in a list. It is
%    therefore also not necessary to reset them in other recipes
%    (right now---this may change if we get more templates (like
%    inline lists)). 
%    \begin{macrocode}
  \cs_set_eq:NN \__kernel_list_item_begin:    \@@_list_item_begin:
  \cs_set_eq:NN \__kernel_list_item_end:      \@@_list_item_end:
%    \end{macrocode}
%    End environment \tn{par} handling:
%    \begin{macrocode}
  \socket_assign_plug:nn{tagsupport/block-endpe}{on}
%    \end{macrocode}
%
%    Handle the tag name and attribute classes using the key values
%    from the current list instance.
%    \begin{macrocode}
  \tl_if_empty:NTF \l_@@_tag_name_tl
     { \tl_set:Nn    \l__tag_L_tag_tl {L}               }
     { \tl_set_eq:NN \l__tag_L_tag_tl \l_@@_tag_name_tl }
  \tl_if_empty:NTF \l_@@_tag_class_tl
     { \tl_set:Nn    \l__tag_L_attr_class_tl {}                 }
     { \tl_set_eq:NN \l__tag_L_attr_class_tl \l_@@_tag_class_tl }
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
% \section[Implementation of document-level block environments]
%         {Implementation of document-level block\\ environments}
%
%    Most such environments are pretty simple: they take an optional
%    argument and call a \texttt{blockenv} instance to do the work. At
%    the end of environment we call \tn{endblockenv} to finish.
%
%
% \subsection{Displayblock environments}
%
%
%    There are two basic block environment which are similar to
%    \LaTeXe{}'s \env{trivlist} except that there aren't degenerated
%    lists and thus have no hidden \tn{item} inside.
%
%
%  \begin{environment}{displayblock}
%    
%    \begin{macrocode}
\NewDocumentEnvironment{displayblock}{ !O{} }
  { \UseInstance{blockenv}{displayblock} {#1} }
  { \endblockenv }
%    \end{macrocode}
% \end{environment}
%
%
%  \begin{environment}{displayblockflattened}
%    
%    \begin{macrocode}
\NewDocumentEnvironment{displayblockflattened}{ !O{} }
  { \UseInstance{blockenv}{displayblockflattened} {#1} }
  { \endblockenv }
%    \end{macrocode}
%  \end{environment}
%
%
%
%
% \subsection{The \env{center}, \env{flushleft}, and \env{flushright}  environments}
%
%
%
%  \begin{environment}{center,flushleft,flushright}
%    
%    \begin{macrocode}
\AddToHook{begindocument/before}{
  \RenewDocumentEnvironment{center} { !O{} }
  { \UseInstance{blockenv}{center}{#1} }
  { \endblockenv }
%    \end{macrocode}
%
%    \begin{macrocode}
  \RenewDocumentEnvironment{flushright} { !O{} }
  { \UseInstance{blockenv}{flushright}{#1} }
  { \endblockenv }
%    \end{macrocode}
%
%    \begin{macrocode}
  \RenewDocumentEnvironment{flushleft} { !O{} }
  { \UseInstance{blockenv}{flushleft}{#1} }
  { \endblockenv }
}
%    \end{macrocode}
%  \end{environment}
%
%
%
% \subsection{Display quote environments}
%
%
%  \begin{environment}{quote,quotation}
%    
%    \begin{macrocode}
\AddToHook{begindocument/before}{
  \RenewDocumentEnvironment{quote}{ !O{} }
    { \UseInstance{blockenv}{quote} {#1} }
    { \endblockenv }
%    \end{macrocode}
%    
%    \begin{macrocode}
  \RenewDocumentEnvironment{quotation}{ !O{} }
    { \UseInstance{blockenv}{quotation} {#1} }
    { \endblockenv }
}
%    \end{macrocode}
% \end{environment}
%
%
%
%
%
%
% \subsection{Verbatim environments}
%
%
%  \begin{environment}{verbatim,verbatim*}
%    
%    \begin{macrocode}
\AddToHook{begindocument/before}{
  \RenewDocumentEnvironment{verbatim}{ !O{} }
    { \UseInstance{blockenv}{verbatim} {#1}
%    \end{macrocode}
%    This is the part of the code where \env{verbatim}
%    and\env{verbatim*} differ.
%    \begin{macrocode}
      \@setupverbinvisiblespace\frenchspacing\@vobeyspaces
      \@xverbatim
    }
    { \endblockenv }
%    \end{macrocode}
%    
%    \begin{macrocode}
  \RenewDocumentEnvironment{verbatim*}{ !O{} }
    { \UseInstance{blockenv}{verbatim} {#1}
      \@setupverbvisiblespace\frenchspacing\@vobeyspaces
      \@sxverbatim
    }
    { \endblockenv }
}
%    \end{macrocode}
% \end{environment}
%
%
%
% \subsubsection{Helper commands for verbatim}
%
%
%  \begin{macro}{\legacyverbatimsetup}
%
%    This code resembles the \LaTeXe{} verbatim implementation with a
%    slight twist: in \LaTeXe{} each code line was a paragraph using
%    \tn{leftskip}=\tn{@totalleftmargin}. This was possible because
%    the whole environment was implemented as a trivlist. As this is
%    no longer the case setting \tn{leftskip} would alter the layout
%    of a surrounding list. So instead we need to make sure that the
%    paragraph end is executed in a group so that any parshape setup
%    is preserved.
% \changes{v0.8x}{2025/01/12}{flattened para inside verbatim using codeline tag}   
%    \begin{macrocode}
%&lt;@@=&gt;  
\def\legacyverbatimsetup{%
  \language\l@nohyphenation
  \@tempswafalse
  \def\par{%
    \if@tempswa
      \leavevmode \null {\@@par}\penalty\interlinepenalty
    \else
      \@tempswatrue
      \ifhmode{\@@par}\penalty\interlinepenalty\fi
    \fi}%
  \let\do\@makeother \dospecials
  \obeylines \verbatim@font \@noligs
  \everypar \expandafter{\the\everypar \unpenalty}%
%    \end{macrocode}
%    
%    \begin{macrocode}
  \tl_set:Nn \l__tag_para_tag_tl {codeline}
}
%&lt;@@=block&gt;  
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\@setupverbinvisiblespace}
%    In the \pdfTeX{} engine we need to use \tn{pdffakespace} chars
%    for the invisible spaces.
%    \begin{macrocode}
\newcommand\@setupverbinvisiblespace{}
\tag_if_active:T {
  \bool_if:NF\g__tag_mode_lua_bool
   {
     \renewcommand\@setupverbinvisiblespace
         {\def\@xobeysp{\nobreakspace\pdffakespace}}
   }
}
%    \end{macrocode}
%  \end{macro}
%
%
% \subsection{Standard list environments}
%
%
% \begin{environment}{itemize,enumerate,description}
%
%    For the standard lists everything is managed by the blockenv instance.
%    \begin{macrocode}
\AddToHook{begindocument/before}{
  \RenewDocumentEnvironment{itemize}{!O{}}
    { \UseInstance{blockenv}{itemize} {#1} }
    { \endblockenv }
%    \end{macrocode}
%
%    \begin{macrocode}
  \RenewDocumentEnvironment{enumerate}{!O{}}
    { \UseInstance{blockenv}{enumerate} {#1} }
    { \endblockenv }
%    \end{macrocode}
%
%    \begin{macrocode}
  \RenewDocumentEnvironment{description}{!O{}}
    { \UseInstance{blockenv}{description} {#1} }
    { \endblockenv }
}
%    \end{macrocode}
% \end{environment}
%
%
% \subsection{verse environment}
%
%  \begin{environment}{verse}
%  The verse environment has not special tagging currently. It is
%  defined as a simple standard list and takes the tagging from there.
%  But it must be redefined so that \tn{itemindent} is correctly set.
%    \begin{macrocode}
\AddToHook{begindocument/before}{
  \RenewDocumentEnvironment{verse}{ !O{} }
    { 
      \let\\\@centercr
      \UseInstance{blockenv}{list} 
        {
          item-indent=-1.5em,
          parindent=-1.5em,
          item-skip=0pt,
          rightmargin=\leftmargin,
          leftmargin=\leftmargin+1.5em,
          #1
         }
      \item\relax    
    }
    { \endblockenv }
  }   
%    \end{macrocode}
% \end{environment}
%
%
% \begin{environment}{list}
%
%    The legacy 2e list environment is more complicated as we have to get the
%    extra arguments accounted for.
%    \begin{macrocode}
\AddToHook{begindocument/before}{
  \RenewDocumentEnvironment{list}{O{} m m }
    {
%    \end{macrocode}
%    We do this by storing them away and then call the list
%    instance. Inside this instance the \key{setup-code} key
%    contains \tn{legacylistsetupcode}, which makes use of the stored values.
%  \changes{v0.8v}{2024/10/11}{Update \tn{@itemlabel} in
%    \cs{l_@@_legacy_env_params_tl} and not at the start of the
%    environment (tagging/730)}
%    \begin{macrocode}
      \tl_set:Nn \l_@@_legacy_env_params_tl
         {
           \tl_set:Nn \@itemlabel {#2}
           #3
         }
%    \end{macrocode}
%
%    \begin{macrocode}
      \UseInstance{blockenv}{list} {#1}
    }
    { \endblockenv }
}
%    \end{macrocode}
%
% \end{environment}
%
%
%
%  \begin{macro}{\legacylistsetupcode}
%    
%    And here is the extra code for use in the list instance setup
%    inside the key \key{setup-code}.
%    \begin{macrocode}
\cs_new:Npn \legacylistsetupcode {
%    \end{macrocode}
%    Reset values to defaults:
%    \begin{macrocode}
    \dim_zero:N \listparindent
    \dim_zero:N \rightmargin
    \dim_zero:N \itemindent
%    \end{macrocode}
%    
%    By default a \env{list} environment is not numbered, but this
%    happens already in the block template.
%  \changes{v0.8v}{2024/10/11}{Set the defaults for \tn{@itemlabel},
%    \tn{@listctr} and \texttt{@nmbrlist} early in the block code
%    before the setup code gets executed (tagging/730)}
%    \begin{macrocode}
%    \tl_set:Nn \@listctr {}
%    \legacy_if_set_false:n { @nmbrlist } % needed if lists are nested
%    \end{macrocode}
%    By default there is a simple definition for \tn{makelabel}. It can be
%    overwritten in the second mandatory argument to the list
%    environment (stored in \cs{l_@@_legacy_env_params_tl}) and 
%    is used if the instance sets the compatibility key to true.
%    \begin{macrocode}
   \let\makelabel\@mklab % TODO: customize
%    \end{macrocode}
%    Now we use the argument with parameter settings to update some or
%    all of the above defaults:
%    \begin{macrocode}
   \l_@@_legacy_env_params_tl
%    \end{macrocode}
%    As we don't know much about this list we can only make a guess about
%    the nature of the list and the setting of the tag name (default
%    \keyvalue{list} rolemapped to \struct{L}) and any tag attributes
%    may have to be overwritten in the optional key/value argument.
%    But we do have some hints to play with.
%    \begin{macrocode}
    \legacy_if:nTF { @nmbrlist }
      { \tl_set:Nn \l__tag_L_attr_class_tl {enumerate} }   % numbered list
      { \tl_if_empty:NTF \@itemlabel
          { \tl_set:Nn \l__tag_L_attr_class_tl {list}    } % no label
          { \tl_set:Nn \l__tag_L_attr_class_tl {itemize} } % unnumbered,
                                                           %   unordered
      }
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\l_@@_legacy_env_params_tl}
%    
%    \begin{macrocode}
\tl_new:N\l_@@_legacy_env_params_tl
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{environment}{trivlist}
%    \fmi{Replace with code not using \tn{list}}
%    \begin{macrocode}
\AddToHook{begindocument/before}{
  \RenewDocumentEnvironment{trivlist}{ !O{} }
                           { \list[#1]{}
                             {
                               \dim_zero:N \leftmargin
                               \dim_zero:N \labelwidth
                               \cs_set_eq:NN \makelabel \use:n
                             }
                           }
    { \endblockenv }
}
%    \end{macrocode}
%  \end{environment}
%
%
% \subsection{Theorem-like environments}
%
% Theorem-like environments are defined in \LaTeX{} with the help of
% \tn{newtheorem} declarations. Internally they used a list with a
% single item. Using lists was convenient back then, but in a tagged
% document you end up with a strange structure. We therefore alter the
% mechanism.
%
%
%  \begin{macro}{\newtheorem}
%    This is a slightly streamlined version of \tn{newtheorem}, but it
%    still uses a lot of the 2e code for now. Eventually this will change.
%    \begin{macrocode}
\RenewDocumentCommand \newtheorem { m O{#1} m o }
{
  \expandafter\@ifdefinable\csname #1\endcsname
    {
      \str_if_eq:nnTF{#1}{#2}
         {
           \@definecounter {#2}
           \IfNoValueTF {#4}
             {  % @ynthm
               \tl_gset:ce { the #2 }
                  {
                    \@thmcounter{#2}
                  }
             }
             {  % @xnthm
               \@newctr{#1}[#4]
               \tl_gset:ce { the #2 }
                  {
                    \expandafter\noexpand\csname the#4\endcsname
                    \@thmcountersep
                    \@thmcounter{#2}
                  }
             }
         }
         {  % @othm
           \@ifundefined{c@#2}
              { \@nocounterr{#2} }
              {
                \tl_gset:cn { the #1 }
                   { \UseName { the #2 } }
              }
         }
      \global\@namedef{#1}   { \@thm{#2}{#3} }
      \global\@namedef{end#1}{ \@endtheorem  }
    }
}
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\@thm}
%  \tn{@thm} executes \tn{refstepcounter} too early for hyperref
%  and structure destinations: the generated target is outside the structure
%  and can be separated from the theorem by a page break. We therefore move
%  the anchor setting into \tn{@begintheorem}. \tn{@begintheorem} doesn't
%  currently get the name of the counter as argument, so we store it in variable
%  for now, to be able to pass it along.
%    \begin{macrocode}
\tl_new:N \l_@@_thm_current_counter_tl
\def\@thm#1#2{%
  \@kernel@refstepcounter{#1}
  \tl_set:Nn \l_@@_thm_current_counter_tl{#1}
  \@ifnextchar[{\@ythm{#1}{#2}}{\@xthm{#1}{#2}}}
%    \end{macrocode}
%  To avoid that hyperref overwrites the definition again we must its patch:     
%    \begin{macrocode}
\def\hyper@nopatch@thm{}
%    \end{macrocode}
%  \end{macro}
%  
%  \begin{macro}{\@begintheorem,\@opargbegintheorem}
%
%    The \tn{@thm} command expands to either \tn{@beginthorem} or
%    \tn{@opargbegintheorem}. For the moment we stick with this as it
%    will help with the transition. But instead of using a
%    \env{trivlist} we use a blockenv and some tagging for the title
%    (as a Caption).
%    We do not want potential tagging from \tn{textbf} here,
%    so we use \tn{bfseries} to set the font. The commands set also the link targets
%    which should be inside the main structure.
%    \begin{macrocode}
\def\@begintheorem#1#2{
  \UseInstance{blockenv}{theorem}{}
  \tagpdfparaOff
%    \end{macrocode}
%    
%  \changes{v0.8w}{2024/11/23}{\LaTeXe{} theorems always start out
%    without indentation (tagging/767)}
%    \begin{macrocode}
  \noindent 
  \MakeLinkTarget{\l_@@_thm_current_counter_tl} 
  \tag_struct_begin:n{tag=Caption}
   \group_begin:
   \bfseries
   \tag_mc_begin:n {}
     #1\ 
   \tag_mc_end:
    \tag_struct_begin:n{tag=Lbl}
      \tag_mc_begin:n {}
          #2
      \tag_mc_end:
    \tag_struct_end:          
    \group_end:
  \tag_struct_end:
  \tagpdfparaOn
%    \end{macrocode}
%    
%    \begin{macrocode}
  \@@_start_para_structure_unconditionally:n { \PARALABEL }
%    \end{macrocode}
%    
%    \begin{macrocode}
  \itshape
  \hskip\labelsep
  \ignorespaces
}
\def\@opargbegintheorem#1#2#3{
  \UseInstance{blockenv}{theorem}{}
  \tagpdfparaOff
%    \end{macrocode}
%    
%  \changes{v0.8w}{2024/11/23}{\LaTeXe{} theorems always start out
%    without indentation (tagging/767)}
%    \begin{macrocode}
  \noindent 
  \MakeLinkTarget{\l_@@_thm_current_counter_tl}
  \tag_struct_begin:n{tag=Caption}
   \group_begin:
   \bfseries 
   \tag_mc_begin:n {}
      #1\
   \tag_mc_end:
   \tag_struct_begin:n{tag=Lbl}
     \tag_mc_begin:n {}
       #2
     \tag_mc_end:
   \tag_struct_end:
     \tag_mc_begin:n {}
      \ (#3)
     \tag_mc_end:
   \group_end:  
  \tag_struct_end:  
  \tagpdfparaOn
%    \end{macrocode}
%    
%    \begin{macrocode}
  \@@_start_para_structure_unconditionally:n { \PARALABEL }
%    \end{macrocode}
%    
%    \begin{macrocode}
  \itshape
  \hskip\labelsep
  \ignorespaces
}
%    \end{macrocode}
%    
%    \begin{macrocode}
\def\@endtheorem{\endblockenv}
%    \end{macrocode}
%  \end{macro}
%
%
%
% \section{Instance declarations for environments}
%
% \subsection{Blockenv instances}
%
% The blockenv instances handle overall setup for the document-level
% environments, i.e.,
% \begin{itemize}
%  \raggedright
%  \item name of the environment for debugging purposes (\key{env-name})
%  \item how tagging should be performed (\key{tagging-recipe},
%        \key{tag-name}, \key{tag-class})
%  \item does this environment changes the block level if nested
%        (\key{level-increase})
%  \item any special setup code; normally not used (\key{setup-code})
%  \item what kind of block instance should be used  (\key{block-instance})
%  \item what kind of para instance should be used; empty means
%        inherit from the outside (\key{para-instance})
%  \item are inner paragraphs real paragraphs (default) or are they
%        just \struct{text} structures and part of an outer
%        paragraph (\key{para-flattened}) 
%  \item what kind of inner instance should be used, if any
%        (\key{inner-instance}, \key{inner-instance-type})
%  \item the counter name of the inner level, if any (\key{inner-level-counter})
%  \item supported nesting depth of the inner level, if relevant
%        (\key{max-inner-levels})
%  \item extra code executed at the end, by default \tn{ignorespaces}
%        (\key{final-code})
% \end{itemize}
% The blockenv displayblock instance below shows the full set with
% those using default values being commented out.
%
% \subsubsection{Basic instances}
%
%
%  \begin{instance}{blockenv displayblock}
%    This is like \LaTeXe{}'s \env{trivlist}, i.e., it produces a
%    vertical block with default setting, but doesn't put a list
%    inside but uses a \struct{Figure} structure.
%    \fmi{should this really generate a /Figure structure?}
%    \begin{macrocode}
\DeclareInstance{blockenv}{displayblock}{display}
{
  env-name       = displayblock,
%  tagging-recipe = standard,
%  tag-name       = ,
%  tag-class      = ,
  level-increase = false,
%  setup-code     = ,
%  block-instance = displayblock ,
%  para-instance  = ,
%  para-flattened = false ,
%  inner-instance = ,
%  inner-instance-type = list , % not relevant as there is no inner instance
%  inner-level-counter  = ,     % not relevant as there is no inner instance 
%  max-inner-levels = 4,        % not relevant as there is no inner instance
%  final-code = \ignorespaces ,  
}
%    \end{macrocode}
%  \end{instance}
%
%
%
%
%  \begin{instance}{blockenv displayblockflattened}
%    This flattens inner paragraphs without any surrounding tag
%    structure by using the \keyvalue{basic} tagging recipe.
%    \begin{macrocode}
\DeclareInstance{blockenv}{displayblockflattened}{display}
{
  env-name       = displayblockflattened,
  tag-name       = ,
  tag-class      = ,
  tagging-recipe = basic,
  inner-level-counter  = ,
  level-increase = false,
  setup-code     = ,
  block-instance = displayblock ,
  para-flattened = true ,
  inner-instance = ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%
%
%
% \subsubsection{Center, flushleft, and flushright instances}
%
%  All three environments use the \texttt{displayblock} instance as
%  block instance. They only differ in the choice of para instance. 
%
%  \begin{instance}{blockenv center}
%    The \env{center} environment without using a list internally.
%    \begin{macrocode}
\DeclareInstance{blockenv}{center}{display}
{
  env-name       = center,
  tag-name       = ,
  tag-class      = ,
  tagging-recipe = basic,
  inner-level-counter  = ,
  level-increase = false,
  setup-code     = ,
  block-instance = displayblock ,
  para-flattened = true ,
  para-instance  = center ,
  inner-instance = ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%  \begin{instance}{blockenv flushleft}
%    The \env{flushleft} environment without using a list internally.
%    \begin{macrocode}
\DeclareInstance{blockenv}{flushleft}{display}
{
  env-name       = flushleft,
  tag-name       = ,
  tag-class      = ,
  tagging-recipe = basic,
  inner-level-counter  = ,
  level-increase = false,
  setup-code     = ,
  block-instance = displayblock ,
  para-flattened = true ,
  para-instance  = raggedright ,
  inner-instance = ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%
%  \begin{instance}{blockenv flushright}
%    
%    The \env{flushright} environment without using a list internally.
%    \begin{macrocode}
\DeclareInstance{blockenv}{flushright}{display}
{
  env-name       = flushleft,
  tag-name       = ,
  tag-class      = ,
  tagging-recipe = basic,
  inner-level-counter  = ,
  level-increase = false,
  setup-code     = ,
  block-instance = displayblock ,
  para-flattened = true ,
  para-instance  = raggedleft ,
  inner-instance = ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%
%
% \subsubsection{Blockquote instances}
%

%  \LaTeXe{} has two environments for quoting: \env{quote} and
%  \env{quoation}. By default they differ only in indentation of inner
%  paragraphs. This is handled by using separate block instances.
%
%  The tag names are both roll-mapped to \struct{BlockQuote}.
%
%  \begin{instance}{blockenv quotation}
%    For the \env{quotation} environment:
%    \begin{macrocode}
\DeclareInstance{blockenv}{quotation}{display}
{
  env-name       = quotation,
  tag-name       = quotation,
  tag-class      = ,
  tagging-recipe = standard,
  inner-level-counter  = ,
  level-increase = true,
  setup-code     = ,
  block-instance = quotationblock ,
  inner-instance =  ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%
%  \begin{instance}{blockenv quote}
%    For the \env{quote} environment:
%    \begin{macrocode}
\DeclareInstance{blockenv}{quote}{display}
{
  env-name       = quote,
  tag-name       = quote,
  tag-class      = ,
  tagging-recipe = standard,
  inner-level-counter  = ,
  level-increase = true,
  setup-code     = ,
  block-instance = quoteblock ,
  inner-instance =  ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%
% \subsubsection{The theorem instance}
%
%  \begin{instance}{blockenv theorem}
%    
%   We use \struct{theorem-like} as the structure name and rolemap it
%   to a \struct{Sect} because that can hold a \struct{Caption}.
%
%    
%  \changes{v0.8w}{2024/11/23}{Theorems use their own block-instance
%    and not displayblock to allow for customization (tagging/767)}
%    \begin{macrocode}
\DeclareInstance{blockenv}{theorem}{display}
{
  env-name       = theorem-like,
  tag-name       = theorem-like,
  tag-class      = ,
  tagging-recipe = standalone,
  inner-level-counter  = ,
  level-increase = false,
  setup-code     = ,
  block-instance = theoremblock ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%
% \subsubsection{The verbatim instance}
%
%  \begin{instance}{blockenv verbatim}
%    
%  The rolemapping is \struct{verbatim} to \struct{Code} and
%  \struct{codeline} to \struct{Sub} (which is role mapped 
%  to \struct{Span} in pdf 1.7). Sub inside Code is allowed according
%  the errata of ISO 32005. The paragraphs inside verbatim are flattened.
%  Line numbers should inside the \struct{codeline} structure
%  and be tagged either as \struct{Lbl} or \struct{Artifact}\struct{Lbl}.
%  
% \changes{v0.8x}{2025/01/12}{use flattened para inside verbatim}   
%    \begin{macrocode}
\DeclareInstance{blockenv}{verbatim}{display}
{
  env-name       = verbatim,
  tag-name       = verbatim,
  tag-class      = ,
  tagging-recipe = standard,
  para-flattened = true,
  inner-level-counter  = ,
  level-increase = false,
  setup-code     = ,
  block-instance = verbatimblock ,
  inner-instance = ,
  final-code     = \legacyverbatimsetup ,
  para-instance  = justify
}
%    \end{macrocode}
%  \end{instance}
%
%
% \subsubsection{Standard list instances}
%
%  \begin{instance}{blockenv itemize}
%    For the \env{itemize} environment:
%    \begin{macrocode}
\DeclareInstance{blockenv}{itemize}{display}
{
  env-name       = itemize,
  tag-name       = itemize,
  tag-class      = itemize,
  tagging-recipe = list,
  inner-level-counter  = \@itemdepth,
  level-increase = true,
  max-inner-levels = 4,
  setup-code     = ,
  block-instance = list ,
  inner-instance = itemize ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%  \begin{instance}{blockenv enumerate}
%    
%    For the \env{enumerate} environment:
%    \begin{macrocode}
\DeclareInstance{blockenv}{enumerate}{display}
{
  env-name            = enumerate,
  tag-name            = enumerate,
  tag-class           = enumerate,
  tagging-recipe      = list,
  level-increase      = true,
  setup-code          = ,
  block-instance      = list ,
  inner-level-counter = \@enumdepth,
  max-inner-levels    = 4,
  inner-instance      = enum ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%  \begin{instance}{blockenv description}
%    
%    For the \env{description} environment:
%    \begin{macrocode}

\DeclareInstance{blockenv}{description}{display}
{
  env-name       = description,
  tag-name       = description,
  tag-class      = description,
  tagging-recipe = list,
  inner-level-counter  = ,
  level-increase = true,
  setup-code     = ,
  block-instance = list ,
  inner-instance = description ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%  \begin{instance}{blockenv list}
%    The general (legacy) \env{list} environment does some of its
%    setup in the \key{setup-code} key.
%    \begin{macrocode}
\DeclareInstance{blockenv}{list}{display}
{
  env-name       = list,
  tag-name       = list,
  tag-class      = ,
  tagging-recipe = list,
  level-increase = true,
  setup-code     = \legacylistsetupcode ,
  block-instance = list ,
  inner-level-counter  = ,
  inner-instance = legacy ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%
%
% \subsection{Block instances}
%
%    Below, we declare the different block instances for the
%  document-level environments. Some, such as the displayblock ones
%  are shared between different environments (as long as one doesn't
%  need to adjust individual values), other environments have their
%  own instances (for precisely that reason).
%
% \subsubsection{Displayblock instances}
%  
%    We provide 6 nesting levels (as in \LaTeXe{}). If you want to
%    provide more you need to change the \texttt{maxblocklevels}
%    counter, offer further \texttt{displayblock-xx} instances but
%    also define further (legacy) \tn{list\meta{romannumeral}} commands
%    for the defaults. If not, then the settings from the previous
%    level are reused automatically---which may or may not be good enough).
%    \begin{macrocode}
\setcounter{maxblocklevels}{6}
%    \end{macrocode}
%
%  \begin{instance}{block displayblock-0,
%                   block displayblock-1,
%                   block displayblock-2,
%                   block displayblock-3,
%                   block displayblock-4,
%                   block displayblock-5,
%                   block displayblock-6 }
%
%    Here we need level zero as well in case a flattened displayblock
%    (like the center env) it is used on top-level.
%
%    We show all keys here for reference, with those using their
%    default values commented out:
%    \begin{macrocode}
\DeclareInstance{block}{displayblock-0}{display}
  {
%    heading        = ,                               %??
%    beginsep       = \topsep ,
%    begin-par-skip = \partopsep ,
%    par-skip       = \parsep ,
%    end-skip       = \KeyValue{beginsep} ,
%    end-par-skip   = \KeyValue{begin-par-skip} ,
%    item-skip      = \itemsep ,
%    beginpenalty   = \UseName{@beginparpenalty} ,
%    endpenalty     = \UseName{@endparpenalty} ,
    leftmargin      = 0pt ,
%    rightmargin    = \rightmargin ,
%    parindent      = 0pt ,
  } 
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareInstanceCopy{block}{displayblock-1}{displayblock-0}
\DeclareInstanceCopy{block}{displayblock-2}{displayblock-0}
\DeclareInstanceCopy{block}{displayblock-3}{displayblock-0}
\DeclareInstanceCopy{block}{displayblock-4}{displayblock-0}
\DeclareInstanceCopy{block}{displayblock-5}{displayblock-0}
\DeclareInstanceCopy{block}{displayblock-6}{displayblock-0}
%    \end{macrocode}
%  \end{instance}
%
%
%
% \subsubsection{Verbatim instances}
%
%  Verbatim instances have there own levels so that one can specify
%  specific indentations or vertical separations between line.
%  
%  \begin{instance}{block verbatimblock-0,
%                   block verbatimblock-1,
%                   block verbatimblock-2,
%                   block verbatimblock-3,
%                   block verbatimblock-4,
%                   block verbatimblock-5,
%                   block verbatimblock-6 }
%
%    \begin{macrocode}
\DeclareInstance{block}{verbatimblock-0}{display}
  {
    leftmargin      = 0pt ,
    par-skip        = 0pt ,
  } 
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareInstanceCopy{block}{verbatimblock-1}{verbatimblock-0}
\DeclareInstanceCopy{block}{verbatimblock-2}{verbatimblock-0}
\DeclareInstanceCopy{block}{verbatimblock-3}{verbatimblock-0}
\DeclareInstanceCopy{block}{verbatimblock-4}{verbatimblock-0}
\DeclareInstanceCopy{block}{verbatimblock-5}{verbatimblock-0}
\DeclareInstanceCopy{block}{verbatimblock-6}{verbatimblock-0}
%    \end{macrocode}
%  \end{instance}
%
%
%
%
% \subsubsection{Quote/quotationblock instances}
%
%  Quote and quotation are not flattened, i.e., they change levels,
%    thus they start with level 1 not 0.
%  
%  \begin{instance}{block quoteblock-1,
%                   block quoteblock-2,
%                   block quoteblock-3,
%                   block quoteblock-4,
%                   block quoteblock-5,
%                   block quoteblock-6 }
%    Default layout is to indent equally from both sides.
%    \begin{macrocode}
\DeclareInstance{block}{quoteblock-1}{display}
  { rightmargin = \KeyValue{leftmargin} }
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareInstanceCopy{block}{quoteblock-2}{quoteblock-1}
\DeclareInstanceCopy{block}{quoteblock-3}{quoteblock-1}
\DeclareInstanceCopy{block}{quoteblock-4}{quoteblock-1}
\DeclareInstanceCopy{block}{quoteblock-5}{quoteblock-1}
\DeclareInstanceCopy{block}{quoteblock-6}{quoteblock-1}
%    \end{macrocode}
%  \end{instance}
%  
%
%  
%  \begin{instance}{block quotationblock-1,
%                   block quotationblock-2,
%                   block quotationblock-3,
%                   block quotationblock-4,
%                   block quotationblock-5,
%                   block quotationblock-6 }
%    Quotation additionally changes the parindent.
%    \begin{macrocode}
\DeclareInstance{block}{quotationblock-1}{display}
  { parindent = 1.5em , rightmargin = \KeyValue{leftmargin} }
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareInstanceCopy{block}{quotationblock-2}{quotationblock-1}
\DeclareInstanceCopy{block}{quotationblock-3}{quotationblock-1}
\DeclareInstanceCopy{block}{quotationblock-4}{quotationblock-1}
\DeclareInstanceCopy{block}{quotationblock-5}{quotationblock-1}
\DeclareInstanceCopy{block}{quotationblock-6}{quotationblock-1}
%    \end{macrocode}
%  \end{instance}
%  
%
% \subsubsection{Block instances for the theorems}
%
%  
%  \begin{instance}{block theoremblock-0}
%    Theorems do not support nesting, so we have only one to set up.
%    The \LaTeX{} default reused the general value of \tn{parindent}
%    and \tn{parskip} and, of course, they start at the outer margin.
%  \changes{v0.8w}{2024/11/23}{Add block instance for theorems}
%    \begin{macrocode}
\DeclareInstance{block}{theoremblock-0}{display}
  {
    leftmargin      = 0pt ,
    parindent       = \parindent ,
    par-skip        = \parskip ,
  } 
%    \end{macrocode}
%  \end{instance}
%  
%  
%
% \subsubsection{Block instances for the standard lists}
%
%  \begin{instance}{block list-1,
%                   block list-2,
%                   block list-3,
%                   block list-4,
%                   block list-5,
%                   block list-6 }
%    The block instances for the various list environments use the
%    same underlying instance (well, by default) and nothing 
%    needs to be set up specifically (because that is already done in
%    the legacy \tn{list\meta{romannumeral}} unless a
%    different layout is wanted.
%    \begin{macrocode}
\DeclareInstance{block}{list-1}{display}{
%   heading          = ,                   % unused, might vanish
%   beginsep         = \topsep ,
%   begin-par-skip   = \partopsep ,
%   par-skip         = \parsep ,
%   end-skip         = \KeyValue{beginsep} ,
%   end-par-skip     = \KeyValue{begin-par-skip} ,
%   beginpenalty     = \UseName{@beginparpenalty} ,
%   endpenalty       = \UseName{@endparpenalty} ,
%   leftmargin       = \leftmargin ,
%   rightmargin      = \rightmargin ,
%   parindent        = 0pt ,
}
\DeclareInstance{block}{list-2}{display}{}
\DeclareInstance{block}{list-3}{display}{}
\DeclareInstance{block}{list-4}{display}{}
\DeclareInstance{block}{list-5}{display}{}
\DeclareInstance{block}{list-6}{display}{}
%    \end{macrocode}
%  \end{instance}
%  
%
%  
% \subsection{List instances for the standard lists}
%
%    For all list instances we have to say what kind of label we want
%    (\key{item-label})  and how it should be formatted.
%
%  \begin{instance}{list itemize-1,
%                   list itemize-2,
%                   list itemize-3,
%                   list itemize-4}
%    For \env{itemize} environments this is all we need to do and we
%    refer back to the external definitions rather than defining the
%    \key{item-label} code in the instance to ensure that old
%    documents still work.
%
%    \begin{macrocode}
\DeclareInstance{list}{itemize-1}{std}{ item-label = \labelitemi }
\DeclareInstance{list}{itemize-2}{std}{ item-label = \labelitemii }
\DeclareInstance{list}{itemize-3}{std}{ item-label = \labelitemiii }
\DeclareInstance{list}{itemize-4}{std}{ item-label = \labelitemiv }
%    \end{macrocode}
%  \end{instance}
%  
%  
%  
%  \begin{instance}{list enumerate-1,
%                   list enumerate-2,
%                   list enumerate-3,
%                   list enumerate-4}
%    \env{enumerate} environments are similar, except that we also
%    have to say which counter to use on each level.
%    \begin{macrocode}
\DeclareInstance{list}{enum-1}{std}
  { item-label = \labelenumi ,   counter = enumi }
\DeclareInstance{list}{enum-2}{std}
  { item-label = \labelenumii ,  counter = enumii }
\DeclareInstance{list}{enum-3}{std}
  { item-label = \labelenumiii , counter = enumiii }
\DeclareInstance{list}{enum-4}{std}
  { item-label = \labelenumiv ,  counter = enumiv }
%    \end{macrocode}
%  \end{instance}
%  
%  
%
%  \begin{instance}{list legacy}
%    For the legacy \env{list} environment there is only one instance
%    which is reused on all levels. This is done this way one because
%    the legacy \env{list} environment sets all its
%    parameters through its arguments. So this instances shouldn't
%    really be touched. It sets the \key{legacy-support} key to
%    true, which means that the list code uses \tn{makelabel} for
%    formatting the label 
%    \begin{macrocode}
\DeclareInstance{list}{legacy}{std} {
  item-instance = basic ,
  legacy-support = true ,
}
%    \end{macrocode}
%  \end{instance}
%  
%
%  \begin{instance}{list description}
%    The \env{description} lists also use only a single list instance
%    with only one key not using the default:
%    \begin{macrocode}
\DeclareInstance{list}{description}{std} { item-instance = description }
%    \end{macrocode}
%  \end{instance}
%
%  
% \subsection{Item instances}
%
%
%  \begin{instance}{item basic, item description}
%    There two item instances set up: \keyvalue{description} for use
%    with the \env{description} environment and \keyvalue{basic} for use
%    with all other lists (up to now).
%    \begin{macrocode}
\DeclareInstance{item}{basic}{std}
                { label-align = right }
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareInstance{item}{description}{std}
  {
    label-format = \normalfont\bfseries #1 ,
    label-align = left
  }
%    \end{macrocode}
%  \end{instance}
%
%
%
% \subsection{Para instances}
%
%    \begin{macrocode}
\tag_if_active:T
{
  \tagpdfsetup
      {
        role/new-attribute = {justify}    {/O /Layout /TextAlign/Justify},
        role/new-attribute = {center}     {/O /Layout /TextAlign/Center},
        role/new-attribute = {raggedright}{/O /Layout /TextAlign/Start},
        role/new-attribute = {raggedleft} {/O /Layout /TextAlign/End},
      }
}
%    \end{macrocode}
%
%  \begin{instance}{para center}
%    \begin{macrocode}
\DeclareInstance{para}{center}{std}
{
  para-class            = center ,
  indent-width          = 0pt ,                  
%  start-skip            = 0pt ,
  left-skip             = \@flushglue ,
  right-skip            = \@flushglue ,
  end-skip              = \z@skip ,
  final-hyphen-demerits = 0 ,
  cr-cmd                = \@centercr ,
}
%    \end{macrocode}
%  \end{instance}
%
%  \begin{instance}{para raggedright}
%    \begin{macrocode}
\DeclareInstance{para}{raggedright}{std}
{
  para-class            = raggedright ,
  indent-width          = 0pt ,                  
%  start-skip            = 0pt ,
  left-skip             = \z@skip ,
  right-skip            = \@flushglue ,
  end-skip              = \z@skip ,
  final-hyphen-demerits = 0 ,
  cr-cmd                = \@centercr ,
}
%    \end{macrocode}
%  \end{instance}
%
%  \begin{instance}{para raggedleft}
%    \begin{macrocode}
\DeclareInstance{para}{raggedleft}{std}
{
  para-class            = raggedleft ,
  indent-width          = 0pt ,                  
%  start-skip            = 0pt ,
  left-skip             = \@flushglue ,
  right-skip            = \z@skip ,
  end-skip              = \z@skip ,
  final-hyphen-demerits = 0 ,
  cr-cmd                = \@centercr ,
}
%    \end{macrocode}
%  \end{instance}
%
%  \begin{instance}{para justify}
%    Justifying is exactly what the default values do, so the instance
%    hasn't any special setup.
%    \begin{macrocode}
\DeclareInstance{para}{justify}{std}
{
%  para-class            = justify ,
%  indent-width          = \parindent ,                  
%  start-skip            = 0pt ,
%  left-skip             = \z@skip ,
%  right-skip            = \z@skip ,
%  end-skip              = \@flushglue ,
%  final-hyphen-demerits =  5000 ,
%  cr-cmd                = \@normalcr ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%
%
%  \begin{macro}[no-user-doc]{\centering,\raggedleft,\raggedright,\justifying}
%    
%    \begin{macrocode}
\DeclareRobustCommand\centering  {\UseInstance{para}{center}{}}
\DeclareRobustCommand\raggedleft {\UseInstance{para}{raggedleft}{}}
\DeclareRobustCommand\raggedright{\UseInstance{para}{raggedright}{}}
\DeclareRobustCommand\justifying {\UseInstance{para}{justify}{}}
%    \end{macrocode}
%    
%    \begin{macrocode}
\justifying
%    \end{macrocode}
%  \end{macro}
%
%
%
%  
%
%    \begin{macrocode}
%&lt;/package&gt;
%    \end{macrocode}
%
%
%
%    \begin{macrocode}
%&lt;*latex-lab&gt;
\ProvidesFile{block-latex-lab-testphase.ltx}
        [\ltlabblockdate\space v\ltlabblockversion\space
                            blockenv implementation]
\RequirePackage{latex-lab-testphase-block}
%&lt;/latex-lab&gt;
%    \end{macrocode}
%
% \end{implementation}
%
% \appendix
%
% \section{Documentation from first prototype implementations}
%
%
% \subsection{Open questions}
% \begin{itemize}
% \item Existing questions --- moved to issues ---
% \end{itemize}
%
% \subsection{Code cleanup}
% \begin{itemize}
% \raggedright
% \item Actually implement what's announced.
%
% \item Encapsulate most uses of \cs[no-index]{legacy_if\dots} into
%   commands with \pkg{expl3} syntax: we cannot rename these booleans
%   for compatibility reasons but we can make the code cleaner
%   nevertheless. --- made issue ---
%
% \item The \tn{topsep} and \tn{partopsep} business is tricky to
%   reproduce exactly (see \tn{@topsepadd} and \tn{@topsep}) because of
%   how it accumulates when lists are nested immediately.
%
% \end{itemize}
%
%
%
% \subsection{Tasks}
% \begin{itemize}
%
% \item Change author to LaTeX Team once it's nice enough to deserve
%   that label.
%
% \item Reproducing exactly the standard layouts and examples in the
%   \pkg{enumitem} documentation.
%
% \item Hooks, but do not duplicate those that already exist as
%   environment hooks.  Hence, mostly around items.
%
% \item Customization and interaction with LDB:
%   \begin{itemize}
%   \item Allow arbitrary nesting depth with automatically defined
%     styles for labels, counters etc.
%   \item Adapt everything to font size! (e.g. footnotes).
%   \item How to model the inheritance from trivlist to list to
%     enumerate?
%   \end{itemize}
%
% \item Add key--value settings mimicking \pkg{enumitem}'s ability to
%   set any four of five horizontal parameters and deduce the fifth by
%   $\tn{leftmargin} + \tn{itemindent} = \tn{labelindent} +
%   \tn{labelwidth} + \tn{labelsep}$.
%
% \item Provide good ways to customize how overlong labels are dealt with.
%
% \item Use the \texttt{.aux} file.
%   \begin{itemize}
%   \item Implement the \tn{ref} styles that \pkg{enumitem} provides.
%   \item Reverse enumerations, important in publication lists and the
%     like.  Somehow avoid needing 3 compilations for references to
%     reverse enumerations to settle?
%   \item Ability to calculate \tn{labelwidth} from the label contents.
%     Share calculated parameters between multiple environments (cf.\
%     \texttt{resume} option).
%   \end{itemize}
%
% \item Related to grabbing the whole list environment, and input syntax
%   variations:
%   \begin{itemize}
%   \item Other layouts: tabular (see \pkg{listliketab} vs
%     \pkg{typed-checklist}), multicolumn and horizontally numbered (see
%     \pkg{tasks}), inline lists, runin lists in the easy case where
%     there is no intervening \tn{par}.
%   \item Formatting the item text in a
%     box or similar (requires grabbing the whole list).
%   \item Filtering which items to show: hide certain items according to
%     criteria (useful together with list reuse), see
%     \pkg{typed-checklist}.
%   \item Shorthands \tn{iitem} for automatic nested lists, or \cs{1},
%     \cs{2} etc from \pkg{outlines}.
%   \item Support markdown input like \pkg{asciilist}.
%   \end{itemize}
%
% \item Check interaction with \texttt{babel} options such as
%   \texttt{french} or \texttt{accadian} (see FrenchItemizeSpacing)
%
% \item RTL and vertical typesetting.
% \end{itemize}
%
% \section{Plan of attack of first prototype}
%
% Typesetting list environments involves a rather large number of
% parameters.  They can be affected by the context such as the total
% list nesting level, the nesting level of the given type of list, and
% the font size.  An environment like \texttt{enumerate} has two main
% aspects.
% \begin{itemize}
% \item It has a certain layout in the page, with vertical and
%   horizontal spacing around it.  This type of layout is shared with
%   environments such as \texttt{quote}, \texttt{flushright}, or
%   \texttt{tabbing}.  This common layout is implemented in \LaTeXe{}
%   through \tn{trivlist} (or \tn{list}).
% \item It defines how each \tn{item} should be typeset: how to
%   construct the label, in particular the \texttt{counter} name, and
%   how to format the content of the item.
% \end{itemize}
%
% This suggests defining two object types, \xt{block} and \xt{item}
% covering these two aspects.\footnote{Possibly also \xt{endblock} to
% deal with decorations at the end?}  While the \xt{item} type will
% perhaps have a single template, one could typeset a \xt{block} object
% in several ways, for instance the standard \LaTeXe{} way or a fancy
% colored box.
%
% The \xt{general} \xt{block} template should receive the following
% parameters.  The \xt{plain} \xt{block} template is a restricted
% template that freezes all item-related parameters to dummy values
% (\texttt{counter}, \texttt{start}, \texttt{resume},
% \texttt{label-width}, \texttt{label-sep} and all \texttt{item-*}).
% The \xt{list} \xt{block} template is a restricted template\footnote{A
% better approach could be to have a notion of inheritance for object
% types, so that we end up with two different \emph{object types}.  Then
% we can implement other template for the list object type: \xt{table}
% for lists typeset as rows/columns of a table, \xt{inline} for lists
% typeset in horizontal mode within a paragraph, and \xt{runin} for
% run-in lists.} that omits the \texttt{heading} parameter and whose
% default for \texttt{item-instance} is non-empty.
% \begin{itemize}
% \raggedright
% \item Structural parameters: the \texttt{heading} to place before,
%   \texttt{counter} name, \texttt{start} value, whether to
%   \texttt{resume} a previous list, and the \texttt{item-instance} (an
%   \xt{item} instance) to use when typesetting items.
% \item Vertical spacing and penalties: \texttt{beginpenalty},
%   \texttt{beginsep}, \texttt{begin-par-skip}, \texttt{item-penalty},
%   \texttt{item-skip}, \texttt{item-par-skip}, \texttt{endpenalty},
%   \texttt{end-skip}, \texttt{end-par-skip}.
% \item Horizontal spacing: \texttt{rightmargin}, \texttt{leftmargin},
%   \texttt{parindent}, \texttt{item-indent}, \texttt{label-width},
%   \texttt{label-sep}.
% \end{itemize}
% A \docclass should edit these templates (or define restricted
% templates) to set up default values that depend on \tn{g_block_nesting_depth_int},
% namely how many lists are nested overall.\footnote{Does
% \pkg{xtemplate} provide a way to specify default values that are only
% evaluated once an instance is used?}  The document class should then
% set up an instance of these templates for each environment, with
% appropriate settings such as a \texttt{heading}, a suitable
% \texttt{item-instance}, or making \texttt{margin-right} equal to
% \texttt{margin-left} in a \texttt{quote} environment.
%
% The \xt{inline-list} \xt{block} template receives many fewer
% parameters.  Note that \texttt{beginsep}, \texttt{item-skip},
% \texttt{end-skip} are now \emph{horizontal} skips.
% \begin{itemize}
% \item Structural parameters: \texttt{counter}, \texttt{start},
%   \texttt{resume}, \texttt{item-instance}.
% \item Spacing and penalties: \texttt{beginpenalty},
%   \texttt{beginsep}, \texttt{item-penalty}, \texttt{item-skip},
%   \texttt{endpenalty}, \texttt{end-skip}.
% \item Horizontal spacing: \texttt{label-width}, \texttt{label-sep}.
% \end{itemize}
%
% The \xt{std} \xt{item} template should receive the following
% parameters.  They depend on the type of list and its nesting level
% among lists of such type, but typically not on the total nesting
% level.
% \begin{itemize}
% \item Counter name (\texttt{counter}), shared with the parent
%   \xt{list} \xt{block} template, but needed for incrementing.
% \item Label construction: a function \texttt{counter-label} that
%   produces the label from the counter name, used if \tn{item} is given
%   without argument.
% \item References: a function \texttt{counter-ref} for how the label
%   should be referred to when it is constructed from the counter,
%   \texttt{label-ref} and \texttt{label-autoref} used when \tn{item}
%   has an optional argument.
% \item Label formatting: \texttt{label-format} function,
%   \texttt{label-strut} boolean.
% \item Label alignment (\texttt{label-align}, \texttt{label-boxed},
%   \texttt{next-line}).
% \item Content parameters: \key{text-font}.
% \item A \texttt{compatibility} boolean that controls for instance
%   whether \tn{makelabel} is used.
% \end{itemize}
% The \docclass should set up an instance such as \xt{enumiii} for each
% environment and nesting level.\footnote{This should be made easily
% extendible to deeper levels.}
%
% A given environment will adjust some nesting levels, then call the
% \xt{block} instance appropriate to the environment type, passing it
% the \xt{item} instance appropriate to the environment and depth.
% Additional context-dependence could be provided by \pkg{l3ldb}, but
% the main context-dependence should not rely on it for simplicity
% reasons and incidentally because \pkg{l3ldb} is not yet available.
%
%
% \Finale
%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\endinput
</pre></body></html>