%% page-canons.sty
%% Version: 2026/06/29 v3.9.4 
%% Daniel Quigley <dquigleydev@gmail.com>
%% License:     LaTeX Project Public License 1.3c

\NeedsTeXFormat{LaTeX2e}
\ProvidesPackage{page-canons}[2026/06/29 v3.9.4 classical page canons with margins]

% lualatex is recommended for PDF/UA-2 accessibility
\RequirePackage{iftex}
\ifluatex\else
  \PackageWarning{page-canons}{%
    LuaLaTeX is the recommended engine for page-canons (for PDF/UA-2
    accessibility support).\MessageBreak
    The package will load under your current engine; accessibility
    features may be limited}%
\fi

% geometry is required

\providecommand\marginfont{}

% even-odd detection
\@ifpackageloaded{ifoddpage}{%
  \PackageInfo{page-canons}{ifoddpage already loaded; using it}%
}{%
  \newcount\c@checkoddpage
  \def\thecheckoddpage{\number\c@checkoddpage}%
  \newif\ifoddpage
  \newif\ifoddpageoroneside
  \def\oddpage@label{\@newl@bel{checkoddpage}}%
  \write\@auxout{\noexpand\providecommand\noexpand\oddpage@label[2]{}}%
  \def\oddpage@checkpage#1{%
    \@bsphack
    \write\@auxout{\string\oddpage@label{#1}{\the\c@page}}%
    \@esphack}%
  \def\oddpage@page{%
    \expandafter\ifx\csname checkoddpage@\thecheckoddpage\endcsname\relax
      \the\c@page
    \else
      \csname checkoddpage@\thecheckoddpage\endcsname
    \fi}%
  \DeclareRobustCommand\checkoddpage{%
    \stepcounter{checkoddpage}%
    \expandafter\oddpage@checkpage\expandafter{\number\c@checkoddpage}%
    \ifodd\oddpage@page\relax
      \oddpagetrue \oddpageoronesidetrue
    \else
      \oddpagefalse \oddpageoronesidefalse
    \fi
    \if@twoside\else \oddpageoronesidetrue \fi}%
  \def\@ifoddpage{%
    \ifoddpage \expandafter\@firstoftwo
    \else \expandafter\@secondoftwo \fi}%
  \def\@ifoddpageoroneside{%
    \ifoddpageoroneside \expandafter\@firstoftwo
    \else \expandafter\@secondoftwo \fi}%
  \PackageInfo{page-canons}{In-house odd/even page detection active}%
}

% keyval
\def\pagecanon@trimkey#1{%
  \def\pagecanon@kvkey{#1}%
  \expandafter\pagecanon@trimkey@i\pagecanon@kvkey\pagecanon@kv@end}
\def\pagecanon@trimkey@i{\futurelet\pagecanon@kv@sptok\pagecanon@trimkey@ii}
\def\pagecanon@trimkey@ii{%
  \ifx\pagecanon@kv@sptok\@sptoken
    \expandafter\pagecanon@kv@eatsp
  \else
    \expandafter\pagecanon@kv@keepkey
  \fi}
{\def\:{\pagecanon@kv@eatsp}%
  \expandafter\gdef\: #1\pagecanon@kv@end{\def\pagecanon@kvkey{#1}}}
\def\pagecanon@kv@keepkey#1\pagecanon@kv@end{\def\pagecanon@kvkey{#1}}

\long\def\pagecanon@defkey#1{\@namedef{pagecanon@kv@#1}##1}
\long\def\CM@defkey#1{\@namedef{CM@kv@#1}##1}
\long\def\FW@defkey#1{\@namedef{FW@kv@#1}##1}

% processor tries pagecanon@, then CM@, then warns
\def\canons@setkeys#1{%
  \@for\canons@kv@raw:=#1\do{%
    \ifx\canons@kv@raw\@empty\else
      \expandafter\canons@kvsplit\canons@kv@raw==\canons@kv@end
    \fi}}
