% \iffalse meta-comment
%
%% File: latex-lab-block.dtx (C) Copyright 2021-2026 LaTeX Project
%
% It may be distributed and/or modified under the conditions of the
% LaTeX Project Public License (LPPL), either version 1.3c of this
% license or (at your option) any later version.  The latest version
% of this license is in the file
%
%    https://www.latex-project.org/lppl.txt
%
\def\ltlabblockdate{2026-05-08}
\def\ltlabblockversion{0.9w}

%<*driver>
\DocumentMetadata{tagging=on,pdfstandard=ua-2,lang=en}
\documentclass[kernel]{l3in2edoc}

\usepackage{amstext}
\EnableCrossrefs
\CodelineIndex

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

\usepackage{todonotes}

\begin{document}
  \DocInput{latex-lab-block.dtx}
\end{document}
%</driver>
%
% \fi
%
%
%
% \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\struct[1]{\texttt{<#1>}}
%
% \newcommand\key[1]{\texttt{#1}}
% \newcommand\keyvalue[1]{\texttt{#1}}
% \newcommand\valuefrom[1]{\textrm{value from }\key{#1}}
%
% \newcommand\instname[1]{\texttt{#1}}
% \newcommand\insttype[1]{\texttt{#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}}}
%
% 
% \begin{abstract}
% \end{abstract}
%
%
% \tableofcontents
% \medskip
%
%
% \begin{documentation}
%
% \changes{v0.9p}{2026-03-12}{Switch from \texttt{x}- to \texttt{e}-type
%   expansion in expl3 code}
%
% \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 template
% types: \insttype{block} (horizontally or vertically oriented data that
% needs some handling at the start and the end), \insttype{para} (that deals
% with different paragraph layouts), \insttype{list} (that handles list
% related parameters, and \insttype{item} (for item layouts and handling).
%
% To address the independent aspects we have the template type
% \insttype{blockenv} that ties them together as necessary when we
% build document level environments.
%
% For example, a \env{quote} environment would make use of a (display)
% \insttype{block} and some \insttype{para} instance while a standard
% \env{enumerate} would make use of a display \insttype{block}, a \insttype{list},
% and  an \insttype{item} and a \insttype{para} instance.
% An inline list (like \env{enumerate*} from the \pkg{enumitem}
% package) would be using the same \insttype{list} instance but a different
% (horizontally oriented) \insttype{block} instance build from a
% different template.
%
% Instead of a \insttype{list} instance to handle the inner structure
% of the environment one can use an instance of the type
% \insttype{captionedtext} to produce a display environment with an
% associated heading/caption, such as a theorem-like environment or a
% proof environment. Further possibilities (not yet implemented) are
% templates for producing boxed text or formal quotes like those
% produced by the \pkg{csquotes} package.
%
% 
% \section{Template types and templates for blocks and lists}
%
% \subsection{Template types}
% 
%
% \begin{TemplateInterfaceDescription}{blockenv}
%    \TemplateArgument{1}{key/value list to alter the default parameters of the template
%       instances used by the particular blockenv environment}
%    \TemplateArgument{2}{Boolean to suppress a number in case this
%       environment normally produces a numbered caption}
%    \TemplateArgument{3}{Caption/heading text in case this environment
%       supports a caption (most don't), otherwise \cs{NoValue}}
%    \TemplateArgument{4}{Sub-caption/heading text in case this environment
%       supports a caption (most don't), otherwise \cs{NoValue}}
%    \TemplateSemantics
%    This template type is used to implement document-level
%    environments. It defines a \insttype{block} instance to handle the
%    layout at the \enquote{edge} of the environment data, possibly
%    some paragraph setup through a \insttype{para} instance, potentially an
%    \enquote{inner} instance for more complicated environments (such
%    as lists), and possibly some additional setup code for certain
%    environments.
%
%    Arguments 2--4 are passed to the instance handling the inner
%    structure, e.g., \insttype{list} or \insttype{captionedtext}
%    which may or may not make use of it.
%
%    It also defines how the \insttype{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 template type defines how it appears in a tagged PDF
%    document, what tag names are used, how they are role-mapped and
%    whether it adds additional attributes, etc. 
% \end{TemplateInterfaceDescription}
%
% \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,
%    prohibiting or encouraging line breaks, and so forth.
% \end{TemplateInterfaceDescription}
% 
% \begin{TemplateInterfaceDescription}{para}
%    \TemplateArgument{1}{key/value list to alter the default paragraph parameters}
%    \TemplateSemantics
%    Sets up paragraph-specific parameters for H\&J, e.g., to
%    implement justification variations, the behavior of \verb=\\=
%    etc. The instances are used in higher-level templates, e.g., in a
%    \insttype{block}.
% \end{TemplateInterfaceDescription}
% 
% \begin{TemplateInterfaceDescription}{list}
%    \TemplateArgument{1}{key/value list to alter the default list parameters}
%    \TemplateArgument{2}{Boolean to suppress a number in case this
%       list environment also produces a numbered heading/caption}
%    \TemplateArgument{3}{Caption/heading text in case this environment
%       supports a caption (lists normally don't), otherwise \cs{NoValue}}
%    \TemplateArgument{4}{Sub-caption/heading text in case this environment
%       supports a caption, otherwise \cs{NoValue}}
%    \TemplateSemantics
%    Handle the aspects related to list design, e.g., the use and
%    formatting of counters, etc.
%
%    Standard \LaTeXe{} lists have no heading/caption, so arguments
%    2--4 are ignored in the standard \insttype{list} template. But
%    special lists, such as a list of ingredients for a cookbook,
%    might so there might be other templates that make use of them in
%    the future.
%
%    Note that this template type does not cover block-related
%    aspects, i.e., a list instance could be used both for a display
%    list or for an inline list.
% \end{TemplateInterfaceDescription}
% 
% \begin{TemplateInterfaceDescription}{captionedtext}
%    \TemplateArgument{1}{key/value list to alter the default captiontext parameters}
%    \TemplateArgument{2}{Boolean to suppress a number in case this
%       environment also produces a numbered heading/caption}
%    \TemplateArgument{3}{Caption/heading text for this text block; if
%       not given then \cs{NoValue}}
%    \TemplateArgument{4}{Sub-caption/heading text in case this environment
%       supports a caption, otherwise \cs{NoValue}}
%    \TemplateSemantics
%    Produces a text block with an associated caption/heading, e.g., a
%    theorem-like environment. There may not be a user-supplied
%    caption text---the caption may consist of a fixed text only like ``Lemma''.
%
%    Handles the aspects related to the caption design and typically
%    supports keys for adjusting the layout of the body text,
%    e.g., its font, etc.
%
%    Note that this template type does not cover block-related
%    aspects, e.g., the dimensions of the display block are handled there.
% \end{TemplateInterfaceDescription}
% 
% \begin{TemplateInterfaceDescription}{item}
%    \TemplateArgument{1}{key/value list to alter the default item parameters}
%    \TemplateSemantics
%    A sub-type used as part of \insttype{list} to easily cover alternative layout
%    for list items.
% \end{TemplateInterfaceDescription}
%
% \begin{TemplateInterfaceDescription}{thmstyle}
%    \TemplateArgument{1}{key/value list to alter the default thmstyle parameters}
%    \TemplateArgument{2}{Boolean to suppress a number in case this
%       environment also produces a numbered heading/caption}
%    \TemplateArgument{3}{Caption/heading text for this text block; if
%       not given then \cs{NoValue}}
%    \TemplateArgument{4}{Sub-caption/heading text in case this environment
%       supports a caption, otherwise \cs{NoValue}}
%    \TemplateSemantics
%    A sub-type used as part of \insttype{captionedtext} when
%    producing theorem-like environments. It does the bulk of the work
%    and sets up most of the formatting. It has been separated out
%    because many theorem-like environments use the same theorem
%    layout and only differ in the fixed caption text they
%    generate.
%
%    Not all templates of type \insttype{captionedtext} use
%    \insttype{thmstyle} as an inner instance, e.g., proofs are
%    implemented with a template that does everything necessary
%    directly.
% \end{TemplateInterfaceDescription}
%
%
%
% \subsection{Templates}
% 
% 
% \begin{TemplateDescription}{blockenv}{std}
%
%  \TemplateKey{name}{tokenlist}
%              {Name of the environment used in tracing and error messages.}{}
%  \TemplateKey{tag-name}{tokenlist}
%              {Name of the tag used for the block inside the PDF. If not explicitly given
%               the name is defined by the \key{tagging-recipe}. Note that in case of
%              \key{tagging-recipe}\texttt{=basic} no tag for the block is produced, so any
%              key settings are ignored.}{\meta{empty}}
%  \TemplateKey{tag-attr-class}{tokenlist}
%              {An explicit tag class attribute.}{\meta{empty}}
%  \TemplateKey{tagging-recipe}{tokenlist}
%              {Defines the way tagging is done. Currently the values
%               \keyvalue{basic}, \keyvalue{standard}, and \keyvalue{list}
%               are supported.}{standard}
%  \TemplateKey{transparent-level}{boolean}{Is this \insttype{blockenv}
%               transparent for any blocks nested inside?}{false}
%  \TemplateKey{legacy-code}{tokenlist}
%              {Legacy setup code. This is
%               executed after legacy defaults (from \tn{@listi},
%               \tn{@listii}, etc.) are used but before the block instance
%               is called.}{\meta{empty}}
%  \TemplateKey{block-instance}{tokenlist}{Part of the name of the
%               \insttype{block} instance that is called. The full name has
%               a \texttt{-}\meta{level} appended.}{std-display}
%  \TemplateKey{para-instance}{tokenlist}{Paragraph settings to use
%               within the environment. If \meta{empty} then the
%               current (outer) values are
%               retained. However, the \key{inner-instance} template
%               might reset/overwrite some of the \instname{para}
%               values, e.g., \instname{list} makes used of
%               \cs{listparindent} to explicitly set the paragraph indentation
%               for compatibility.}{\meta{empty}}
%  \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}{Template type of the
%               inner instance. Currently supported types are
%               \insttype{list} and \insttype{captionedtext}.}{\meta{empty}}
%  \TemplateKey{inner-instance}{tokenlist}{Name of the inner instance
%               (if any). If there is an \key{inner-level-counter} then
%               the instance name gets \texttt{-}\meta{counter value}
%               appended.}{\meta{empty}}
%  \TemplateKey{tagging-suppress-paras}{boolean}{\emph{describe}}{false}
%  \TemplateKey{final-code}{tokenlist}{Final setup code}{\tn{ignorespaces}}
%
%    \TemplateSemantics
%
%    The \insttype{blockenv} type handles the overall setup for the
%    document-level environments.
%
%    This \insttype{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).
%
%
%    The internal block nesting level is stored (for historical
%    reasons) in the \tn{@listdepth} counter and incremented by each
%    block by one. The starting value at top-level (outside any block)
%    is zero. A block environment with
%    \key{transparent-level}\texttt{=true} also increments the level
%    before it evaluates and sets its parameters but then decrements
%    it again, just before it starts processing its body.
%
%    The template first checks that the block is not too deeply nested.
%
%    After the level was increased then corresponding \tn{@list...} macro
%    to update the legacy defaults is called.
%
%    It then sets up the
%    tagging via the \key{tagging-recipe} setting and executes any
%    code in \key{legacy-code}.
%
%    Afterwards it calls the appropriate \insttype{block} instance
%    based on \key{block-instance} and current level, e.g.,
%    \texttt{std-display-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 \insttype{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{std-display-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{transparent-level} is set to \keyvalue{true} then
% such an environment alters the nesting level only temporarily (while
% processing the \insttype{blockenv} template) and you can therefore
% nest those environments as often as you like (a typical example
% would be \env{flushleft} anywhere in the nesting hierarchy) as long
% as the level isn't already at \texttt{maxblocklevels}).
%  
%  
% \changes{v0.9l}{2025/11/04}{Fix default for para-vspace, should be the outer \cs{parskip}}
% 
% \begin{TemplateDescription}{block}{std}
%
%  \TemplateKey{begin-vspace}{skip}{Vertical space before the block.}{\tn{topsep}}
%  \TemplateKey{begin-extra-vspace}{skip}{Extra vertical space before
%       the block if the block forms its own paragraph.}{\tn{partopsep}}
%  \TemplateKey{begin-unchained-vspace}{skip}{Vertical space before
%       the block to use if this is a nested block, both blocks have
%       items or captions, and these should not be chained; see
%       description below.}{.5\tn{topsep}}
%  \TemplateKey{para-vspace}{skip}{The default for ordinary blocks is to use the
%       \cs{parskip} from the outer galley. In lists and some other special blocks
%       this is then changed.}{\tn{parskip}}
%  \TemplateKey{end-vspace}{skip}{Vertical space after the
%       block.}{\valuefrom{begin-vspace}}
%  \TemplateKey{end-extra-vspace}{skip}{Extra vertical space after the
%       block if the block forms its own paragraph.}{\valuefrom{begin-extra-vspace}}
%  \TemplateKey{item-vspace}{skip}{The space in front of an item if the
%       block is a list; if not, the setting has no effect.}{\tn{itemsep}}
%  \TemplateKey{begin-penalty}{integer}{Penalty for breaking before
%       the block.}{\tn{@beginparpenalty}}
%  \TemplateKey{end-penalty}{integer}{Penalty for breaking after
%       the block.}{\tn{@endparpenalty}}
%  \TemplateKey{item-penalty}{integer}{Penalty for breaking before
%       an item in the list (except the first).}{\tn{@itempenalty}}
%  \TemplateKey{left-margin}{length}{Space on the left of the block.}{\tn{leftmargin}}
%  \TemplateKey{right-margin}{length}{Space on the right of the block.}{\tn{rightmargin}}
%  \TemplateKey{para-indent}{length}{Paragraph indention for
%       paragraphs within the block.}{0pt}
%
%    \TemplateSemantics
%    Sets up the main block parameters, e.g. its spacing before and
%    after and the indentation on either side.
%
%    It also sets up some parameter defaults for the inner level,
%    e.g., \texttt{item-penalty}, \texttt{item-vspace} and
%    \texttt{para-indent}, which may get overwritten by inner
%    instances that are called.
%
%    The vertical spacing before the block covers four different use
%    cases: If there is a caption or an item waiting to be placed, and
%    this item allows for \enquote{chaining}, and the new block also wants
%    to place an item then no space is added (spacing was already
%    added by the outer block). Instead, the items are chained and
%    placed that the start of the block, i.e., producing a layout like the
%    two nested \env{itemize} environments here:
%    \begin{itemize}
%    \item \begin{itemize}
%          \item A second-level item
%          \item Another \ldots
%          \end{itemize}
%          More text for the first-level item
%    \item Another first-level item
%    \end{itemize}
%    In that case there is also no vertical space after the block.
%    If the items should not be chained (as specified by the setup of
%    the outer block), then one gets a result like this one (using
%    \env{itemize} environments inside \env{description} with
%    different treatment of individual description \cs{item}s):
% \begin{description}
%  \item[label={An normal label},label-placement=chained]
%   \begin{itemize}
%       \item A second-level item
%       \item Another \ldots
%   \end{itemize}
%   More text for the first-level item
% \item[label={An unchained label},label-placement=unchained]
%   \begin{itemize}
%       \item A second-level item
%       \item Another \ldots
%   \end{itemize}
%   More text for the first-level item
%  \item[A normal label] Another first-level item
% \end{description}
%    If \enquote{unchaining} happens, as in the second item, then
%    vertical spacing with the value of \key{begin-unchained-vspace}
%    is used and at the end you get \key{end-vertical-space}.
%
%    Otherwise, if there is no item or caption waiting to be placed
%    you get a vertical space of \key{begin-vspace} before the block
%    and if the block is its own paragraph you additionally get
%    \key{begin-extra-vspace} added to this.
%
%    Note that \LaTeXe{} always chained the list items, so the ability
%    to prohibit this is a new functionality.
% \end{TemplateDescription}
%
%  
% \begin{TemplateDescription}{para}{std}
%
%  \TemplateKey{para-indent}{length}{}{\tn{parindent}}
%  \TemplateKey{begin-hspace}{skip}{Horizontal skip added just in
%    front of the indentation box if non-zero}{0pt}
%  \TemplateKey{left-hspace}{skip}{}{0pt}
%  \TemplateKey{right-hspace}{skip}{}{0pt}
%  \TemplateKey{end-hspace}{skip}{}{\tn{@flushglue}}
%  \TemplateKey{fixed-word-spaces}{boolean}{}{false}
%  \TemplateKey{final-hyphen-demerits}{integer}{}{5000}
%  \TemplateKey{newline-cmd}{function(0)}{This defines the meaning of
%      \cs{\bslash}}{\tn{@normalcr}}
%  \TemplateKey{para-attr-class}{tokenlist}{}{justify}
%
%  \TemplateSemantics
%
%    The \key{begin-hspace} (normally \texttt{0pt}) is the counterpart
%    of \key{end-hspace} (which is normally \texttt{0pt plus 1fil}).
%    It can be useful in special paragraph shapes.  The skip is only
%    inserted into the paragraph if it is non-zero.  If it is made
%    non-zero then paragraphs are always at least one line including a
%    construct like \verb=\noindent\par=!
% 
%    The \key{para-attr-class} takes one of the attributes \texttt{justify},
%    \texttt{center}, \texttt{raggedright}, \texttt{raggedleft}. They are declared
%    in latex-lab-namespace.
%    
%  TODO: to be further documented
% 
% \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.}{\meta{empty}}
%  \TemplateKey{item-label}{tokenlist}
%              {Label \enquote{string} for a fixed label or as
%               generated from the current \key{counter} value.}{\meta{empty}}
%  \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?
%               If true value of \key{start} is ignored.}{false}
%  \TemplateKey{item-instance}{instance}
%              {Instance of type \texttt{item} to be used to format
%               the label string.}{basic}
%  \TemplateKey{item-vspace}{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-penalty}{integer}
%              {Penalty for breaking before an item (except the
%               first). If not specified the value specified in the
%               block template instance is used.}{} 
%  \TemplateKey{item-indent}{length}{Horizontal displacement of the item.}{0pt}
%  \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
%    Sets up handling of list material, e.g., numbering (if any),
%    layout of items and list elements, and tagging, if requested. 
% 
% \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-placement}{choice}
%              {Placement of the label in relation to a directly following label
%               (of a following inner list). Supported values
%               are \keyvalue{chained},  \keyvalue{unchained}, and
%               \keyvalue{standalone}.}{chained}
%  \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!\fmi{fix}
% 
% \end{TemplateDescription}
%
%
%
% \begin{TemplateDescription}{captionedtext}{thmlike}
%
%  \TemplateKey{counter}{tokenlist}
%              {Counter name to be used if the caption is numbered,
%               otherwise empty.}{\meta{empty}}
%  \TemplateKey{title}{tokenlist}
%              {Fixed part of the caption, e.g., a theorem-like
%               environment may want to specify \enquote{Lemma} here.}{\meta{empty}}
%  \TemplateKey{style}{instance}
%              {Instance of type \insttype{thmstyle} that actually
%               implements the theorem-like environment.}{plain}
%    \TemplateSemantics
%
%    The template combines the fixed \key{title} and a number (if
%    present) with the caption text as specified on the document
%    element, if one is given, e.g., \enquote{Theorem 1. (Fermat)}.
%    See also the \texttt{proof} template, which handles this
%    differently.
%
%    The bulk of the work is then outsourced to an instance of
%    type \insttype{thmstyle}. As many such theorem-like
%    environments share the same layout and only differ in the first
%    caption string they use, there is this split for convenience.
% \end{TemplateDescription}
%
%  
% \begin{TemplateDescription}{captionedtext}{proof}
%
%  \TemplateKey{title}{tokenlist}
%              {Heading for the environment unless overwritten on
%               document level. The default value, i.e.,
%              \cs{proofname} resolves to \enquote{Proof}
%              unless changed}{\cs{proofname}}
%  \TemplateKey{punct}{tokenlist}
%              {Punctuation following the heading.}{.}
%  \TemplateKey{caption-placement}{choice}
%              {Supported values
%               \keyvalue{chained},\keyvalue{unchained}, and
%               \keyvalue{standalone}}{unchained}
%  \TemplateKey{caption-unbreakable}{boolean}
%              {Can this caption have (implicit or explicit) line breaks?}{false}
%  \TemplateKey{before-hspace}{skip}
%              {Horizontal displacement of the heading.}{0pt}
%  \TemplateKey{after-hspace}{skip}
%              {Space following the heading, only relevant if text
%               follows on the same line.}{5pt}
%  \TemplateKey{caption-decls}{tokenlist}
%              {Declarations that are applied to the whole caption,
%               e.g., some font settings.}{\meta{empty}}
%  \TemplateKey{title-decls}{tokenlist}
%              {Declarations that are applied only to the caption
%               title.}{\meta{empty}}
%  \TemplateKey{punct-decls}{tokenlist}
%              {Declarations that are applied only to the caption
%               punctuation.}{\meta{empty}}
%  \TemplateKey{title-format}{function{1}}
%              {Formatting applied to the \key{title} value.}{\#1}
%  \TemplateKey{punct-format}{function{1}}
%              {Formatting applied to the \key{punct} value.}{\#1}
%  \TemplateKey{body-decls}{tokenlist}
%              {Declarations that are applied to body of the
%               environment, e.g., font settings.}{\meta{empty}}
%    \TemplateSemantics
%
%    The \enquote{unnumbered?} argument (\texttt{\#2}) is ignored, as
%    proofs aren't numbered.  The template makes use of the caption
%    argument (\texttt{\#3}) but in contrast to theorem-like
%    environments this template replaces the \key{title} key value with the content of
%    this argument (if not \cs{NoValue}).
%
%    Typically there is only one layout for proofs so that there is no
%    need to split the formatting over two templates as done for
%    theorem-like environment. That's the reason why the template has
%    several layout customization parameters.
% \end{TemplateDescription}
%
%  
% \begin{TemplateDescription}{thmstyle}{std}
%
%  \TemplateKey{numbered}{boolean}
%              {Is this kind of environment numbered?}{true}
%  \TemplateKey{separator}{tokenlist}
%              {Separation to be applied between elements of the
%               heading, typically a space command of some
%               sort.}{\textbackslash\textvisiblespace }
%  \TemplateKey{punct}{tokenlist}
%              {Punctuation following the heading.}{.}
%  \TemplateKey{caption-placement}{choice}
%              {Supported values
%               \keyvalue{chained},\keyvalue{unchained}, and
%               \keyvalue{standalone}}{unchained}
%  \TemplateKey{caption-unbreakable}{boolean}
%              {Can this caption have (implicit or explicit) line breaks?}{false}
%  \TemplateKey{before-hspace}{skip}
%              {Horizontal displacement of the heading.}{0pt}
%  \TemplateKey{after-hspace}{skip}
%              {Space following the heading, only relevant if text
%               follows on the same line.}{5pt}
%  \TemplateKey{order}{commalist}
%              {Order of elements in the environment
%    caption/heading. Supported values are \texttt{title},
%    \texttt{number}, \texttt{punct}, \texttt{separator}, and
%    \texttt{note}.}{title,separator,number,separator,note,punct}
%  \TemplateKey{title-decls}{tokenlist}
%              {Declarations that are applied only to the caption
%               title.}{\meta{empty}}
%  \TemplateKey{number-decls}{tokenlist}
%              {Declarations that are applied only to the caption
%               number.}{\meta{empty}}
%  \TemplateKey{punct-decls}{tokenlist}
%              {Declarations that are applied only to the caption
%               punctuation.}{\meta{empty}}
%  \TemplateKey{note-decls}{tokenlist}
%              {Declarations that are applied only to the caption
%               note.}{\meta{empty}}
%  \TemplateKey{title-format}{function{1}}
%              {Formatting applied to the \key{title} value.}{\#1}
%  \TemplateKey{number-format}{function{1}}
%              {Formatting applied to the \key{number} value.}{\#1}
%  \TemplateKey{punct-format}{tokenlist}
%              {Formatting applied to the \key{punct} value.}{\#1}
%  \TemplateKey{note-format}{function{1}}
%              {Formatting applied to the \key{note} value.}{(\#1)}
%  \TemplateKey{body-decls}{tokenlist}
%              {Declarations that are applied to body of the
%               environment, e.g., font settings.}{\meta{empty}}
%
%    \TemplateSemantics
%
%    Numbering of the environment is suppressed unconditionally if the
%    \key{numbered} is set to \keyvalue{false}. Otherwise the
%    environment is numbered except when \texttt{\#2} is
%    \cs{BooleanTrue}, i.e., if the star form of the environment was
%    used.
%
%    The caption of the environment can consist of a title, a number,
%    a punctuation, some separators (typically spaces) and a note. Their order is defined by
%    the key \key{order}. If a component is specified but has no
%    value, e.g., no note or the numbering suppressed on an individual
%    environment, then the component and any preceding separators are
%    ignored.
%
%    Spaces between elements are uniform (as one can only specify a
%    \texttt{separator} in the \key{order} key), but it is possible to
%    use this several times in a row and adjust the \key{separator} key
%    accordingly.
%
%    Alternatively, one can omit using \texttt{separator} in the
%    \key{order} key and instead put all necessary spacing into the
%    individual \key{...-format} keys. This approach is used, for example, if a
%    theorem style is set up with \cs{newtheoremstyle} and its ninth
%    argument contains a declaration such as
%\begin{verbatim}
%   \thmname{#1}\thmnumber{ #2}\thmnote{ (#3)}
%\end{verbatim}
%    This is then translated to
%\begin{verbatim}
%   order         = {title,number,punct,note} ,
%   title-format  = {#1} ,
%   number-format = { #2} ,
%   note-format   = { (#3)} ,
%\end{verbatim}
%    when \cs{newtheoremstyle} sets up a new instance.
%    The downside of this approach is that \cs{swapnumbers} would not
%    work with such styles (because it would be necessary to transfer the
%    space inside value for the \key{number-format} key to the value
%    of \key{title-format}).
%
%    If you look closely you also see that in the \key{order} key a
%    \texttt{punct} was added in the list even though it was not present
%    originally. This is the way \cs{newtheoremstyle} worked and so
%    we mimic that.
% \end{TemplateDescription}
%
%  
%
%
% \section{Declaring standard display block environments and their instances}
%
%    Historically the \LaTeX{} kernel has defined a number of block
%    environments directly, e.g., \env{center} or lists like
%    \env{itemize}, but left others to be set up by document
%    classes. For now we declare all of them here, but in the future,
%    some (or even all) might get moved to new class files.
%
% \noindent
% \DescribeMacro\SimpleBlockEnv
%    Most of the standard block environments have no need for a caption,
%    so to simplify the setup we have added the command
%    \cs{SimpleBlockEnv} that hides the arguments 2--4 required by a
%    \insttype{blockenv} instance and gives them suitable values, i.e.,
%    \cs{BooleanFalse}\cs{NoValue}\cs{Novalue}. This way, a document
%    level definition for the \env{center} environment will look like this:
% \begin{verbatim}
% \NewDocumentEnvironment{center} { !O{} }
%    { \SimpleBlockEnv{center}{#1} } { \BlockEnvEnd }
% \end{verbatim}
%    instead of the more verbose
% \begin{verbatim}
% \NewDocumentEnvironment{center} { !O{} }
%   { \UseInstance{blockenv}{center}{#1} \BooleanFalse \NoValue \NoValue }
%   { \BlockEnvEnd }
% \end{verbatim}
%
%    We use \verb=!O{}= for the optional argument so that it is only
%    recognized if it immediately follows \verb=\begin{center}= without
%    any spaces to avoid that a \texttt{[} at the start of the body text
%    is misinterpreted as the opening bracket of the optional
%    argument. This is only done for environments where this could be a
%    problem.
%
%    This will then call the \texttt{center} instance of type
%    \insttype{blockenv} that handles the rest.
%
% \noindent
% \DescribeMacro\BlockEnv
% \DescribeMacro\BlockEnvEnd
%    For the environments that make use of the other arguments, we
%    offer \cs{BlockEnv} as syntactic sugar so that most environment
%    declarations look similar. And we use \cs{BlockEnvEnd} in both
%    cases to finish off.
%    \begin{macrocode}
%<*class-code>
%    \end{macrocode}
%
%    In the following sections we provide for all block environments
%    the top-level definition and all instances that are used by
%    it. Instances of type \insttype{block} are often reused across
%    the environments, in which case we just provide
%    cross-references. Note that this is a design decision, different
%    classes may want to have adjusted settings for individual
%    environments, in which case they would provide special
%    \insttype{block} instances instead of reusing, say, the
%    \instname{std-display-\meta{level}} instances.
%
%
% \subsection{The \env{display} and \env{displayflattened} environments}
%
%
%  \begin{environment}{displayblock,displayblockflattened}
%    There are two basic block environments (\env{displayblock} and
%    \env{displayblockflattened}) which are similar to \LaTeXe{}'s
%    \env{trivlist} except that they aren't degenerated lists and
%    thus have no hidden \tn{item} inside.
%
%    \begin{macrocode}
\NewDocumentEnvironment{displayblock}{ !O{} }
  { \SimpleBlockEnv{displayblock} {#1} } { \BlockEnvEnd }
%    \end{macrocode}
%
%    \begin{macrocode}
\NewDocumentEnvironment{displayblockflattened}{ !O{} }
  { \SimpleBlockEnv{displayblockflattened} {#1} } { \BlockEnvEnd }
%    \end{macrocode}
%  \end{environment}
%
%  \subsubsection{Their \insttype{blockenv} 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{Div} structure.
%  
%    We list all keys, those with default values, commented out.
%    \begin{macrocode}
\DeclareInstance{blockenv}{displayblock}{std}
{
   name                = displayblock
%  ,tagging-recipe      = standard
%  ,tag-name            =
%  ,tag-attr-class      =
  ,transparent-level    = true
%  ,legacy-code         =
%  ,block-instance      = std-display
%  ,para-instance       =
%  ,tagging-suppress-paras = false
%  ,inner-instance      =
%  ,inner-instance-type =         % 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}
%
%    The  \insttype{block} uses the instance \instname{std-display}
%    which is shown below.
%  \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}{std}
{
   name                   = displayblockflattened
  ,tagging-recipe         = basic
  ,tagging-suppress-paras = true
  ,transparent-level      = true
}
%    \end{macrocode}
%  \end{instance}
%
%
%
%  \subsubsection{Their \insttype{block} instances}
%  \label{sec:std-display}
%  
%    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{std-display-\meta{level}} 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 std-display-1,
%                   block std-display-2,
%                   block std-display-3,
%                   block std-display-4,
%                   block std-display-5,
%                   block std-display-6 }
% ^^A
%    We show all keys here for reference, with those using their
%    default values commented out:
%    \begin{macrocode}
\DeclareInstance{block}{std-display-1}{std}
  {
%    ,begin-vspace       = \topsep
%    ,begin-extra-vspace = \partopsep
%    ,para-vspace        = \parskip
%    ,end-vspace         = \KeyValue{begin-vspace}
%    ,end-extra-vspace   = \KeyValue{begin-extra-vspace}
%    ,item-vspace        = \itemsep
%    ,begin-penalty      = \UseName{@beginparpenalty}
%    ,end-penalty        = \UseName{@endparpenalty}
    ,left-margin        = 0pt
%    ,right-margin       = \rightmargin
%    ,para-indent        = 0pt
  } 
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareInstanceCopy{block}{std-display-2}{std-display-1}
\DeclareInstanceCopy{block}{std-display-3}{std-display-1}
\DeclareInstanceCopy{block}{std-display-4}{std-display-1}
\DeclareInstanceCopy{block}{std-display-5}{std-display-1}
\DeclareInstanceCopy{block}{std-display-6}{std-display-1}
%    \end{macrocode}
%  \end{instance}
%
%
%
%
%
%
%
% \subsection{The \env{center}, \env{flushleft}, and \env{flushright} environments}
%
%    All three environments use the \instname{std-display} instance as
%    block instance. They only differ in the choice of para instance.
%
%  \begin{environment}{center,flushleft,flushright}
%    For now we redeclare various document environments as late as
%    possible in order to make tagging work, even if classes have changed
%    the definitions. Of course, this means that such changes get lost.
%    \begin{macrocode}
\AddToHook{begindocument/before}[./legacy-core]{
%    \end{macrocode}
%
%    \begin{macrocode}
  \RenewDocumentEnvironment{center} { !O{} }
  { \SimpleBlockEnv{center}{#1} } { \BlockEnvEnd }
%    \end{macrocode}
%
%    \begin{macrocode}
  \RenewDocumentEnvironment{flushright} { !O{} }
  { \SimpleBlockEnv{flushright}{#1} } { \BlockEnvEnd }
%    \end{macrocode}
%
%    \begin{macrocode}
  \RenewDocumentEnvironment{flushleft} { !O{} }
  { \SimpleBlockEnv{flushleft}{#1} } { \BlockEnvEnd }
}
%    \end{macrocode}
%  \end{environment}
%
%
%  \subsubsection{Their \insttype{blockenv} instances}
%
%  \begin{instance}{blockenv center}
%     The \env{center} environment is defined through the
%    \insttype{blockenv} instance \instname{center} which makes use of
%    the \insttype{block} instance \instname{std-display-\meta{level}}
%    and the \insttype{para} instance \instname{center}. The block
%    nesting level is not incremented. With respect to tagging, text
%    separated by \cs{par} commands (or empty lines) inside the
%    environment is not tagged as separate paragraphs, i.e., the whole
%    environment is considered to be part of an outer paragraph.
%    \begin{macrocode}
\DeclareInstance{blockenv}{center}{std}
{
   name                   = center
  ,tag-name               =
  ,tag-attr-class         =
  ,tagging-recipe         = basic
  ,tagging-suppress-paras = true
  ,inner-level-counter    =
  ,transparent-level      = true
  ,legacy-code            =
  ,block-instance         = std-display
  ,para-instance          = center
  ,inner-instance         =
}
%    \end{macrocode}
%  \end{instance}
%
%  \begin{instance}{blockenv flushleft}
%    Same as  \instname{center} except that we use the
%    \insttype{para} instance \instname{raggedright}.
%    \begin{macrocode}
%\DeclareInstance{blockenv}{flushleft}{std}
%{
%   name                   = flushleft
%  ,tag-name               =
%  ,tag-attr-class         =
%  ,tagging-recipe         = basic
%  ,tagging-suppress-paras = true
%  ,inner-level-counter    =
%  ,transparent-level      = true
%  ,legacy-code            =
%  ,block-instance         = std-display
%  ,para-instance          = raggedright
%  ,inner-instance         =
%}
%    \end{macrocode}
%    Or more concise in the source and perhaps even faster in
%    processing if only few keys are changed:
%    \begin{macrocode}
 \DeclareInstanceCopy{blockenv}{flushleft}{center}
 \EditInstance{blockenv}{flushleft}{
     name          = flushleft
    ,para-instance = raggedright }
%    \end{macrocode}
%  \end{instance}
%
%
%  \begin{instance}{blockenv flushright}
%    Same game for \instname{flushright}.
%    \begin{macrocode}
\DeclareInstanceCopy{blockenv}{flushright}{center}
\EditInstance{blockenv}{flushright}{
   name          = flushright
  ,para-instance = raggedleft }
%    \end{macrocode}
%  \end{instance}
%
%
%
%  \subsubsection{Their \insttype{block} instances}
%
%    They all use the \insttype{block} instances \instname{std}
%    which have already been set up in section~\ref{sec:std-display}.
%
%
%  \subsubsection{Their \insttype{para} instances}
%
%    Formatting of paragraphs is handled through the
%    \key{para-instance} key which either refers to a
%    instance of type \insttype{para} or is empty, in which case the
%    handling of paragraphs is inherited. The predefined instances are
%    discussed in section~\ref{sec:para-instances}.
%
%
%
% \subsection{The \env{quote} and \env{quotation} environments}
%
%    \LaTeXe{} has two environments for quoting: \env{quote} and
%    \env{quotation}. By default they differ only in indentation of
%    inner paragraphs. This is handled by using separate block
%    instances.  The paragraph setup is inherited. The block nesting
%    level is incremented.
%
%    The tag names are both role-mapped to \struct{BlockQuote}.
%
%  \begin{environment}{quote,quotation}
%    We can't use \cs{RenewDocumentEnvironment} for \env{quote} and
%    other environments that are class defined, because some classes
%    aren't implementing them at all. So we use
%    \cs{DeclareDocumentEnvironment} instead. This problem will vanish
%    if all such definitions move in new versions of the classes instead.
%
%  \changes{v0.9l}{2025/11/20}{Use \cs{DeclareDocumentEnvironment} for \env{quote},
%    \env{quotation}, \env{description}, and \env{verse} (tagging/284)}
%    \begin{macrocode}
\AddToHook{begindocument/before}[./legacy-quotes]{
  \DeclareDocumentEnvironment{quote}{ !O{} }
    { \SimpleBlockEnv{quote} {#1} } { \BlockEnvEnd }
%    \end{macrocode}
%    
%    \begin{macrocode}
  \DeclareDocumentEnvironment{quotation}{ !O{} }
    { \SimpleBlockEnv{quotation} {#1} } { \BlockEnvEnd }
}
%    \end{macrocode}
% \end{environment}
%
%  \subsubsection{Their \insttype{blockenv} instances}
%
%  \begin{instance}{blockenv quotation}
%    For the \env{quotation} environment:
%    \begin{macrocode}
\DeclareInstance{blockenv}{quotation}{std}
{
   name                = quotation
  ,tag-name            = \UseStructureName{block/quotation}
  ,tag-attr-class      =
  ,tagging-recipe      = standard
  ,inner-level-counter =
  ,transparent-level   = false
  ,legacy-code         =
  ,block-instance      = quotation
  ,inner-instance      = 
}
%    \end{macrocode}
%  \end{instance}
%
%  \begin{instance}{blockenv quote}
%    For the \env{quote} environment:
%    \begin{macrocode}
\DeclareInstance{blockenv}{quote}{std}
{
   name                = quote
  ,tag-name            = \UseStructureName{block/quote}
  ,tag-attr-class      =
  ,tagging-recipe      = standard
  ,inner-level-counter =
  ,transparent-level   = false
  ,legacy-code         =
  ,block-instance      = quote
  ,inner-instance      = 
}
%    \end{macrocode}
%  \end{instance}
%
%
%
%
%  \subsubsection{Their \insttype{block} instances}
%
%  \begin{instance}{block quote-1,
%                   block quote-2,
%                   block quote-3,
%                   block quote-4,
%                   block quote-5,
%                   block quote-6 }
%    Default layout is to indent equally from both sides.
%  \changes{0.9t}{2026-04-27}{Set para-vspace to \cs{parsep} as that is the default in legacy LaTeX.}  
%  Note that settings here also affect verse as it currently reuses the block instances!
%    \begin{macrocode}
\DeclareInstance{block}{quote-1}{std}
  { 
     right-margin = \KeyValue{left-margin} 
    ,para-vspace = \parsep
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareInstanceCopy{block}{quote-2}{quote-1}
\DeclareInstanceCopy{block}{quote-3}{quote-1}
\DeclareInstanceCopy{block}{quote-4}{quote-1}
\DeclareInstanceCopy{block}{quote-5}{quote-1}
\DeclareInstanceCopy{block}{quote-6}{quote-1}
%    \end{macrocode}
%  \end{instance}
%  
%
%  
%  \begin{instance}{block quotation-1,
%                   block quotation-2,
%                   block quotation-3,
%                   block quotation-4,
%                   block quotation-5,
%                   block quotation-6 }
%    Quotation additionally changes the \key{para-indent}.
%    \begin{macrocode}
\DeclareInstance{block}{quotation-1}{std}
   { para-indent = 1.5em , right-margin = \KeyValue{left-margin} }
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareInstanceCopy{block}{quotation-2}{quotation-1}
\DeclareInstanceCopy{block}{quotation-3}{quotation-1}
\DeclareInstanceCopy{block}{quotation-4}{quotation-1}
\DeclareInstanceCopy{block}{quotation-5}{quotation-1}
\DeclareInstanceCopy{block}{quotation-6}{quotation-1}
%    \end{macrocode}
%  \end{instance}
%
%
%
%
%
%
% \subsection{The \env{verse} environment}
%
%    The \env{verse} environment of \LaTeX{} is intended for
%    poetry. Not sure what that should mean with respect to
%    tagging. 
%
%  \begin{environment}{verse}
%    Implementation is like \env{quote} etc.
%    \begin{macrocode}
\AddToHook{begindocument/before}[./legacy]{
  \DeclareDocumentEnvironment{verse}{!O{}}
    { \SimpleBlockEnv{verse} {#1} } { \BlockEnvEnd }
}
%    \end{macrocode}
% \end{environment}
%
%  \subsubsection{Their \insttype{blockenv} instances}
%
%  \begin{instance}{blockenv verse}
%    \begin{macrocode}
\DeclareInstance{blockenv}{verse}{std}
{
   name                = verse
  ,tag-name            = \UseStructureName{block/verse}
  ,tag-attr-class      =
  ,tagging-recipe      = standard
  ,inner-level-counter =
  ,transparent-level   = false
  ,legacy-code         =
  ,block-instance      = quote       % reuse?
  ,para-instance       = verse
  ,inner-instance      = 
}
%    \end{macrocode}
%    The special indentation on continuation lines (the way \LaTeX{}
%    handled poetry) is done in the \insttype{para} instance
%    \instname{verse}, defined later on.
%  \end{instance}
%
%
%
%
%
% \subsection{The \env{verbatim}, \env{verbatim*} and \env{alltt} environments}
%
%
%  \begin{environment}{verbatim,verbatim*}
%    Here are the definitions for the verbatim environments. They look
%    somewhat different than others (but this isn't the final
%    definition).
%    At the moment we use 2 optional arguments, the second is only
%    there so that there is yet another scan even if one optional
%    argument got detected. That then scans away the newline so that
%    afterwards we can reinsert one via \cs{obeyedline}. A better
%    solution will be to use a \texttt{c} specifier for grabbing the
%    body, but that is for another day not Christmas Eve.\fmi{fix}
%  \changes{v0.9f}{2025/06/21}{Move special verbatim code into a key}
%    \begin{macrocode}
\AddToHook{begindocument/before}[./legacy-verbatims]{
  \RenewDocumentEnvironment{verbatim}{ ={legacy-code} !o !o }
    { \SimpleBlockEnv{verbatim} {#1} \obeyedline } { \BlockEnvEnd }
%    \end{macrocode}
%    
%  \changes{v0.9f}{2025/06/21}{Use separate blockenv instances for
%    verbatim and verbatim*}
%    \begin{macrocode}
  \RenewDocumentEnvironment{verbatim*}{ ={legacy-code} !o !o }
    { \SimpleBlockEnv{verbatim*} {#1}  \obeyedline } { \BlockEnvEnd }
%    \end{macrocode}
% \end{environment}
%
%
%  \begin{environment}{alltt,alltt*}
%    The  \pkg{alltt} package implements a variation on verbatim
%    handling where backslash and braces retain their normal
%    meanings. We also reimplement it using the template approach    
%    The \env{alltt*} variant didn't exist in the package,
%    but it is trivial to set it up as well.\fmi{The parsing here
%    should be adjusted as well, eventually.}
%    \begin{macrocode}
  \NewDocumentEnvironment{alltt}{ ={legacy-code} !o }
    { \SimpleBlockEnv{alltt} {#1} } { \BlockEnvEnd }
  \NewDocumentEnvironment{alltt*}{ ={legacy-code} !o }
    { \SimpleBlockEnv{alltt*} {#1} } { \BlockEnvEnd }
}
%    \end{macrocode}
% \end{environment}
%
%  \subsubsection{Their \insttype{blockenv} instances}
%
%  \begin{instance}{blockenv verbatim}
%    The \env{verbatim} environment is defined through 
%    \insttype{blockenv} instance \instname{verbatim} that makes use
%    of the \insttype{block} instance
%    \instname{verbatim-\meta{level}} and the \insttype{para}
%    instance \instname{justify}.  The block nesting level is not
%    incremented. Verbatim processing requires various \cs{catcode}
%    changes, etc.\ and as a consequence a special parsing routine
%    that grabs the whole environment while these catcodes are in
%    force. This setup is done in the \key{final-code} key and its
%    last action is to initiate the special parsing.
%
% \changes{v0.8x}{2025/01/12}{Use flattened para inside verbatim}   
%    \begin{macrocode}
\DeclareInstance{blockenv}{verbatim}{std}
{
   name                   = verbatim
  ,tag-name               = \UseStructureName{block/verbatim}
  ,tag-attr-class         =
  ,tagging-recipe         = standard
  ,tagging-suppress-paras = true
  ,inner-level-counter    =
  ,transparent-level      = true
  ,legacy-code            =
  ,block-instance         = verbatim
  ,inner-instance         =
  ,para-instance          = justify
%    \end{macrocode}
%    Here is where \env{verbatim} and \env{verbatim*} technically
%    differ: in the former we set up spaces to become nonbreakable
%    spaces (if necessary followed by a \tn{pdffakespace} in the
%    pdf\TeX{} engine)
%    and in \env{verbatim*} we set it up to generate visible space chars.
%  \changes{v0.9f}{2025/06/21}{Move special verbatim code into a key}
%    \begin{macrocode}
  ,final-code             = \legacyverbatimsetup{invisible}
%    \end{macrocode}
%    Then we start the special scanning process to look for
%    \verb=\end{verbatim}= with special catcodes and grab everything
%    in between. For \env{verbatim*} we use \cs{@sxverbatim} to look
%    for \verb=\end{verbatim*}= instead.\footnote{Perhaps there should
%    be some other command names for this?}
%    \begin{macrocode}
                            \@xverbatim
}
%    \end{macrocode}
%  \end{instance}
%
%  The role-mapping 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 be inside the \struct{codeline} structure
%  and be tagged either as \struct{Lbl} or \struct{Artifact}\struct{Lbl}.
%
%
%  \begin{instance}{blockenv verbatim*}
%    The implementation of \env{verbatim*} is similar using the
%    \insttype{blockenv} instance \instname{verbatim*}. Its
%    \key{final-code} sets up visible spaces and a slightly different
%    parsing that grabs everything up to
%    \verb=\end{verbatim*}=. Otherwise the setup is identical.
%    
%  \changes{v0.9f}{2025/06/21}{Use separate blockenv instances for
%    verbatim and verbatim*}
%    \begin{macrocode}
\DeclareInstance{blockenv}{verbatim*}{std}
{
   name                   = verbatim
  ,tag-name               = \UseStructureName{block/verbatim}
  ,tag-attr-class         =
  ,tagging-recipe         = standard
  ,tagging-suppress-paras = true
  ,inner-level-counter    =
  ,transparent-level      = true
  ,legacy-code            =
  ,block-instance         = verbatim
  ,inner-instance         =
  ,para-instance          = justify
  ,final-code             = \legacyverbatimsetup{visible}
                            \@sxverbatim
}
%    \end{macrocode}
%  \end{instance}
%
%  \begin{instance}{blockenv alltt}
%    The implementation of the \env{alltt} environment from the
%    \pkg{alltt} is more or less identical as well.
%    We just need a slightly different final code to keep backslash
%    and braces functional.
%    
%    \begin{macrocode}
\DeclareInstance{blockenv}{alltt}{std}
{
   name                   = alltt
  ,tag-name               = \UseStructureName{block/verbatim}   % private tag instead?
  ,tag-attr-class         =
  ,tagging-recipe         = standard
  ,tagging-suppress-paras = true
  ,inner-level-counter    =
  ,transparent-level      = true
  ,legacy-code            =
  ,block-instance         = verbatim
  ,inner-instance         =
  ,para-instance          = justify
%    \end{macrocode}
%    Now set up the special environment settings with most characters
%    verbatim.
%    We don't even have to scan ahead for the \verb=\end{alltt}=
%    because backslash and braces still have their normal meaning.
%    \begin{macrocode}
  ,final-code             = \legacyallttsetup {invisible}
}
%    \end{macrocode}
%  \end{instance}
%
%    
%  \begin{instance}{blockenv alltt*}
%    The \env{alltt*} variant didn't exist in the \pkg{alltt} package,
%    but it is trivial to set it up as well.
%    \begin{macrocode}
\DeclareInstance{blockenv}{alltt*}{std}
{
   name                   = alltt*
  ,tag-name               = \UseStructureName{block/verbatim}   % private tag instead?
  ,tag-attr-class         =
  ,tagging-recipe         = standard
  ,tagging-suppress-paras = true
  ,inner-level-counter    =
  ,transparent-level      = true
  ,legacy-code            =
  ,block-instance         = verbatim
  ,inner-instance         =
  ,para-instance          = justify
  ,final-code             = \legacyallttsetup {visible}
}
%    \end{macrocode}
%  \end{instance}
%
%
%
%  \subsubsection{Their \insttype{block} instances}
%
%  
%  \begin{instance}{block verbatim-1,
%                   block verbatim-2,
%                   block verbatim-3,
%                   block verbatim-4,
%                   block verbatim-5,
%                   block verbatim-6 }
%  Verbatim instances have there own levels so that one can specify
%  specific indentations or vertical separations between lines.
%    \begin{macrocode}
\DeclareInstance{block}{verbatim-1}{std}
  {
    ,left-margin      = 0pt
    ,para-vspace      = 0pt
  } 
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareInstanceCopy{block}{verbatim-2}{verbatim-1}
\DeclareInstanceCopy{block}{verbatim-3}{verbatim-1}
\DeclareInstanceCopy{block}{verbatim-4}{verbatim-1}
\DeclareInstanceCopy{block}{verbatim-5}{verbatim-1}
\DeclareInstanceCopy{block}{verbatim-6}{verbatim-1}
%    \end{macrocode}
%  \end{instance}
%
%
%
%
%
% \subsection{The standard lists: \env{itemize}, \env{enumerate}, and \env{description}}
%
%
%  \begin{environment}{itemize,enumerate,description}
%    For the standard lists everything is managed by the blockenv
%    instances. For the list we do not require that the optional argument
%    directly follows without spaces as there can be no conflict with
%    any following text (only \cs{item} or an empty line or the
%    optional argument would be possible).
% \changes{v0.9o}{2026/02/16}{Allow spaces before the optional argument (tagging/1237)}
%    \begin{macrocode}
\AddToHook{begindocument/before}[./legacy-lists]{
  \RenewDocumentEnvironment{itemize}{ O{} }
    { \SimpleBlockEnv{itemize} {#1} } { \BlockEnvEnd }
%    \end{macrocode}
%    
%    \begin{macrocode}
  \RenewDocumentEnvironment{enumerate}{ O{} }
    { \SimpleBlockEnv{enumerate} {#1} } { \BlockEnvEnd }
%    \end{macrocode}
%    
%    \begin{macrocode}
  \DeclareDocumentEnvironment{description}{ O{} }
    { \SimpleBlockEnv{description} {#1} } { \BlockEnvEnd }
}
%    \end{macrocode}
% \end{environment}
%
%  \subsubsection{Their \insttype{blockenv} instances}
%
%  \begin{instance}{blockenv itemize}
%    The \env{itemize} environment is defined through the
%    \insttype{blockenv} instance \instname{itemize} which makes use
%    of the \insttype{block} instance \instname{list-\meta{level}},
%    and an inner instance \instname{itemize-\meta{inner-level}} of
%    type \insttype{list}. The paragraph setup is
%    inherited.\footnote{In the \LaTeXe{} implementation justified
%    paragraphs where forced, even if the whole document was set in
%    ragged text. If this slightly strange behavior is desired then one has to set
%    the \key{para-instance} key to \keyvalue{justify}.}  The
%    \meta{inner-level} is determined through \cs{@itemdepth}. The
%    block nesting level and the inner list nesting level are
%    incremented.
%    \begin{macrocode}
\DeclareInstance{blockenv}{itemize}{std}
{
   name                = itemize
  ,tag-name            = \UseStructureName{block/itemize}
  ,tag-attr-class      = itemize
  ,tagging-recipe      = list
  ,inner-level-counter = \@itemdepth
  ,transparent-level   = false
  ,max-inner-levels    = 4
  ,legacy-code         =
  ,block-instance      = std-list
  ,inner-instance-type = list
  ,inner-instance      = itemize
  ,para-instance       =
}
%    \end{macrocode}
%  \end{instance}
%
%  \begin{instance}{blockenv enumerate}
%^^A
%    The \env{enumerate} environment is similar to \env{itemize} but
%    uses the \insttype{blockenv} instance \instname{enumerate}, the
%    \insttype{block} instance \instname{list-\meta{level}}, and the
%    inner instance \instname{enumerate-\meta{inner-level}}. The
%    \meta{inner-level} is determined through \cs{@enumdepth}.
%
%    \begin{macrocode}
\DeclareInstance{blockenv}{enumerate}{std}
{
   name                = enumerate
  ,tag-name            = \UseStructureName{block/enumerate}
  ,tag-attr-class      = enumerate
  ,tagging-recipe      = list
  ,transparent-level   = false
  ,max-inner-levels    = 4
  ,legacy-code         =
  ,block-instance      = std-list
  ,inner-level-counter = \@enumdepth
  ,inner-instance-type = list
  ,inner-instance      = enumerate
}
%    \end{macrocode}
%  \end{instance}
%
%
%  \begin{instance}{blockenv description}
%^^A
%    The \env{description} environment uses the \insttype{blockenv}
%    instance \instname{description}, the \insttype{block} instance
%    \instname{list-\meta{level}}, and the inner instance
%    \instname{description}.
%
%    In \LaTeXe{} that was no dependency on the nesting level,
%    i.e., the environment has the same appearance on all nesting
%    levels, but there is actually no good reason for disallowing
%    layout adjustments on each level. All we have to do for this is
%    to provide a value \key{inner-level-counter} and allocate a
%    counter register for that.
%
%    We allow for 6 levels.
% \changes{v0.9r}{2026-04-18}{Support layout customization of
%    \env{description} on individual nesting levels}
%    \begin{macrocode}

\DeclareInstance{blockenv}{description}{std}
{
   name                = description
  ,tag-name            = \UseStructureName{block/description}
  ,tag-attr-class      = description
  ,tagging-recipe      = list
  ,inner-level-counter = \@descriptiondepth
  ,transparent-level   = false
  ,max-inner-levels    = 6
  ,legacy-code         =
  ,block-instance      = std-list
  ,inner-instance-type = list
  ,inner-instance      = description
}
%    \end{macrocode}
%  \end{instance}
%
%
%  \begin{macro}{\@descriptiondepth}
%    Counting nested \env{description} environments.
% \changes{v0.9r}{2026-04-18}{Support layout customization of
%    \env{description} on individual nesting levels}
%    \begin{macrocode}
\newcount\@descriptiondepth
%    \end{macrocode}
%  \end{macro}
%
%
%  \subsubsection{Their \insttype{block} instances}
%
%  \begin{instance}{block std-list-1,
%                   block std-list-2,
%                   block std-list-3,
%                   block std-list-4,
%                   block std-list-5,
%                   block std-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}{std-list-1}{std}{
%    begin-vspace       = \topsep
%   ,begin-extra-vspace = \partopsep
%    \end{macrocode}
%    This is the only one we have to explicitly set for lists if the default
%    setup is wanted.
%  \changes{v0.9l}{2025/11/04}{Fix default for para-vspace, should be
%    \cs{parsep} (only) inside lists}
%    \begin{macrocode}
   ,para-vspace        = \parsep
%   ,end-vspace         = \KeyValue{begin-vspace}
%   ,end-extra-vspace   = \KeyValue{begin-extra-vspace}
%   ,item-vspace        = \itemsep
%   ,begin-penalty      = \UseName{@beginparpenalty}
%   ,end-penalty        = \UseName{@endparpenalty}
%   ,left-margin        = \leftmargin
%   ,right-margin       = \rightmargin
%   ,para-indent        = 0pt
}
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareInstanceCopy{block}{std-list-2}{std-list-1}
\DeclareInstanceCopy{block}{std-list-3}{std-list-2}
\DeclareInstanceCopy{block}{std-list-4}{std-list-3}
\DeclareInstanceCopy{block}{std-list-5}{std-list-4}
\DeclareInstanceCopy{block}{std-list-6}{std-list-5}
%    \end{macrocode}
%
%    If the legacy \tn{list\meta{romannumeral}} is not used in a
%    modern class then, of course, these instances all need to set up
%    the different parameters explicitly. The new implementation of
%    the standard classes (will) show that approach.
%  \end{instance}
%  
%
%  
%  \subsubsection{Their \insttype{list} instances}
%
%    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}{enumerate-1}{std}
  { item-label = \labelenumi ,   counter = enumi   }
\DeclareInstance{list}{enumerate-2}{std}
  { item-label = \labelenumii ,  counter = enumii  }
\DeclareInstance{list}{enumerate-3}{std}
  { item-label = \labelenumiii , counter = enumiii }
\DeclareInstance{list}{enumerate-4}{std}
  { item-label = \labelenumiv ,  counter = enumiv  }
%    \end{macrocode}
%  \end{instance}
%  
%
%  \begin{instance}{list description}
%    In \LaTeXe{} the \env{description} lists used only a single list
%    instance with only one key not using the default. But in this
%    implementation we allow for customization of every level, even
%    though we aren't making use of it by default.
%
%    Doing that means that you can only use a limited number of nested
%    environments (while in \LaTeXe{} one could have arbitrary
%    nestings, so let's hope 6 levels are enough.
%
%    TODO: consider reusing the last level if you run out of
%    specified levels rather than using \key{max-inner-levels}.
% \changes{v0.9r}{2026-04-18}{Support layout customization of
%    \env{description} on individual nesting levels}
%    \begin{macrocode}
\DeclareInstance{list}{description-1}{std} { item-instance = description }
%    \end{macrocode}
%
%    \begin{macrocode}
\DeclareInstanceCopy{list}{description-2}{description-1}
\DeclareInstanceCopy{list}{description-3}{description-1}
\DeclareInstanceCopy{list}{description-4}{description-1}
\DeclareInstanceCopy{list}{description-5}{description-1}
\DeclareInstanceCopy{list}{description-6}{description-1}
%    \end{macrocode}
%  \end{instance}
%
%
%  \subsubsection{Their \insttype{item} instances}
%
%  \begin{instance}{item basic, item description}
%    There are two item instances to 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{The legacy \env{list} and \env{trivlist} environments}
%
%    In \LaTeXe{}, \env{trivlist} was used to define various display
%    environments that aren't really lists at all. To support such
%    legacy definitions (even though they should be updated to achieve
%    proper tagging) we continue to support and implement it as a
%    \env{list} environment with a few hardwired settings mimicking
%    the original behavior.\fmi{maybe we should simply implement it as
%    a \instname{displayblock} instance (at least when doing tagging)
%    - decide}
%
%
% \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}[./legacy]{
  \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{legacy-code} key
%    contains \tn{legacylistsetup} 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}
%    The \LaTeXe{} lists don't support captions so we use \cs{SimpleBlockEnv}.
%    \begin{macrocode}
      \SimpleBlockEnv{list} {#1}
    }
    { \BlockEnvEnd }
}
%    \end{macrocode}
% \end{environment}
%
%
%
%  \begin{environment}{trivlist}
%    \LaTeXe{} defined \env{trivlist} as an implementation of
%    \env{list} (or rather the other way around).\fmi{Replace with
%    code not using \tn{list}} 
%    \begin{macrocode}
\AddToHook{begindocument/before}[./legacy]{
  \RenewDocumentEnvironment{trivlist}{ !O{} }
                           { \list[#1]{}
                             {
                               \dim_zero:N \leftmargin
                               \dim_zero:N \labelwidth
                               \cs_set_eq:NN \makelabel \use:n
                             }
                           }
    { \BlockEnvEnd }
}
%    \end{macrocode}
%  \end{environment}
%
%
%
%  \subsubsection{Its \insttype{blockenv} instance}
%
%  \begin{instance}{blockenv list}
%    The generic \env{list} environment of \LaTeXe{} is modeled with a
%    \insttype{blockenv} instance named \instname{list}, a
%    \insttype{block} instance named \instname{std-list-\meta{level}}, and
%    an inner instance named \instname{legacy} (with no dependency on
%    the nesting level). This environment has two arguments and
%    customization of the layout is expected to be directly set in the
%    second argument. For this reason this \instname{legacy} instance
%    is something that shouldn't be changed (all that is attempted to
%    provide a way to support legacy setups).
%
%    To set up the default settings (as they were used in \LaTeXe{})
%    the \key{legacy-code} key gets \cs{legacylistsetup} assigned
%    that contains the necessary code to set up these defaults.
%    Changing the \insttype{blockenv} is therefore not recommended for
%    the legacy \env{list} environment.
%    \begin{macrocode}
\DeclareInstance{blockenv}{list}{std}
{
   name                = list
  ,tag-name            = \UseStructureName{block/list}
  ,tag-attr-class      =
  ,tagging-recipe      = list
  ,transparent-level   = false
  ,legacy-code         = \legacylistsetup
  ,block-instance      = std-list
  ,inner-level-counter =
  ,inner-instance-type = list
  ,inner-instance      = legacy
}
%    \end{macrocode}
%  \end{instance}
%
%
%  \subsubsection{Its \insttype{list} 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 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}
%  
%
%
% \subsection{Theorem-like environments declared through \cs{newtheorem}}
%
% In standard \LaTeX{} theorem-like environments are not defined
% directly, but with the help of a \cs{newtheorem}
% declaration. That allows specifying the typeset environment title,
% e.g., \enquote{Lemma}, and the counter to use to number the
% environments, e.g., they could be all numbered individually or one
% could number them using the same counter as some other theorem-like
% environment.
%
% This was first augmented by the \pkg{theorem} package which
% implemented the idea of a \cs{theoremstyle}; this is now considered
% obsolete. Michael Downes from the AMS improved on these early ideas
% and wrote the \pkg{amsthm} package, which offered more functionality
% including a \cs{newtheoremstyle} declaration and for the document
% level a \cs{swapnumbers} and an \env{proof} environment. It also
% provided star-forms for \cs{newtheorem} (to define an unnumbered
% environment) and allowed to use star-forms of the theorem-like
% environments to suppress numbering on an individual instance in the
% document.
%
% This new implementation based on templates, is supposed to cover the
% functionality of \pkg{amsthm} including it declarations so that
% documents that use \pkg{amsthm} explicitly or implicitly via their
% class should continue to work seamlessly.
%
% For other packages that provide theorem-like environments we have to
% see if they could be easily remodeled using the new implementation
% or if there is a need for extended templates.
%
% Assuming declarations such as
%\begin{verbatim}
%  % \swapnumbers              % <- commented out
%  \theoremstyle{definition}
%  \newtheorem{axiom}[def]{Axiom}
%\end{verbatim}
% in a document, then the following instances of type \insttype{blockenv} and
% \insttype{captionedtext} are declared by \cs{newtheorem}.
%
%
%  \subsubsection{The \insttype{blockenv} instances they use}
%
%    Given the above input \cs{newtheorem} defines the following
%    \insttype{blockenv} instance:
%\begin{verbatim}
%  \DeclareInstance{blockenv}{axiom}{std}
%  {
%     name                = theorem-like
%    ,tag-name            = \UseStructureName{block/theorem-like}
%    ,tagging-recipe      = standalone
%    ,transparent-level   = true
%    ,block-instance:e    = thm-
%                         \IfInstanceExistsTF{block}
%                            { thm-definition-1 }
%                            { definition } { plain }
%    ,inner-instance-type = captionedtext
%    ,inner-instance      = axiom
%    ,para-instance       = justify
%  }
%\end{verbatim}
%
%    The setting for \key{block-instance} means that it checks if a
%    \insttype{block} instance with the name
%    \instname{thm-definition-1} exists. If so then the value
%    \keyvalue{thm-definition} is used, otherwise
%    \keyvalue{thm-plain} is used which is always defined, i.e.,
%    if the theoremstyle does not specify any special vertical spacing
%    the \insttype{block} instance from the \texttt{plain} style is
%    reused.
%
%    What varies from \insttype{blockenv} instance to instance are the
%    values for \key{block-instance} and \key{inner-instance}.
%
%    We use \struct{\UseStructureName{block/theorem-like}} as the
%    structure name and role-map it to a \struct{Sect} because that
%    can hold a \struct{Caption}.
%
%
%
%  \subsubsection{The \insttype{captionedtext} instances they use}
%
%    The instance of type \insttype{captionedtext} is also defined by
%    \cs{newtheorem} and in this case it looks like this:
%\begin{verbatim}
% \DeclareInstance{captionedtext}{axiom}{thmlike}
% {
%   ,counter = def
%   ,title   = Axiom       % <-- that the title provided to \newtheorem
%   ,style   = definition  % <-- that's the used \theoremstyle
% }
%\end{verbatim}
%
% If we uncomment the \cs{swapnumbers} line in the example above then we get
%\begin{verbatim}
%   ,style   = definition-swap
%\end{verbatim}
% in the \insttype{captionedtext} instance instead.
%
%
%
%
%
%
%  \subsubsection{The \insttype{thmstyle} instances they use}
%
%    New theorem styles can be declared with \cs{newtheoremstyle}
%    which then generates an instance of type
%    \insttype{thmstyle}. Alternatively, it is, of course, possible to
%    declare the instances directly (which gives you a bit more
%    flexibility).  A few such styles are predeclared, matching what
%    is offered by \pkg{amsthm}. These are shown below.
%
%  \begin{instance}{thmstyle plain}
%    The main style used for many theorem-like environments, i.e., the
%    one you get if no special \cs{theoremstyle} has been specified.
%
% \changes{v0.9n}{2026/02/01}{Change order of elements (tagging/1199)}
% \changes{v0.9n}{2026/02/01}{Add further decl keys (tagging/1199)}
%    \begin{macrocode}
\DeclareInstance{thmstyle}{plain}{std}
  {
    ,caption-placement = unchained
    ,numbered          = true
    ,separator         = \ 
    ,punct             = . 
    ,before-hspace     = 0pt
    ,after-hspace      = 5pt plus 1pt minus 1pt
    ,order             = {title, separator, number, separator, note, punct}
    ,caption-decls     = \bfseries
    ,title-decls       = 
    ,number-decls      = \upshape
    ,punct-decls       = 
    ,note-decls        = \upshape\mdseries
    ,title-format      = #1
    ,number-format     = #1
    ,punct-format      = #1
    ,note-format       = (#1)
    ,body-decls        = \itshape
  }
%    \end{macrocode}
%
%  \end{instance}
%
%  \begin{instance}{thmstyle remark}
%    The \instname{remark} is like \instname{plain} with two changes:  
%    \begin{macrocode}
\DeclareInstanceCopy{thmstyle}{remark}{plain}
\EditInstance{thmstyle}{remark}
{
  ,caption-decls = \itshape
  ,body-decls    = \normalfont
}
%    \end{macrocode}
%  \end{instance}
%
%  
%
%  \begin{instance}{thmstyle definition}
%    The \instname{definition} is like \instname{plain} with only a
%    difference in the font used for the body:  
%    \begin{macrocode}
\DeclareInstanceCopy{thmstyle}{definition}{plain}
\EditInstance{thmstyle}{definition}
{
  ,body-decls = \normalfont
}
%    \end{macrocode}
%
%  \end{instance}
%
%
%  \begin{instance}{thmstyle legacy2e}
%    Vanilla \LaTeXe{} (without \pkg{amsthm} loaded) had a slightly
%    different default. We provide this under the name
%    \instname{legacy2e}. It doesn't use a punctuation after the
%    number and it has slightly different vertical spacing (defined by
%    \instname{thm-legacy2e-1} below).
%
%    Thus, to reprocess an old document for tagging that uses
%    \cs{newtheorem} without loading \pkg{amsthm} one has to set
%    \verb=\theoremstyle{legacy2e}= to avoid layout changes. How
%    such a compatibility setting is automated is not yet decided.
%    \begin{macrocode}
\DeclareInstanceCopy{thmstyle}{legacy2e}{plain}
\EditInstance{thmstyle}{legacy2e}{ punct = }
%    \end{macrocode}
%
%  \end{instance}
%
%
%
%
% \subsubsection{The \insttype{block} instances they use}
%
%  
%  \begin{instance}{block thm-plain-1,
%                   block thm-plain-2}
%    Theorems do not support nesting, so in theory we have only one to set up.
%    There are, however, documents that put theorem-like environments
%    inside of lists or other block environments.
%    While that is in most case somewhat dubious, it
%    can make sense, for example, in \env{description} lists. So we
%    support it by providing \instname{thm-plain} instances for
%    levels 1 and 2. If somebody really nests them further down, then
%    more such instances need to be declared.
%
%    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}{thm-plain-1}{std}
{
  ,begin-extra-vspace = 0pt
  ,left-margin        = 0pt
  ,para-indent        = \parindent
  ,para-vspace        = \parskip
} 
%    \end{macrocode}
%    \begin{macrocode}
\DeclareInstanceCopy{block}{thm-plain-2}{thm-plain-1}
%    \end{macrocode}
%  \end{instance}
%  
%  \begin{instance}{block thm-remark-1,
%                   block thm-remark-2}
%    The \cs{thmstyle} for \enquote{remarks} is defined by
%    \pkg{amsthm} to use less vertical spacing. It therefore needs its
%    own \insttype{block} instance.
%    \begin{macrocode}
\DeclareInstance{block}{thm-remark-1}{std}
{
  ,begin-vspace       = 0.5\topsep
  ,begin-extra-vspace = 0pt
  ,left-margin        = 0pt
  ,para-indent        = \parindent
  ,para-vspace        = \parskip
}
%    \end{macrocode}
%  
%    \begin{macrocode}
\DeclareInstanceCopy{block}{thm-remark-2}{thm-remark-1}
%    \end{macrocode}
%  \end{instance}
%  
%  
%  \begin{instance}{block thm-legacy2e-1,
%                   block thm-legacy2e-2}
%    These are like the \texttt{plain} ones but without resetting
%    \key{begin-extra-vspace} to zero.
%    \begin{macrocode}
\DeclareInstance{block}{thm-legacy2e-1}{std}
{
  ,left-margin        = 0pt
  ,para-indent        = \parindent
  ,para-vspace        = \parskip
} 
%    \end{macrocode}
%    \begin{macrocode}
\DeclareInstanceCopy{block}{thm-legacy2e-2}{thm-legacy2e-1}
%    \end{macrocode}
%  \end{instance}
%
%
%
% \subsection{The \env{proof} environment (from \pkg{amsthm})}
%
%
%
%  \begin{environment}{proof}
%    The \env{proof} environment expects one optional argument holding
%    an alternative title for the proof. We parse this optional
%    argument as an implicit key/value argument, so that it is
%    possible to interpret it either as the value for the key
%    \key{note} or as a key/value list that holds special key settings
%    for this particular environment instance. The result is analyzed
%    by \cs{ParseLaTeXeTheoremlike} which then calls a \insttype{blockenv}
%    instance with the name \instname{proof}.
%
%    In addition we have to set up handling of QED symbols using
%    \cs{pushQED} and \cs{popQED} using the logic already defined in
%    \pkg{amsthm}. Details on all this is given in the code section of
%    this module but normally this top-level declaration doesn't
%    require any changes.
%
%    Conceptually, it would be better to disallow spaces before the
%    optional argument here. But \pkg{amsthm} never did this, so for
%    compatibility we aren't doing this either.
% \changes{v0.9o}{2026/02/16}{Allow spaces before the optional argument (tagging/1237)}
%    \begin{macrocode}
\NewDocumentEnvironment{proof}{ ={note}o }
   { \pushQED{\qed}%
     \ParseLaTeXeTheoremlike {proof} \BooleanTrue {#1} }
   { \popQED \BlockEnvEnd }
%    \end{macrocode}
%  \end{environment}


%
%  \begin{instance}{blockenv proof}
%    A proof uses its own \instname{proofblock} instance of type
%    \insttype{block} for vertical spacing. As the proof has a heading
%    we use a \insttype{captionedtext} instance with name
%    \instname{proof} as the inner instance and the paragraphs of the
%    proof are justified.
%    \begin{macrocode}
 \DeclareInstance{blockenv}{proof}{std}
{
   name                 = proof
  ,tag-name             = \UseStructureName{block/proof}
  ,tag-attr-class       =
  ,tagging-recipe       = standalone
  ,inner-level-counter  =
  ,transparent-level    = true
  ,legacy-code          =
  ,block-instance       = proof
  ,inner-instance-type  = captionedtext
  ,inner-instance       = proof
  ,para-instance        = justify
}
%    \end{macrocode}
%  \end{instance}
%
%
%
%  \begin{instance}{captionedtext proof}
%    We use a special \insttype{captionedtext} template to set up the
%    proof because proofs are not numbered and the argument to a proof
%    environment has a somewhat different semantic meaning than that
%    of theorem-like environments.
%
%    \begin{macrocode}
\DeclareInstance{captionedtext}{proof}{proof}
  {
    ,title         = \proofname    % default value
    ,punct         = . 
    ,before-hspace = 0pt
    ,after-hspace  = 5pt plus 1pt minus 1pt
    ,caption-decls = \itshape
    ,title-format  = #1
    ,punct-format  = #1
    ,body-decls    = \normalfont
  }
%    \end{macrocode}
%  \end{instance}
%
%
% \subsubsection{Block instances for the proofs}
%
%
%  \begin{instance}{block proof-1,
%                   block proof-2}
%    Blocks for proofs are pretty normal (the values are taken from
%    the \pkg{amsthm} implementation):
%    \begin{macrocode}
\DeclareInstance{block}{proof-1}{std}
{
  ,begin-vspace       = 6pt plus 6pt
  ,left-margin        = 0pt
  ,para-indent        = \parindent
  ,para-vspace        = \parskip
} 
\DeclareInstanceCopy{block}{proof-2}{proof-1}
%    \end{macrocode}
%
%  \end{instance}
%
%
% \section{Declaring \insttype{para} instances}\label{sec:para-instances}
%
%    Display block environments often require special paragraph
%    settings and therefore have a \key{para-instance} key to specify
%    and appropriate instance. Here are the standard instances that
%    are predefined for this purpose.
%
%  \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-attr-class       = justify
%  ,para-indent           = \parindent                  
%  ,begin-hspace          = 0pt
%  ,left-hspace           = \z@skip
%  ,right-hspace          = \z@skip
%  ,end-hspace            = \@flushglue
%  ,final-hyphen-demerits =  5000
%  ,newline-cmd           = \@normalcr
}
%    \end{macrocode}
%  \end{instance}
%
%
%  \begin{instance}{para center}
%    Centering a paragraph means putting stretchable glue on both sides.
%    \begin{macrocode}
\DeclareInstance{para}{center}{std}
{
  ,para-attr-class        = center
  ,para-indent           = 0pt                  
%  ,begin-hspace          = 0pt
  ,left-hspace           = \@flushglue
  ,right-hspace          = \@flushglue
  ,end-hspace            = \z@skip
  ,final-hyphen-demerits = 0
  ,newline-cmd           = \@centercr
}
%    \end{macrocode}
%  \end{instance}
%
%  \begin{instance}{para raggedright}
%    This is the plain \TeX{} version of ragged right, which basically
%    means no hyphenation unless a word is truly longer than a
%    line. This implements \env{flushleft}.
%    \begin{macrocode}
\DeclareInstance{para}{raggedright}{std}
{
  ,para-attr-class       = raggedright
  ,para-indent           = 0pt                  
%  ,begin-hspace          = 0pt
  ,left-hspace           = \z@skip
  ,right-hspace          = \@flushglue
  ,end-hspace            = \z@skip
  ,final-hyphen-demerits = 0
  ,newline-cmd           = \@centercr
}
%    \end{macrocode}
%  \end{instance}
%
%  \begin{instance}{para raggedleft}
%    This here is for \env{flushright}.
%    \begin{macrocode}
\DeclareInstance{para}{raggedleft}{std}
{
  ,para-attr-class       = raggedleft
  ,para-indent           = 0pt                  
%  ,begin-hspace          = 0pt
  ,left-hspace           = \@flushglue
  ,right-hspace          = \z@skip
  ,end-hspace            = \z@skip
  ,final-hyphen-demerits = 0
  ,newline-cmd           = \@centercr
}
%    \end{macrocode}
%  \end{instance}
%
%  \begin{macro}[no-user-doc]{\centering,\raggedleft,\raggedright,\justifying}
%    These instances are also used to implement declarations for
%    direct use in documents or in user definitions.
%    \begin{macrocode}
\DeclareRobustCommand\centering  {\UseInstance{para}{center}{}}
\DeclareRobustCommand\raggedleft {\UseInstance{para}{raggedleft}{}}
\DeclareRobustCommand\raggedright{\UseInstance{para}{raggedright}{}}
\DeclareRobustCommand\justifying {\UseInstance{para}{justify}{}}
%    \end{macrocode}
%    \LaTeX{}'s default is to typeset paragraphs justified.
%    \begin{macrocode}
\justifying
%    \end{macrocode}
%  \end{macro}
%
%  \begin{instance}{para verse}
%    For the \env{verse} environment we use a special para
%    instance. If the right hand side should be ragged then a
%    different \key{right-hspace} is needed.
%    \begin{macrocode}
\DeclareInstance{para}{verse}{std}
{
  para-attr-class       = justify ,
  para-indent           = 0pt ,                  
  begin-hspace          = -1.5em ,
  left-hspace           =  1.5em ,
  right-hspace          = 0pt ,
  end-hspace            = \@flushglue ,
  final-hyphen-demerits = 0 ,
  newline-cmd           = \@centercr ,
}
%    \end{macrocode}
%  \end{instance}
%
%
%    \begin{macrocode}
%</class-code>
%    \end{macrocode}
%
%
%
%
% \section{Advice on adjusting the layout of standard block environments}
%
% \emph{to document}
%
%
%
%
% \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 life, 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{\UseStructureName{para/semantic}}
%  and use \struct{\UseStructureName{para/textblock}} (role-mapped to \struct{P})
%  only for (portions of) the actual paragraph text in a way that the
%  \struct{\UseStructureName{para/textblock}}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
%    \>    \struct{\UseStructureName{para/textblock}}\\
%    \>\>  \struct{\UseStructureName{para/textblock}}\\
%    \>\>\> The paragraph text \ldots\\
%    \>\>  \struct{/\UseStructureName{para/textblock}}\\
%    \>    \struct{/\UseStructureName{para/textblock}}
% \end{tabbing}
% The \struct{\UseStructureName{para/semantic}} structure is
% role-mapped 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{\UseStructureName{para/semantic}}
% 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
%    \>     \struct{\UseStructureName{para/semantic}}\\
%    \>\>   \struct{\UseStructureName{para/textblock}}\\
%    \>\>\> The paragraph text before the display element \ldots\\
%    \>\>   \struct{/\UseStructureName{para/textblock}}\\
%    \>\>   \struct{display element structure}\\
%    \>\>\>  Content of the display structure possibly involving inner
%            \struct{\UseStructureName{para/semantic}} tags\\
%    \>\>   \struct{/display element structure}\\
%    \>\>   \struct{\UseStructureName{para/textblock}}\\
%    \>\>\> \ldots{} continuing the outer paragraph text\\
%    \>\>   \struct{/\UseStructureName{para/textblock}}\\
%    \>     \struct{/\UseStructureName{para/semantic}}
% \end{tabbing}
% In other words such a display block is always embedded in a
% \struct{\UseStructureName{para/semantic}} structure, possibly
% preceded by a \struct{\UseStructureName{para/textblock}}\ldots
% \struct{/\UseStructureName{para/textblock}} 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
%    \>          \struct{\UseStructureName{para/semantic}}\\
%    \>\>        \struct{\UseStructureName{para/textblock}}\\
%    \>\>\>      The intro text for the \env{itemize} environment \ldots\\
%    \>\>        \struct{/\UseStructureName{para/textblock}}\\
%    \>\>        \struct{itemize}\\
%    \>\>\>      \struct{LI}\\
%    \>\>\>\>    \struct{\UseStructureName{block/list/label}} label \struct{/\UseStructureName{block/list/label}}\\
%    \>\>\>\>    \struct{\UseStructureName{block/list/body}}\\
%    \>\>\>\>\>  The text of the first item involving
%                \struct{\UseStructureName{para/semantic}} as necessary \ldots\\
%    \>\>\>\>    \struct{/\UseStructureName{block/list/body}}\\
%    \>\>\>      \struct{/LI}\\
%    \>\>\>      \struct{LI}\\
%    \>\>\>\>    The second item \ldots{}\\
%    \>\>\>      \struct{/LI}\\
%    \>\>\>      \ldots{} further items \ldots\\
%    \>\>        \struct{/itemize}\\
%    \>          \struct{/\UseStructureName{para/semantic}}
% \end{tabbing}
% The \struct{itemize} is role-mapped 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{\UseStructureName{para/semantic}} structure but their body
% uses simple \struct{\UseStructureName{para/textblock}} blocks and
% not
% \struct{\UseStructureName{para/semantic}}\struct{\UseStructureName{para/textblock}}
% 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
%    \>          \struct{\UseStructureName{para/semantic}}\\
%    \>\>        \struct{\UseStructureName{para/textblock}}\\
%    \>\>\>      This is a paragraph with some\\
%    \>\>        \struct{/\UseStructureName{para/textblock}}\\
%    \>\>        \struct{text /O /Layout /TextAlign/Center}\\
%    \>\>\>      centered lines\\
%    \>\>        \struct{/\UseStructureName{para/textblock}}\\
%    \>\>        \struct{text /O /Layout /TextAlign/Center}\\
%    \>\>\>      with a paragraph break between them\\
%    \>\>        \struct{/\UseStructureName{para/textblock}}\\
%    \>\>        \struct{\UseStructureName{para/textblock}}\\
%    \>\>\>      followed by some more text.\\
%    \>          \struct{/\UseStructureName{para/semantic}}
% \end{tabbing}
% 
% The text-unit structures are added by using the tagging sockets 
% \texttt{para/semantic/begin} and \texttt{para/semantic/end} declared in 
% \texttt{lttagging.dtx}. They can be disabled by assigning these sockets the 
% plug \texttt{noop}.
%
%
% \subsubsection{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 \insttype{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 \insttype{blockenv} is not inside a
%     \struct{\UseStructureName{para/semantic}} structure. If
%     necessary, close the open one (and any open
%     \struct{\UseStructureName{para/textblock}} structure).
%
%   \item Text inside the body of the environment start with
%     \struct{\UseStructureName{para/semantic}}\struct{\UseStructureName{para/textblock}}
%     unless the key \key{tagging-suppress-paras} is set to
%     \keyvalue{true} (which is most likely the wrong thing to do
%     because we then get just
%     \struct{\UseStructureName{para/textblock}} as the structure).
%
%   \item At the end of the environment close
%     \struct{/\UseStructureName{para/textblock}} and possibly an
%     inner \struct{/\UseStructureName{para/semantic}} if open.
%
%   \item
%    Finally, ensure that after the environment a new
%     \struct{\UseStructureName{para/semantic}} 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 \insttype{blockenv} is inside a
%    \struct{\UseStructureName{para/semantic}}
%     structure, if necessary, start one. 
%
%   \item If inside a
%     \struct{\UseStructureName{para/semantic}}\struct{\UseStructureName{para/textblock}},
%     then close the \struct{/\UseStructureName{para/textblock}} but
%     leave the \struct{\UseStructureName{para/semantic}} open.
%
%   \item Text inside the body of the environment start with
%     \struct{\UseStructureName{para/semantic}}\struct{\UseStructureName{para/textblock}}
%     if \key{tagging-suppress-paras} is set to \keyvalue{false},
%     otherwise just with \struct{\UseStructureName{para/textblock}}.
%
%   \item At the end of the environment close
%     \struct{/\UseStructureName{para/textblock}} and possibly an
%     inner \struct{/\UseStructureName{para/semantic}} if open.
%
%   \item Then look if the environment is followed by an empty line
%     (\tn{par}). If so, close the outer
%    \struct{/\UseStructureName{para/semantic}} and start any
%     following text with
%     \struct{\UseStructureName{para/semantic}}\struct{\UseStructureName{para/textblock}}.
%     Otherwise, don't and following text restarts with a just a
%     \struct{\UseStructureName{para/textblock}} (and no paragraph
%     indentation)
%   \end{itemize}
%
% \item[\keyvalue{standard}]
%  This recipe is like the \keyvalue{basic}
%  one as far as handling \struct{\UseStructureName{para/semantic}}
%  and \struct{\UseStructureName{para/textblock}} is concerned. In
%  addition
%   \begin{itemize}
%   \item
%     it starts an inner tagging structure (i.e., which is therefore a
%     child of the outer \struct{\UseStructureName{para/semantic}}).
%   \item
%     By default this structure is a \struct{Div} unless overwritten
%     by the key \key{tag-name}. If that key is used, a suitable
%     role-map 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{\UseStructureName{para/semantic}} 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{\UseStructureName{block/list/label}} for the item
%     labels and \struct{\UseStructureName{block/list/body}} 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 role-map.
%   \item
%     If the key \key{tag-attr-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{/\UseStructureName{block/list/body}}, \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{Tracing and debugging}
% 
% \begin{function}{\DebugBlocksOn,\DebugBlocksOff, \block_debug_on:, \block_debug_off:}
%    These commands enable/disable debugging messages for blocks. They also
%    enable/disable debugging of templates (e.g., call
%    \cs{DebugTemplatesOn} or \cs{DebugTemplatesOff}).
% \end{function}
%
%    The data that is produced is rather verbose and largely guided
%    (so far) by what seemed helpful while developing the code. This
%    needs some cleanup at a later stage.\fmi{cleanup} At the moment,
%    if you have the following simple document
%
%\begin{footnotesize}
%\begin{verbatim}[xleftmargin=-20pt,numbers=left,numbersep=6pt,numberblanklines]
%         \DocumentMetadata{tagging=on, lang=en}
%
%         \documentclass{article}
%
%         \DebugBlocksOn
%
%         \begin{document}
%           \begin{itemize}[item-vspace=3pt]
%             \item             A normal item
%             \item[\textbf{+}] A special item
%           \end{itemize}
%         \end{document}
%\end{verbatim}
%\end{footnotesize}
%
%    \smallskip
%    \noindent
%    then you will get the following information on the screen and in
%    the \texttt{.log} file:
%    \smallskip
%
%\begin{footnotesize}
%\begin{verbatim}[xleftmargin=-40pt]
% [Template] ==> Use 'blockenv' instance: itemize on input line 8
% [Template] ==>   template: 'std'; arguments: |item-vspace=3pt|\BooleanFalse |\NoValue |\NoValue |
% [Template] ==> Use 'block' instance: std-list-1 on input line 8
% [Template] ==>   template: 'std'; argument: |item-vspace={3pt}|
% [Blocks] ==> @endpe=false on input line 8
% [Template] ==> Use 'list' instance: itemize-1 on input line 8
% [Template] ==>   template: 'std'; arguments: ||\BooleanFalse |\NoValue |\NoValue |
% [Blocks] ==> Set first block everypar on input line 8
% [Blocks] ==> template:list:std end
%
% [Template] ==> Use 'item' instance: basic on input line 9
% [Template] ==>   template: 'std'; argument: ||
% [Blocks] ==> Set item block everypar on input line 9
% [Blocks] ==> ... in item block everypar on input line 9
% [Blocks] ==> increment P on input line 9
% [Blocks] ==> Set noop block everypar on input line 9
%
% [Template] ==> Use 'item' instance: basic on input line 10
% [Template] ==>   template: 'std'; argument: |label={\textbf {+}}|
% [Blocks] ==> item with optional
% [Blocks] ==> Set item block everypar on input line 10
% [Blocks] ==> ... in item block everypar on input line 10
% [Blocks] ==> increment P on input line 10
% [Blocks] ==> Set noop block everypar on input line 10
%
% [Blocks] ==> blockenv common ending on input line 11
%
% [Blocks] ==> flattened=false on input line 12
% [Blocks] ==> Structure-end text-unit after displayblock on input line 12
%\end{verbatim}
%\end{footnotesize}
%
%
%
% \section{New and redefined kernel command}
% 
% \begin{function}{\SimpleBlockEnv,\BlockEnv,\BlockEnvEnd,\g_block_nesting_depth_int}
% \emph{to be documented}
% \end{function}
% 
% \begin{function}{\legacyverbatimsetup,\legacyallttsetup,\legacylistsetup}
% \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}{\newtheorem,\newtheoremstyle}
%   Reimplemented to fit the template approach. \cs{newtheoremstyle}
%    was defined by \pkg{amsthm}.
% \end{function}
%
% \begin{function}{\@nthm,\@xnthm,\@ynthm,
%                  \@thm,\@xthm,\@ythm,\@othm,
%                  \@begintheorem,\@opargbegintheorem,\@endtheorem}
%   These are no longer used (to be removed).
% \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 redefined to handle \tn{@doendpe} better.
% TODO: move to kernel
% \end{function}
%
% \begin{function}{\@doendpe}
%   The original \LaTeXe{} command is augmented to allow for tagging.
% \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}
%<*package-start>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=block>
%    \end{macrocode}
%
%
%    \begin{macrocode}
\ProvidesPackage {latex-lab-testphase-block}
                 [\ltlabblockdate\space v\ltlabblockversion\space
                            blockenv implementation]
%    \end{macrocode}
%
%
%    \begin{macrocode}
\ExplSyntaxOn
%    \end{macrocode}
%
%
% \subsubsection{Augmented \cs{SetKnownTemplateKeys}}
%
%
%  \begin{macro}{\SetKnownTemplateKeys}
%    A key/val list passed to  \cs{SetKnownTemplateKeys} can either be
%    empty (in which we do not want to start up the parsing machinery)
%    or it could be \cs{NoValue} in which we do not want to do that
%    either. The latter can happen, for example, with \env{verbatim}
%    where we define the optional argument with
%    \verb/={legacy-code} !o/ so that people can write
%    \verb/\begin{verbatim}[\small]/ a syntax promoted by the TUGboat
%    class.
%    \begin{macrocode}
\cs_set_protected:Npn \SetKnownTemplateKeys #1#2#3
  {
%    \end{macrocode}
%    An \enquote{empty} argument (or rather one that is empty after one
%    expansion) is the most likely case so we test for this first.
%    \begin{macrocode}
    \tl_if_empty:oTF {#3}
      {
        \tl_set_eq:NN  \UnusedTemplateKeys \c_empty_tl
      }
      {
        \tl_if_novalue:nTF {#3}
          {
            \tl_set_eq:NN  \UnusedTemplateKeys \c_empty_tl
          }
          {
            \keys_set_known:noN { template / #1 / #2 } {#3}
                                \UnusedTemplateKeys
          }
      }
  }
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\SetTemplateKeys}
%    Same kind of extension for \cs{SetTemplateKeys}:
%    \begin{macrocode}
\cs_set_protected:Npn \SetTemplateKeys #1#2#3
  {
    \tl_if_empty:oF {#3}
      {
        \tl_if_novalue:nF {#3}
          {
            \keys_set:no { template / #1 / #2 } {#3}
          }
      }
  }
%    \end{macrocode}
%  \end{macro}
%
% \subsubsection{Tracing templates and instances}
%
%  \begin{macro}{\template_debug_typeout:n}
%    I guess that tracing macro is needed in several modules, so
%    should become public (or at least kernel).
%    \begin{macrocode}
\cs_new_protected:Npn \template_debug_typeout:n { \__template_debug_typeout:n }
%    \end{macrocode}
%  \end{macro}
%
%
%
% \subsubsection{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}
%    The original \LaTeXe{} command is augmented to allow for tagging.
%    TODO: 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.
%
%    But we first have to restore \cs{par}, otherwise
%    \cs{skip_vertical:n} might trigger \cs{par} in horizontal mode
%    and then loop because it never returns to vertical mode.
%  \changes{v0.9p}{2026/04/07}{Restore \cs{par} first before
%    attempting to add a \cs{skip_vertical:n} (tagging/1298)}
%    \begin{macrocode}
      \@restorepar
      \clubpenalty\@clubpenalty
%    \end{macrocode}
%  \changes{v0.8x}{2024/12/01}{Handle \cs{parskip} after \texttt{\$\$}
%    display (tagging/762)}
%    \begin{macrocode}
      \if@domathendpe
        \skip_vertical:n { \tex_parskip:D }
        \@domathendpefalse
      \fi
%    \end{macrocode}
%    At this point we add the tagging code that closes an open
%    \struct{\UseStructureName{para/semantic}},
%    \struct{\UseStructureName{para/textblock}} tag combination, if
%    necessary:
%    \begin{macrocode}
      \tag_socket_use:n {@doendpe}
%    \end{macrocode}
%
%    The standard \tn{par} command (\cs{par_end:}) acts on
%    \texttt{@endpe} and attempts to close a still open
%    \struct{\UseStructureName{para/semantic}}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}
% \end{macro}




%  \begin{macro}{\@endpefalse,\@endpetrue}
%    Some extra debugging lines, but commented out for now.
%    \begin{macrocode}
\def\@endpefalse{
%  \@@_debug_typeout:n { @endpe~ :=~ \if@endpe true \else false \fi -> false \on@line }
  \global\let\if@endpe\iffalse
}
\def\@endpetrue {%
%  \@@_debug_typeout:n { @endpe~ :=~ \if@endpe true \else false \fi -> true \on@line }
  \global\let\if@endpe\iftrue
  \ifnum\currentgrouptype =14        % semi-simple group
    \aftergroup\propagate@doendpe
  \else
    \ifnum\currentgrouptype =\z@     % no group: top-level
    \else
      \ifnum\currentgrouptype =\@ne  % simple group
        \aftergroup\propagate@doendpe
     \fi
    \fi
  \fi
}

%    \end{macrocode}
%  \end{macro}


%
% \begin{socketdecl}{tagsupport/@doendpe}
% The socket is used in the \cs{@doendpe}
% TODO: if this goes into the kernel, the name should probably be different.
%    \begin{macrocode}
\socket_if_exist:nF{ tagsupport/@doendpe }
  {
    \NewTaggingSocket {@doendpe}{0}
  }
%    \end{macrocode}
% \end{socketdecl}
% 
% \begin{plugdecl}{default}
%  If a display block ends and is followed by a blank line we have to end the
%  enclosing paragraph tagging structure.
%    \begin{macrocode}
\NewTaggingSocketPlug {@doendpe}{default}
  {
   \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
%    the socket code is called while
%    \texttt{@endpe} is already handled and then we should not attempt
%    to close a \struct{\UseStructureName{para/semantic}} structure).
%    So we need to check for this.
%    \begin{macrocode}
       \legacy_if:nTF { @endpe }
         {
%           \typeout{===>~ handle~ @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{\UseStructureName{para/semantic}} followed by \struct{\UseStructureName{para/textblock}}, but simply
%    with a \struct{\UseStructureName{para/textblock}}),
%    then we don't have to do anything, because the \struct{\UseStructureName{para/textblock}} 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
             {
%    \end{macrocode}
% \changes{v0.9k}{2025/07/21}{Use tagging socket for text-unit structure}
%    \begin{macrocode}             
               \UseTaggingSocket{para/semantic/end}
                {
                  \@@_debug_typeout:n{Structure-end~
                      \l__tag_para_main_tag_tl\space
                      after~ displayblock \on@line     }
                }  
             }
         }
         {
%           \typeout{===>~ @endpe~ already~ handled}
         }
      }
  }
%    \end{macrocode}
%
%    \begin{macrocode}
\AssignTaggingSocketPlug{@doendpe}{default} 
%    \end{macrocode}
% \end{plugdecl}
%
%
%
%  \begin{macro}[int]{\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}
%
%
%    There is a general bug in the para handling: when the output routine is
%    triggered the current setting of \texttt{@endpe} affects what
%    happens in the OR. But it shouldn't, so we need to reset its value
%    (which is global) and set it back after the OR has finished. This
%    is what the following code does (final implementation should
%    probably not involve a normal hook):\fmi{fix in kernel}
%    \begin{macrocode}
\AddToHook{build/column/before}{%
  \if@endpe \@endpefalse \aftergroup\@endpetrue \fi
}  
%    \end{macrocode}
%
%
%
%
%
% \subsubsection{Other useful \pkg{expl3} commands}
%
% This section collects \pkg{expl3} commands that will be useful in
% the code here and possibly generally.
%
%  \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{macro}{\tl_if_novalue:oTF}
%    Not sure this is still necessary (or even correct) after the move
%    to \cs{NoValue}.
%    \fmi{check}
%    \begin{macrocode}
\cs_generate_variant:Nn \tl_if_novalue:nTF { o }
%    \end{macrocode}
%  \end{macro}
%    
%
% \subsection{Tracing and debugging interfaces}
%
%    This follows the same convention as in other modules, but
%    eventually that should be given a better
%    implementation.\fmi{refactor at some stage}
%    
%  \begin{variable}{\g_@@_debug_bool}
%    Boolean to indicate if we want to get debugging info from
%    commands and templates handling block displays.
%    \begin{macrocode}
\bool_new:N \g_@@_debug_bool
%    \end{macrocode}
%  \end{variable}
%
%
%  \begin{macro}{\@@_debug:n,\@@_debug_typeout:n}
%    Put debugging info in the code, displayed or not displayed
%    depending on the value in \cs{g_@@_debug_bool}.
%    \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:}
%    Changing the debugging status.
%    \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:Npe \@@_debug:n ##1
      { \bool_if:NT \g_@@_debug_bool {##1} }
    \cs_gset_protected:Npe \@@_debug_typeout:n ##1
       { \bool_if:NT \g_@@_debug_bool
         { \iow_term:e { ^^J [Blocks]~ ==>~ ##1} } }
  }
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\DebugBlocksOn,\DebugBlocksOff}
% \changes{2026-03-19}{v0.9p}{Move template debugging support to kernel}
%    If we are debugging blocks we also want to know about template
%    instances, so we turn the debugging for templates as well (for now).
%    \begin{macrocode}
\cs_new_protected:Npn \DebugBlocksOn  { \block_debug_on: \DebugTemplatesOn }
\cs_new_protected:Npn \DebugBlocksOff { \block_debug_off: \DebugTemplatesOff }
%    \end{macrocode}
%    
%    \begin{macrocode}
\DebugBlocksOff
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\DebugSwitchesOn,\DebugSwitchesOff}
%    This debugs the use of legacy switches (so perhaps better
%    called \cs{DebugLegacySwitchesOn}) but so far it was just a quick
%    debugging aid while I was trying to understand. It needs some
%    further thoughts and is probably not necessary at all in the end.
%    \begin{macrocode}
\cs_new_protected:Npn \DebugSwitchesOn {
  \AddToHookWithArguments{cmd/legacy_if_gset_false:n/before}[debug]
                         {\typeout{[Switch]~==>~ ##1~=~false~(global)}}
  \AddToHookWithArguments{cmd/legacy_if_gset_true:n/before}[debug]
                         {\typeout{[Switch]~==>~ ##1~=~true~(global)}}
  \AddToHookWithArguments{cmd/legacy_if_set_false:n/before}[debug]
                         {\typeout{[Switch]~==>~ ##1~=~false}}
  \AddToHookWithArguments{cmd/legacy_if_set_true:n/before}[debug]
                         {\typeout{[Switch]~==>~ ##1~=~true}}
}
%    \end{macrocode}
%    
%    \begin{macrocode}
\cs_new_protected:Npn \DebugSwitchesOff {
  \RemoveFromHook{cmd/legacy_if_gset_false:n/before}[debug]
  \RemoveFromHook{cmd/legacy_if_gset_true:n/before}[debug]
  \RemoveFromHook{cmd/legacy_if_set_false:n/before}[debug]
  \RemoveFromHook{cmd/legacy_if_set_true:n/before}[debug]
}
%    \end{macrocode}
%    
%    \begin{macrocode}
%\DebugSwitchesOn
%\DebugSwitchesOff
%    \end{macrocode}
%  \end{macro}
%
%
%
%
% \subsection{Template types and template interfaces}
%
%    This section is devoted to the template interfaces, and the template
%    code is covered later.
%
% \begin{templatetype}{blockenv,list,captionedtext,thmstyle,block,item,para}
% ^^A
%    All template types expect a first key--value argument used to
%    tweak template parameters at a specific point in the document for
%    a single environment or command.  The template types
%    \insttype{blockenv}, \insttype{list}, \insttype{captionedtext},
%    and \insttype{thmstyle} take three more arguments which are a
%    boolean for suppressing numbering, a possible caption, and a
%    possible sub-caption.
%
%    \begin{macrocode}
\NewTemplateType{blockenv}{4}
\NewTemplateType{list}{4}
\NewTemplateType{captionedtext}{4}
\NewTemplateType{thmstyle}{4}
%    \end{macrocode}
%    
%    \begin{macrocode}
\NewTemplateType{block}{1}
\NewTemplateType{item}{1}
\NewTemplateType{para}{1}
%    \end{macrocode}
% \end{templatetype}
%
%
%
%  \begin{template}{blockenv std}
% ^^A
%    \begin{macrocode}
\DeclareTemplateInterface{blockenv}{std}{4}
{
  name                   : tokenlist ,
%    \end{macrocode}
%    If not explicitly set then \key{tag-name} and
%    \key{tag-attr-class} are set by the
%    \key{tagging-recipe}. However, we have to default both to
%    \meta{empty} so that nested blocks do not inherit from the outer
%    level.
%  \changes{v0.9g}{2025/06/30}{ (tagging/925)}
%    \begin{macrocode}
  ,tag-name               : tokenlist =
  ,tag-attr-class         : tokenlist =
  ,tagging-recipe         : tokenlist = standard
  ,transparent-level      : boolean   = false
  ,legacy-code            : tokenlist = 
  ,block-instance         : tokenlist = std-display
%    \end{macrocode}
%    Paragraph instance is normally inherited so no default.
%    \begin{macrocode}
  ,para-instance          : tokenlist
  ,inner-level-counter    : tokenlist
  ,max-inner-levels       : tokenlist = 4
  ,inner-instance-type    : tokenlist =
  ,inner-instance         : tokenlist =
  ,tagging-suppress-paras : boolean = false
  ,final-code             : tokenlist = \ignorespaces
}
%    \end{macrocode}
%  \end{template}
%
%
%  \begin{template}{block std}
% ^^A
%  \changes{v0.8s}{2024/10/03}{Offer item-vspace key also on block templates}
%  \changes{v0.9l}{2025/11/04}{Fix default for para-vspace, should be the outer \cs{parskip}}
%    \begin{macrocode}
\DeclareTemplateInterface{block}{std}{1}    
{
  ,begin-vspace           : skip = \topsep
  ,begin-extra-vspace     : skip = \partopsep
  ,begin-unchained-vspace : skip = .5\topsep
  ,para-vspace            : skip = \parskip
  ,end-vspace             : skip = \KeyValue{begin-vspace}
  ,end-extra-vspace       : skip = \KeyValue{begin-extra-vspace}
  ,item-vspace            : skip = \itemsep
  ,begin-penalty          : integer = \UseName{@beginparpenalty}
  ,end-penalty            : integer = \UseName{@endparpenalty}
  ,item-penalty           : integer = \UseName{@itempenalty}
  ,left-margin            : length = \leftmargin
  ,right-margin           : length = \rightmargin
  ,para-indent            : length = 0pt
}
%    \end{macrocode}
%  \end{template}
%
%
%  \begin{template}{para std}    
% ^^A
%    \begin{macrocode}
\DeclareTemplateInterface{para}{std}{1}    
{
  ,para-attr-class       : tokenlist = justify                          
  ,para-indent           : length = \parindent
  ,begin-hspace          : skip = 0pt 
  ,left-hspace           : skip = 0pt
  ,right-hspace          : skip = 0pt
  ,end-hspace            : skip = \@flushglue
  ,fixed-word-spaces     : boolean = false
  ,final-hyphen-demerits : integer = 5000
  ,newline-cmd           : function(0) = \@normalcr
}
%    \end{macrocode}
%  \end{template}
%
%
%  \begin{template}{list std}
% ^^A
%    \begin{macrocode}
\DeclareTemplateInterface{list}{std}{4}
{
  ,counter         : tokenlist =
  ,item-label      : tokenlist =
  ,start           : integer = 1
  ,resume          : boolean = false
  ,item-instance   : instance{item} = basic
  ,item-vspace     : 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}
% ^^A
%    \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     % <- review viz standalone below
    ,text-font       : tokenlist
    ,compatibility   : boolean = true
    ,label-placement : choice {chained,unchained,standalone} = chained ,
  }
%    \end{macrocode}
% \end{template}
%
%
% \begin{template}{captionedtext thmlike}
% ^^A
%     The \insttype{captionedtext} \instname{thmlike} template for
%    theorem-like environments has only three keys because it
%    delegates most of the work to the \insttype{thmstyle}
%    template specified in the key \key{style}.
%    \begin{macrocode}
\DeclareTemplateInterface{captionedtext}{thmlike}{4}
{
  ,counter         : tokenlist =
  ,title           : tokenlist =      % <- bad name?
  ,style           : instance{thmstyle} = plain
}
%    \end{macrocode}
% \end{template}
%
%
% \begin{template}{captionedtext proof}
% ^^A
%    In contrast, the \insttype{captionedtext} \instname{proof}
%    template implements all of the \env{proof} environment without
%    any delegation and therefore shows several keys for customizing
%    the layout (similar to those seen with \insttype{thmstyle}
%    \instname{std}).
% \changes{v0.9n}{2026/02/01}{Add further decl keys (tagging/1199)}
% \changes{v0.9n}{2026/02/01}{Add caption-unbreakable key (tagging/1200)}
% \changes{v0.9n}{2026/02/02}{Use \cs{proofname} as value for title (tagging/1207)}
%    \begin{macrocode}
\DeclareTemplateInterface{captionedtext}{proof}{4}
{
  ,title             : tokenlist = \proofname
  ,punct             : tokenlist = .
  ,caption-placement : choice {chained,unchained,standalone} = unchained
  ,caption-unbreakable : boolean = false
  ,before-hspace     : skip = 0pt 
  ,after-hspace      : skip = 5pt 
  ,caption-decls     : tokenlist =
  ,title-decls       : tokenlist = 
  ,punct-decls       : tokenlist = 
  ,title-format      : function{1} = #1
  ,punct-format      : function{1} = #1
  ,body-decls        : tokenlist =
}
%    \end{macrocode}
% \end{template}
%
%  \begin{macro}{\proofname}
%    The \pkg{amsthm} package supported redefinition of \cs{proofname}
%    as a means to alter default caption for proofs. We continue to
%    support this as long as the instance declaration doesn't
%    overwrite it.
% \changes{v0.9n}{2026/02/02}{Macro \cs{proofname} added (tagging/1207)}
%    \begin{macrocode}
\newcommand\proofname{Proof}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
% \begin{template}{thmstyle std}
%
% \changes{v0.9n}{2026/02/01}{Add further decl keys (tagging/1199)}
% \changes{v0.9n}{2026/02/01}{Add caption-unbreakable key (tagging/1200)}
%    \begin{macrocode}
\DeclareTemplateInterface{thmstyle}{std}{4}
{
  ,numbered          : boolean = true
  ,separator         : tokenlist = \ 
  ,punct             : tokenlist = .
  ,caption-placement : choice {chained,unchained,standalone} = unchained
  ,caption-unbreakable : boolean = false
  ,before-hspace     : skip = 0pt
  ,after-hspace      : skip = 5pt
  ,order             : commalist = { title, separator, number, punct, separator, note }
  ,caption-decls     : tokenlist =
  ,title-decls       : tokenlist =
  ,number-decls      : tokenlist =
  ,punct-decls       : tokenlist =
  ,note-decls        : tokenlist =
  ,title-format      : function{1} = #1
  ,number-format     : function{1} = #1
  ,punct-format      : function{1} = #1
  ,note-format       : function{1} = (#1)
  ,body-decls        : tokenlist   =
}
%    \end{macrocode}
% \end{template}
%
%
%
%
%
% \subsection{Implementation of templates}
%
%
% \subsubsection{Some notes on the \LaTeXe{} legacy switches}
%
%    \LaTeXe{} used a number of switches to manage its list environments
%    and everything that was based on them.
%
%    For the reimplementation I made some notes about the original
%    usage and how this got changed (while keeping the names for now).
%
%    Some of these switches really need to keep their names, e.g.,
%    \texttt{@nobreak} or \texttt{minipage}, because they are used all
%    over the place. Others can probably replaced with L3 booleans
%    which makes things faster and cleaner, but for now I kept them
%    too.
%
% \paragraph{Original usage:}
%    \begin{macrocode}
%
% @newlist (global):  signal that we are at the start of a list
%
% -> true   at the start of a list before the first item when control
%           is returned to document
% -> false  in everypar setting the first item
% -> false  at end of list if still true (after generating an error)
%
% -> tests: at list start setting @noparitemtrue and @noparlisttrue
%
%
% @inlabel (global): signaling that some item label waits to be typeset
%
% -> true   in \@item  
% -> false  at list end
% -> false  in everypar after label has been typeset
% -> false  in \newpage after \leavevmode to typeset item label
%           (probably not needed)
%
% -> tests: at list start setting @noparitemtrue and @noparlisttrue
% -> tests: at list end to ensure that dangling label is typeset
% -> tests: in \@item to output a dangling item label by switching to hmode
% -> tests: in \everypar to output a dangling item label
% -> tests: in \newpage to output a dangling item label before the page is ended
% -> tests: in tagging hook {para/begin}{kernel}
%
%
% @noparlist (local):
%
% -> true   at start of list if already @inlabel=true
% -> false  at start of list otherwise
%
% -> tests: in \endtrivlist. If true suppress vertical spacing after the list
%
%
% @noparitem (local):
%
% -> true   at start of list if already @inlabel=true
% -> false  
%
%    \end{macrocode}
%    \paragraph{Repurpose:}
%    \begin{macrocode}
%
% Interpret legacy switches as follows (keeping the names for now)
%
% @newlist   ->  signals that we are at the start of a new block with a caption or
%                at the start of a list block expecting an item next
%
%                In other words this is now really start of a block
%                with inner structure.
%
% @noparlist ->  signals that we are on a new block with @inlabel already true, i.e.,
%                and this placement should happen horizontally
%
% @inlabel   ->  Signals that we have at least one item or caption waiting to be typeset
%                inside the label box
%
% @noparitem ->  dropped (handled directly)
%
%    \end{macrocode}
%
%
%
%
%
% \subsubsection{Implementation of \insttype{blockenv} templates}
%
% So far there is only one, but who knows \ldots\ --- however, the
%    majority will be vertically oriented blocks, so we make this the \texttt{std}.
%
%  \begin{template}{blockenv std}
% ^^A
%    \begin{macrocode}
\DeclareTemplateCode{blockenv}{std}{4}
{
   name                   = \l_@@_env_name_tl
  ,tag-name               = \l_@@_tag_name_tl
  ,tag-attr-class         = \l_@@_tag_class_tl
  ,tagging-recipe         = \l_@@_tagging_recipe_tl
  ,transparent-level      = \l_@@_transparent_level_bool
  ,legacy-code            = \l_@@_legacy_code_tl
  ,block-instance         = \l_@@_block_instance_tl
  ,para-instance          = \l_@@_para_instance_tl
  ,tagging-suppress-paras = \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 
}
{
  \template_debug_typeout:n{~\space template:~ 'std;~
                            arguments:~ \exp_not:n{|#1|#2|#3|#4|}}
%    \end{macrocode}
%    For special legacy support we start with a hook that receives the
%    \key{name} value as its argument (so that it contains code that
%    is only executed for a specific name).  Before calling this hook we also set
%    \cs{UnusedTemplateKeys} to empty. In the hook code this macro can then
%    be filled with key/value settings (for example, from \cs{setlist})
%    to be fed below into \cs{SetKnownTemplateKeys}.
%    \begin{macrocode}
  \tl_set_eq:NN  \UnusedTemplateKeys \c_empty_tl
  \exp_args:Nnno \hook_use:nnw {blockenv} 1 \l_@@_env_name_tl
%    \end{macrocode}
%    To the \cs{UnusedTemplateKeys} (empty or filled) we append any
%    keys specified in the first argument to the template unless
%    \texttt{\#1} is empty or contains just \cs{NoValue}. This allows
%    keys set on the document level to overwrite those set by
%    \cs{setlist} and ultimately also those set in the instance.
  %    \begin{macrocode}
  \tl_if_empty:oF {#1}
    {
      \tl_if_novalue:nF {#1}
        {
%    \end{macrocode}
%    We expand \texttt{\#1} once because the keys might be hidden in a
%    user macro.
%    \begin{macrocode}
          \tl_set:Ne \UnusedTemplateKeys
             { \exp_not:o \UnusedTemplateKeys \exp_not:o { #1 } }
        }
    }
%    \end{macrocode}
%    Finally the key list stored in \cs{UnusedTemplateKeys} is then
%    fed to \cs{SetKnownTemplateKeys} for
%    evaluation. \cs{SetKnownTemplateKeys} applies all keys that apply
%    to the \insttype{blockenv} template and saves those that don't
%    back in \cs{UnusedTemplateKeys} to be applied to inner instances
%    below. This is why we had to combine all keys and evaluate them
%    in one go.
%    \begin{macrocode}
  \SetKnownTemplateKeys {blockenv} {std} \UnusedTemplateKeys
%    \end{macrocode}
%    We need to know later if we have nested \insttype{blockenv}s
%    inside a flattened environment. Whenever we start a new
%    \insttype{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{\UseStructureName{para/semantic}} tag, while for any
%    value above \texttt{1} we have to omit the
%    \struct{\UseStructureName{para/semantic}}.
%    \begin{macrocode}
  \int_compare:nNnTF \l__tag_block_flattened_level_int > 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
             }
      }
%    \end{macrocode}
%    
%    \begin{macrocode}
  \tl_if_empty:NF \l_@@_inner_level_counter_tl
     {
       \int_compare:nNnTF  \l_@@_inner_level_counter_tl >
                           { \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}
  \int_compare:nNnTF  \g_block_nesting_depth_int >
                      { \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.
%
%    If have a transparent level (e.g., something like a \env{center}
%    environment) we omit setting the legacy defaults, because that is
%    the way \LaTeXe{} lists worked as well.
%    \changes{v0.9m}{2026-01-05}{Don't use legacy \texttt{@listi..} values for
%    transparent blocks (tagging/1163)}
%    \begin{macrocode}
       \bool_if:NF \l__block_transparent_level_bool
         {
           \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.
%    \changes{v0.9g}{2025-07-01}{use tagging socket for recipe}
%    \begin{macrocode}
     \UseTaggingSocket{block/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
%    overwritten 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 overwritten by the legacy setup code for
%    the \env{list} environment in \cs{l_@@_legacy_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 legacy setup code if any is given in the instance.
%    \begin{macrocode}
  \l_@@_legacy_code_tl
%    \end{macrocode}
%    Next call a block instance at the appropriate level passing it
%    any remaining key/value from the optional document-level argument
%    (i.e., those now stored in \cs{UnusedTemplateKeys}).
%
%
%  \changes{v0.9j}{2025/07/11}{Expand arguments before passing them to
%    \cs{UseInstance} to get better error messages}
%    \begin{macrocode}
  \exp_args:Nee \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. But 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 
    {
%    \end{macrocode}
%    For now we don't offer to alter instance parameters here so we
%    pass an empty argument.^^A
%  \changes{v0.9j}{2025/07/11}{Expand arguments before passing them to
%    \cs{UseInstance} to get better error messages}
%    \begin{macrocode}
      \exp_args:Nee \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
    {
%    \end{macrocode}
%    We expand the first two arguments so that we get proper names for
%    template type and instance, because \cs{UseInstance} is not doing
%    that for us in the right way.
%  \changes{v0.9j}{2025/07/11}{Expand arguments before passing them to
%    \cs{UseInstance} to get better error messages}
%    \begin{macrocode}
      \exp_args:Nee
      \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
                    #2      % <-- \BooleanTrue or False
                  { #3 }    % <-- \NoValue or content
                  { #4 }    % <-- \NoValue or content
%    \end{macrocode}
%    Again the instance may have processed a few keys from the so far
%    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 really clean.\fmi{fix}
%    \begin{macrocode}
%  \tl_if_empty:NF \l_@@_unused_blockenv_keys_tl
%    {
%       % check if only item template keys remain
%    }
%    \end{macrocode}
%    If this is supposed to be a transparent block environment then we
%    have to decrement the nesting level again so that nested
%    environments think nothing is there.
%    \begin{macrocode}
  \bool_if:NT \l_@@_transparent_level_bool
     {  \int_gdecr:N \g_block_nesting_depth_int }
%    \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{hookdecl}{blockenv}
%    For legacy support we want a hook with one argument (the name of
%    the \insttype{blockenv} instance). This way code could be added
%    that is conditional based on which instance is executed.
%    \begin{macrocode}
\NewHookWithArguments{blockenv}{1}
%    \end{macrocode}
%  \end{hookdecl}
%
%  \begin{macro}{\BlockEnv,\SimpleBlockEnv}
%    To simplify the environment declarations later we provide two
%    simple commands that invoke a \insttype{blockenv} instance. The
%    matching counterpart to these commands is \cs{BockEnvEnd}
%    (defined below) that carries out all necessary action when a
%    block environment ends.
%    \begin{macrocode}
\cs_new_protected:Npn \BlockEnv            % #1#2#3#4 implicit
   { \UseInstance{blockenv} }
%    \end{macrocode}
%
%    This here is the most common one that hides arguments 2--4 when
%    they aren't needed, e.g., in a \env{center} environment.
%    \begin{macrocode}
\cs_new_protected:Npn \SimpleBlockEnv #1#2
   { \UseInstance{blockenv}{#1}{#2} \BooleanFalse \NoValue \NoValue }
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \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_protected:Npn \g_block_nesting_depth_int { \@listdepth }  % a fake int
                                                                  % for now
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\l_@@_unused_blockenv_keys_tl}
%    The token list that holds key values we haven't yet used while
%    we are processing the instances in a block environment.
%    \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 \insttype{blockenv}s 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}{\BlockEnvEnd}
%    The code executed when a \insttype{blockenv} ends is 99\% the
%    same for all \insttype{blockenv}s (at least up to now). Small
%    differences exist, though. They are accounted for first in the
%    conditionals.
%
% \changes{v0.9l}{2025/11/21}{Renamed \cs{endblockenv} to \cs{BlockEnvEnd}}
%
%    We make this a public command so that new block environments can
%    be set up without the need to resort to L3 layer
%    programming.
%    \begin{macrocode}
\cs_new_protected:Npn \BlockEnvEnd {
  \@@_debug_typeout:n{blockenv~ common~ ending \on@line}
%    \end{macrocode}
%    If this block is not a transparent one we have to decrement the level
%    now again, otherwise that had happened earlier:
%    \begin{macrocode}
  \bool_if:NF \l_@@_transparent_level_bool
    { \int_gdecr:N \g_block_nesting_depth_int }
%    \end{macrocode}
%    If the \texttt{@inlabel} switch is true, i.e., if there is a
%    caption or an item waiting 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:TF
     { \legacy_if:nT { @newlist } { \@noitemerr } }
%    \end{macrocode}
%    If we aren't in a list we check if there are still unused keys
%    and in that case generate an error. In lists that is already done
%    at each \cs{item} command.
%  \changes{v0.9s}{2026/04/22}{Generate error when the block ends and
%    some keys are still unused (tagging/1317)}
%    \begin{macrocode}
     {
       \tl_if_empty:NF \UnusedTemplateKeys
          {
            \msg_error:nnee { block } { unknown-keys }
                { \l_@@_env_name_tl \space environment}
                \UnusedTemplateKeys
          }
     }
%    \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 environment is a list.
%  \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}
%    
%    There is a possibility that the \texttt{@nobreak} switch is still
%    true so we set it back just in case.
%    \begin{macrocode}
  \legacy_if_gset_false:n { @nobreak }
%    \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 environments 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 > \c_zero_dim
        {
          \skip_vertical:n { - \l_tmpa_skip }
          \skip_vertical:n { \l_tmpa_skip + \parskip - \@outerparskip }
        }
      \addpenalty \@endparpenalty
%    \end{macrocode}
%    
% \changes{v0.9o}{2026/02/15}{Support \texttt{end-vspace} and
%                             \texttt{end-extra-vspace} keys (tagging/738)}
%    \begin{macrocode}
      \addvspace  \l_@@_effective_bot_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_@@_effective_top_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 {block/endpe}
}
%    \end{macrocode}
%
%  \end{macro}
%
%
%  \begin{macro}{\@@_if_list:T,\@@_if_list:TF}
%    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 as \tn{item}s are only
%    supported if the \key{inner-instance-type} is \keyvalue{list}.
%  \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_@@_inner_instance_type_tl {list} }
\cs_new:Npn \@@_if_list:TF
   { \tl_if_eq:NnTF \l_@@_inner_instance_type_tl {list} }
%    \end{macrocode}
%  \end{macro}
%
%
%      
%  \begin{macro}{\__kernel_displayblock_end:}
%    The kernel hook for tagging at the end of the block.
%    \changes{v0.9s}{2026-04-18}{If inside a list execute the item/after hook.}
%    Without tagging it executes the \texttt{item/after} hook if inside a list, 
%    with active tagging it is overwritten by other commands in the recipes. 
%    \begin{macrocode}
\cs_new_protected:Npn \__kernel_displayblock_end: {
  \@@_if_list:T{\hook_use:n{item/after}}
  \@@_debug_typeout:n{\detokenize{__kernel_displayblock_end:}}
}
%    \end{macrocode}
%  \end{macro}
%
%
%
% \begin{socketdecl}{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 {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.
%
%    We can't use \cs{legacy_if_gset_true:n} because this is now doing
%    more than setting the legacy switch:
%    \begin{macrocode}
\socket_new_plug:nnn{block/endpe} {on}  { \@endpetrue  }
\socket_new_plug:nnn{block/endpe} {off} { \@endpefalse }
%    \end{macrocode}
%
%    \begin{macrocode}
\socket_assign_plug:nn{block/endpe}{on}
%    \end{macrocode}
% \end{plugdecl}
%
%
%
%
%
% \subsubsection{Implementation of \insttype{para} templates}
%
%  \begin{template}{para std}
%    
%    \begin{macrocode}
\DeclareTemplateCode{para}{std}{1}
{
  ,para-indent           = \parindent
%    \end{macrocode}
%    The next parameter needs integrating in the basic paragraph
%    handling (not done yet) and it should therefore probably a public
%    name like the rest.\fmi{integrate/fix}
%    \begin{macrocode}
  ,begin-hspace          = \l_para_begin_skip
  ,left-hspace           = \leftskip 
  ,right-hspace          = \rightskip 
  ,end-hspace            = \parfillskip
%    \end{macrocode}
%    Next isn't yet implemented (and the variable name is wrong).\fmi{fix}
%    \begin{macrocode}
  ,fixed-word-spaces     = \l__par_fixed_word_spaces_bool  % name??
  ,final-hyphen-demerits = \finalhyphendemerits
  ,newline-cmd           = \\
  ,para-attr-class       = \l__tag_para_attr_class_tl                          
}
{
  \template_debug_typeout:n{~\space template:~ 'std';~
                            argument:~ \exp_not:n{|#1|}}
  \SetTemplateKeys{para}{std}{#1}
%    \end{macrocode}
%
%    \begin{macrocode}
  \skip_set:Nn \@rightskip \rightskip
}
%    \end{macrocode}
%  \end{template}
%
%
%  \begin{macro}{\__para_handle_indent:}
%    We insert \cs{l_para_begin_skip} directly in front of the
%    indentation box. This way it is hidden from any special setting
%    of \cs{everypar} (whether that is used to remove the
%    indentation box or whether it attempts to do something with the
%    first token(s) of the paragraph). However, we only insert it if
%    it differs from 0.0pt to avoid adding
%    \verb=\penalty 10000 \glue 0.0= all over the place.
%    \begin{macrocode}
\tl_const:Ne \c__zero_skip_tl { \skip_use:N \z@skip }
\tl_new:N  \l__para_begin_skip_tl
%    \end{macrocode}
%    
%    \begin{macrocode}
\cs_set:Npn \__para_handle_indent: {
  \tl_set:Ne \l__para_begin_skip_tl { \skip_use:N \l_para_begin_skip }
  \if_meaning:w \l__para_begin_skip_tl
                \c__zero_skip_tl
  \else:
    \nobreak
    \tex_hskip:D \l_para_begin_skip
  \fi:
  \box_use_drop:N \g_para_indent_box
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\para_raw_noindent:}
%    \cs{para_raw_noindent:} doesn't call \cs{__para_handle_indent:}
%    so we have to manually do the \cs {l_para_begin_skip} handling. 
%    \begin{macrocode}
\cs_set:Npn \para_raw_noindent: {
  \mode_if_vertical:TF
       {
         \tex_everypar:D {
           \tex_everypar:D { \g__para_standard_everypar_tl }
           \tl_set:Ne \l__para_begin_skip_tl { \skip_use:N \l_para_begin_skip }
           \if_meaning:w \l__para_begin_skip_tl
                         \c__zero_skip_tl
           \else:
             \nobreak
             \tex_hskip:D \l_para_begin_skip
           \fi:
           \the\everypar }
       }
       { \msg_error:nn { latex2e }{ raw-para } }
  \tex_noindent:D
}
%    \end{macrocode}
%  \end{macro}
%
%
% \subsubsection{Implementation of \insttype{block} templates}
%
%
% \begin{template}{block std}
% ^^A   
%    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-vspace 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}{std}{1}
{
  ,begin-vspace           = \topsep
  ,begin-extra-vspace     = \partopsep
  ,begin-unchained-vspace = \l_@@_unchained_skip
  ,para-vspace            = \parsep
%    \end{macrocode}
%    The bottom skips aren't used yet, even if set instead as before
%    \cs{topsep} is applied there.\fmi{fix}
%    \begin{macrocode}
  ,end-vspace             = \l_@@_botsep_skip
  ,end-extra-vspace       = \l_@@_parbotsep_skip
  ,item-vspace            = \itemsep
  ,begin-penalty          = \@beginparpenalty
  ,end-penalty            = \@endparpenalty
  ,item-penalty           = \@itempenalty
  ,right-margin           = \rightmargin
  ,left-margin            = \leftmargin
  ,para-indent            = \l_@@_parindent_dim
}
{
    \template_debug_typeout:n{~\space template:~ 'std';~
                              argument:~ \exp_not:o{\exp_after:wN |#1|}}
    \SetKnownTemplateKeys{block}{std}{#1}
%    \end{macrocode}
%    One aspect that needs a different handling is the management of
%    \cs{par} after a block environment. If there is no empty line the
%    following text is considered to be a continuation of the current
%    paragraph. To manage this both \cs{par} and \cs{everypar} are
%    redefined with the latter removing the paragraph indentation from
%    the next paragraph. But if an empty line was seen after the block
%    then the redefined \cs{par} would cancel the redefinition of
%    \cs{everypar} so that the next paragraph again had its
%    indentation. The other case in which the following indentation
%    should not get suppressed is when two block environments directly
%    follow each other. In the original \LaTeXe{} implementation that
%    simply worked because the \cs{item} command canceled any
%    \cs{everypar} and all block environments were implemented as
%    \enquote{lists}, i.e., contained an \cs{item}, even if it was
%    only there to get the vertical spacing right. With the new block
%    implementation this is no longer the case, so we have handle the
%    cancelation ourselves.
%    
%    We can't simply use \verb/\mode_if_vertical:T { \par }/ because
%    that would also end the semantic paragraph. Instead we check is
%    \texttt{@endpe} handling is requested and if so reset \cs{everypar}.
%  \changes{v0.9p}{2026/03/29}{Cancel env par env handling on
%    consecutive block envs (tagging/1279)}
%    \begin{macrocode}
    \legacy_if:nT { @endpe } { \everypar{} }
%    \end{macrocode}
%    
%    The remaining 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
%    most of the legacy variables (e.g., \texttt{@noskipsec}) if there is
%    some chance that they are set/used in classes or packages.
%    \begin{macrocode}
    \legacy_if:nTF { @noskipsec }
%    \end{macrocode}
%    A \texttt{@noskipsec} heading is a heading that is placed in the
%    same line as the following text (using \cs{everypar}) but not if
%    that text starts with a display block, so we ensure that the
%    heading gets typeset now.\fmi{This is similar to the standalone case
%    for block captions so perhaps that can be combined, check}
%    \begin{macrocode}
       { \mode_leave_vertical: }
%    \end{macrocode}
%    If no such heading is waiting we might have a block caption
%    waiting to be typeset and this might be requested to be set
%    \enquote{unchained}. In that case we also have to ensure
%    that this gets typeset now.
%       
%    The situation is slightly different though, because we want to
%    end in vertical mode in that case also add
%    some special vertical space and have to properly deal with
%    avoiding page breaks.
%    \begin{macrocode}
       {
          \bool_if:NT \g_@@_label_unchained_bool
            {
              \@@_debug_typeout:n{Set~ captioned~ block~ everypar \on@line }
              \cs_set_eq:NN \@@_everypar: \@@_captioned_everypar_std:
              \legacy_if:nT { @inlabel }
                     {
                       \hbox_unpack_drop:N \g_@@_labels_box
                       \legacy_if_gset_false:n { @inlabel }
                       \par
                       \nobreak
                       \skip_vertical:n { \l_@@_unchained_skip }
                       \legacy_if_gset_true:n { @nobreak }
                     }
            }
        }
%    \end{macrocode}
%    The variable \cs{l_@@_effective_top_skip} is used for the
%    vertical skip at the start. It is initialized with
%    \key{begin-vspace} and below we add \key{begin-extra-vspace} if
%    the block starts in vmode.
%    \begin{macrocode}
    \skip_set:Nn \l_@@_effective_top_skip { \topsep }
%    \end{macrocode}
%    For the vertical space at the end we do something similar.
% \changes{v0.9o}{2026/02/15}{Support \texttt{end-vspace} and
%                             \texttt{end-extra-vspace} keys (tagging/738)}
%    \begin{macrocode}
    \skip_set:Nn \l_@@_effective_bot_skip { \l_@@_botsep_skip }
    \mode_if_vertical:TF
      {
        \skip_add:Nn \l_@@_effective_top_skip { \partopsep }
%    \end{macrocode}
%    
% \changes{v0.9o}{2026/02/15}{Support \texttt{end-vspace} and
%                             \texttt{end-extra-vspace} keys (tagging/738)}
%    \begin{macrocode}
        \skip_add:Nn \l_@@_effective_bot_skip { \l_@@_parbotsep_skip }
%    \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}
%    Next lines set some paragraph defaults, any of them may get overwritten
%    if there is a \key{para-instance} specified on the \insttype{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 > { 1000 }
                { \@noitemerr
                  { \para_end: }
                }
          }
          {
            { \para_end: }
          }
      }
%    \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=<L>=, a \verb=<Figure>= 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 is suppressed. This
%    is controlled through the legacy switches \texttt{@inlabel},
%    \texttt{minipage}, and \texttt{@nobreak}.
%
%    Now we are back to legacy list implementation \ldots
%    \begin{macrocode}
    \skip_set_eq:NN \@outerparskip \parskip
    \skip_set_eq:NN \parskip \parsep
%
    \legacy_if:nTF { @inlabel }
      {
        \legacy_if_set_true:n { @noparlist }
        \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 - \parsep }
          }
      }      
      {
        \legacy_if_set_false:n { @noparlist }
        \legacy_if:nT { @newlist } { \@noitemerr }
        \legacy_if:nTF { @nobreak }
          {
%    \end{macrocode}
%    We are not resetting \texttt{@nobreak} here as it should also
%    apply to the upcoming item.
%    \begin{macrocode}
            \addpenalty{ 10000 }
            \addvspace{ \skip_eval:n{\@outerparskip-\parsep} }
          }
          {
            \addpenalty \@beginparpenalty
            \addvspace { \skip_eval:n { \l_@@_effective_top_skip +
                                        \@outerparskip } }
            \addvspace { - \parsep }
          }
     }
}
%    \end{macrocode}
% \end{template}
%
%
%
%
%
%  \begin{macro}{\@@_captioned_everypar_std:}
%    The captioned text is typeset at the start of a paragraph using
%    code triggered in \cs{everypar} (by setting \cs{@@_everypar} to
%    this code here).
%    \begin{macrocode}
\cs_new_protected:Npn \@@_captioned_everypar_std: {
    \@@_debug_typeout:n{...~ in~ captioned~ block~ everypar \on@line }
%    \end{macrocode}
%    First set some control switches to false:
%    \begin{macrocode}
    \legacy_if_set_false:n { @minipage }
    \legacy_if_gset_false:n { @newlist }
%    \end{macrocode}
%    The \texttt{@inlabel} is normally true at this point, but if we
%    also have \texttt{@nobreak} then the same routine is called again
%    at the next paragraph to reset \cs{clubpenalty} and at that point
%    the \cs{g_@@_labels_box} has been typeset and \texttt{@inlabel}
%    is false.
%    \begin{macrocode}
    \legacy_if:nT { @inlabel }
       {
%    \end{macrocode}
%    Typeset the saved label (aka captioned text):
%    \begin{macrocode}
         \legacy_if_gset_false:n { @inlabel }
         \para_omit_indent:
         \bool_if:NTF \l_@@_caption_unbreakable_bool
                      \box_use_drop:N
                      \hbox_unpack_drop:N
            \g_@@_labels_box
         \__kernel_list_label_after:n { \PARALABEL }     % <- change
                                                         % this name
         \penalty \c_zero_int
       }
%    \end{macrocode}
%    If \texttt{@nobreak} is true we prevent a break after the first
%    line by setting \cs{clubpenalty}.
%    \begin{macrocode}
   \legacy_if:nTF { @nobreak }
       {
         \legacy_if_gset_false:n { @nobreak }
         \int_set:Nn \clubpenalty { 10000 }
       }
       {
%    \end{macrocode}
%    Otherwise we reset \cs{clubpenalty} and disable \cs{@@_everypar}.
%    \begin{macrocode}
         \int_set_eq:NN \clubpenalty \@clubpenalty
         \@@_debug_typeout:n{Set~ noop~ block~ everypar \on@line }
         \cs_set_eq:NN \@@_everypar: \prg_do_nothing:
       }
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
%
%
%  \begin{macro}{\__kernel_displayblock_begin:,
%                \__kernel_displayblock_beginpar_hmode:w,
%                \__kernel_displayblock_beginpar_vmode:}
%    The internal kernel hooks for tagging.
%    \begin{macrocode}
\cs_new_protected:Npn \__kernel_displayblock_begin: {
  \@@_debug_typeout:n
     {\detokenize{__kernel_displayblock_begin:}}
}
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_new_protected:Npn \__kernel_displayblock_beginpar_hmode:w {
  \@@_debug_typeout:n
     {\detokenize{__kernel_displayblock_beginpar_hmode:w}}
}
%    \end{macrocode}
%
%    \begin{macrocode}
\cs_new_protected:Npn \__kernel_displayblock_beginpar_vmode: {
  \@@_debug_typeout:n
     {\detokenize{__kernel_displayblock_beginpar_vmode:}}
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
% \subsubsection{Implementation of \insttype{list} templates}
%
%   This \insttype{list} is one of the template types that can be used
%   as an \key{inner-type} in a \insttype{blockenv}; the other one
%   currently implemented is \insttype{captionedtext}.
%
%  \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}{4}
{
  ,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-vspace     = \itemsep
%  ,item-para-vspace   = \parsep
  ,item-penalty    = \@itempenalty
  ,item-indent     = \itemindent
  ,label-width     = \labelwidth
  ,label-sep       = \labelsep
  ,legacy-support  = \l_@@_legacy_support_bool % FMi questionable
}
{
  \template_debug_typeout:n{~\space template:~ 'std';~
                            arguments:~ \exp_not:o{\exp_after:wN |#1|#2|#3|#4|}}
%    \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 tricky
%    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 later on. 
%
%    The definition of \cs{@@_evaluate_saved_user_keys:nn} made here
%    is later used when an \cs{item} is processed and passes
%    remaining keys to the item instance. After that nothing should
%    remain, so we test that and issue an error if not.
%    \begin{macrocode}
       \cs_set:Npe \@@_evaluate_saved_user_keys:nn ##1##2
          { \SetKnownTemplateKeys{##1}{##2}{
              \exp_not:o { \UnusedTemplateKeys }
            }
            \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 no counter name has been specified as part of the instance
%    setup the list might still be numbered if it is a legacy list
%    that uses \cs{usecounter} in the second argument of the legacy
%    \env{list} environment. However, in that case we don't have to do
%    much because \cs{usecounter} sets up \cs{@listctr} and sets
%    it to zero so that the first item is numbered 1.
%      
%    So all we do is to check if there was a \key{start} value given
%    that differs from 1 and if so we change the counter value to
%    match that. This makes it possible to define a legacy \env{list}
%    in which the counter doesn't start with 1 by explicitly setting
%    the counter value in the second argument of the \env{list}
%    environment but also overwriting that through a \key{start} key
%    setting on invocation.
%  \changes{v0.8v}{2024/10/11}{Correct logic for setting up the list
%    counter  (tagging/730)}
%  \changes{v0.9f}{2025/06/21}{Correct logic for setting up the list
%    counter further (tagging/893)}
%    \begin{macrocode}
     \int_compare:nNnF \l_@@_counter_start_int = 1  
       {
         \int_gset:cn{ c@ \@listctr }
             { \l_@@_counter_start_int - 1 }
       } 
    }
%    \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}
%    \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 have 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 set up \cs{@@_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}
    \@@_debug_typeout:n{Set~ first~ block~ everypar \on@line }
    \cs_set_eq:NN \@@_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}
%  \end{template}
%
%
% \subsubsection{Implementation of \insttype{item} templates}
%
%
%
% \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}
%    The key{label-placement} is implemented using two booleans (at
%    the moment). 
%    \begin{macrocode}
    ,label-placement = {
      chained    = \bool_gset_false:N \g_@@_label_standalone_bool
                   \bool_gset_false:N \g_@@_label_unchained_bool ,
      unchained  = \bool_gset_false:N \g_@@_label_standalone_bool
                   \bool_gset_true:N  \g_@@_label_unchained_bool ,
      standalone = \bool_gset_true:N  \g_@@_label_standalone_bool
                   \bool_gset_false:N \g_@@_label_unchained_bool ,
     }
  }
%    \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}
  {
    \template_debug_typeout:n{~\space template:~ 'std';~
                              argument:~ \exp_not:n{|#1|}}
%    \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}. This generates an error if
%    not all key can be used, but it should really do so only on the
%    first item.
%  TODO: improve error handling!
%    
%    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 applicable, 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 distinguish
%    that from \verb=\item[]=.
%
%    \fmi{next line needs checking after novalue implementation was changed}
%    \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 } } }
      }
%    \end{macrocode}
% \changes{v0.9c}{2025/05/17}{Add \cs{MakeLinkTarget}, tagging issue \#840}
%    \begin{macrocode}
      {
        \@@_debug_typeout:n{item~ with~ optional}
        \@@_make_label_box:n {
          \MakeLinkTarget [\l_@@_env_name_tl]{}
          \l_@@_label_given_tl
        }
      }
    \bool_if:nT
      {
        \l_@@_label_boxed_bool
%   TODO: is \linewidth correct?
        && \dim_compare_p:n
               { \box_wd:N \l_@@_one_label_box <= \linewidth }
      }
      {
        \dim_compare:nNnT
          { \box_wd:N \l_@@_one_label_box } < \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 } > \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}
%    environment 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{@@_everypar:}
%    inside \hook{para/begin}. By default this command does nothing, now we
%    change it to attach the pending label or labels.
%    \begin{macrocode}
    \@@_debug_typeout:n{Set~ item~ block~ everypar \on@line }
    \cs_set_eq:NN \@@_everypar: \@@_item_everypar_std:
  }
%    \end{macrocode}
% \end{template}
%
%
%  \begin{macro}{g_@@_label_standalone_bool,g_@@_label_unchained_bool}
%    The two booleans for implementing \key{label-placement} and below
%    \key{caption-placement}.
%    \begin{macrocode}
\bool_new:N \g_@@_label_standalone_bool       % tmp until replaced
\bool_new:N \g_@@_label_unchained_bool        % tmp until replaced
%    \end{macrocode}
%  \end{macro}
%
%  \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=<Lbl>=.
%    \begin{macrocode}
        \tag_socket_use:nnn {block/list/label}{}
          {
%    \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}
          }
      }
  }
%    \end{macrocode}
% \end{macro}
%
% \begin{socketdecl}{block/list/label}
% A tagging socket to tag the label. It takes two arguments so that it can transparently
% pass the label content.\fmi{I think this socket should just be
%    called list/label}
% \changes{v0.9k}{2025/07/21}{Removed fallback declaration here}
% Declaration is in \file{lttagging.dtx}.
% \end{socketdecl}
% \begin{plugdecl}{default}
%    \begin{macrocode}
\NewTaggingSocketPlug{block/list/label}{default}
 {
   %
   % 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=\UseStructureName{block/list/label}}
   \tagmcbegin{tag=\UseStructureName{block/list/label}}
   %     }
   #2
   \tagmcend               % end mc-\UseStructureName{block/list/label} or artifact
   % FMi: unconditionally for now
   %  \tl_if_empty:oF \@itemlabel
   \tagstructend   % end   label
   \tagstructbegin{tag=\UseStructureName{block/list/body}}
 }
\AssignTaggingSocketPlug{block/list/label}{default}  
%    \end{macrocode}
% \end{plugdecl}
%  
%
%
% \begin{macro}{\@@_everypar:, \@@_item_everypar_std:, \@@_item_everypar_first:}
%    The \cs{@@_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 \@@_everypar: \prg_do_nothing:
%    \end{macrocode}
%    
%    \begin{macrocode}
\AddToHook{para/begin}[items]{\@@_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.
%    \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{@@_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{...~ in~ item~ block~ 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}
% \changes{v0.9w}{2026-05-08}{Unpack the box if next line is active, tagging/1276}
% TODO: that boxing/unboxing need to be reevaluated at some point 
%    \begin{macrocode}
        \bool_if:NTF \l_@@_next_line_bool
         {
           \hbox_unpack_drop:N \g_@@_labels_box
         }
         {
           \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:n {LI-}
%    \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{@@_everypar:} to do
%    nothing.
%    \begin{macrocode}
         \@@_debug_typeout:n{Set~ noop~ block~ everypar \on@line }
         \cs_set_eq:NN \@@_everypar: \prg_do_nothing:
       }
}
%    \end{macrocode}
%
%    This is the definition of \cs{@@_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_protected:Npn \@@_item_everypar_first: {
  \@@_debug_typeout:n{...~ in~ first~ block~ everypar \on@line }
  \legacy_if:nT { @newlist }  { \@noitemerr }
}
%    \end{macrocode}
%
% \end{macro}
%
%
% \begin{variable}{\l_@@_tmpa_skip}
%    \begin{macrocode}
\skip_new:N \l_@@_tmpa_skip
%    \end{macrocode}
% \end{variable}
%
%
%
%
%
%
%
% \begin{variable}{\l_@@_effective_top_skip, \l_@@_effective_bot_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_@@_effective_top_skip
\skip_new:N \l_@@_effective_bot_skip
%    \end{macrocode}
% \end{variable}
%
%
%
%
%
%  \begin{hookdecl}{item/before,item/after}
% We provide hooks at the begin and the end of an item. 
% The before hook is just after the tagging code opens the LI structure (if tagging is active).
% The after hook is just before the tagging code closes the LI structure.
% The hooks are executed in vmode. 
% In the item/before hook no typesetting should be done.
% It is possible to add content in the item/after but for correct tagging it must be
% wrapped in an \texttt{LBody} structure (e.g., with \verb+tag=\UseStructureName{block/list/body}+).
%    \begin{macrocode}
\NewHook{item/before}
\NewHook{item/after}
%    \end{macrocode}
%  \end{hookdecl}
%
%
% \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}[./legacy-lists]{
  \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
        }
        {
%    \end{macrocode}
%    If the previous \cs{item} ended in an environment requesting
%    \texttt{@endpe} handling we have to ensure that a \cs{par} is
%    seen so that the semantic paragraph surrounding that environment
%    ends (as it can't extend to the next item.
%    \begin{macrocode}
          \if@endpe \par \fi
%    \end{macrocode}
%    
%    \begin{macrocode}
          \legacy_if:nTF { @newlist }
            {
              \__kernel_list_item_begin:
              \hook_use:n{item/before}
%    \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}
%    The \insttype{item} instance puts the item label into
%    \cs{g_@@_label_standalone_bool} ready to be placed later. To make
%    that happen we need to signal that by setting the legacy switch
%    \texttt{@inlabel} to true. However, if this is a label that
%    should be always placed \enquote{standalone} we instead typeset it
%    immediately and ensure that there is no page break after
%    it.\fmi{support extra vertical space as well?}
%    \begin{macrocode}
          \bool_if:NTF \g_@@_label_standalone_bool
             {
               \bool_gset_false:N \g_@@_label_standalone_bool
               \leavevmode
               \box_use_drop:N \g_@@_labels_box
               \par
               \legacy_if_gset_true:n { @nobreak }  % do not break after
                                                    % a standalone item
             }
             {
               \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 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}
  \hook_use:n{item/after}
  \__kernel_list_item_end:
  \__kernel_list_item_begin:
  \hook_use:n{item/before}
%    \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}
%
%
%
%
% \subsubsection{Implementation of \insttype{captionedtext}
%                and \insttype{thmstyle} templates}
%
%
% \begin{template}{captionedtext thmlike}
%    The template for typical theorem-like environments is rather
%    trivial, just setting keys and then passing used keys and the
%    arguments to a \insttype{thmstyle} instance to do the real work.
%    \begin{macrocode}
\DeclareTemplateCode{captionedtext}{thmlike}{4}
{
  ,counter         = \l_@@_counter_tl
  ,title           = \l_@@_title_tl
  ,style           = \l_@@_style:nnnn
}
{
%    \end{macrocode}
%    Some debugging info as usual (showing the arguments that are passed):
%    \begin{macrocode}
  \template_debug_typeout:n{~\space template:~ 'thmlike';~
                            arguments:~ \exp_not:o{\exp_after:wN |#1|#2|#3|#4|}}
%    \end{macrocode}
%    Then we check if there are any keys passed to the instance from
%    the outside.
%    \begin{macrocode}
  \SetKnownTemplateKeys{captionedtext}{thmlike}{#1}
%    \end{macrocode}
%    Finally, we apply the style which is just an instance of
%    type \insttype{thmstyle}:
%    \begin{macrocode}
  \l_@@_style:nnnn \UnusedTemplateKeys {#2} {#3} {#4}
}
%    \end{macrocode}
% \end{template}
%
%
%
%  \begin{macro}{\theoremstyle,\l_@@_thmstyle_tl}
%  ^^A   
%    All that the \cs{theoremstyle} declaration does is saving its
%    argument so that it can be used in \cs{newtheorem}.
%    \begin{macrocode}
\cs_new_protected:Npn \theoremstyle #1{ \tl_set:Nn \l_@@_thmstyle_tl {#1} }
%    \end{macrocode}
%    \begin{macrocode}
\tl_new:N \l_@@_thmstyle_tl
%    \end{macrocode}
%    And the default is \texttt{plain}:
%    \begin{macrocode}
\theoremstyle{plain}
%    \end{macrocode}
%  \end{macro}
%
%
%
% \begin{template}{thmstyle std}
%    The \insttype{thmstyle} implements the theorem-like
%    environment and assumes that the fixed part of the caption is
%    already stored in \cs{l_@@_title_tl}. The reason for this
%    separation into two templates is that typically the same design
%    is used for different theorem-like environments only differing in
%    this fixed string.
% \changes{v0.9n}{2026/02/01}{Add further decl keys (tagging/1199)}
%    \begin{macrocode}
\DeclareTemplateCode{thmstyle}{std}{4}
{
  ,numbered        = \l_@@_numbered_bool
  ,separator       = \l_@@_separator_tl
  ,punct           = \l_@@_punct_tl
  ,caption-placement = {
     chained    = \bool_gset_false:N \g_@@_label_standalone_bool
                  \bool_gset_false:N \g_@@_label_unchained_bool 
    ,unchained  = \bool_gset_false:N \g_@@_label_standalone_bool
                  \bool_gset_true:N  \g_@@_label_unchained_bool
    ,standalone = \bool_gset_true:N  \g_@@_label_standalone_bool
                  \bool_gset_false:N \g_@@_label_unchained_bool
   }
  ,caption-unbreakable = \l_@@_caption_unbreakable_bool
  ,before-hspace   = \l_@@_caption_before_skip
  ,after-hspace    = \l_@@_caption_after_skip
  ,order           = \l_@@_order_clist
  ,caption-decls   = \l_@@_caption_decls_tl
  ,title-decls     = \l_@@_title_decls_tl
  ,number-decls    = \l_@@_number_decls_tl
  ,punct-decls     = \l_@@_punct_decls_tl
  ,note-decls      = \l_@@_note_decls_tl
  ,title-format    = \@@_title_format:n
  ,number-format   = \@@_number_format:n
  ,punct-format    = \@@_punct_format:n
  ,note-format     = \@@_note_format:n
  ,body-decls      = \l_@@_body_decls_tl
}
{
%    \end{macrocode}
%    Some tracing:
%    \begin{macrocode}
  \template_debug_typeout:n{~\space template:~ 'std';~
                            arguments:~ \exp_not:o{\exp_after:wN |#1|#2|#3|#4|}}
%    \end{macrocode}
%    Applying any user keys:
%    \begin{macrocode}
  \SetKnownTemplateKeys{thmstyle}{std}{#1}
%    \end{macrocode}
%    Since this is the last template that gets applied for
%    theorem-like environments, all keys should make sense, so if
%    something is left over we better generate an error:
%    \begin{macrocode}
  \tl_if_empty:NF \UnusedTemplateKeys
     {
       \msg_error:nnee { block } { unknown-keys }
           { \l_@@_env_name_tl \space environment}
           \UnusedTemplateKeys
     }
%    \end{macrocode}
%    
%    In case there is a dangling \cs{item} we can either join that
%    with the caption or we can output the item first. For now we
%    provide no customization for this, but it could be made
%    customizable.
%    \begin{macrocode}
%  \legacy_if:nT { @inlabel } { \indent \par }
%    \end{macrocode}
%    Determine if we do numbering:
%    \begin{macrocode}
    \bool_lazy_or:nnT
      { \tl_if_empty_p:N \l_@@_counter_tl }
      { #2 }
      { \bool_set_false:N \l_@@_numbered_bool }
%    \end{macrocode}
%    Save any note for later use (\verb=\#3= might contain \cs{NoValue}):
%    \begin{macrocode}
    \tl_set:Nn \l_@@_note_tl {#3}
%    \end{macrocode}
%    If we use numbering then we need a link target and increment the counter.
%    \begin{macrocode}
    \bool_if:NTF \l_@@_numbered_bool
       {  
         \@kernel@refstepcounter{ \l_@@_counter_tl }
         \MakeLinkTarget{ \l_@@_counter_tl }
       }
       {
         \MakeLinkTarget[theorem-like]{}
       }
%    \end{macrocode}
%    Add the caption into \cs{g_@@_labels_box}:
%    \begin{macrocode}
    \hbox_gset:Nn \g_@@_labels_box
      {
        \box_use_drop:N \g__block_labels_box % <- does nothing if
                                             % there is no dangling label
%    \end{macrocode}
%    Now apply the declarations that are for the whole caption.
%    \begin{macrocode}
        \l_@@_caption_decls_tl
%    \end{macrocode}
%    Then we apply the tagging socket for the caption to the complete content:
%    \begin{macrocode}
        \tag_socket_use:nnn {captionedtext/caption} {}
            {
              \skip_horizontal:n { \l_@@_caption_before_skip }
%    \end{macrocode}
%    For flexibility, the inner structure is given as a clist stored
%    in \cs{l_@@_order_clist}. We loop through it and call a
%    processing function for each item in this clist. Everything
%    happens in a group
%    \begin{macrocode}
              \clist_map_inline:Nn \l_@@_order_clist
                    { \group_begin:
                        \use:c { @@_do_##1: } 
                      \group_end:
                    }
              \skip_horizontal:n { \l_@@_caption_after_skip }
            }
      }
%    \end{macrocode}
%    If the title should be standalone we immediately push it out:
%    \begin{macrocode}
   \bool_if:NTF \g_@@_label_standalone_bool
      {
        \bool_gset_true:N \g_@@_label_standalone_bool
        \para_omit_indent:
        \box_use_drop:N \g_@@_labels_box
        \par
%    \end{macrocode}
%    \fmi{Do we need a \cs{nobreak} here or is this covered? check}
%    \begin{macrocode}
      }
%    \end{macrocode}
%    Otherwise we signal that we are at the start and have a label
%    dangling. The name \texttt{@newlist} is a bit unfortunate, but
%    for now we keep this name.\fmi{check if @newlist could be
%    replaced by something more general} 
%    \begin{macrocode}
      {
        \legacy_if_gset_true:n { @newlist }
        \legacy_if_gset_true:n { @inlabel }
      }
%    \end{macrocode}
%    Do not break after the first line:
%    \begin{macrocode}
    \legacy_if_gset_true:n { @nobreak }
%    \end{macrocode}
%    Then set up a special everypar to handle the dangling caption:
%    \begin{macrocode}
    \@@_debug_typeout:n{Set~ captioned~ block~ everypar \on@line }
    \cs_set_eq:NN \@@_everypar: \@@_captioned_everypar_std:
%    \end{macrocode}
%    Finally, set up any declarations for the body of the environment:
%    \begin{macrocode}
    \l_@@_body_decls_tl
%    \end{macrocode}
%    
%    \begin{macrocode}
  \@@_debug_typeout:n{template:thmstyle:std~end}
}
%    \end{macrocode}
% \end{template}
%
%
%
%
% \begin{socketdecl}{tagsupport/captionedtext/caption}
%    \begin{macrocode}  
\NewTaggingSocket{captionedtext/caption}{2}
%    \end{macrocode}
% \end{socketdecl}
%    
% \begin{plugdecl}{kernel}
%    \fmi{why kernel?}
%    \begin{macrocode}
\NewTaggingSocketPlug{captionedtext/caption}{kernel}
 {
   \tag_struct_begin:n{tag=\UseStructureName{block/theorem-like/caption}}
   #2
   \tag_struct_end:
 } 
\AssignTaggingSocketPlug{captionedtext/caption}{kernel} 
%    \end{macrocode}
% \end{plugdecl}
%
%
%
%    Here are the functions that are called when the corresponding name appears
%    in the caption clist.
%    
%
%  \begin{macro}{\@@_do_title:}
%    Handle the title:
%    \begin{macrocode}
\cs_new_protected:Npn \@@_do_title: {
%    \end{macrocode}
%    Check if there is a title.
%    \begin{macrocode}
  \tl_if_empty:NTF \l_@@_title_tl
%    \end{macrocode}
%    If the title is empty we drop accumulated but not yet typeset separators:
%    \begin{macrocode}
     { \@@_drop_separators: }
%    \end{macrocode}
%    Otherwise we typeset the title, first inserting separator (or separators)
%    that have been waiting.
%    \begin{macrocode}
     { \tag_socket_use:nnn {mc} {}{
         \@@_insert_separators:
%    \end{macrocode}
%    The title may have its own formatting:
% \changes{v0.9n}{2026/02/01}{Add decl key (tagging/1199)}
%    \begin{macrocode}
         \l_@@_title_decls_tl
         \@@_title_format:n \l_@@_title_tl }
     }
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\@@_do_note:}
%    Formatting of a note (if present) uses the same structure.
% \changes{v0.9n}{2026/02/01}{Add decl key (tagging/1199)}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_do_note: {
  \tl_if_novalue:oTF \l_@@_note_tl
     { \@@_drop_separators: }
     { \tag_socket_use:nnn {mc} {} {
         \@@_insert_separators:
         \l_@@_note_decls_tl
         \@@_note_format:n \l_@@_note_tl }
     }
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\@@_do_number:}
%    The number (if present) has a similar formatting but it uses an
%    \UseStructureName{block/theorem-like/label} structure:
% \changes{v0.9n}{2026/02/01}{Add decl key (tagging/1199)}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_do_number: {
  \bool_if:NTF \l_@@_numbered_bool
     { \tag_socket_use:nnn {struct-mc} {tag=\UseStructureName{block/theorem-like/label}}
         { \@@_insert_separators:
         \l_@@_number_decls_tl
           \@@_number_format:n {
             \use:c{ the \l_@@_counter_tl } }
         }
     }
     { \@@_drop_separators: }
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\@@_do_punct:}
%    The punctuation is handled slightly differently. It unconditionally drops any
%    dangling separators whether or not it is empty:
% \changes{v0.9n}{2026/02/01}{Add decl key (tagging/1199)}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_do_punct: {
  \@@_drop_separators:
  \tl_if_empty:NF \l_@@_punct_tl
     { \tag_socket_use:nnn {mc} {}{
         \l_@@_punct_decls_tl
         \@@_punct_format:n \l_@@_punct_tl }
     }
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\@@_do_separator:,\@@_insert_separators:,\@@_drop_separators:,
%                \g_@@_collected_separators_tl}
% ^^A
%    What's still missing is what \texttt{separator} should do. It simply
%    adds a \cs{l_@@_separator_tl} to the \cs{g_@@_collected_separators_tl}
%    tokenlist.  This way the clist can contain
%    \texttt{separator,separator,...} to indicate multiple separators
%    (mainly useful if they are some amount of space). The storage
%    tokenlist is global as the functions are executed inside their
%    own group, but the collected separator is used outside of that group.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_do_separator: {
  \tl_gput_right:Nn \g_@@_collected_separators_tl \l_@@_separator_tl
}
%    \end{macrocode}
%    So \cs{@@_insert_separators:} is trivial, all we have to do is to
%    insert the collected separators and then clear the tokenlist
%    \begin{macrocode}
\cs_new_protected:Npn \@@_insert_separators: {
  \g_@@_collected_separators_tl
  \tl_gclear:N \g_@@_collected_separators_tl
}
%    \end{macrocode}
%    Even simpler is \cs{@@_drop_separators:}
%    \begin{macrocode}
\cs_new_protected:Npn \@@_drop_separators: {
  \tl_gclear:N \g_@@_collected_separators_tl
}
%    \end{macrocode}
%    What remains is to declare the tokenlist.
%    \begin{macrocode}
\tl_new:N \g_@@_collected_separators_tl
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
%
%
%
%
%
%
%
%
% \begin{template}{captionedtext proof}
%    In case of the templates for proofs we do everything in a single template.
% \changes{v0.9n}{2026/02/01}{Add further decl keys (tagging/1199)}
% \changes{v0.9n}{2026/02/01}{Add caption-unbreakable key (tagging/1200)}
%    \begin{macrocode}
\DeclareTemplateCode{captionedtext}{proof}{4}
{
  ,title         = \l_@@_title_tl
  ,punct         = \l_@@_punct_tl
  ,caption-placement = {
     chained    = \bool_gset_false:N \g_@@_label_standalone_bool
                  \bool_gset_false:N \g_@@_label_unchained_bool
    ,unchained  = \bool_gset_false:N \g_@@_label_standalone_bool
                  \bool_gset_true:N  \g_@@_label_unchained_bool
    ,standalone = \bool_gset_true:N  \g_@@_label_standalone_bool
                  \bool_gset_false:N \g_@@_label_unchained_bool
   }
  ,caption-unbreakable = \l_@@_caption_unbreakable_bool
  ,before-hspace = \l_@@_caption_before_skip
  ,after-hspace  = \l_@@_caption_after_skip
  ,caption-decls = \l_@@_caption_decls_tl
  ,title-decls   = \l_@@_title_decls_tl
  ,punct-decls   = \l_@@_punct_decls_tl
  ,title-format  = \@@_title_format:n
  ,punct-format  = \@@_punct_format:n
  ,body-decls    = \l_@@_body_decls_tl
}
{
%    \end{macrocode}
%    Display the template's arguments when tracing:
%    \begin{macrocode}
  \template_debug_typeout:n{~\space template:~ 'proof';~
                            arguments:~ \exp_not:o{\exp_after:wN |#1|#2|#3|#4|}}
%    \end{macrocode}
%    Evaluate document-level key settings. As all given keys should be
%    handled we use \cs{SetTemplateKeys} to raise an error if one or
%    more are not recognized:
%    \begin{macrocode}
  \SetTemplateKeys{captionedtext}{proof}{#1}
%    \end{macrocode}
%    By default the title is defined by the proof instance, but if the
%    user provides an optional argument that optional argument
%    overwrites the title (in contrast to theorem-like environments
%    that use the optional argument to provide an additional note):
%    \begin{macrocode}
  \IfNoValueF {#3} { \tl_set:Nn \l_@@_title_tl {#3} }
%    \end{macrocode}
%    Now we prepare typesetting the title by placing it in the \cs{g_@@_labels_box}:
%    \begin{macrocode}
  \hbox_gset:Nn \g_@@_labels_box
    {
      \box_use_drop:N \g_@@_labels_box % <- does nothing if there
                                       %    is no dangling label
      \l_@@_caption_decls_tl
      \tag_socket_use:nnn {captionedtext/caption} {}
          {
            \skip_horizontal:n { \l_@@_caption_before_skip }
%    \end{macrocode}
%    \cs{@@_do_title:} and \cs{@@_do_punct:} unnecessarily call
%    \cs{@@_drop_separators:} but otherwise they do well, so \ldots
%    \begin{macrocode}
            \group_begin: \@@_do_title: \group_end:
            \group_begin: \@@_do_punct: \group_end:
            \skip_horizontal:n { \l_@@_caption_after_skip }
          }
    }
%    \end{macrocode}
%    The remaining code is identical to the one in \insttype{thmstyle}
%    \instname{std}; for documentation see there:
% \changes{v0.9n}{2026/02/01}{Allow caption to break by default (tagging/1200)}
%    \begin{macrocode}
  \bool_if:NTF \g_@@_label_standalone_bool
     {
       \bool_gset_true:N \g_@@_label_standalone_bool
       \para_omit_indent:
       \bool_if:NTF \l_@@_caption_unbreakable_bool
                    \box_use_drop:N
                    \hbox_unpack_drop:N
          \g_@@_labels_box
       \par
     }
     {
       \legacy_if_gset_true:n { @newlist }
       \legacy_if_gset_true:n { @inlabel }
     }
  \legacy_if_gset_true:n { @nobreak }
  \@@_debug_typeout:n{Set~ captioned~ block~ everypar \on@line }
  \cs_set_eq:NN \@@_everypar: \@@_captioned_everypar_std:
  \l_@@_body_decls_tl
%    \end{macrocode}
%    
%    \begin{macrocode}
  \@@_debug_typeout:n{template:captionedtext:proof~end}
}
%    \end{macrocode}
% \end{template}  
%
%
%
%
%
%
%
%
%
%
%
%
% \subsection{Tagging support commands}
%
% In this section we provide code to the various kernel hooks to support
% the tagging of different displayblock environments. 
% 
% \changes{v0.9g}{2025-07-01}{Define the following command 
%  even if tagging is not active, to allow to activate tagging later}   
% \changes{v0.9g}{2025-07-01}{Removed para-hook code, it is in tagpdf currently}   
% 
% 
%  \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{\UseStructureName{para/semantic}}, i.e., it is already
%    open.
%    
%    The command is mapped to
%    \cs{__kernel_displayblock_beginpar_vmode:} in various tagging
%    recipes.  It is also used in the math code!
%    \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{<2} because the first flattened environment
%    has to surround itself with a
%    \struct{\UseStructureName{para/semantic}}. Only any inner ones
%    then have to avoid adding another
%    \struct{\UseStructureName{para/semantic}}.
%    \begin{macrocode}
    {
      \int_compare:nNnT \l__tag_block_flattened_level_int < 2
          {
%    \end{macrocode}
% \changes{v0.9k}{2025/07/21}{Use tagging socket for text-unit structure}
%    \begin{macrocode}          
%            \typeout{===> @@_beginpar_vmode:}
%            \ShowTagging{struct-stack}
            \UseTaggingSocket{para/semantic/begin}
              { \__tag_para_main_store_struct: } 
%            \ShowTagging{struct-stack}
          }
    }
  }
%    \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.
%    
%    The command is mapped to
%    \cs{__kernel_displayblock_beginpar_hmode:w} in various tagging
%    recipes.
%    \begin{macrocode}
\cs_set:Npn \@@_beginpar_hmode:N #1
   {
      \UseTaggingSocket{para/textblock/end}
      \tagpdfparaOff \par \tagpdfparaOn
   }
%    \end{macrocode}
%  \end{macro}
%
%    Paragraph tagging is mainly done using the paragraph hooks. 
%    The code is in \file{lttagging.dtx}.     
%  
% \begin{socketdecl}{tagsupport/block/startpara/direct}
%    A tagging socket to start a paragraph structure. It takes an
%    argument (which is only used in debugging) that should be gobbled
%    if tagging is not active.  Not yet in lttagging (name and
%    function should be reviewed).
% 
%    This is a similar code to the one used in the para/begin hook but
%    without testing \texttt{@endpe}. This is not needed in the
%    standalone case and wrong inside lists.
%    
%    This code is used in various places and should be a dummy if
%    tagging is not active.
%    \begin{macrocode}
\socket_if_exist:nF {tagsupport/block/startpara/direct}
 {
   \NewTaggingSocket {block/startpara/direct}{1}
 }
%    \end{macrocode}
% \end{socketdecl}
%
% \begin{plugdecl}{default}
%    \begin{macrocode}
\NewTaggingSocketPlug{block/startpara/direct}{default}
 {
   \bool_if:NT \l__tag_para_bool 
      {
        \bool_if:NF \l__tag_para_flattened_bool
           {
%    \end{macrocode}
% \changes{v0.9k}{2025/07/21}{Use tagging socket for text-unit structure}
%    \begin{macrocode}
%             \typeout{===> block/startpara/direct}
%             \ShowTagging{struct-stack}
             \UseTaggingSocket{para/semantic/begin}
                              { \__tag_para_main_store_struct: }  
           }
         \UseTaggingSocket{para/textblock/begin} { #1 }
      }
 }
\AssignTaggingSocketPlug{block/startpara/direct}{default}  
%    \end{macrocode}
% \end{plugdecl}
%    
% The para/end hook code is in lttagging. 
% Currently we still need to remove the tagpdf chunk 
% to avoid that the socket is added twice.
% We add empty chunks to avoid warning messages from code parts trying to remove
% the chunks.
%    \begin{macrocode}
\AddToHook{para/end}[tagpdf]{}
\RemoveFromHook{para/end}[tagpdf]
\AddToHook{para/end}{}
%    \end{macrocode}
%
%    \begin{macrocode}
\def\PARALABEL{NP-}
%    \end{macrocode}
%
%
% \begin{socketdecl}{tagsupport/kernel/endpe/vmode}
%    A tagging socket which ends a structure. Used in \cs{begin} and
%    \cs{para_end:}. Not yet in lttagging (name and function should be
%    reviewed).
%    \begin{macrocode}
\socket_if_exist:nF {tagsupport/kernel/endpe/vmode}
 {
   \NewTaggingSocket {kernel/endpe/vmode}{0}
 }
%    \end{macrocode}
% \end{socketdecl}
% \begin{plugdecl}{default}
%    \begin{macrocode}
\NewTaggingSocketPlug{kernel/endpe/vmode}{default}
 {
   \if@endpe \ifvmode
     \bool_if:NT \l__tag_para_bool
      {
        \bool_if:NF \l__tag_para_flattened_bool
          {
%    \end{macrocode}
% \changes{v0.9k}{2025/07/21}{Use tagging socket for text-unit structure}
%    \begin{macrocode}          
             \UseTaggingSocket{para/semantic/end}{}
          }
%    \end{macrocode}
% \cs{@endpefalse} is needed by \cs{para_end:}, see test tagging-0097.
%    \begin{macrocode}
       \@endpefalse
     }
   \fi \fi
 }
\AssignTaggingSocketPlug{kernel/endpe/vmode}{default}  
%    \end{macrocode}
% \end{plugdecl}
% 
%  \begin{macro}{\para_end:}
%    If we see a \tn{par} in vmode and a
%    \struct{\UseStructureName{para/semantic}} 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} }
    }
  }
  {
%    \end{macrocode}
% TODO 2025-07-01. This is not exactly as before, this doesn't insert an \cs{\@endpefalse}
% when tagging is active. Check if this a problem.
%    \begin{macrocode}
    \UseTaggingSocket{kernel/endpe/vmode}%    
    \tex_par:D
  }
}
%    \end{macrocode}
%    Now reset \LaTeXe{} functions to use the changed \cs{para_end:}
%  \changes{v0.9j}{2025/07/19}{Use \texttt{@@@@} to obtain 2; found by
%    explcheck analysis}
% \TODO{Need to check if \cs{@@@@par} is ever used in a way that the
%    vmodetagging hook is needed.}
%    \begin{macrocode}
\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}
\protected\def\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
%    \end{macrocode}
%    The original \LaTeXe{} version did set \cs{@endpefalse}
%    unconditionally at this point, but this is conceptually wrong
%    because it prevents the upcoming environment from seeing if
%    \texttt{@endpe} handling was requested, which matters if tagging
%    is done. Instead, resetting \texttt{@endpe} should only happen at
%    the start of block environments after they have evaluate the
%    current status of this flag. For the same reason it is not
%    correct to unconditionally end a semantic paragraph here, because
%    \texttt{@endpe} is \texttt{true} we are in a semantic paragraph
%    that should continue.
%  \changes{v0.9q}{2026/04/11}{Do not use \cs{@endpefalse} in
%    \cs{begin} when tagging}
%    \begin{macrocode}
%    \@endpefalse
    \reserved@a}
%    \end{macrocode}
%  \end{macro}
%
%

%
%  \begin{macro}{\__kernel_list_label_after:n}
%  If starting the text-unit/text tags got delayed because of a pending label we
%  have to do it after the label got typeset.
%  TODO: it should do nothing without tagging that's why there is a test,
%  this should be better hidden in a tagging socket, but it is not quite clear
%  how to do this.\fmi{internally this is now a tagging socket, why the outer test then?}
%    \begin{macrocode}
\cs_new_protected:Npn \__kernel_list_label_after:n #1 {
  \tag_socket_use:nn {block/startpara/direct} { #1 }
}
%    \end{macrocode}
%  \end{macro}
%
%
%  \begin{macro}{\@@_inner_begin:}
%    Start a block that has an inner structure if it isn't also a list.
%  This command is tagging specific, it is mapped to \cs{__kernel_displayblock_begin:}
%   in some tagging recipes. 
%    \begin{macrocode}
\cs_new_protected: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).
%   This command is tagging specific, it is mapped to \cs{__kernel_displayblock_end:}
%   in some tagging recipes.
%    \begin{macrocode}
\cs_new_protected:Npn \@@_inner_end: {
  \@@_debug_typeout:n{block-end \on@line}
  \legacy_if:nT { @endpe }
    {
      \UseTaggingSocket{para/semantic/end}
        { \@@_debug_typeout:n{close~ /text-unit \on@line}}
    }
  \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 {\UseStructureName{block/list}}
%    \end{macrocode}
% \begin{variable}{\l__tag_L_attr_class_tl}
% The variable should be set to one of the list attributes \texttt{list}, \texttt{itemize}
% \texttt{enumerate} or \texttt{description} declared in latex-lab-namespace.
%    \begin{macrocode}
\tl_new:N\l__tag_L_attr_class_tl
\tl_set:Nn \l__tag_L_attr_class_tl {list}
%    \end{macrocode}
% \end{variable}
%
%
%  \begin{macro}{\@@_list_begin:}
%    Start a list \ldots
%    This command is tagging specific, it is mapped to \cs{__kernel_displayblock_begin:}
%    in a tagging recipe.  
%    \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.
%    This command is tagging specific, it is mapped to \cs{__kernel_list_item_begin:}
%    in a tagging recipe.
%    \begin{macrocode}
\cs_set:Npn \@@_list_item_begin: {
  \tagstructbegin{tag=\UseStructureName{block/list/item}}
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
%  \begin{macro}{\@@_list_item_end:}
%    When a list item ends we have to close \struct{\UseStructureName{block/list/body}} and
%    \struct{LI} but also a \struct{\UseStructureName{para/textblock}} in the special case that the
%    item material ends in a list (identifiable via \texttt{@endpe}).
%   This command is tagging specific. 
%   This command is copied to \cs{__kernel_list_item_end:} in the list recipe.
%    \begin{macrocode}
\cs_set:Npn \@@_list_item_end: {
  \legacy_if:nT { @endpe }
    {
%    \end{macrocode}
% \changes{v0.9k}{2025/07/21}{Use tagging socket for text-unit structure}
%    \begin{macrocode}    
      \UseTaggingSocket{para/semantic/end}
        { \@@_debug_typeout:n{Structure-end~ P~ at~ item-end \on@line } }
    }
  \tagstructend \tagstructend   % end \UseStructureName{block/list/body}, LI
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\@@_list_end:}
%    Finally, at the list end we have to close the open
%    \struct{\UseStructureName{block/list/body}}, \struct{LI}, \struct{L}, and possibly a
%    \struct{\UseStructureName{para/textblock}} 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{\UseStructureName{block/list/body}} 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 \UseStructureName{block/list/body} if they
%    never were opened.}
%   This command is tagging specific. 
%   This command is copied to \cs{__kernel_displayblock_end:} in the list recipe.
%    \begin{macrocode}
\cs_new_protected: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 }
        {
%    \end{macrocode}
% \changes{v0.9k}{2025/07/21}{Use tagging socket for text-unit structure}
%    \begin{macrocode}        
          \UseTaggingSocket{para/semantic/end}
           {\@@_debug_typeout:n{Structure-end~ text-unit~ at~ list-end \on@line }}
        }
      \tagstructend  % end \UseStructureName{block/list/body},
      \hook_use:n{item/after}
      \tagstructend  %  LI
    }
  \tagstructend               % end L
}
%    \end{macrocode}
%  \end{macro}
%    End of tagging related declarations.
%
%
%
% \subsubsection{Tagging recipes}
%
% \changes{v0.9g}{2025-07-01}{a tagging socket for recipe}
% \begin{socketdecl}{tagsupport/block/recipe}
% A tagging socket to call the tagging recipe.
% Declared in lttagging.
%    \begin{macrocode}
\socket_if_exist:nF {tagsupport/block/recipe}
 {
   \NewTaggingSocket{block/recipe}{1}
 }
%    \end{macrocode}
% \end{socketdecl}
% \begin{plugdecl}{default}
%    \begin{macrocode}
\NewTaggingSocketPlug{block/recipe}{default}
 {
   \use:c { @@_recipe_#1: }
 }
\AssignTaggingSocketPlug{block/recipe}{default}  
%    \end{macrocode}
% \end{plugdecl}
% 
%  \begin{macro}{\@@_recipe_basic:}
%    The \keyvalue{basic} recipe simply ensures that the block is inside
%    a \struct{\UseStructureName{para/semantic}} structure and if necessary starts one. When the
%    block ends and is followed by a blank line the \struct{\UseStructureName{para/semantic}}
%    structure is closed too, otherwise it remains open and further
%    text starts with just a \struct{\UseStructureName{para/textblock}} structure.
%
%    There is otherwise no inner structure so
%    \cs{__kernel_displayblock_begin:} and
%    \cs{__kernel_displayblock_end:} do nothing---\insttype{blockenv}s with inner
%    structure use the \keyvalue{standard} or \keyvalue{list} recipe instead.
%    \begin{macrocode}
\cs_new_protected: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{block/endpe}{on}
}
%    \end{macrocode}
%  \end{macro}
%
%  \begin{macro}{\@@_recipe_standalone:}
%    
%    The \keyvalue{standalone} recipe produces a block that ensures that
%    a previous \struct{\UseStructureName{para/semantic}} ends and that after the block a new
%    \struct{\UseStructureName{para/semantic}} starts.
%    \begin{macrocode}
\cs_new_protected: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:
%  \changes{v0.9q}{2026/04/11}{Use \cs{@endpefalse} in
%    \texttt{standalone} recipe}
%    \begin{macrocode}
  \@endpefalse
  \socket_assign_plug:nn{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{\UseStructureName{para/semantic}} structure if not
%       already in a \struct{\UseStructureName{para/semantic}}. In
%       the latter case end the MC and the
%       \struct{\UseStructureName{para/textblock}} but leave the
%       \struct{\UseStructureName{para/semantic}} open.
%
%       If we are producing flattened paragraphs, just close any
%       \struct{\UseStructureName{para/textblock}} but do not open a
%       \struct{\UseStructureName{para/semantic}}.
%
%    \item Then open an new (inner) structure (by default \struct{Div}
%       but typically the one specified on the instance).
%
%    \item At the end of the block close the inner structure
%       (\struct{Div} or explicit one) but leave the
%       \struct{\UseStructureName{para/semantic}} open to be either
%       continued or closed due to a following \tn{par}.
%    \end{itemize}
%    \begin{macrocode}
\cs_new_protected: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{block/endpe}{on}
%    \end{macrocode}
%    
%  \changes{v0.9g}{2025/06/30}{ (tagging/925)}
%    \begin{macrocode}
  \tl_if_empty:NTF \l_@@_tag_name_tl
     { \tl_set:Nn    \l_@@_tag_inner_tag_tl {\UseStructureName{block/inner}} }
     { \tl_set_eq:NN \l_@@_tag_inner_tag_tl \l_@@_tag_name_tl }
} 
%    \end{macrocode}
%  \end{macro}
%
%
%
%  \begin{macro}{\l_@@_tag_inner_tag_tl}
%    The tag name that is used if the block has an inner structure.
%    \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{\UseStructureName{para/semantic}}-structure or keeps
%       the current one open (only closing the MC).
%
%    \item It then starts a new structure role-mapped to L-structure
%       and arranges for handling list items, e.g., Li,
%       \UseStructureName{block/list/label} and
%       \UseStructureName{block/list/body} structures.
%
%    \item At the end it closes open list structures as needed but
%       keeps the \struct{\UseStructureName{para/semantic}}-structure
%       open to continue the paragraph after the list, if necessary.
%    \end{itemize}
%    \begin{macrocode}
\cs_new_protected: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{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:Ne    \l__tag_L_tag_tl {\UseStructureName{block/list}}               }
     { \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}
%
%
%    
%    \begin{macrocode}
%</package-start>
%    \end{macrocode}
%
%
% \section[Support code for document-level block environments]
%         {Support code for document-level block\\ environments}
%
%
%
% \subsection{Verbatim-like environments}
%
% \subsubsection{Helper commands for \env{verbatim} and \env{verbatim*}}
%
%  \begin{macro}{\legacyverbatimsetup}
% ^^A
%    This code is called as part of the \key{final-code} of the
%    \insttype{blockenv} instance and sets up the special conventions
%    needed for \env{verbatim} environments. We pass one argument to
%    differentiate between visible and invisible spaces.
%
%    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}
%<*package-finish>
%    \end{macrocode}
%
%    \begin{macrocode}
%<@@=>  
\def\legacyverbatimsetup #1 {%
  \language\l@nohyphenation
  \@tempswafalse
  \def\par{%
    \if@tempswa
      \leavevmode \null {\@@par}\penalty\interlinepenalty
    \else
      \@tempswatrue
      \ifhmode{\@@par}\penalty\interlinepenalty\fi
      \fi
%    \end{macrocode}
%    Do something at the very beginning of each verbatim line:\fmi{might
%       also need a hook not just a socket}
%    \begin{macrocode}
    \UseSocket{verbatim/startline}%
  }%
  \let\do\@makeother \dospecials
  \obeylines \verbatim@font \@noligs
  \everypar \expandafter{\the\everypar \unpenalty}%
%    \end{macrocode}
%    
%    \begin{macrocode}
  \frenchspacing
%    \end{macrocode}
%    \fmi{Should next line be hidden in a tagging socket?}
%    \begin{macrocode}
  \AssignStructureRole {para/textblock}%
                       {\UseStructureName{block/verbatim/codeline}}%
%    \end{macrocode}
%    If the argument is neither \texttt{visible} nor
%    \texttt{invisible} nothing will happen---tough.
%    \begin{macrocode}
  \use:c { @setupverb #1 space }
  \@vobeyspaces
}
%    \end{macrocode}
%  \end{macro}
%
%
% \begin{socketdecl}{verbatim/startline}
%    A socket that is executed at the start of each verbatim line, to
%    be used, for example, to check for
%    \verb*=% = when the \pkg{doc} package is
%    active.\fmi{We might also need a hook for line numbers.}
%    \begin{macrocode}
\NewSocket{verbatim/startline}{0}
%    \end{macrocode}
% \end{socketdecl}
%
%
%
%
%  \begin{macro}{\@setupverbinvisiblespace}
%  ^^A
%    In the \pdfTeX{} engine we need to use \tn{pdffakespace} chars
%    for the invisible spaces. In luatex we do not want this as it
%    would lead to doubling the number of real space chars. In
%    dvi-mode we do not want that either: with pdftex it would error,
%    with xetex it does nothing.  \changes{v0.9g}{2025-07-01}{changed
%    logic}
%    \begin{macrocode}
%<@@=block>  
\newcommand\@setupverbinvisiblespace{}
\bool_lazy_or:nnF 
 { \sys_if_engine_luatex_p: }
 { \sys_if_output_dvi_p: }
 {
   \renewcommand\@setupverbinvisiblespace
     {\def\@xobeysp{\nobreakspace\pdffakespace}}
 }
%    \end{macrocode}
%  \end{macro}
%
%   The command \cs{@setupverbvisiblespace} is already defined in the kernel.
%
%
%
%
% \subsubsection{Helper commands for \env{alltt} and \env{alltt*}}
%
%
%  \begin{macro}{\legacyallttsetup}
%    The \env{alltt} environment also needs some special setup. We can
%    reuse \cs{legacyverbatimsetup} but we have to take out \verb=\=,
%    \verb={=, and \verb=}= from \cs{dospecials} as they should remain
%    available with their normal catcodes and adjust \verb='= inside
%    math. This is lifted straight from the original package code.
%    \begin{macrocode}
%<@@=>
\ExplSyntaxOff
%    \end{macrocode}
%
%    \begin{macrocode}
\def\legacyallttsetup #1{%
  \let\org@prime~%
  \everymath\expandafter{\the\everymath
    \catcode`\'=12 \let~\org@prime}%
  \everydisplay\expandafter{\the\everydisplay
    \catcode`\'=12 \let~\org@prime}%
%    \end{macrocode}
%    This alters \cs{dospecials}:
%    \begin{macrocode}
  \let\org@dospecials\dospecials
  \g@remfrom@specials{\\}%
  \g@remfrom@specials{\{}%
  \g@remfrom@specials{\}}%
%    \end{macrocode}
%    Then call \cs{legacyverbatimsetup}:
%    \begin{macrocode}
  \legacyverbatimsetup {#1}%
%    \end{macrocode}
%    And afterwards restore \cs{dospecials:}
%    \begin{macrocode}
  \let\dospecials\org@dospecials
}
%    \end{macrocode}
%    
%  \begin{macro}{\g@remfrom@specials}
%    Copied from \pkg{alltt}.
%    \begin{macrocode}
\def\g@remfrom@specials#1{%
  \def\@new@specials{}%
  \def\@remove##1{%
    \ifx##1#1\else
    \g@addto@macro\@new@specials{\do ##1}\fi}%
  \let\do\@remove\dospecials
  \let\dospecials\@new@specials
}
%    \end{macrocode}
%
%    \begin{macrocode}
\ExplSyntaxOn
%<@@=block>  
%    \end{macrocode}
%  \end{macro}
%  \end{macro}
%
%
%
% \subsubsection{Helper command for legacy \env{list} environment}
%
%
%  \begin{macro}{\legacylistsetup}
%  ^^A    
%    And here is the extra code for use in the list instance setup
%    in the key \key{legacy-code}:
%    \begin{macrocode}
\cs_new_protected:Npn \legacylistsetup {
%    \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 (this holds whatever was put into the
%    second argument to the \env{list} environment):
%    \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} role-mapped 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}
%    The token list in which the declarations from the second argument
%    of \env{list} are temporarily stored. This is then used in
%    \cs{legacylistsetup}.
%    \begin{macrocode}
\tl_new:N\l_@@_legacy_env_params_tl
%    \end{macrocode}
%  \end{macro}
%
%
% \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.
%
%
% \subsubsection{Declarations for theorem-like environments}
%
%  \begin{macro}[no-user-doc]{\newtheorem}
%    We reimplement the extended \pkg{amsthm} version of the declaration which
%    also supports a star form indicating that this theorem-like
%    environment should not be numbered.
%    \changes{v0.9m}{2025-12-31}{Use an alias counter} 
%    \begin{macrocode}
\RenewDocumentCommand \newtheorem { s m o m o } {
%    \end{macrocode}
%    Is the environment definable at all? If not there is not much
%    point in continuing.
%    \begin{macrocode}
  \expandafter\@ifdefinable\csname #2\endcsname
   {
%    \end{macrocode}
%    
%    If a star was given then there is no need to set up a counter for
%    this environment. Otherwise we do what \LaTeX2e{} did, except
%    that we do all the variations in one go, rather than using
%    \cs{@ynthm}, \cs{@xnthm}, and \cs{@othm}.\fmi{undefined the old
%    internal commands?}
%    \begin{macrocode}
     \IfBooleanF #1
       {
         \IfNoValueTF {#3}
%    \end{macrocode}
%    If there was no counter to use (\verb=#2=) then we set up a
%    counter with the same name as the environment (\verb=#2=).
%    \begin{macrocode}
            {
              \@definecounter {#2}
%    \end{macrocode}
%    If there was no \enquote{counter within} the counter
%    representation is simple, otherwise we build it up from the two
%    counters:
%    \begin{macrocode}
              \IfNoValueTF {#5}
                {  % @ynthm
                  \tl_gset:ce { the #2 }
                     {
                       \@thmcounter{#2}
                     }
                }
                {  % @xnthm
                  \@newctr{#2}[#5]
                  \tl_gset:ce { the #2 }
                     {
                       \expandafter\noexpand\csname the#5\endcsname
                       \@thmcountersep
                       \@thmcounter{#2}
                     }
                }
            }
            {  % @othm
%    \end{macrocode}
%    If we should reuse an existing counter (\verb=#3= was given) we
%    check that this counter actually exists and if so use it:
%    \begin{macrocode}
              \@ifundefined{c@#3}
                 { \@nocounterr{#3} }
                 {
                   \newcounteralias{#2}{#3}
                 }
            }
       }
%    \end{macrocode}
%    With the counter defined we are ready to declare the
%    environments. There is a slight complication though: the
%    \enquote{theorem-like} environments have an optional argument
%    which contains a possible note, but now we also want to use the
%    first optional argument to hold a key/value list with parameter
%    settings. We therefore define this argument via \verb/={note}o/
%    so that a simple note, if given is assigned to a \key{note} key.
%    Further processing is then delegated to the command
%    \cs{ParseLaTeXeTheoremlike} which, after sorting out the argument
%    situation, eventually calls \cs{BlockEnv}.
%    \begin{macrocode}
     \NewDocumentEnvironment{#2}{ ={note}o }
        { \ParseLaTeXeTheoremlike {#2} \BooleanFalse {##1} }
        { \BlockEnvEnd }
%    \end{macrocode}
%    The starred form of the environment suppresses the  number so we
%    pass it \cs{BooleanTrue}, otherwise it is identical to the
%    previous definition.
%    \begin{macrocode}
     \NewDocumentEnvironment{#2*}{ ={note}o }
        { \ParseLaTeXeTheoremlike {#2} \BooleanTrue {##1} }
        { \BlockEnvEnd }
%    \end{macrocode}
%
%    Now it is about time to provide all necessary template
%    instances. They depend on the \cs{theoremstyle} specified by the
%    user and possibly by a \cs{swapnumbers} declaration. We start by
%    checking the requested \cs{theoremstyle} (if none was given then
%    \texttt{plain} is the default and if it is an unknown name we
%    also revert to \texttt{plain} after issuing a warning).
%    \begin{macrocode}
     \IfInstanceExistsF{thmstyle}{\l_@@_thmstyle_tl}
                       { \@latex@warning{Unknown~ theoremstyle~
                              '\l_@@_thmstyle_tl'~ using~ 'plain'}
                         \theoremstyle {plain}
                       }
%    \end{macrocode}
%    So now we know that \cs{l_@@_thmstyle_tl} holds a valid
%    style. What we don't know is  whether or not there are special
%    \insttype{block} instances that go with that style (it might be a style
%    that reuses the \instname{thm-\meta{style}block-...} instances).
%    \begin{macrocode}
    \IfInstanceExistsTF{block} { thm- \l_@@_thmstyle_tl -1 }
       { \@@_debug_typeout:n{...~ style~ \l_@@_thmstyle_tl\space exists } }
       { \@@_debug_typeout:n{...~ style~ \l_@@_thmstyle_tl\space
           does~ not ~exist;~ 'plain'~ used } }
%    \end{macrocode}
%    So here is the \insttype{blockenv} instance for the new
%    \enquote{theorem-like} environment. It uses a
%    \insttype{captionedtext} instance for the \key{inner-instance}
%    which we also have to declare.
%    \begin{macrocode}
    \DeclareInstance{blockenv}{#2}{std}
      {
         name                 = theorem-like
        ,tag-name             = \UseStructureName{block/theorem-like}
        ,tag-attr-class       =
        ,tagging-recipe       = standalone
        ,inner-level-counter  =
        ,transparent-level    = true
        ,legacy-code          =
%    \end{macrocode}
%    What block instance to use is determined by checking if a special
%    one exists or whether we should use \texttt{plain}:
%    \begin{macrocode}
        ,block-instance:e     = thm-
                               \IfInstanceExistsTF{block}
                                  {thm- \l_@@_thmstyle_tl -1}
                                  { \l_@@_thmstyle_tl } { plain }
        ,inner-instance-type  = captionedtext
        ,inner-instance       = #2
%    \end{macrocode}
%    By default the body text is justified, but perhaps we should not
%    set anything here and use whatever is current.\fmi{decide}
%    \begin{macrocode}
        ,para-instance        = justify
      }
%    \end{macrocode}
%    The \insttype{captionedtext} instance is simple: the counter, if
%    present, is either argument \texttt{\#2} or \texttt{\#3}; the \key{title}
%    receives argument \texttt{\#4}, and the \key{style} to use is
%    stored in \cs{l_@@_thmstyle_tl}. If \cs{swapnumbers} was
%    requested we use a style variant with the suffix \texttt{-swap} appended.
%    \begin{macrocode}
    \DeclareInstance{captionedtext}{#2}{thmlike}
      {
%    \end{macrocode}
%    The counter to use is either none or \texttt{\#2} 
%    based on the arguments given:
%    \begin{macrocode}
        ,counter:e = \IfBooleanF #1 { #2 }
        ,title     = #4
        ,style:e   = \l_@@_thmstyle_tl
                     \bool_if:NT \l_@@_swap_number_bool {-swap} 
      }
%    \end{macrocode}
%    We already know that the style \cs{l_@@_thmstyle_tl} exists, since
%    we have tested that earlier, but we don't know if that is also
%    true for the \texttt{-swap} variant. So we have to check that and
%    declare it if necessary.
%    \begin{macrocode}
    \bool_if:NT \l_@@_swap_number_bool {
      \IfInstanceExistsF{thmstyle}{\l_@@_thmstyle_tl -swap}
      {
%    \end{macrocode}
%    If it doesn't exist we first make a copy of the base instance.
%    \begin{macrocode}
        \DeclareInstanceCopy{thmstyle}
                            {\l_@@_thmstyle_tl -swap}
                            {\l_@@_thmstyle_tl}
%    \end{macrocode}
%    Then we retrieve the value of the \key{order} key from that
%    instance which is a clist.
%    \begin{macrocode}
        \clist_set:Ne \l_@@_order_clist
            { \InstanceValue { thmstyle }
                             { \l_@@_thmstyle_tl }
                             { order }
            }                              
%    \end{macrocode}
%    Then we step through this clist and build a new one in
%    \cs{l_@@_tmp_clist} with the \texttt{title} and \texttt{number}
%    swapped. That is done under the assumption that both actually
%    exist in the clist which would be the case if the instance was
%    declared with \cs{newtheoremstyle}, i.e., for legacy setups.
%    \begin{macrocode}
        \clist_clear:N \l_@@_tmp_clist
        \clist_map_inline:Nn \l_@@_order_clist
          {
            \clist_put_right:Ne \l_@@_tmp_clist {
              \str_case:nnF {##1}
                { {title} {number}
                  {number} {title} }
                {##1}
            }    
          }
%    \end{macrocode}
%    Once that is done we put the new value for \key{order} in the new
%    instance.
%    \begin{macrocode}
        \EditInstance {thmstyle}{\l_@@_thmstyle_tl -swap}
          { order:e = \l_@@_tmp_clist }
      }
    }
  }
}
%    \end{macrocode}
%  \end{macro}
%
%  
%
%
%
%  \begin{macro}{\ParseLaTeXeTheoremlike}
%    The arguments to \cs{ParseLaTeXeTheoremlike} are as follows:
%    \begin{itemize}
%    \item[\#1:] instance name to use (of type \enquote{blockenv})
%    \item[\#2:] unnumbered? boolean normally provided by using the star
%    form of the environment
%    \item[\#3:] key/val for layout adjustments settings provided in the
%       optional argument of the \enquote{theorem-like}
%       environment. If a note to the theorem was given in that argument,
%       then it has been turned into \verb=note={...}=
%    \end{itemize}
%    To be able to pick up the \key{note}, if provided, we make the
%    following declaration:
%    \begin{macrocode}
\keys_define:nn {blockenv} {
  , note        .tl_set:N  = \l_@@_note_tl
  , note        .groups:n  = { interface }
}
%    \end{macrocode}
%    
%    \begin{macrocode}
\cs_new_protected:Npn \ParseLaTeXeTheoremlike #1 #2 #3 {
%
%  \@@_debug_typeout:n{Parse~#1.~ Arguments~ found:~ \IfBooleanT{#2}{*}
%                \IfValueT{#3}{[\exp_not:n{#3}]}}
%  
%    \end{macrocode}
%    Normally, no note is provided, so that's the starting point:
%    \begin{macrocode}
  \tl_set:Nn \l_@@_note_tl { \NoValue }
%    \end{macrocode}
%    Then we check \texttt{\#3} if it contains a key/val list
%    containing \key{note}. This then sets \cs{l_@@_note_tl} and puts
%    all other key/vals in \cs{l_@@_instance_keys_tl}. Otherwise the
%    complete key/val list ends up there.
%    \begin{macrocode}
  \IfNoValueTF { #3 }
               { \tl_clear:N \l_@@_instance_keys_tl }
               { \keys_set_groups:nnnN {blockenv} {interface} { #3 }
                                       \l_@@_instance_keys_tl        }
%    \end{macrocode}
%    We are now ready to invoke the \insttype{blockenv} instance for
%    \texttt{\#1} but we need to expand some of the values first,
%    hence the \cs{use:e}. 
%    \begin{macrocode}
  \use:e {
    \exp_not:N \BlockEnv { #1 }
        { \exp_not:o \l_@@_instance_keys_tl }
        { #2 }
        { \exp_not:o \l_@@_note_tl }
  }
%    \end{macrocode}
%    We don't have any use for the last argument (the sub-caption) in
%    the standard setup, so we pass \cs{NoValue}.
%    \begin{macrocode}
        \NoValue
}
%    \end{macrocode}
%  \end{macro}
%  
%
%  
%  \begin{macro}{\swapnumbers}
%    Beside declaring theorem-like environments with \cs{newtheorem}
%    and \cs{theoremstyle}, the \pkg{amsthm} package also introduced
%    \cs{swapnumbers} to swap title and number in all environments
%    (because that is a common requirement). The new implementation
%    supports this approach as well.
%
%    It is implemented with a boolean \cs{l_@@_swap_number_bool} which
%    is toggled by \cs{swapnumbers}.
%    \begin{macrocode}
\bool_new:N \l_@@_swap_number_bool
\cs_new_protected:Npn \swapnumbers { \bool_set_inverse:N \l_@@_swap_number_bool }
%    \end{macrocode}
%  \end{macro}
%
%
%
%  
%
%  
%
%
%
%  
%  \begin{macro}{\newtheoremstyle}
%    The \cs{newtheoremstyle} declaration was originally provided in
%    the \pkg{amsthm} package. It has 9 mandatory arguments that sets
%    some aspects of theorem styles. We map those to the template
%    mechanism and generate \insttype{thmstyle} instances from them.
%
%    \cs{newtheoremstyle} has a bunch of argument conventions that
%    haven't been fully implemented yet, e.g., \texttt{\#8} can be a
%    blank (meaning normal word space or \cs{newline}) or a skip. Those
%    should eventually also be covered.\fmi{extend}
%    \begin{macrocode}
\cs_set_protected:Npn \newtheoremstyle #1#2#3#4#5#6#7#8#9 {
%    \end{macrocode}
%    First we build a \insttype{thmstyle} instance:
% \changes{v0.9n}{2026/02/01}{Argument applied to the wrong keys (tagging/1202)}
%    \begin{macrocode}
  \DeclareInstance{thmstyle}{#1}{std}{
    ,caption-decls   = {#6}
    ,before-hspace:e = \tl_if_empty:nTF{#5}{0pt}{#5}
    ,body-decls      = {#4}
    ,punct           = {#7}
    ,order           = {title, space, number, space, note, punct}
    ,number-decls    = \upshape
    ,note-decls      = \upshape\mdseries
%    \end{macrocode}
%    This setting doesn't cover all syntax possibilities.
%    \begin{macrocode}
    ,after-hspace:e  = \tl_if_empty:nTF{#8}{0pt}
                          {\tl_if_blank:nTF{#8}{3.3pt}{#8}}
  }
%    \end{macrocode}
%    If \texttt{\#2} or \texttt{\#3} are not empty we also have to set
%    up a \insttype{block} instance to account for the fact that
%    special vertical spacing is requested:
%    \begin{macrocode}
  \tl_if_empty:nF { #2#3 }
    {
      \DeclareInstance{block}{thm-#1-1}{std}{
        ,begin-vspace:e = \tl_if_empty:nTF{#2}{0pt}{#2}
        ,end-vspace:e   = \tl_if_empty:nTF{#3}{0pt}{#3}
        ,left-margin      = 0pt
        ,para-indent      = \parindent
        ,para-vspace      = \parskip
      }
%    \end{macrocode}
%    As elsewhere we provide two levels.
%    \begin{macrocode}
      \DeclareInstanceCopy{block}{thm-#1-2}{thm-#1-1}
    }
%    \end{macrocode}
%    More complicated is argument \texttt{\#9}. If not empty it can
%    contain \cs{thmname}, \cs{thmnumber}, and/or \cs{thmnote} to
%    define the layout of the theorem caption. All the spacing has to
%    be given inside the arguments of these commands which means that
%    this doesn't work together with \cs{swapnumbers}, but this is the
%    way \pkg{amsthm} was defined. If the instances are manually
%    defined then it is easy to make them work with and without a
%    \cs{swapnumbers} declaration. So basically, this here is good for
%    a subset of cases and for backwards compatibility with
%    \pkg{amsthm}.
%    
%    The approach used doesn't cover all circumstances, e.g., if the
%    argument contains low-level programming on top of the interface
%    commands that the translation below will fail, but most existing
%    code should work and the rest would need a replacement using
%    instances that are directly set up.
%    \begin{macrocode}
  \tl_if_empty:oF { \exp_not:n{#9} }
     {
%    \end{macrocode}
%    Give special definitions for the commands and then expand
%    \texttt{\#9} and use the result to edit the instance we defined
%    earlier.
%    \begin{macrocode}
       \cs_set:Npn \thmname   ##1 {title-format={{\exp_not:n{##1}}},}
       \cs_set:Npn \thmnumber ##1 {number-format={{\exp_not:n{##1}}},}
       \cs_set:Npn \thmnote   ##1 {note-format={{\exp_not:n{##1}}},}
       \cs_set:Npn \@@_tmp:w ##1##2##3 {
         \exp_args:Nnne \EditInstance{thmstyle}{#1}{#9}}
       \@@_tmp:w {##1} {##1} {##1}
%    \end{macrocode}
%    We then also use the commands to deduce a suitable \key{order}
%    and put that into the instance as well.
%    \begin{macrocode}
       \cs_set:Npn \thmname   ##1 {title,}
       \cs_set:Npn \thmnumber ##1 {number,}
       \cs_set:Npn \thmnote   ##1 {note,}
       \cs_set:Npn \@@_tmp:w##1##2##3 {
         \exp_args:Nnne \EditInstance{thmstyle}{#1}{order={#9 punct}}}
       \@@_tmp:w {##1} {##1} {##1}
     } 
%    \end{macrocode}
%    If block tracing is turned on we show the final result:
%    \begin{macrocode}
  \@@_debug:n { \ShowInstanceValues{thmstyle}{#1} }
}
%    \end{macrocode}
%  \end{macro}
%
%
%
%
%
% \subsubsection{Supporting QED in proofs}
%
%  The \pkg{amsthm} package contains some elaborate code to support
%  placing a QED symbol into the proof (by default at the end, but
%  alternatively manually placed with \cs{qedhere}). This code is
%  simply lifted and not adjusted in any way for now (and therefore
%  also not documented---see the \pkg{amsthm} package for
%  documentation for now).
%   
% \changes{v0.9n}{2026/02/01}{Stray definition of \cs{math@qedhere} removed (taggging/1203)}
%    \begin{macrocode}
\ExplSyntaxOff
  \def\math@qedhere{%
    \@ifundefined{\@currenvir @qed}{%
      \qed@warning\quad\hbox{\qedsymbol}%
    }{%
      \@xp\aftergroup\csname\@currenvir @qed\endcsname
    }%
  }
  \def\displaymath@qed{%
    \relax
    \ifmmode
      \ifinner \aftergroup\linebox@qed
      \else
        \eqno
        \let\eqno\relax \let\leqno\relax \let\veqno\relax
        \hbox{\qedsymbol}%
      \fi
    \else
       \aftergroup\linebox@qed
    \fi
  }
  \expandafter\let\csname equation*@qed\endcsname\displaymath@qed
  \def\equation@qed{%
    \iftagsleft@
      \hbox{\phantom{\quad\qedsymbol}}%
      \gdef\alt@tag{%
        \rlap{\hbox to\displaywidth{\hfil\qedsymbol}}%
        \global\let\alt@tag\@empty
      }%
    \else
      \gdef\alt@tag{%
        \global\let\alt@tag\@empty
        \vtop{\ialign{\hfil####\cr
                \tagform@\theequation\cr
                \qedsymbol\cr}}%
%    \end{macrocode}
%    The original code in \pkg{amsthm} only contained
%    \verb=\setbox\z@= at this point to remove \cs{hbox} produced by
%    \cs{maketag@@@@@@}. However, when the sockets for the tagging are
%    added this doesn't work any more because they come between the
%    \cs{setbox} and the \cs{hbox}. We therefore set
%    \texttt{measuring@} to true so that the branch without the
%    sockets is used.
% \changes{v0.9o}{2026/02/05}{Add \cs{measuring@true} before grabbing
%    the equation tag box (tagging/1037)}
%    \begin{macrocode}
        \measuring@true
        \setbox\z@
      }%
    \fi
  }
  \def\qed@tag{%
    \global\tag@true \nonumber
    &\omit\setboxz@h {\strut@ \qedsymbol}\tagsleft@false
    \place@tag@gather
    \kern-\tabskip
    \ifst@rred \else \global\@eqnswtrue \fi \global\advance\row@\@ne \cr
  }
  \def\split@qed{%
    \def\endsplit{\crcr\egroup \egroup \ctagsplit@false \rendsplit@
      \aftergroup\align@qed
    }%
  }
  \def\align@qed{%
    \ifmeasuring@ \tag*{\qedsymbol}%
    \else \let\math@cr@@@\qed@tag
    \fi
  }
  \expandafter\let\csname align*@qed\endcsname\align@qed
  \expandafter\let\csname gather*@qed\endcsname\align@qed
  %
  \DeclareRobustCommand{\qed}{%
    \ifmmode \mathqed
    \else
      \leavevmode\unskip\penalty9999 \hbox{}\nobreak\hfill
      \quad\hbox{\qedsymbol}%
    \fi
  }%
  \let\QED@stack\@empty
  \let\qed@elt\relax
  \newcommand{\pushQED}[1]{%
    \toks@{\qed@elt{#1}}\@temptokena\expandafter{\QED@stack}%
    \xdef\QED@stack{\the\toks@\the\@temptokena}%
  }%
  \newcommand{\popQED}{%
    \begingroup\let\qed@elt\popQED@elt \QED@stack\relax\relax\endgroup
  }%
  \def\popQED@elt#1#2\relax{#1\gdef\QED@stack{#2}}%
  \newcommand{\qedhere}{%
    \begingroup \let\mathqed\math@qedhere
      \let\qed@elt\setQED@elt \QED@stack\relax\relax \endgroup
  }%
  \def\setQED@elt#1#2\relax{%
    \ifmeasuring@
    \else \iffirstchoice@ \gdef\QED@stack{\qed@elt{}#2}\fi
    \fi
    #1%
  }%
  \def\qed@warning{%
    \PackageWarning{amsthm}{The \@nx\qedhere command may not work
      correctly here}%
  }%
  \newcommand{\mathqed}{\quad\hbox{\qedsymbol}}%
  \DeclareRobustCommand{\qed}{%
    \ifmmode \mathqed
    \else
      \leavevmode\unskip\penalty9999 \hbox{}\nobreak\hfill
      \quad\hbox{\qedsymbol}%
    \fi
  }
  \newcommand{\openbox}{\leavevmode
    \hbox to.77778em{%
    \hfil\vrule
    \vbox to.675em{\hrule width.6em\vfil\hrule}%
    \vrule\hfil}}
  \providecommand{\qedsymbol}{\openbox}
\ExplSyntaxOn
%    \end{macrocode}
%
%
%
%
%
%
% \section{Support for other packages and classes}
%
% \subsection{Replacement for \pkg{alltt}}
%
%    The tools package \pkg{alltt} by Leslie Lamport has been
%    completely implemented using the template approach and is
%    therefore no longer necessary. In fact it has also been extended
%    by providing \env{alltt*}.
%    \begin{macrocode}  
\declare@file@substitution{alltt.sty}{null.tex}
%    \end{macrocode}
%
%
% \subsection{Replacement for \pkg{amsthm}}
%
%    The \pkg{amsthm} package is basically supported out of the box (though there
%    are currently still a few limitation with \cs{newtheoremstyle} and
%    perhaps also in other places). So this here is a bit premature,
%    but for now we disable loading \pkg{amsthm} and wait to see how
%    far this gets us.
%    We may have to provide a bit more for better compatibility.
%    \begin{macrocode}  
\declare@file@substitution{amsthm.sty}{null.tex}
%    \end{macrocode}
%    
%    
%    
% \subsection{Support for \cls{amsart} and \cls{amsbook} classes}
%
%    Unfortunately, the \cls{amsart} class contains a full
%    implementation of \pkg{amsthm} inside the class (why ever) 
%    and they use \cs{newcommand}, sigh.
%
%    Thus, to make the new code work with this class we have to hide
%    some definitions, load the class and only afterwards restore our
%    own versions.
%
%    So first save some of the problematical definitions under some
%    other names:
%    \begin{macrocode}
\let \amsnewtheorem      \newtheorem
\let \amsnewtheoremstyle \newtheoremstyle
\let \amstheoremstyle    \theoremstyle
\let \amsproof           \proof
\let \amsendproof        \endproof
%    \end{macrocode}
%
%    Then undefine them just before the class gets loaded (quite a handful):
%    \begin{macrocode}
\AddToHook{class/amsart/before}[block]{
  \let \newtheoremstyle \relax
  \let \theoremstyle    \relax
%    \end{macrocode}
%    
%    \begin{macrocode}
  \let \proof           \relax
  \let \endproof        \relax
%    \end{macrocode}
%    
%    \begin{macrocode}
  \let \pushQED    \relax
  \let \popQED     \relax
  \let \qedhere    \relax
  \let \mathqed    \relax
  \let \openbox    \relax
}
%    \end{macrocode}
%    Same for \cls{amsbook} and \cls{amsproc}:
%    \begin{macrocode}
\AddToHook{class/amsbook/before}[block]{
  \let \newtheoremstyle \relax
  \let \theoremstyle    \relax
  \let \proof           \relax
  \let \endproof        \relax
  \let \pushQED    \relax
  \let \popQED     \relax
  \let \qedhere    \relax
  \let \mathqed    \relax
  \let \openbox    \relax
}
%    \end{macrocode}
%    \begin{macrocode}
\AddToHook{class/amsproc/before}[block]{
  \let \newtheoremstyle \relax
  \let \theoremstyle    \relax
  \let \proof           \relax
  \let \endproof        \relax
  \let \pushQED    \relax
  \let \popQED     \relax
  \let \qedhere    \relax
  \let \mathqed    \relax
  \let \openbox    \relax
}
%    \end{macrocode}
%    And once the class is loaded restore our versions again. Note
%    that we don't have to restored all the QED-related commands as
%    ours are identical to those defined by the AMS.
%    \begin{macrocode}
\AddToHook{class/amsart/after}[block]{
  \let \newtheorem      \amsnewtheorem  
  \let \newtheoremstyle \amsnewtheoremstyle
  \let \theoremstyle    \amstheoremstyle
  \let \proof           \amsproof
  \let \endproof        \amsendproof
}
%    \end{macrocode}
%    
%    \begin{macrocode}
\AddToHook{class/amsbook/after}[block]{
  \let \newtheorem      \amsnewtheorem  
  \let \newtheoremstyle \amsnewtheoremstyle
  \let \theoremstyle    \amstheoremstyle
  \let \proof           \amsproof
  \let \endproof        \amsendproof
}
%    \end{macrocode}
%    
%    \begin{macrocode}
\AddToHook{class/amsproc/after}[block]{
  \let \newtheorem      \amsnewtheorem  
  \let \newtheoremstyle \amsnewtheoremstyle
  \let \theoremstyle    \amstheoremstyle
  \let \proof           \amsproof
  \let \endproof        \amsendproof
}
%    \end{macrocode}
%
%
%
%
%
% \subsection{Support for the \pkg{enumitem} interfaces}
%
%    The current implementation  incorporates most features of
%    \pkg{enumitem}. The plan is that the enumitem interfaces are
%    either natively available or are emulated and mapped to new
%    interfaces, so that documents using \pkg{enumitem} work
%    seamlessly.
%
%    Most (or even all of the \pkg{enumitem} keys have gotten new
%    names, so there the task is to map old names to new names. One
%    question to decide here is which (if any) of the original keys
%    should remain natively available even if \pkg{enumitem} is not
%    loaded, and which should only be supported if the document
%    explicitly loads \pkg{enumitem}, i.e., support them only for
%    compatibility with old documents. Providing the full set by
%    default means one ends up with a fairly inconsistent interface,
%    but not providing some of them may result in people unnecessarily
%    loading \pkg{enumitem} in new documents just to get at, say,
%    \key{nosep}.\fmi{decide}
%
%    The \pkg{enumitem} package also provides declarations to build
%    out new lists and adjust the layout of existing list using
%    commands like \cs{newlist} or \cs{setlist}.
%    With the new implementation this is normally done differently,
%    e.g., defining instances and simple document level commands via
%    \cs{SimpleBlockEnv}, etc. However, we probably also want a
%    declaration such as \cs{newlist} (same name?) to provide a simple
%    way to make this happen in the document preamble in one go.
%
%    I'm less sure about \cs{setlist} at least as far as its optional
%    argument is concerned (even though we have to support it in an
%    emulation.\fmi{decide}
%
%    We put the code that emulates \pkg{enumitem} in a separate file
%    to be loaded instead of the original package, but eventually some
%    of the code from there has to move back to the kernel to be
%    always present.
%    
%    \begin{macrocode}
%\declare@file@substitution{enumitem.sty}{latex-lab-enumitem.sty}
%    \end{macrocode}
%    But for now we simply disable \pkg{enumitem} loading and
%    unconditionally load our replacement into the kernel for ease of
%    testing. In the end we have to decide which parts of the
%    interface (if any) we provide out of the box and which parts are
%    only available if the document requests \pkg{enumitem}.
%    \begin{macrocode}
\declare@file@substitution{enumitem.sty}{null}
\RequirePackage{latex-lab-enumitem}
%    \end{macrocode}
%    
%
% \subsection{Support for the \pkg{doc} package}
%
%    When the \pkg{doc} package is loaded it wants to remove a
%    \texttt{\%} sign from the start of each verbatim line. For this
%    it uses \cs{check@percent} which we stick into the
%    \socket{verbatim/startline} socket.
%
% \begin{plugdecl}{doc}
%    \begin{macrocode}
\NewSocketPlug {verbatim/startline}{doc}{ \check@percent }
\AddToHook{package/doc/after}{
  \AssignSocketPlug{verbatim/startline}{doc}
}
%    \end{macrocode}
% \end{plugdecl}
%
%    \begin{macrocode}
%</package-finish>
%    \end{macrocode}
%
% \end{implementation}
%
%
% \Finale
%
% \endinput  ^^A don't typeset the first prototype notes -------
%
%
%
% \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 (historical info)}
%
% 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 template 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} template
% 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 template
% types, so that we end up with two different \emph{template types}.  Then
% we can implement other template for the list template 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{begin-penalty},
%   \texttt{begin-vspace}, \texttt{begin-extra-vspace}, \texttt{item-penalty},
%   \texttt{item-vspace}, \texttt{item-par-skip}, \texttt{end-penalty},
%   \texttt{end-vspace}, \texttt{end-extra-vspace}.
% \item Horizontal spacing: \texttt{right-margin}, \texttt{left-margin},
%   \texttt{para-indent}, \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{begin-vspace}, \texttt{item-vspace},
% \texttt{end-vspace} are now \emph{horizontal} skips.\fmi{Text wrong
%    and or concept with vspace and hspace questionable!}
% \begin{itemize}
% \item Structural parameters: \texttt{counter}, \texttt{start},
%   \texttt{resume}, \texttt{item-instance}.
% \item Spacing and penalties: \texttt{begin-penalty},
%   \texttt{begin-vspace}, \texttt{item-penalty}, \texttt{item-vspace},
%   \texttt{end-penalty}, \texttt{end-vspace}.\fmi{revisit!}
% \item Horizontal spacing: \texttt{label-width}, \texttt{label-sep}.\fmi{check!}
% \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.
%
%
%

%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
\endinput