\def\canons@kvsplit#1=#2=#3\canons@kv@end{%
  \pagecanon@trimkey{#1}%
  \ifx\pagecanon@kvkey\@empty\else
    \@ifundefined{pagecanon@kv@\pagecanon@kvkey}{%
      \@ifundefined{CM@kv@\pagecanon@kvkey}{%
        \PackageWarning{page-canons}{Unknown key '\pagecanon@kvkey'}%
      }{\@nameuse{CM@kv@\pagecanon@kvkey}{#2}}%
    }{\@nameuse{pagecanon@kv@\pagecanon@kvkey}{#2}}%
  \fi}

\def\FW@setkeys#1{%
  \@for\FW@kv@raw:=#1\do{%
    \ifx\FW@kv@raw\@empty\else
      \expandafter\FW@kvsplit\FW@kv@raw==\FW@kv@end
    \fi}}
\def\FW@kvsplit#1=#2=#3\FW@kv@end{%
  \pagecanon@trimkey{#1}%
  \ifx\pagecanon@kvkey\@empty\else
    \@ifundefined{FW@kv@\pagecanon@kvkey}%
      {\PackageWarning{page-canons}{Unknown fullwidth key '\pagecanon@kvkey'}}%
      {\@nameuse{FW@kv@\pagecanon@kvkey}{#2}}%
  \fi}

% strings
\def\pagecanon@ifeq#1#2{%
  \edef\pagecanon@tmp@a{#1}\edef\pagecanon@tmp@b{#2}%
  \ifx\pagecanon@tmp@a\pagecanon@tmp@b
    \expandafter\@firstoftwo
  \else
    \expandafter\@secondoftwo
  \fi}
\let\CM@ifeq\pagecanon@ifeq

% simple class detect
\newif\ifpagecanon@book
\newif\ifpagecanon@report
\newif\ifpagecanon@article

\@ifclassloaded{book}{\pagecanon@booktrue}{}
\@ifclassloaded{report}{\pagecanon@reporttrue}{}
\@ifclassloaded{article}{\pagecanon@articletrue}{}
\@ifclassloaded{memoir}{%
  \PackageWarning{page-canons}{memoir detected; page-canons may conflict}}{}
\@ifclassloaded{scrbook}{%
  \PackageWarning{page-canons}{KOMA-Script class detected; page-canons may conflict}}{}
\@ifclassloaded{scrreprt}{%
  \PackageWarning{page-canons}{KOMA-Script class detected; page-canons may conflict}}{}
\@ifclassloaded{scrartcl}{%
  \PackageWarning{page-canons}{KOMA-Script class detected; page-canons may conflict}}{}

% defaults
\newif\ifpagecanon@showframe
\newif\ifpagecanon@showbleed
\newif\ifpagecanon@showgutter
\newif\ifpagecanon@landscape
\newif\ifpagecanon@debug
\newif\ifpagecanon@insetup
\newif\ifpagecanon@afterbegin
\newif\ifpagecanon@twocolwarn
\newif\ifpagecanon@nomarginalia

\def\pagecanon@canon{vdg}
\def\pagecanon@gutterval{0mm}
\def\pagecanon@guttermode{geometry}
\def\pagecanon@paper{}
\def\pagecanon@vdhN{6}
\def\pagecanon@ateliersstyle{ordinary}
\def\pagecanon@gridN{6}
\def\pagecanon@gridinner{1}
\def\pagecanon@gridouter{2}
\def\pagecanon@gridtop{1}
\def\pagecanon@gridbottom{2}
\def\pagecanon@margins{symmetric}

% bleed value strings
\def\pagecanon@innerbleedval{0pt}
\def\pagecanon@outerbleedval{0pt}
\def\pagecanon@topbleedval{0pt}
\def\pagecanon@bottombleedval{0pt}

\ifpagecanon@article
  \def\pagecanon@margins{right}%
\fi

\let\pagecanon@geometryoptions\@empty
\let\pagecanon@ouroptions\@empty

% maregin defaults
\newif\ifCM@sizeunified   \CM@sizeunifiedtrue
\newif\ifCM@justunified    \CM@justunifiedtrue

\def\CM@size{footnotesize}
\def\CM@mnsize{footnotesize}
\def\CM@snsize{footnotesize}
\def\CM@justify{default}
\def\CM@mnjustify{default}
\def\CM@snjustify{default}
\def\CM@numbering{global}
\def\CM@notespread{1.05}

\def\pagecanon@debugmsg#1{%
  \ifpagecanon@debug \PackageInfo{page-canons}{[DEBUG] #1}\fi}

% param reset
\def\pagecanon@resetcanonparams{%
  \def\pagecanon@vdhN{6}\def\pagecanon@ateliersstyle{ordinary}%
  \def\pagecanon@gridN{6}\def\pagecanon@gridinner{1}%
  \def\pagecanon@gridouter{2}\def\pagecanon@gridtop{1}%
  \def\pagecanon@gridbottom{2}}

% defs layout
\pagecanon@defkey{canon}{%
  \pagecanon@ifeq{#1}{\pagecanon@canon}{}{\pagecanon@resetcanonparams}%
  \def\pagecanon@canon{#1}}
\pagecanon@defkey{gutterval}{\def\pagecanon@gutterval{#1}}
\pagecanon@defkey{guttermode}{\def\pagecanon@guttermode{#1}}
\pagecanon@defkey{paper}{\def\pagecanon@paper{#1}}
\pagecanon@defkey{vdhN}{\def\pagecanon@vdhN{#1}}
\pagecanon@defkey{ateliersstyle}{\def\pagecanon@ateliersstyle{#1}}
\pagecanon@defkey{gridN}{\def\pagecanon@gridN{#1}}
\pagecanon@defkey{gridinner}{\def\pagecanon@gridinner{#1}}
\pagecanon@defkey{gridouter}{\def\pagecanon@gridouter{#1}}
\pagecanon@defkey{gridtop}{\def\pagecanon@gridtop{#1}}
\pagecanon@defkey{gridbottom}{\def\pagecanon@gridbottom{#1}}
\pagecanon@defkey{margins}{\def\pagecanon@margins{#1}}
\pagecanon@defkey{innerbleed}{\def\pagecanon@innerbleedval{#1}}
\pagecanon@defkey{outerbleed}{\def\pagecanon@outerbleedval{#1}}
\pagecanon@defkey{topbleed}{\def\pagecanon@topbleedval{#1}}
\pagecanon@defkey{bottombleed}{\def\pagecanon@bottombleedval{#1}}
\pagecanon@defkey{debug}{%
  \pagecanon@ifeq{#1}{true}{\pagecanon@debugtrue}{%
  \pagecanon@ifeq{#1}{false}{\pagecanon@debugfalse}{\pagecanon@debugtrue}}}

% defs margins
\CM@defkey{marginsize}{%
  \CM@ifeq{#1}{true}{\CM@sizeunifiedtrue}{%
  \CM@ifeq{#1}{false}{\CM@sizeunifiedfalse}{%
    \PackageWarning{page-canons}{marginsize expects true/false, got '#1'}}}}
\CM@defkey{size}{\def\CM@size{#1}}
\CM@defkey{marginnotesize}{\def\CM@mnsize{#1}}
\CM@defkey{sidenotesize}{\def\CM@snsize{#1}}
\CM@defkey{marginjustify}{%
  \CM@ifeq{#1}{true}{\CM@justunifiedtrue}{%
  \CM@ifeq{#1}{false}{\CM@justunifiedfalse}{%
    \PackageWarning{page-canons}{marginjustify expects true/false, got '#1'}}}}
\CM@defkey{justification}{\def\CM@justify{#1}}
\CM@defkey{marginnotejustify}{\def\CM@mnjustify{#1}}
\CM@defkey{sidenotejustify}{\def\CM@snjustify{#1}}
\CM@defkey{numbering}{\def\CM@numbering{#1}}
\CM@defkey{notespread}{\def\CM@notespread{#1}}

% fullwidth (from prior external scripts)
\def\FW@skip{0.5\baselineskip}
\def\FW@just{centering}
\FW@defkey{skip}{\def\FW@skip{#1}}
\FW@defkey{justification}{\def\FW@just{#1}}
\def\FW@resetdefaults{%
  \def\FW@skip{0.5\baselineskip}\def\FW@just{centering}}

% opts
\def\pagecanon@appendgeomopt#1{%
  \ifx\pagecanon@geometryoptions\@empty
    \edef\pagecanon@geometryoptions{#1}%
  \else
    \edef\pagecanon@geometryoptions{\pagecanon@geometryoptions,#1}\fi}
\def\pagecanon@appendouropt#1{%
  \ifx\pagecanon@ouroptions\@empty
    \edef\pagecanon@ouroptions{#1}%
  \else
    \edef\pagecanon@ouroptions{\pagecanon@ouroptions,#1}\fi}

%key marker
\@namedef{pagecanon@isourkey@canon}{}
\@namedef{pagecanon@isourkey@gutterval}{}
\@namedef{pagecanon@isourkey@guttermode}{}
\@namedef{pagecanon@isourkey@paper}{}
\@namedef{pagecanon@isourkey@vdhN}{}
\@namedef{pagecanon@isourkey@ateliersstyle}{}
\@namedef{pagecanon@isourkey@gridN}{}
\@namedef{pagecanon@isourkey@gridinner}{}
\@namedef{pagecanon@isourkey@gridouter}{}
\@namedef{pagecanon@isourkey@gridtop}{}
\@namedef{pagecanon@isourkey@gridbottom}{}
\@namedef{pagecanon@isourkey@margins}{}
\@namedef{pagecanon@isourkey@innerbleed}{}
\@namedef{pagecanon@isourkey@outerbleed}{}
\@namedef{pagecanon@isourkey@topbleed}{}
\@namedef{pagecanon@isourkey@bottombleed}{}
\@namedef{pagecanon@isourkey@debug}{}
\@namedef{pagecanon@isourkey@marginsize}{}
\@namedef{pagecanon@isourkey@size}{}
\@namedef{pagecanon@isourkey@marginnotesize}{}
\@namedef{pagecanon@isourkey@sidenotesize}{}
\@namedef{pagecanon@isourkey@marginjustify}{}
\@namedef{pagecanon@isourkey@justification}{}
\@namedef{pagecanon@isourkey@marginnotejustify}{}
\@namedef{pagecanon@isourkey@sidenotejustify}{}
\@namedef{pagecanon@isourkey@numbering}{}
\@namedef{pagecanon@isourkey@notespread}{}

\def\pagecanon@isourkey#1{%
  \expandafter\pagecanon@isourkey@split#1==\@nil}
\def\pagecanon@isourkey@split#1=#2=\@nil{%
  \pagecanon@trimkey{#1}%
  \@ifundefined{pagecanon@isourkey@\pagecanon@kvkey}{%
    \def\pagecanon@tmp@isours{false}}{%
    \def\pagecanon@tmp@isours{true}}}

\DeclareOption*{%
  \edef\pagecanon@tmp@opt{\CurrentOption}%
  \def\pagecanon@tmp@processed{false}%
  \pagecanon@ifeq{\pagecanon@tmp@opt}{showframe}{%
    \pagecanon@showframetrue \pagecanon@appendgeomopt{showframe}%
    \def\pagecanon@tmp@processed{true}}{}%
  \pagecanon@ifeq{\pagecanon@tmp@opt}{showbleed}{%
    \pagecanon@showbleedtrue \def\pagecanon@tmp@processed{true}}{}%
  \pagecanon@ifeq{\pagecanon@tmp@opt}{showgutter}{%
    \pagecanon@showguttertrue \def\pagecanon@tmp@processed{true}}{}%
  \pagecanon@ifeq{\pagecanon@tmp@opt}{landscape}{%
    \pagecanon@landscapetrue \pagecanon@appendgeomopt{landscape}%
    \def\pagecanon@tmp@processed{true}}{}%
  \pagecanon@ifeq{\pagecanon@tmp@opt}{debug}{%
    \pagecanon@debugtrue \def\pagecanon@tmp@processed{true}}{}%
  \pagecanon@ifeq{\pagecanon@tmp@opt}{nomarginalia}{%
    \pagecanon@nomarginaliatrue \def\pagecanon@tmp@processed{true}}{}%
  \pagecanon@ifeq{\pagecanon@tmp@processed}{false}{%
    \@expandtwoargs\in@{=}{\pagecanon@tmp@opt}%
    \ifin@
      \pagecanon@isourkey{\pagecanon@tmp@opt}%
      \edef\pagecanon@tmp@chk{\pagecanon@tmp@isours}%
      \def\pagecanon@tmp@yes{true}%
      \ifx\pagecanon@tmp@chk\pagecanon@tmp@yes
        \expandafter\pagecanon@appendouropt\expandafter{\pagecanon@tmp@opt}%
      \else
        \expandafter\pagecanon@appendgeomopt\expandafter{\pagecanon@tmp@opt}%
        \pagecanon@ifeq{\pagecanon@kvkey}{paper}{%
          \expandafter\pagecanon@appendouropt\expandafter{\pagecanon@tmp@opt}}{}%
      \fi
    \else
      \expandafter\pagecanon@appendgeomopt\expandafter{\pagecanon@tmp@opt}%
    \fi
  }{}}

\ProcessOptions\relax

\ifx\pagecanon@ouroptions\@empty\else
  \expandafter\canons@setkeys\expandafter{\pagecanon@ouroptions}%
\fi

\pagecanon@ifeq{\pagecanon@margins}{antisymmetric}{%
  \pagecanon@appendgeomopt{reversemarginpar}}{}
\pagecanon@ifeq{\pagecanon@margins}{right}{%
  \pagecanon@appendgeomopt{asymmetric}}{%
  \pagecanon@ifeq{\pagecanon@margins}{left}{%
    \pagecanon@appendgeomopt{asymmetric}}{}}

\ifx\pagecanon@geometryoptions\@empty
  \RequirePackage{geometry}%
\else
  \expandafter\PassOptionsToPackage\expandafter{\pagecanon@geometryoptions}{geometry}%
  \RequirePackage{geometry}%
\fi

% font size
\@namedef{CM@sz@tiny}{\tiny}
\@namedef{CM@sz@scriptsize}{\scriptsize}
\@namedef{CM@sz@footnotesize}{\footnotesize}
\@namedef{CM@sz@small}{\small}
\@namedef{CM@sz@normalsize}{\normalsize}
\@namedef{CM@sz@large}{\large}
\@namedef{CM@sz@Large}{\Large}
\@namedef{CM@sz@LARGE}{\LARGE}
\@namedef{CM@sz@huge}{\huge}
\@namedef{CM@sz@Huge}{\Huge}

\def\CM@resolvefont#1#2{%
  \@ifundefined{CM@sz@#2}{%
    \PackageWarning{page-canons}{Unknown size '#2', using footnotesize}%
    \expandafter\let\expandafter#1\csname CM@sz@footnotesize\endcsname
  }{\expandafter\let\expandafter#1\csname CM@sz@#2\endcsname}}

\newcommand*\canonsmarginfont{\footnotesize}
\newcommand*\CM@sn@font{\footnotesize}

% justification
\@namedef{CM@just@raggedright}{\raggedright}
\@namedef{CM@just@raggedleft}{\raggedleft}
\@namedef{CM@just@centered}{\centering}
\@namedef{CM@just@justified}{\relax}

\newcommand*\CM@mn@justify{\raggedright}
\newcommand*\CM@sn@justify{\raggedright}

\def\CM@justify@symmetric{%
  \checkoddpage\ifoddpage\raggedright\else\raggedleft\fi}
\def\CM@justify@antisymmetric{%
  \checkoddpage\ifoddpage\raggedleft\else\raggedright\fi}

\def\CM@resolvejust#1#2{%
  \CM@ifeq{#2}{default}{\CM@setautojust#1}{%
    \@ifundefined{CM@just@#2}{%
      \PackageWarning{page-canons}{Unknown justification '#2', using raggedright}%
      \let#1\raggedright
    }{\expandafter\let\expandafter#1\csname CM@just@#2\endcsname}}}

\def\CM@setautojust#1{%
  \CM@ifeq{\pagecanon@margins}{right}{\let#1\raggedright}{%
  \CM@ifeq{\pagecanon@margins}{left}{\let#1\raggedleft}{%
  \CM@ifeq{\pagecanon@margins}{symmetric}{\let#1\CM@justify@symmetric}{%
  \CM@ifeq{\pagecanon@margins}{antisymmetric}{\let#1\CM@justify@antisymmetric}{%
    \let#1\raggedright}}}}}

\def\CM@resolvealljust{%
  \ifCM@justunified
    \edef\CM@mn@juststr{\CM@justify}\edef\CM@sn@juststr{\CM@justify}%
  \else
    \edef\CM@mn@juststr{\CM@mnjustify}\edef\CM@sn@juststr{\CM@snjustify}%
  \fi
  \CM@resolvejust\CM@mn@justify{\CM@mn@juststr}%
  \CM@resolvejust\CM@sn@justify{\CM@sn@juststr}}

\def\CM@resolveallfont{%
  \ifCM@sizeunified
    \CM@resolvefont\canonsmarginfont{\CM@size}%
    \CM@resolvefont\CM@sn@font{\CM@size}%
  \else
    \CM@resolvefont\canonsmarginfont{\CM@mnsize}%
    \CM@resolvefont\CM@sn@font{\CM@snsize}%
  \fi}

% initialize font at load time 
\CM@resolveallfont

% per page counter
\newcount\CM@pp@seq  \global\CM@pp@seq\z@
\def\CM@pp@data#1#2{\global\@namedef{CM@pp@p@#1}{#2}}
\def\CM@pp@writelabel{%
  \@bsphack
  \edef\CM@pp@tmp{%
    \write\@auxout{%
      \string\CM@pp@data{\number\CM@pp@seq}{\noexpand\the\noexpand\c@page}}}%
  \CM@pp@tmp\@esphack}
\def\CM@pp@checkandstep{%
  \global\advance\CM@pp@seq\@ne \CM@pp@writelabel
  \expandafter\let\expandafter\CM@pp@cur
    \csname CM@pp@p@\number\CM@pp@seq\endcsname
  \ifx\CM@pp@cur\relax\else
    \ifnum\CM@pp@seq>\@ne
      \count@\CM@pp@seq \advance\count@\m@ne
      \expandafter\let\expandafter\CM@pp@prev
        \csname CM@pp@p@\number\count@\endcsname
      \ifx\CM@pp@prev\relax\else
        \ifx\CM@pp@cur\CM@pp@prev\else \setcounter{sidenote}\z@ \fi
      \fi
    \fi
  \fi
  \refstepcounter{sidenote}}
\def\CM@stepsidenote{\refstepcounter{sidenote}}

% numbering
\def\CM@apply@numbering{%
  \@ifundefined{c@sidenote}{\newcounter{sidenote}}{}%
  \immediate\write\@auxout{%
    \string\providecommand\string\CM@pp@data[2]{}}%
  \CM@ifeq{\CM@numbering}{global}{}{%
  \CM@ifeq{\CM@numbering}{persection}{\@addtoreset{sidenote}{section}}{%
  \CM@ifeq{\CM@numbering}{perchapter}{%
    \@ifundefined{c@chapter}{}{\@addtoreset{sidenote}{chapter}}}{%
  \CM@ifeq{\CM@numbering}{perpage}{%
    \@ifpackageloaded{sidenotes}{%
      \@ifpackageloaded{perpage}{\MakePerPage{sidenote}}{}%
    }{\let\CM@stepsidenote\CM@pp@checkandstep}%
  }{%
    \PackageWarning{page-canons}{Unknown numbering '\CM@numbering', using global}}}}}}

% \savepos, \lastxpos, \lastypos
\newif\ifCM@hassavepos \CM@hassavepostrue
\let\CM@savepos\savepos
\let\CM@xposprim\lastxpos
\let\CM@yposprim\lastypos

% position labels
\newcount\CM@pos@seq  \global\CM@pos@seq\z@
\newbox\CM@notebox
\newdimen\CM@ydim@a  \newdimen\CM@ydim@b

\def\CM@pos@data#1#2#3#4{%
  \global\@namedef{CM@pos@x@#1}{#2}%
  \global\@namedef{CM@pos@y@#1}{#3}%
  \global\@namedef{CM@pos@pg@#1}{#4}}

\def\CM@pos@writelabel#1{%
  \ifCM@hassavepos
    \CM@savepos
    \edef\CM@pos@tmp{%
      \write\@auxout{%
        \string\CM@pos@data{#1}%
          {\noexpand\the\noexpand\CM@xposprim\space sp}%
          {\noexpand\the\noexpand\CM@yposprim\space sp}%
          {\noexpand\the\noexpand\c@page}}}%
    \CM@pos@tmp
  \fi}

\def\CM@pos@getx#1{%
  \expandafter\let\expandafter\CM@currxpos
    \csname CM@pos@x@#1\endcsname}
\def\CM@pos@gety#1{%
  \expandafter\let\expandafter\CM@tmpypos
    \csname CM@pos@y@#1\endcsname}

% side selection
\newif\ifCM@rightside
\def\CM@selectside{%
  \if@mparswitch
    \checkoddpage
    \ifoddpage \CM@rightsidetrue \else \CM@rightsidefalse \fi
  \else \CM@rightsidetrue \fi
  \if@reversemargin
    \ifCM@rightside \CM@rightsidefalse \else \CM@rightsidetrue \fi
  \fi}

% line spread and inter-note gap
% note: override at load time or mid-document via notespread= key
\newdimen\CM@internotegap

% PDF/UA-2 tagging hooks; might be deprecated if just DocumentMetadata?
\def\CM@tagging@marginpar@begin{}
\def\CM@tagging@marginpar@end{}
\def\CM@tagging@suspend{}
\def\CM@tagging@resume{}

\ExplSyntaxOn

\tl_new:N   \l__CM_tag_parent_tl
\seq_new:N  \l__CM_tag_parent_seq

\cs_new_protected:Npn \__CM_tag_parent_aux:nn #1 #2
  {
    \str_if_eq:eeT { \use_ii:nn #1 } { Part }
      { \seq_put_right:Nn \l__CM_tag_parent_seq {#2} }
    \str_if_eq:eeT { \use_ii:nn #1 } { Sect }
      { \seq_put_right:Nn \l__CM_tag_parent_seq {#2} }
  }

\cs_new_protected:Npn \__CM_tag_get_parent:
  {
    \seq_clear:N \l__CM_tag_parent_seq
    \seq_map_pairwise_function:NNN
      \g__tag_struct_tag_stack_seq
      \g__tag_struct_stack_seq
      \__CM_tag_parent_aux:nn
    \seq_put_right:Nn \l__CM_tag_parent_seq { 2 }
    \seq_get_left:NN \l__CM_tag_parent_seq \l__CM_tag_parent_tl
  }

\cs_new_protected:Npn \__CM_tagging_marginpar_begin:
  {
    \if_mode_horizontal:
      \tag_mc_end:
      \__CM_tag_get_parent:
      \tag_struct_begin:e { tag=Aside, parent=\l__CM_tag_parent_tl }
    \else:
      \tag_struct_begin:n { tag=Aside }
    \fi:
  }

\cs_new_protected:Npn \__CM_tagging_marginpar_end:
  {
    \tag_struct_end:
    \if_mode_horizontal:
      \tag_mc_begin:n { }
    \fi:
  }

\cs_new_protected:Npn \__CM_tagging_suspend:
  { \tag_suspend:n { canons } }
\cs_new_protected:Npn \__CM_tagging_resume:
  { \tag_resume:n { canons } }

\cs_new_protected:Npn \__CM_activate_tagging_hooks:
  {
    \bool_set_false:N \l_tmpa_bool
    \cs_if_exist:NTF \tag_if_active:TF
      {
        \tag_if_active:TF
          { \bool_set_true:N \l_tmpa_bool }
          { }
      }
      {
        \cs_if_exist:NT \tag_struct_begin:n
          {
            \cs_if_exist:NT \g__tag_active_bool
              {
                \bool_if:NT \g__tag_active_bool
                  { \bool_set_true:N \l_tmpa_bool }
              }
          }
      }
    \bool_if:NT \l_tmpa_bool
      {
        \cs_generate_variant:Nn \tag_struct_begin:n { e }
        \cs_set:cpn { CM@tagging@marginpar@begin }
          { \__CM_tagging_marginpar_begin: }
        \cs_set:cpn { CM@tagging@marginpar@end }
          { \__CM_tagging_marginpar_end: }
        \cs_set:cpn { CM@tagging@suspend }
          { \__CM_tagging_suspend: }
        \cs_set:cpn { CM@tagging@resume }
          { \__CM_tagging_resume: }
        \PackageInfo { page-canons }
          { Tagging~hooks~activated~(Aside~via~direct~tagpdf~API) }
      }
  }

\AtBeginDocument { \__CM_activate_tagging_hooks: }

\ExplSyntaxOff

% per-note box storage
\def\CM@allocnotebox#1{%
  \@ifundefined{CM@nb@#1}{%
    \expandafter\newbox\csname CM@nb@#1\endcsname}{}}

% builder (source level)
\long\def\CM@buildcontent#1#2{%
  \CM@allocnotebox{#1}%
  \global\expandafter\setbox\csname CM@nb@#1\endcsname\vbox{%
    \hsize\marginparwidth \linewidth\hsize
    \kern-\parskip \@parboxrestore
    {\normalfont\marginfont \linespread{\CM@notespread}\selectfont
     \global\CM@internotegap\baselineskip
     \strut\hspace{\z@}\ignorespaces#2\endgraf}%
    \vss}}

% positioning primitive
\def\CM@placenote#1#2{%
  \bgroup
    \CM@pos@getx{#1}%
    \setbox\CM@notebox\vbox{%
      \expandafter\unvbox\csname CM@nb@#1\endcsname}%
    \setbox\@tempboxa\vbox to\z@{%
      \vss \CM@pos@writelabel{#1}%
      \ifCM@rightside
        \rlap{%
          \begingroup
            \ifx\CM@currxpos\relax\else\ifx\CM@currxpos\@empty\else
              \kern-\dimexpr\CM@currxpos\relax \fi\fi
            \ifoddpage\kern\oddsidemargin\else\kern\evensidemargin\fi
            \kern1in
          \endgroup
          \kern\textwidth \kern\marginparsep
          \vbox to\z@{\kern#2\relax \box\CM@notebox \vss}}%
      \else
        \llap{%
          \vbox to\z@{\kern#2\relax \box\CM@notebox \vss}%
          \begingroup
            \ifx\CM@currxpos\relax\else\ifx\CM@currxpos\@empty\else
              \kern\dimexpr\CM@currxpos\relax \fi\fi
            \ifoddpage\kern-\oddsidemargin\else\kern-\evensidemargin\fi
            \kern-1in
          \endgroup
          \kern\marginparsep}%
      \fi}%
    \ht\@tempboxa\z@ \dp\@tempboxa\z@ \wd\@tempboxa\z@
    \box\@tempboxa
  \egroup}

% check for collision
\newdimen\CM@mn@prevtotal  \newdimen\CM@mn@prevht
\newdimen\CM@mn@accum      \newcount\CM@mn@prevpage
\newcount\CM@mn@prevseq    \newdimen\CM@mn@prevoffset
\global\CM@mn@prevtotal\z@ \global\CM@mn@prevht\z@
\global\CM@mn@accum\z@     \global\CM@mn@prevpage\z@
\global\CM@mn@prevseq\z@   \global\CM@mn@prevoffset\z@

\def\CM@collision@reset{%
  \global\CM@mn@prevtotal\z@ \global\CM@mn@prevht\z@
  \global\CM@mn@accum\z@     \global\CM@mn@prevseq\z@
  \global\CM@mn@prevoffset\z@}

\def\CM@collision@compute{%
  \ifnum\CM@mn@prevseq=\z@ \global\CM@mn@accum\z@
  \else
    \CM@pos@gety{\number\CM@mn@prevseq}\let\CM@ypos@prev\CM@tmpypos
    \CM@pos@gety{\number\CM@pos@seq}\let\CM@ypos@curr\CM@tmpypos
    \ifx\CM@ypos@prev\relax \CM@collision@pagetotal
    \else\ifx\CM@ypos@curr\relax \CM@collision@pagetotal
    \else \CM@collision@ypos \fi\fi
  \fi}

\def\CM@collision@ypos{%
  \CM@ydim@a\dimexpr\CM@ypos@curr\relax
  \CM@ydim@b\dimexpr\CM@ypos@prev\relax
  \advance\CM@ydim@a-\CM@ydim@b
  \advance\CM@ydim@a\CM@mn@prevoffset
  \advance\CM@ydim@a\CM@mn@prevht
  \ifdim\CM@ydim@a>\z@ \global\CM@mn@accum\CM@ydim@a
  \else \global\CM@mn@accum\z@ \fi}

\def\CM@collision@pagetotal{%
  \@tempdimb\pagetotal \advance\@tempdimb-\CM@mn@prevtotal
  \ifdim\CM@mn@prevht>\z@
    \@tempdimc\CM@mn@accum
    \advance\@tempdimc\CM@mn@prevht \advance\@tempdimc-\@tempdimb
    \ifdim\@tempdimc>\z@ \global\CM@mn@accum\@tempdimc
    \else \global\CM@mn@accum\z@ \fi
  \fi}

% insertions helper
\long\def\CM@insert#1#2#3{%
  \CM@tagging@marginpar@begin
  \CM@buildcontent{#1}{#2}%
  \CM@tagging@marginpar@end
  \ifmmode \strut \vadjust{\CM@placenote{#1}{#3}}%
  \else
    \if@inlabel\leavevmode\fi
    \ifhmode \strut \vadjust{\CM@placenote{#1}{#3}}%
    \else \CM@placenote{#1}{#3}\fi
  \fi}

%  \marginnote
\long\def\CM@marginnote@public#1{%
  \@ifnextchar[{\CM@marginnote@manual{#1}}{\CM@marginnote@impl{#1}{0pt}}}

% feeds explicit offset into unified implementation
\long\def\CM@marginnote@manual#1[#2]{\CM@marginnote@impl{#1}{#2}}

% unified implementation
\long\def\CM@marginnote@impl#1#2{%
  \CM@selectside \global\advance\CM@pos@seq\@ne
  \CM@tagging@suspend
  \setbox\@tempboxa\vbox{%
    \hsize\marginparwidth \linewidth\hsize \@parboxrestore
    {\normalfont\marginfont \linespread{\CM@notespread}\selectfont
     \global\CM@internotegap\baselineskip
     \strut\ignorespaces#1\endgraf}%
    \vss}%
  \CM@tagging@resume
  \@tempdima\dimexpr\ht\@tempboxa+\dp\@tempboxa+\CM@internotegap\relax
  \ifnum\c@page=\CM@mn@prevpage\else
    \CM@collision@reset \global\CM@mn@prevpage\c@page \fi
  \CM@collision@compute
  \global\advance\CM@mn@accum\dimexpr#2\relax
  \expanded{%
    \noexpand\CM@insert{\the\CM@pos@seq}{\unexpanded{#1}}{\the\CM@mn@accum}}%
  \global\CM@mn@prevtotal\pagetotal
  \ifdim\CM@mn@accum>\z@ \global\advance\CM@mn@prevtotal\CM@mn@accum \fi
  \global\CM@mn@prevht\@tempdima
  \global\CM@mn@prevseq\CM@pos@seq
  \global\CM@mn@prevoffset\CM@mn@accum}

% sidenotes-package integration
% when the sidenotes package is loaded, redefine \marginfont such that
% sidenotes uses our font/justification settings
\def\CM@integ@sidenotes{%
  \def\marginfont{\normalfont\CM@sn@font\CM@sn@justify}}

% own sidenote implementation
\ifpagecanon@nomarginalia\else
\@ifpackageloaded{sidenotes}{}{%
  \newcounter{sidenote}%
  \newcommand*\canonssidenotemarkformat[1]{\textsuperscript{#1}}%
  \newcommand*\canonssidenotelabelformat[1]{\textsuperscript{#1}\,}%

  % always use \CM@marginnote@manual
  \long\def\CM@sidenote@place#1#2[#3]{%
    \begingroup
      \def\marginfont{\normalfont\CM@sn@font\CM@sn@justify}%
      \CM@marginnote@manual{\canonssidenotelabelformat{#1}#2}[#3]%
    \endgroup}

  % \sidenotemark[num]
  \newcommand{\sidenotemark}[1][]{%
    \def\CM@tmp@num{#1}%
    \ifx\CM@tmp@num\@empty
      \CM@stepsidenote \edef\CM@tmp@num{\arabic{sidenote}}\fi
    \canonssidenotemarkformat{\CM@tmp@num}}%

  % \sidenote[num]{text}[voffset]
  \newcommand{\sidenote}[2][]{%
    \def\CM@tmp@num{#1}%
    \ifx\CM@tmp@num\@empty
      \CM@stepsidenote \edef\CM@tmp@num{\arabic{sidenote}}\fi
    \canonssidenotemarkformat{\CM@tmp@num}%
    \@ifnextchar[{%
      \CM@sidenote@place{\CM@tmp@num}{#2}%
    }{%
      \CM@sidenote@place{\CM@tmp@num}{#2}[0pt]%
    }}%

  % \sidenotetext[num]{text}[voffset]
  \newcommand{\sidenotetext}[2][]{%
    \def\CM@tmp@num{#1}%
    \ifx\CM@tmp@num\@empty
      \edef\CM@tmp@num{\arabic{sidenote}}\fi
    \@ifnextchar[{%
      \CM@sidenote@place{\CM@tmp@num}{#2}%
    }{%
      \CM@sidenote@place{\CM@tmp@num}{#2}[0pt]%
    }}%
}
\fi

% lengths
\newlength{\pagecanon@pagewidth}   \newlength{\pagecanon@pageheight}
\newlength{\pagecanon@leafwidth}   \newlength{\pagecanon@innermargin}
\newlength{\pagecanon@outermargin} \newlength{\pagecanon@topmargin}
\newlength{\pagecanon@bottommargin}\newlength{\pagecanon@footskip}
\newlength{\pagecanon@marginparsep}\newlength{\pagecanon@marginparwidth}
\newlength{\pagecanon@gutterlength}\newlength{\pagecanon@textwidth}
\newlength{\pagecanon@textheight}  \newlength{\pagecanon@tmpdima}
\newlength{\pagecanon@cellwidth}   \newlength{\pagecanon@cellheight}
\newcount\pagecanon@totalhoriz     \newcount\pagecanon@totalvert
\newlength\marginandsep  \newlength\fullwidthoverhang
\newlength\overflowingheadlen \newlength\marginandtext
\newlength\textandsep    \newlength{\FW@shift}

% bleed subsystem
\newlength{\pagecanon@innerbleed} \newlength{\pagecanon@outerbleed}
\newlength{\pagecanon@topbleed}   \newlength{\pagecanon@bottombleed}
\newlength{\pagecanon@leftbleed}  \newlength{\pagecanon@rightbleed}
\newlength{\pagecanon@bleedH}     \newlength{\pagecanon@bleedV}
\newlength{\pagecanon@trimw}      \newlength{\pagecanon@trimh}
\newlength{\pagecanon@mediaw}     \newlength{\pagecanon@mediah}
\newdimen\pagecanon@bpdim
\newif\ifpagecanon@hasbleed
\newif\ifpagecanon@bindingleft
\newif\ifpagecanon@pdfout

% trim-line / crop-mark proofing aid
% \pagecanon@framerule is stroke width; override before \begin{document}
\newdimen\pagecanon@framerule \pagecanon@framerule0.4pt
\let\pagecanon@framecode\@empty

% output target
\ifluatex \pagecanon@pdfouttrue \else
  \ifxetex \pagecanon@pdfouttrue \else
    \ifpdf \pagecanon@pdfouttrue \else \pagecanon@pdfoutfalse \fi
  \fi
\fi

% resolve value strings to lengths; clamp negatives; set totals
\def\pagecanon@clampbleed#1#2{%
  \ifdim#1<\z@
    \PackageWarning{page-canons}{#2 < 0; clamped to 0pt}%
    #1\z@
  \fi}
\def\pagecanon@resolvebleed{%
  \setlength\pagecanon@innerbleed{\pagecanon@innerbleedval}%
  \setlength\pagecanon@outerbleed{\pagecanon@outerbleedval}%
  \setlength\pagecanon@topbleed{\pagecanon@topbleedval}%
  \setlength\pagecanon@bottombleed{\pagecanon@bottombleedval}%
  \pagecanon@clampbleed\pagecanon@innerbleed{innerbleed}%
  \pagecanon@clampbleed\pagecanon@outerbleed{outerbleed}%
  \pagecanon@clampbleed\pagecanon@topbleed{topbleed}%
  \pagecanon@clampbleed\pagecanon@bottombleed{bottombleed}%
  \setlength\pagecanon@bleedH{\dimexpr\pagecanon@innerbleed+\pagecanon@outerbleed\relax}%
  \setlength\pagecanon@bleedV{\dimexpr\pagecanon@topbleed+\pagecanon@bottombleed\relax}%
  % introspection: trim = finished page; media = trim + bleed (parity-free)
  \setlength\pagecanon@trimw{\paperwidth}%
  \setlength\pagecanon@trimh{\paperheight}%
  \setlength\pagecanon@mediaw{\dimexpr\paperwidth+\pagecanon@bleedH\relax}%
  \setlength\pagecanon@mediah{\dimexpr\paperheight+\pagecanon@bleedV\relax}%
  \setlength\pagecanon@leftbleed{\pagecanon@innerbleed}%
  \setlength\pagecanon@rightbleed{\pagecanon@outerbleed}%
  \ifdim\dimexpr\pagecanon@bleedH+\pagecanon@bleedV\relax>\z@
    \pagecanon@hasbleedtrue
  \else
    \pagecanon@hasbleedfalse
  \fi
  \ifpagecanon@hasbleed
    \ifpagecanon@pdfout\else
      \PackageWarning{page-canons}{%
        bleed requested but the output route is not PDF;\MessageBreak
        bleed disabled (use lualatex, xelatex, or pdflatex in PDF mode)}%
      \pagecanon@hasbleedfalse
    \fi
  \fi}

% map inner/outer bleed onto the physical left/right edge
\def\pagecanon@bleedsides{%
  \pagecanon@ifeq{\pagecanon@margins}{right}{%
    \pagecanon@bindinglefttrue
    \setlength\pagecanon@leftbleed{\pagecanon@innerbleed}%
    \setlength\pagecanon@rightbleed{\pagecanon@outerbleed}%
  }{\pagecanon@ifeq{\pagecanon@margins}{left}{%
    \pagecanon@bindingleftfalse
    \setlength\pagecanon@leftbleed{\pagecanon@outerbleed}%
    \setlength\pagecanon@rightbleed{\pagecanon@innerbleed}%
  }{%
    \if@twoside
      \ifodd\c@page \pagecanon@bindinglefttrue \else \pagecanon@bindingleftfalse \fi
    \else
      \pagecanon@bindinglefttrue
    \fi
    \ifpagecanon@bindingleft
      \setlength\pagecanon@leftbleed{\pagecanon@innerbleed}%
      \setlength\pagecanon@rightbleed{\pagecanon@outerbleed}%
    \else
      \setlength\pagecanon@leftbleed{\pagecanon@outerbleed}%
      \setlength\pagecanon@rightbleed{\pagecanon@innerbleed}%
    \fi
  }}}

% pdf box arrays are in bp (1/72 in); tex dimens are pt (1/72.27 in)
% factor 7200/7227 = 0.99626401
\def\pagecanon@mkbp#1#2{%
  \pagecanon@bpdim#2\relax
  \pagecanon@bpdim0.99626401\pagecanon@bpdim
  \edef#1{\strip@pt\pagecanon@bpdim}}

% emit /MediaBox, /TrimBox, /BleedBo
\def\pagecanon@setpdfboxes{%
  \pagecanon@mkbp\pagecanon@bb@mx{-\pagecanon@leftbleed}%
  \pagecanon@mkbp\pagecanon@bb@my{-\pagecanon@bottombleed}%
  \pagecanon@mkbp\pagecanon@bb@mX{\dimexpr\pagecanon@trimw+\pagecanon@rightbleed\relax}%
  \pagecanon@mkbp\pagecanon@bb@mY{\dimexpr\pagecanon@trimh+\pagecanon@topbleed\relax}%
  \pagecanon@mkbp\pagecanon@bb@tw{\pagecanon@trimw}%
  \pagecanon@mkbp\pagecanon@bb@th{\pagecanon@trimh}%
  \edef\pagecanon@bb@attr{%
    /MediaBox [\pagecanon@bb@mx\space\pagecanon@bb@my\space
               \pagecanon@bb@mX\space\pagecanon@bb@mY]\space
    /TrimBox [0 0 \pagecanon@bb@tw\space\pagecanon@bb@th]\space
    /BleedBox [\pagecanon@bb@mx\space\pagecanon@bb@my\space
               \pagecanon@bb@mX\space\pagecanon@bb@mY]}%
  \ifluatex
    \expandafter\pagecanon@setluaattr\expandafter{\pagecanon@bb@attr}%
  \else\ifxetex
    \special{pdf:put @thispage <<\pagecanon@bb@attr>>}%
  \else
    \expandafter\pdfpageattr\expandafter{\pagecanon@bb@attr}%
  \fi\fi
  % trim line + crop marks (showbleed), in stream (= trim) coordinates.
  \let\pagecanon@bleedcode\@empty
  \ifpagecanon@showbleed
    \ifxetex\else
      \pagecanon@mkbp\pagecanon@bb@lw{\pagecanon@framerule}%
      \edef\pagecanon@bleedcode{%
        q\space1 0 1 RG\space\pagecanon@bb@lw\space w\space
        % trim rectangle [0 0 trimw trimh]:
        0 0 m\space\pagecanon@bb@tw\space0 l\space
        \pagecanon@bb@tw\space\pagecanon@bb@th\space l\space
        0 \pagecanon@bb@th\space l\space h\space S\space
        % crop marks: trim corner out to the media edge along each axis.
        \pagecanon@bb@mx\space0 m\space0 0 l\space S\space
        0 \pagecanon@bb@my\space m\space0 0 l\space S\space
        \pagecanon@bb@mX\space0 m\space\pagecanon@bb@tw\space0 l\space S\space
        \pagecanon@bb@tw\space\pagecanon@bb@my\space m\space\pagecanon@bb@tw\space0 l\space S\space
        \pagecanon@bb@mx\space\pagecanon@bb@th\space m\space0 \pagecanon@bb@th\space l\space S\space
        0 \pagecanon@bb@mY\space m\space0 \pagecanon@bb@th\space l\space S\space
        \pagecanon@bb@mX\space\pagecanon@bb@th\space m\space\pagecanon@bb@tw\space\pagecanon@bb@th\space l\space S\space
        \pagecanon@bb@tw\space\pagecanon@bb@mY\space m\space\pagecanon@bb@tw\space\pagecanon@bb@th\space l\space S\space
        Q}%
    \fi
  \fi}
\def\pagecanon@setluaattr#1{\pdfvariable pageattr{#1}}

% dashed line along the gutter (showgutter), in stream (= trim) coordinates
\def\pagecanon@buildguttercode{%
  \pagecanon@mkbp\pagecanon@bb@lw{\pagecanon@framerule}%
  \pagecanon@mkbp\pagecanon@bb@th{\pagecanon@trimh}%
  \ifpagecanon@bindingleft
    \pagecanon@mkbp\pagecanon@bb@gx{\pagecanon@gutterlength}%
  \else
    \pagecanon@mkbp\pagecanon@bb@gx{\dimexpr\pagecanon@trimw-\pagecanon@gutterlength\relax}%
  \fi
  \edef\pagecanon@guttercode{%
    q\space0 0 1 RG\space\pagecanon@bb@lw\space w\space[3 3] 0 d\space
    \pagecanon@bb@gx\space0 m\space\pagecanon@bb@gx\space\pagecanon@bb@th\space l\space S\space Q}}

% emit a page-coordinate literal (absolute, bp)
\def\pagecanon@pageliteral#1{%
  \ifluatex \pdfextension literal page{#1}%
  \else \pdfliteral page{#1}\fi}
\def\pagecanon@drawmaybe{%
  \ifx\pagecanon@bleedcode\@empty\else
    \expandafter\pagecanon@pageliteral\expandafter{\pagecanon@bleedcode}%
  \fi
  \ifx\pagecanon@guttercode\@empty\else
    \expandafter\pagecanon@pageliteral\expandafter{\pagecanon@guttercode}%
  \fi}

% shipout
\def\pagecanon@shipoutdraw{%
  \setlength\pagecanon@trimw{\paperwidth}%
  \setlength\pagecanon@trimh{\paperheight}%
  \let\pagecanon@bleedcode\@empty
  \let\pagecanon@guttercode\@empty
  \ifpagecanon@hasbleed
    \pagecanon@bleedsides
    \pagecanon@setpdfboxes
  \else
    \ifpagecanon@showgutter \pagecanon@bleedsides \fi
  \fi
  \ifpagecanon@showgutter
    \ifdim\pagecanon@gutterlength>\z@
      \ifxetex\else \pagecanon@buildguttercode \fi
    \fi
  \fi
  \def\pagecanon@tmp@any{}%
  \ifx\pagecanon@bleedcode\@empty\else \def\pagecanon@tmp@any{x}\fi
  \ifx\pagecanon@guttercode\@empty\else \def\pagecanon@tmp@any{x}\fi
  \ifx\pagecanon@tmp@any\@empty\else
    \setbox\ShipoutBox\hbox{\pagecanon@drawmaybe \box\ShipoutBox}%
  \fi}
\AddToHook{shipout/before}{\pagecanon@shipoutdraw}

% canon defs
\def\pagecanon@vdg#1#2{%
  \pagecanon@innermargin=.111111#1\relax
  \pagecanon@outermargin=.222222#1\relax
  \pagecanon@topmargin=.111111#2\relax
  \pagecanon@bottommargin=.222222#2\relax
  \pagecanon@footskip=.5\pagecanon@bottommargin\relax
  \pagecanon@marginparsep=.022222#1\relax
  \pagecanon@marginparwidth=.177775#1\relax}

\def\pagecanon@vdh#1#2#3{%
  \pagecanon@ifeq{#3}{3}{%
    \pagecanon@innermargin=.166667#1\relax \pagecanon@outermargin=.333333#1\relax
    \pagecanon@topmargin=.25#1\relax \pagecanon@bottommargin=.5#1\relax
    \pagecanon@marginparsep=.047616#1\relax \pagecanon@marginparwidth=.238102#1\relax
  }{\pagecanon@ifeq{#3}{6}{%
    \pagecanon@innermargin=.111111#1\relax \pagecanon@outermargin=.222222#1\relax
    \pagecanon@topmargin=.166667#1\relax \pagecanon@bottommargin=.333333#1\relax
    \pagecanon@marginparsep=.02222#1\relax \pagecanon@marginparwidth=.177782#1\relax
  }{\pagecanon@ifeq{#3}{9}{%
    \pagecanon@innermargin=.083333#1\relax \pagecanon@outermargin=.166667#1\relax
    \pagecanon@topmargin=.125#1\relax \pagecanon@bottommargin=.25#1\relax
    \pagecanon@marginparsep=.01282#1\relax \pagecanon@marginparwidth=.141025#1\relax
  }{\pagecanon@ifeq{#3}{12}{%
    \pagecanon@innermargin=.066667#1\relax \pagecanon@outermargin=.133333#1\relax
    \pagecanon@topmargin=.1#1\relax \pagecanon@bottommargin=.2#1\relax
    \pagecanon@marginparsep=.0083218#1\relax \pagecanon@marginparwidth=.116685#1\relax
  }{\pagecanon@ifeq{#3}{15}{%
    \pagecanon@innermargin=.055556#1\relax \pagecanon@outermargin=.111111#1\relax
    \pagecanon@topmargin=.083333#1\relax \pagecanon@bottommargin=.166667#1\relax
    \pagecanon@marginparsep=.003217#1\relax \pagecanon@marginparwidth=.099411#1\relax
  }{%
    \pagecanon@innermargin=.111111#1\relax \pagecanon@outermargin=.222222#1\relax
    \pagecanon@topmargin=.166667#1\relax \pagecanon@bottommargin=.333333#1\relax
    \pagecanon@marginparsep=.02222#1\relax \pagecanon@marginparwidth=.177782#1\relax
  }}}}}%
  \pagecanon@footskip=.5\pagecanon@bottommargin\relax}

\def\pagecanon@tufte#1#2{%
  \pagecanon@innermargin=.117647#1\relax
  \pagecanon@outermargin=.372941#1\relax
  \pagecanon@topmargin=.090909#2\relax
  \pagecanon@bottommargin=.136364#2\relax
  \pagecanon@footskip=.5\pagecanon@bottommargin\relax
  \pagecanon@marginparsep=.038824#1\relax
  \pagecanon@marginparwidth=.235294#1\relax}

\def\pagecanon@ateliers#1#2#3{%
  \pagecanon@ifeq{#3}{ordinary}{%
    \pagecanon@innermargin=.1#1\relax \pagecanon@outermargin=.15#1\relax
    \pagecanon@topmargin=.125#1\relax \pagecanon@bottommargin=.175#1\relax
  }{\pagecanon@ifeq{#3}{neater}{%
    \pagecanon@innermargin=.133333#1\relax \pagecanon@outermargin=.2#1\relax
    \pagecanon@topmargin=.166667#1\relax \pagecanon@bottommargin=.233333#1\relax
  }{\pagecanon@ifeq{#3}{luxury}{%
    \pagecanon@innermargin=.15#1\relax \pagecanon@outermargin=.225#1\relax
    \pagecanon@topmargin=.1875#1\relax \pagecanon@bottommargin=.2625#1\relax
  }{%
    \pagecanon@innermargin=.1#1\relax \pagecanon@outermargin=.15#1\relax
    \pagecanon@topmargin=.125#1\relax \pagecanon@bottommargin=.175#1\relax
  }}}%
  \pagecanon@footskip=.5\pagecanon@bottommargin\relax
  \pagecanon@marginparsep=.017974#1\relax
  \pagecanon@marginparwidth=.106209#1\relax}

\def\pagecanon@grid#1#2{%
  \ifnum\pagecanon@gridN<3 \def\pagecanon@gridN{3}\fi
  \ifnum\pagecanon@gridN=3
    \pagecanon@ifeq{\pagecanon@gridinner}{1}{%
      \pagecanon@ifeq{\pagecanon@gridouter}{2}{\def\pagecanon@gridouter{1}}{}}{}%
    \pagecanon@ifeq{\pagecanon@gridtop}{1}{%
      \pagecanon@ifeq{\pagecanon@gridbottom}{2}{\def\pagecanon@gridbottom{1}}{}}{}%
  \fi
  \pagecanon@cellwidth=\dimexpr#1/\pagecanon@gridN\relax
  \pagecanon@cellheight=\dimexpr#2/\pagecanon@gridN\relax
  \pagecanon@totalhoriz=\pagecanon@gridinner\relax
  \advance\pagecanon@totalhoriz by\pagecanon@gridouter\relax
  \pagecanon@totalvert=\pagecanon@gridtop\relax
  \advance\pagecanon@totalvert by\pagecanon@gridbottom\relax
  \ifnum\pagecanon@totalhoriz<\pagecanon@gridN\else
    \PackageError{page-canons}{Grid: inner+outer >= N}{}\fi
  \ifnum\pagecanon@totalvert<\pagecanon@gridN\else
    \PackageError{page-canons}{Grid: top+bottom >= N}{}\fi
  \pagecanon@innermargin=\dimexpr\pagecanon@gridinner\pagecanon@cellwidth\relax
  \pagecanon@outermargin=\dimexpr\pagecanon@gridouter\pagecanon@cellwidth\relax
  \pagecanon@topmargin=\dimexpr\pagecanon@gridtop\pagecanon@cellheight\relax
  \pagecanon@bottommargin=\dimexpr\pagecanon@gridbottom\pagecanon@cellheight\relax
  \pagecanon@footskip=.5\pagecanon@bottommargin\relax
  \pagecanon@marginparsep=\dimexpr\pagecanon@cellwidth/6\relax\relax
  \ifdim\pagecanon@marginparsep<7pt \pagecanon@marginparsep=7pt\relax\fi
  \pagecanon@marginparwidth=\dimexpr\pagecanon@outermargin-2\pagecanon@marginparsep\relax\relax
  \ifdim\pagecanon@marginparwidth<20pt
    \pagecanon@marginparsep=\dimexpr(\pagecanon@outermargin-20pt)/2\relax\relax
    \ifdim\pagecanon@marginparsep<3pt \pagecanon@marginparsep=3pt\relax\fi
    \pagecanon@marginparwidth=\dimexpr\pagecanon@outermargin-2\pagecanon@marginparsep\relax\relax
    \ifdim\pagecanon@marginparwidth<10pt \pagecanon@marginparwidth=10pt\relax\fi
  \fi}

% gutter
\def\pagecanon@applyguttergeometry{%
  \pagecanon@ifeq{\pagecanon@margins}{symmetric}{%
    \advance\pagecanon@innermargin by\pagecanon@gutterlength\relax
    \advance\pagecanon@outermargin by-\pagecanon@gutterlength\relax
    \ifdim\pagecanon@outermargin<0pt \pagecanon@outermargin=0pt\relax\fi
  }{%
    \advance\pagecanon@outermargin by\pagecanon@gutterlength\relax
    \advance\pagecanon@innermargin by-\pagecanon@gutterlength\relax
    \ifdim\pagecanon@innermargin<0pt \pagecanon@innermargin=0pt\relax\fi
  }%
  \pagecanon@tmpdima=\dimexpr\pagecanon@outermargin-2\pagecanon@marginparsep\relax\relax
  \pagecanon@ifeq{\pagecanon@margins}{symmetric}{}{%
    \advance\pagecanon@tmpdima by-\pagecanon@gutterlength\relax}%
  \ifdim\pagecanon@marginparwidth>\pagecanon@tmpdima
    \pagecanon@marginparwidth=\pagecanon@tmpdima\relax
    \ifdim\pagecanon@marginparwidth<10pt \pagecanon@marginparwidth=10pt\relax\fi
  \fi}
\def\pagecanon@applyguttersatzspiegel{%
  \pagecanon@leafwidth=\pagecanon@pagewidth\relax
  \advance\pagecanon@leafwidth by-\pagecanon@gutterlength\relax
  \pagecanon@applycanon{\pagecanon@leafwidth}{\pagecanon@pageheight}%
  \pagecanon@ifeq{\pagecanon@margins}{symmetric}{%
    \advance\pagecanon@innermargin by\pagecanon@gutterlength\relax
  }{%
    \advance\pagecanon@outermargin by\pagecanon@gutterlength\relax
  }}
\def\pagecanon@applycanon#1#2{%
  \pagecanon@ifeq{\pagecanon@canon}{vdg}{\pagecanon@vdg{#1}{#2}}{%
  \pagecanon@ifeq{\pagecanon@canon}{vdh}{\pagecanon@vdh{#1}{#2}{\pagecanon@vdhN}}{%
  \pagecanon@ifeq{\pagecanon@canon}{tufte}{\pagecanon@tufte{#1}{#2}}{%
  \pagecanon@ifeq{\pagecanon@canon}{ateliers}{\pagecanon@ateliers{#1}{#2}{\pagecanon@ateliersstyle}}{%
  \pagecanon@ifeq{\pagecanon@canon}{grid}{\pagecanon@grid{#1}{#2}}{%
    \PackageWarning{page-canons}{Unknown canon '\pagecanon@canon', using vdg}%
    \pagecanon@vdg{#1}{#2}}}}}}}

%caption handlers
\long\def\FW@caption@symmetric#1#2{%
  \vskip\abovecaptionskip \checkoddpage
  \ifoddpage
    \parbox{\dimexpr\linewidth-\fullwidthoverhang\relax}{\strut{\small\textbf{#1:} #2}\par}%
  \else
    \hspace*{\fullwidthoverhang}%
    \parbox{\dimexpr\linewidth-\fullwidthoverhang\relax}{\strut{\small\textbf{#1:} #2}\par}%
  \fi \vskip\belowcaptionskip}
\long\def\FW@caption@antisymmetric#1#2{%
  \vskip\abovecaptionskip \checkoddpage
  \ifoddpage
    \hspace*{\fullwidthoverhang}%
    \parbox{\dimexpr\linewidth-\fullwidthoverhang\relax}{\strut{\small\textbf{#1:} #2}\par}%
  \else
    \parbox{\dimexpr\linewidth-\fullwidthoverhang\relax}{\strut{\small\textbf{#1:} #2}\par}%
  \fi \vskip\belowcaptionskip}
\long\def\FW@caption@right#1#2{%
  \vskip\abovecaptionskip
  \parbox{\dimexpr\linewidth-\fullwidthoverhang\relax}{\strut{\small\textbf{#1:} #2}\par}%
  \vskip\belowcaptionskip}
\long\def\FW@caption@left#1#2{%
  \vskip\abovecaptionskip \hspace*{\fullwidthoverhang}%
  \parbox{\dimexpr\linewidth-\fullwidthoverhang\relax}{\strut{\small\textbf{#1:} #2}\par}%
  \vskip\belowcaptionskip}
\def\pagecanon@setFWcaption{%
  \pagecanon@ifeq{\pagecanon@margins}{symmetric}{\let\FW@makecaption\FW@caption@symmetric}{%
  \pagecanon@ifeq{\pagecanon@margins}{antisymmetric}{\let\FW@makecaption\FW@caption@antisymmetric}{%
  \pagecanon@ifeq{\pagecanon@margins}{left}{\let\FW@makecaption\FW@caption@left}{%
    \let\FW@makecaption\FW@caption@right}}}}

% fullwidth helpers
\def\FW@setjust{%
  \pagecanon@ifeq{\FW@just}{centering}{\centering}{%
  \pagecanon@ifeq{\FW@just}{raggedright}{\raggedright}{%
  \pagecanon@ifeq{\FW@just}{raggedleft}{\raggedleft}{%
  \pagecanon@ifeq{\FW@just}{justified}{}{\centering}}}}}

\def\FW@calcshift{%
  \FW@shift=\@totalleftmargin\relax
  \pagecanon@ifeq{\pagecanon@margins}{symmetric}{%
    \checkoddpage \ifoddpage\else\advance\FW@shift by\fullwidthoverhang\relax\fi
  }{\pagecanon@ifeq{\pagecanon@margins}{antisymmetric}{%
    \checkoddpage \ifoddpage\advance\FW@shift by\fullwidthoverhang\relax\fi
  }{\pagecanon@ifeq{\pagecanon@margins}{left}{%
    \advance\FW@shift by\fullwidthoverhang\relax}{}}}}

\def\FW@applycaption{%
  \@ifpackageloaded{caption}{}{\let\@makecaption\FW@makecaption}}

% fullwidth environment
\newenvironment{fullwidth}[1][]{%
  \FW@resetdefaults \FW@setkeys{#1}%
  \par\vspace{\FW@skip}\noindent\begingroup
  \FW@calcshift \hspace*{-\FW@shift}%
  \begin{minipage}{\dimexpr\linewidth+\fullwidthoverhang\relax}%
    \FW@setjust \FW@applycaption
}{\end{minipage}\par\endgroup}

% margin state sync
\def\CM@syncmarginstate{%
  \CM@ifeq{\pagecanon@margins}{symmetric}{%
    \@mparswitchtrue \@reversemarginfalse
  }{\CM@ifeq{\pagecanon@margins}{antisymmetric}{%
    \@mparswitchtrue \@reversemargintrue
  }{\CM@ifeq{\pagecanon@margins}{right}{%
    \@mparswitchfalse \@reversemarginfalse
  }{\CM@ifeq{\pagecanon@margins}{left}{%
    \@mparswitchfalse \@reversemargintrue
  }{\@mparswitchfalse \@reversemarginfalse}}}}%
  \CM@resolvealljust
  \CM@resolveallfont}

% user reconfiguration
\newif\ifpagecanon@iscanonkey
\def\pagecanon@checkcanonkey#1=#2\pagecanon@kv@end{%
  \pagecanon@trimkey{#1}%
  \pagecanon@ifeq{\pagecanon@kvkey}{canon}%
    {\pagecanon@iscanonkeytrue}{\pagecanon@iscanonkeyfalse}}

\newcommand{\pagecanonsetup}[1]{%
  \@for\pagecanon@kv@raw:=#1\do{%
    \ifx\pagecanon@kv@raw\@empty\else
      \@expandtwoargs\in@{=}{\pagecanon@kv@raw}%
      \ifin@
        \expandafter\pagecanon@checkcanonkey\pagecanon@kv@raw=\pagecanon@kv@end
        \ifpagecanon@iscanonkey
          \expandafter\canons@kvsplit\pagecanon@kv@raw==\canons@kv@end
        \fi
      \fi
    \fi}%
  \canons@setkeys{#1}%
  \ifpagecanon@afterbegin
    \ifpagecanon@insetup\relax\else
      \pagecanon@insetuptrue \pagecanon@setup \pagecanon@insetupfalse
    \fi
  \fi}

% main setup
\def\pagecanon@setup{%
  \pagecanon@resolvebleed
  \if@twocolumn
    \ifpagecanon@twocolwarn\else \pagecanon@twocolwarntrue
      \PackageWarning{page-canons}{twocolumn mode: page-canons may behave unexpectedly}\fi
  \fi
  \pagecanon@ifeq{\pagecanon@canon}{false}{%
    \pagecanon@ifeq{\pagecanon@margins}{antisymmetric}{\newgeometry{reversemarginpar}}{%
    \pagecanon@ifeq{\pagecanon@margins}{right}{\newgeometry{asymmetric}}{%
    \pagecanon@ifeq{\pagecanon@margins}{left}{\newgeometry{asymmetric}}{%
      \newgeometry{}}}}%
  }{%
    \pagecanon@gutterlength=\dimexpr\pagecanon@gutterval\relax
    \pagecanon@pagewidth=\paperwidth\relax
    \pagecanon@pageheight=\paperheight\relax
    \pagecanon@leafwidth=\pagecanon@pagewidth\relax
    \pagecanon@applycanon{\pagecanon@leafwidth}{\pagecanon@pageheight}%
    \ifdim\pagecanon@gutterlength>0pt
      \pagecanon@ifeq{\pagecanon@guttermode}{geometry}{\pagecanon@applyguttergeometry}{%
      \pagecanon@ifeq{\pagecanon@guttermode}{satzspiegel}{\pagecanon@applyguttersatzspiegel}{}}%
    \fi
    \pagecanon@textwidth=\dimexpr\pagecanon@pagewidth
      -\pagecanon@innermargin-\pagecanon@outermargin\relax
    \pagecanon@textheight=\dimexpr\pagecanon@pageheight
      -\pagecanon@topmargin-\pagecanon@bottommargin\relax
    \edef\pagecanon@tmp@guardcanon{\pagecanon@canon}%
    \def\pagecanon@tmp@guardgrid{grid}%
    \ifx\pagecanon@tmp@guardcanon\pagecanon@tmp@guardgrid\else
      \pagecanon@tmpdima=\dimexpr\pagecanon@outermargin
        -2\pagecanon@marginparsep\relax\relax
      \ifdim\pagecanon@gutterlength>0pt
        \pagecanon@ifeq{\pagecanon@margins}{symmetric}{}{%
          \advance\pagecanon@tmpdima by-\pagecanon@gutterlength\relax}%
      \fi
      \ifdim\pagecanon@marginparwidth>\pagecanon@tmpdima
        \pagecanon@marginparwidth=\pagecanon@tmpdima\relax
        \ifdim\pagecanon@marginparwidth<10pt \pagecanon@marginparwidth=10pt\relax\fi
      \fi
    \fi
    \pagecanon@ifeq{\pagecanon@margins}{symmetric}{%
      \newgeometry{inner=\the\pagecanon@innermargin,outer=\the\pagecanon@outermargin,
        top=\the\pagecanon@topmargin,bottom=\the\pagecanon@bottommargin,
        footskip=\the\pagecanon@footskip,marginparsep=\the\pagecanon@marginparsep,
        marginparwidth=\the\pagecanon@marginparwidth}%
    }{\pagecanon@ifeq{\pagecanon@margins}{antisymmetric}{%
      \newgeometry{inner=\the\pagecanon@outermargin,outer=\the\pagecanon@innermargin,
        top=\the\pagecanon@topmargin,bottom=\the\pagecanon@bottommargin,
        footskip=\the\pagecanon@footskip,marginparsep=\the\pagecanon@marginparsep,
        marginparwidth=\the\pagecanon@marginparwidth,reversemarginpar}%
    }{\pagecanon@ifeq{\pagecanon@margins}{right}{%
      \newgeometry{left=\the\pagecanon@innermargin,right=\the\pagecanon@outermargin,
        top=\the\pagecanon@topmargin,bottom=\the\pagecanon@bottommargin,
        footskip=\the\pagecanon@footskip,marginparsep=\the\pagecanon@marginparsep,
        marginparwidth=\the\pagecanon@marginparwidth,asymmetric}%
    }{\pagecanon@ifeq{\pagecanon@margins}{left}{%
      \newgeometry{left=\the\pagecanon@outermargin,right=\the\pagecanon@innermargin,
        top=\the\pagecanon@topmargin,bottom=\the\pagecanon@bottommargin,
        footskip=\the\pagecanon@footskip,marginparsep=\the\pagecanon@marginparsep,
        marginparwidth=\the\pagecanon@marginparwidth,asymmetric}%
    }{}}}}%
  }%
  \marginandtext=\dimexpr\textwidth+\marginparwidth+\marginparsep\relax
  \marginandsep=\dimexpr\marginparwidth+\marginparsep\relax
  \textandsep=\dimexpr\textwidth+\marginparsep\relax
  \overflowingheadlen=\dimexpr\textwidth+\marginparsep+\marginparwidth\relax
  \fullwidthoverhang=\dimexpr\marginparwidth+\marginparsep\relax
  \pagecanon@setFWcaption
  \ifpagecanon@showbleed\ifpagecanon@hasbleed\else
    \PackageInfo{page-canons}{showbleed set but no bleed; trim line omitted}%
  \fi\fi
  \ifpagecanon@showgutter\ifdim\pagecanon@gutterlength>\z@\else
    \PackageInfo{page-canons}{showgutter set but gutter is 0pt; line omitted}%
  \fi\fi
  \CM@syncmarginstate
  \CM@collision@reset}

% AtBeginDocument
\AtBeginDocument{%
  \pagecanon@afterbegintrue
  \pagecanon@setup
  \immediate\write\@auxout{%
    \string\providecommand\string\CM@pos@data[4]{}}%
  \ifpagecanon@nomarginalia\else
    \@ifundefined{marginnote}{%
      \def\marginfont{\canonsmarginfont\CM@mn@justify}%
      \let\marginnote\CM@marginnote@public
      \@ifpackageloaded{sidenotes}{\CM@integ@sidenotes}{}%
      \CM@apply@numbering
    }{%
      \PackageInfo{page-canons}{%
        \string\marginnote\space already defined by another package;
        page-canons defers (pass nomarginalia to silence)}%
    }%
  \fi}

% utility commands
\newcommand{\canonsswitchmargin}{%
  \if@reversemargin\@reversemarginfalse\else\@reversemargintrue\fi}
\newcommand{\canonsresetmargin}{%
  \CM@ifeq{\pagecanon@margins}{antisymmetric}{\reversemarginpar}{%
  \CM@ifeq{\pagecanon@margins}{left}{\reversemarginpar}{\normalmarginpar}}}

\def\pagecanonmargins{\pagecanon@margins}


% bleed (left/right resolve per page at shipout; seeded to recto in the body):
\let\canonsinnerbleed\pagecanon@innerbleed
\let\canonsouterbleed\pagecanon@outerbleed
\let\canonstopbleed\pagecanon@topbleed
\let\canonsbottombleed\pagecanon@bottombleed
\let\canonsleftbleed\pagecanon@leftbleed
\let\canonsrightbleed\pagecanon@rightbleed
\let\canonsbleedwidth\pagecanon@bleedH
\let\canonsbleedheight\pagecanon@bleedV
% paper / trim / media (trim == finished page; media == trim + bleed):
\let\canonspaperwidth\paperwidth
\let\canonspaperheight\paperheight
\let\canonstrimwidth\paperwidth
\let\canonstrimheight\paperheight
\let\canonsmediawidth\pagecanon@mediaw
\let\canonsmediaheight\pagecanon@mediah
% canon margins (values handed to geometry; 0pt under canon=false):
\let\canonsinnermargin\pagecanon@innermargin
\let\canonsoutermargin\pagecanon@outermargin
\let\canonstopmargin\pagecanon@topmargin
\let\canonsbottommargin\pagecanon@bottommargin
\let\canonsgutter\pagecanon@gutterlength
\let\canonsleafwidth\pagecanon@leafwidth
\let\canonscellwidth\pagecanon@cellwidth
\let\canonscellheight\pagecanon@cellheight
% resolved layout (aliases to registers geometry set):
\let\canonstextwidth\textwidth
\let\canonstextheight\textheight
\let\canonsmarginparwidth\marginparwidth
\let\canonsmarginparsep\marginparsep
\let\canonsfootskip\footskip
\let\canonsheadheight\headheight
\let\canonsheadsep\headsep
\let\canonsoddsidemargin\oddsidemargin
\let\canonsevensidemargin\evensidemargin
\let\canonscolumnsep\columnsep
\let\canonslinewidth\linewidth
% derived helper widths the package builds for full-width, marginalia work:
\let\canonsmarginandtext\marginandtext
\let\canonsmarginandsep\marginandsep
\let\canonstextandsep\textandsep
\let\canonsoverflowinghead\overflowingheadlen
\let\canonsfullwidthoverhang\fullwidthoverhang

% 1pt = 0.3514598 mm; print a register as "<pt> (<mm> mm)".
\def\pagecanon@metricline#1#2{%
  \pagecanon@bpdim#2\relax
  \pagecanon@bpdim0.3514598\pagecanon@bpdim
  \edef\pagecanon@tmp@mm{\strip@pt\pagecanon@bpdim}%
  \typeout{\space\space#1 = \the#2\space(\pagecanon@tmp@mm\space mm)}}

% every metric to the log/console
\newcommand\pagecanonmetrics{%
  \typeout{page-canons metrics (canon=\pagecanon@canon, margins=\pagecanon@margins):}%
  \typeout{ bleed:}%
  \pagecanon@metricline{innerbleed}\canonsinnerbleed
  \pagecanon@metricline{outerbleed}\canonsouterbleed
  \pagecanon@metricline{topbleed}\canonstopbleed
  \pagecanon@metricline{bottombleed}\canonsbottombleed
  \pagecanon@metricline{leftbleed (this-page)}\canonsleftbleed
  \pagecanon@metricline{rightbleed (this-page)}\canonsrightbleed
  \pagecanon@metricline{bleedwidth}\canonsbleedwidth
  \pagecanon@metricline{bleedheight}\canonsbleedheight
  \typeout{ paper / trim / media:}%
  \pagecanon@metricline{trimwidth}\canonstrimwidth
  \pagecanon@metricline{trimheight}\canonstrimheight
  \pagecanon@metricline{mediawidth}\canonsmediawidth
  \pagecanon@metricline{mediaheight}\canonsmediaheight
  \typeout{ canon margins (0pt if canon=false):}%
  \pagecanon@metricline{innermargin}\canonsinnermargin
  \pagecanon@metricline{outermargin}\canonsoutermargin
  \pagecanon@metricline{topmargin}\canonstopmargin
  \pagecanon@metricline{bottommargin}\canonsbottommargin
  \pagecanon@metricline{gutter}\canonsgutter
  \pagecanon@metricline{leafwidth}\canonsleafwidth
  \pagecanon@metricline{cellwidth}\canonscellwidth
  \pagecanon@metricline{cellheight}\canonscellheight
  \typeout{ resolved layout:}%
  \pagecanon@metricline{textwidth}\canonstextwidth
  \pagecanon@metricline{textheight}\canonstextheight
  \pagecanon@metricline{marginparwidth}\canonsmarginparwidth
  \pagecanon@metricline{marginparsep}\canonsmarginparsep
  \pagecanon@metricline{footskip}\canonsfootskip
  \pagecanon@metricline{headheight}\canonsheadheight
  \pagecanon@metricline{headsep}\canonsheadsep
  \pagecanon@metricline{oddsidemargin}\canonsoddsidemargin
  \pagecanon@metricline{evensidemargin}\canonsevensidemargin}

% opt-in: also bind the bare names (\the\innerbleed etc.)
\def\pagecanon@expose#1#2{%
  \@ifundefined{#1}{\global\expandafter\let\csname#1\endcsname#2}{%
    \PackageInfo{page-canons}{bare name
      \expandafter\string\csname#1\endcsname\space already defined; not exposed}}}
\newcommand\pagecanonexposemetrics{%
  \pagecanon@expose{innerbleed}\pagecanon@innerbleed
  \pagecanon@expose{outerbleed}\pagecanon@outerbleed
  \pagecanon@expose{topbleed}\pagecanon@topbleed
  \pagecanon@expose{bottombleed}\pagecanon@bottombleed
  \pagecanon@expose{leftbleed}\pagecanon@leftbleed
  \pagecanon@expose{rightbleed}\pagecanon@rightbleed
  \pagecanon@expose{bleedwidth}\pagecanon@bleedH
  \pagecanon@expose{bleedheight}\pagecanon@bleedV
  \pagecanon@expose{trimwidth}\paperwidth
  \pagecanon@expose{trimheight}\paperheight
  \pagecanon@expose{mediawidth}\pagecanon@mediaw
  \pagecanon@expose{mediaheight}\pagecanon@mediah
  \pagecanon@expose{innermargin}\pagecanon@innermargin
  \pagecanon@expose{outermargin}\pagecanon@outermargin
  \pagecanon@expose{bottommargin}\pagecanon@bottommargin
  \pagecanon@expose{gutter}\pagecanon@gutterlength
  \pagecanon@expose{leafwidth}\pagecanon@leafwidth}

\endinput