
@font-face{font-family:'PT Serif';font-weight:400;font-style:normal;font-display:block;src:url("../fonts/pt-serif-latin-400-normal.4271064a37f3ffc0.woff2") format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'PT Serif';font-weight:400;font-style:italic;font-display:block;src:url("../fonts/pt-serif-latin-400-italic.cb373bde18855c82.woff2") format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'PT Serif';font-weight:700;font-style:normal;font-display:block;src:url("../fonts/pt-serif-latin-700-normal.bf23a7a4eebedbb8.woff2") format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Source Sans 3';font-weight:300 900;font-style:normal;font-display:block;src:url("../fonts/source-sans-3-latin-wght-normal.7a19a7027e125257.woff2") format('woff2');unicode-range:U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+0304, U+0308, U+0329, U+2000-206F, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;}
@font-face{font-family:'Atlas Symbols';font-weight:400;font-style:normal;font-display:block;size-adjust:102.5%;src:url("../fonts/KaTeX_Main-Regular.c2342cd8b869e017.woff2") format('woff2');unicode-range:U+2208, U+221A, U+2248, U+2264-2265, U+2308-230B;}
/* kpress: katex/katex.min.css */
@font-face{font-display:block;font-family:KaTeX_AMS;font-style:normal;font-weight:400;src:url("../fonts/KaTeX_AMS-Regular.0cdd387c9590a1a9.woff2") format("woff2")}@font-face{font-display:block;font-family:KaTeX_Caligraphic;font-style:normal;font-weight:400;src:url("../fonts/KaTeX_Caligraphic-Regular.5d53e70ad607c235.woff2") format("woff2")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:700;src:url("../fonts/KaTeX_Main-Bold.0f60d1b897938ec9.woff2") format("woff2")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:italic;font-weight:400;src:url("../fonts/KaTeX_Main-Italic.97479ca6cce906ab.woff2") format("woff2")}@font-face{font-display:block;font-family:KaTeX_Main;font-style:normal;font-weight:400;src:url("../fonts/KaTeX_Main-Regular.c2342cd8b869e017.woff2") format("woff2")}@font-face{font-display:block;font-family:KaTeX_Math;font-style:italic;font-weight:400;src:url("../fonts/KaTeX_Math-Italic.7af58c5ec8f132a2.woff2") format("woff2")}@font-face{font-display:block;font-family:KaTeX_Size1;font-style:normal;font-weight:400;src:url("../fonts/KaTeX_Size1-Regular.6b47c40166b6dbe2.woff2") format("woff2")}@font-face{font-display:block;font-family:KaTeX_Size2;font-style:normal;font-weight:400;src:url("../fonts/KaTeX_Size2-Regular.d04c54219f9eaec6.woff2") format("woff2")}@font-face{font-display:block;font-family:KaTeX_Size3;font-style:normal;font-weight:400;src:url("../fonts/KaTeX_Size3-Regular.73d591271b160496.woff2") format("woff2")}@font-face{font-display:block;font-family:KaTeX_Size4;font-style:normal;font-weight:400;src:url("../fonts/KaTeX_Size4-Regular.a4af7d414440a1c1.woff2") format("woff2")}.katex{font:normal 1.21em KaTeX_Main,Times New Roman,serif;line-height:1.2;position:relative;text-indent:0;text-rendering:auto}.katex *{-ms-high-contrast-adjust:none!important;border-color:currentColor}.katex .katex-version:after{content:"0.16.45"}.katex .katex-mathml{clip:rect(1px,1px,1px,1px);border:0;height:1px;overflow:hidden;padding:0;position:absolute;width:1px}.katex .katex-html>.newline{display:block}.katex .base{position:relative;white-space:nowrap;width:-webkit-min-content;width:-moz-min-content;width:min-content}.katex .base,.katex .strut{display:inline-block}.katex .textbf{font-weight:700}.katex .textit{font-style:italic}.katex .textrm{font-family:KaTeX_Main}.katex .textsf{font-family:KaTeX_SansSerif}.katex .texttt{font-family:KaTeX_Typewriter}.katex .mathnormal{font-family:KaTeX_Math;font-style:italic}.katex .mathit{font-family:KaTeX_Main;font-style:italic}.katex .mathrm{font-style:normal}.katex .mathbf{font-family:KaTeX_Main;font-weight:700}.katex .boldsymbol{font-family:KaTeX_Math;font-style:italic;font-weight:700}.katex .amsrm,.katex .mathbb,.katex .textbb{font-family:KaTeX_AMS}.katex .mathcal{font-family:KaTeX_Caligraphic}.katex .mathfrak,.katex .textfrak{font-family:KaTeX_Fraktur}.katex .mathboldfrak,.katex .textboldfrak{font-family:KaTeX_Fraktur;font-weight:700}.katex .mathtt{font-family:KaTeX_Typewriter}.katex .mathscr,.katex .textscr{font-family:KaTeX_Script}.katex .mathsf,.katex .textsf{font-family:KaTeX_SansSerif}.katex .mathboldsf,.katex .textboldsf{font-family:KaTeX_SansSerif;font-weight:700}.katex .mathitsf,.katex .mathsfit,.katex .textitsf{font-family:KaTeX_SansSerif;font-style:italic}.katex .mainrm{font-family:KaTeX_Main;font-style:normal}.katex .vlist-t{border-collapse:collapse;display:inline-table;table-layout:fixed}.katex .vlist-r{display:table-row}.katex .vlist{display:table-cell;position:relative;vertical-align:bottom}.katex .vlist>span{display:block;height:0;position:relative}.katex .vlist>span>span{display:inline-block}.katex .vlist>span>.pstrut{overflow:hidden;width:0}.katex .vlist-t2{margin-right:-2px}.katex .vlist-s{display:table-cell;font-size:1px;min-width:2px;vertical-align:bottom;width:2px}.katex .vbox{align-items:baseline;display:inline-flex;flex-direction:column}.katex .hbox{width:100%}.katex .hbox,.katex .thinbox{display:inline-flex;flex-direction:row}.katex .thinbox{max-width:0;width:0}.katex .msupsub{text-align:left}.katex .mfrac>span>span{text-align:center}.katex .mfrac .frac-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline,.katex .hline,.katex .mfrac .frac-line,.katex .overline .overline-line,.katex .rule,.katex .underline .underline-line{min-height:1px}.katex .mspace{display:inline-block}.katex .smash{display:inline;line-height:0}.katex .clap,.katex .llap,.katex .rlap{position:relative;width:0}.katex .clap>.inner,.katex .llap>.inner,.katex .rlap>.inner{position:absolute}.katex .clap>.fix,.katex .llap>.fix,.katex .rlap>.fix{display:inline-block}.katex .llap>.inner{right:0}.katex .clap>.inner,.katex .rlap>.inner{left:0}.katex .clap>.inner>span{margin-left:-50%;margin-right:50%}.katex .rule{border:0 solid;display:inline-block;position:relative}.katex .hline,.katex .overline .overline-line,.katex .underline .underline-line{border-bottom-style:solid;display:inline-block;width:100%}.katex .hdashline{border-bottom-style:dashed;display:inline-block;width:100%}.katex .sqrt>.root{margin-left:.2777777778em;margin-right:-.5555555556em}.katex .fontsize-ensurer.reset-size1.size1,.katex .sizing.reset-size1.size1{font-size:1em}.katex .fontsize-ensurer.reset-size1.size2,.katex .sizing.reset-size1.size2{font-size:1.2em}.katex .fontsize-ensurer.reset-size1.size3,.katex .sizing.reset-size1.size3{font-size:1.4em}.katex .fontsize-ensurer.reset-size1.size4,.katex .sizing.reset-size1.size4{font-size:1.6em}.katex .fontsize-ensurer.reset-size1.size5,.katex .sizing.reset-size1.size5{font-size:1.8em}.katex .fontsize-ensurer.reset-size1.size6,.katex .sizing.reset-size1.size6{font-size:2em}.katex .fontsize-ensurer.reset-size1.size7,.katex .sizing.reset-size1.size7{font-size:2.4em}.katex .fontsize-ensurer.reset-size1.size8,.katex .sizing.reset-size1.size8{font-size:2.88em}.katex .fontsize-ensurer.reset-size1.size9,.katex .sizing.reset-size1.size9{font-size:3.456em}.katex .fontsize-ensurer.reset-size1.size10,.katex .sizing.reset-size1.size10{font-size:4.148em}.katex .fontsize-ensurer.reset-size1.size11,.katex .sizing.reset-size1.size11{font-size:4.976em}.katex .fontsize-ensurer.reset-size2.size1,.katex .sizing.reset-size2.size1{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size2.size2,.katex .sizing.reset-size2.size2{font-size:1em}.katex .fontsize-ensurer.reset-size2.size3,.katex .sizing.reset-size2.size3{font-size:1.1666666667em}.katex .fontsize-ensurer.reset-size2.size4,.katex .sizing.reset-size2.size4{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size2.size5,.katex .sizing.reset-size2.size5{font-size:1.5em}.katex .fontsize-ensurer.reset-size2.size6,.katex .sizing.reset-size2.size6{font-size:1.6666666667em}.katex .fontsize-ensurer.reset-size2.size7,.katex .sizing.reset-size2.size7{font-size:2em}.katex .fontsize-ensurer.reset-size2.size8,.katex .sizing.reset-size2.size8{font-size:2.4em}.katex .fontsize-ensurer.reset-size2.size9,.katex .sizing.reset-size2.size9{font-size:2.88em}.katex .fontsize-ensurer.reset-size2.size10,.katex .sizing.reset-size2.size10{font-size:3.4566666667em}.katex .fontsize-ensurer.reset-size2.size11,.katex .sizing.reset-size2.size11{font-size:4.1466666667em}.katex .fontsize-ensurer.reset-size3.size1,.katex .sizing.reset-size3.size1{font-size:.7142857143em}.katex .fontsize-ensurer.reset-size3.size2,.katex .sizing.reset-size3.size2{font-size:.8571428571em}.katex .fontsize-ensurer.reset-size3.size3,.katex .sizing.reset-size3.size3{font-size:1em}.katex .fontsize-ensurer.reset-size3.size4,.katex .sizing.reset-size3.size4{font-size:1.1428571429em}.katex .fontsize-ensurer.reset-size3.size5,.katex .sizing.reset-size3.size5{font-size:1.2857142857em}.katex .fontsize-ensurer.reset-size3.size6,.katex .sizing.reset-size3.size6{font-size:1.4285714286em}.katex .fontsize-ensurer.reset-size3.size7,.katex .sizing.reset-size3.size7{font-size:1.7142857143em}.katex .fontsize-ensurer.reset-size3.size8,.katex .sizing.reset-size3.size8{font-size:2.0571428571em}.katex .fontsize-ensurer.reset-size3.size9,.katex .sizing.reset-size3.size9{font-size:2.4685714286em}.katex .fontsize-ensurer.reset-size3.size10,.katex .sizing.reset-size3.size10{font-size:2.9628571429em}.katex .fontsize-ensurer.reset-size3.size11,.katex .sizing.reset-size3.size11{font-size:3.5542857143em}.katex .fontsize-ensurer.reset-size4.size1,.katex .sizing.reset-size4.size1{font-size:.625em}.katex .fontsize-ensurer.reset-size4.size2,.katex .sizing.reset-size4.size2{font-size:.75em}.katex .fontsize-ensurer.reset-size4.size3,.katex .sizing.reset-size4.size3{font-size:.875em}.katex .fontsize-ensurer.reset-size4.size4,.katex .sizing.reset-size4.size4{font-size:1em}.katex .fontsize-ensurer.reset-size4.size5,.katex .sizing.reset-size4.size5{font-size:1.125em}.katex .fontsize-ensurer.reset-size4.size6,.katex .sizing.reset-size4.size6{font-size:1.25em}.katex .fontsize-ensurer.reset-size4.size7,.katex .sizing.reset-size4.size7{font-size:1.5em}.katex .fontsize-ensurer.reset-size4.size8,.katex .sizing.reset-size4.size8{font-size:1.8em}.katex .fontsize-ensurer.reset-size4.size9,.katex .sizing.reset-size4.size9{font-size:2.16em}.katex .fontsize-ensurer.reset-size4.size10,.katex .sizing.reset-size4.size10{font-size:2.5925em}.katex .fontsize-ensurer.reset-size4.size11,.katex .sizing.reset-size4.size11{font-size:3.11em}.katex .fontsize-ensurer.reset-size5.size1,.katex .sizing.reset-size5.size1{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size5.size2,.katex .sizing.reset-size5.size2{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size5.size3,.katex .sizing.reset-size5.size3{font-size:.7777777778em}.katex .fontsize-ensurer.reset-size5.size4,.katex .sizing.reset-size5.size4{font-size:.8888888889em}.katex .fontsize-ensurer.reset-size5.size5,.katex .sizing.reset-size5.size5{font-size:1em}.katex .fontsize-ensurer.reset-size5.size6,.katex .sizing.reset-size5.size6{font-size:1.1111111111em}.katex .fontsize-ensurer.reset-size5.size7,.katex .sizing.reset-size5.size7{font-size:1.3333333333em}.katex .fontsize-ensurer.reset-size5.size8,.katex .sizing.reset-size5.size8{font-size:1.6em}.katex .fontsize-ensurer.reset-size5.size9,.katex .sizing.reset-size5.size9{font-size:1.92em}.katex .fontsize-ensurer.reset-size5.size10,.katex .sizing.reset-size5.size10{font-size:2.3044444444em}.katex .fontsize-ensurer.reset-size5.size11,.katex .sizing.reset-size5.size11{font-size:2.7644444444em}.katex .fontsize-ensurer.reset-size6.size1,.katex .sizing.reset-size6.size1{font-size:.5em}.katex .fontsize-ensurer.reset-size6.size2,.katex .sizing.reset-size6.size2{font-size:.6em}.katex .fontsize-ensurer.reset-size6.size3,.katex .sizing.reset-size6.size3{font-size:.7em}.katex .fontsize-ensurer.reset-size6.size4,.katex .sizing.reset-size6.size4{font-size:.8em}.katex .fontsize-ensurer.reset-size6.size5,.katex .sizing.reset-size6.size5{font-size:.9em}.katex .fontsize-ensurer.reset-size6.size6,.katex .sizing.reset-size6.size6{font-size:1em}.katex .fontsize-ensurer.reset-size6.size7,.katex .sizing.reset-size6.size7{font-size:1.2em}.katex .fontsize-ensurer.reset-size6.size8,.katex .sizing.reset-size6.size8{font-size:1.44em}.katex .fontsize-ensurer.reset-size6.size9,.katex .sizing.reset-size6.size9{font-size:1.728em}.katex .fontsize-ensurer.reset-size6.size10,.katex .sizing.reset-size6.size10{font-size:2.074em}.katex .fontsize-ensurer.reset-size6.size11,.katex .sizing.reset-size6.size11{font-size:2.488em}.katex .fontsize-ensurer.reset-size7.size1,.katex .sizing.reset-size7.size1{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size7.size2,.katex .sizing.reset-size7.size2{font-size:.5em}.katex .fontsize-ensurer.reset-size7.size3,.katex .sizing.reset-size7.size3{font-size:.5833333333em}.katex .fontsize-ensurer.reset-size7.size4,.katex .sizing.reset-size7.size4{font-size:.6666666667em}.katex .fontsize-ensurer.reset-size7.size5,.katex .sizing.reset-size7.size5{font-size:.75em}.katex .fontsize-ensurer.reset-size7.size6,.katex .sizing.reset-size7.size6{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size7.size7,.katex .sizing.reset-size7.size7{font-size:1em}.katex .fontsize-ensurer.reset-size7.size8,.katex .sizing.reset-size7.size8{font-size:1.2em}.katex .fontsize-ensurer.reset-size7.size9,.katex .sizing.reset-size7.size9{font-size:1.44em}.katex .fontsize-ensurer.reset-size7.size10,.katex .sizing.reset-size7.size10{font-size:1.7283333333em}.katex .fontsize-ensurer.reset-size7.size11,.katex .sizing.reset-size7.size11{font-size:2.0733333333em}.katex .fontsize-ensurer.reset-size8.size1,.katex .sizing.reset-size8.size1{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size8.size2,.katex .sizing.reset-size8.size2{font-size:.4166666667em}.katex .fontsize-ensurer.reset-size8.size3,.katex .sizing.reset-size8.size3{font-size:.4861111111em}.katex .fontsize-ensurer.reset-size8.size4,.katex .sizing.reset-size8.size4{font-size:.5555555556em}.katex .fontsize-ensurer.reset-size8.size5,.katex .sizing.reset-size8.size5{font-size:.625em}.katex .fontsize-ensurer.reset-size8.size6,.katex .sizing.reset-size8.size6{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size8.size7,.katex .sizing.reset-size8.size7{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size8.size8,.katex .sizing.reset-size8.size8{font-size:1em}.katex .fontsize-ensurer.reset-size8.size9,.katex .sizing.reset-size8.size9{font-size:1.2em}.katex .fontsize-ensurer.reset-size8.size10,.katex .sizing.reset-size8.size10{font-size:1.4402777778em}.katex .fontsize-ensurer.reset-size8.size11,.katex .sizing.reset-size8.size11{font-size:1.7277777778em}.katex .fontsize-ensurer.reset-size9.size1,.katex .sizing.reset-size9.size1{font-size:.2893518519em}.katex .fontsize-ensurer.reset-size9.size2,.katex .sizing.reset-size9.size2{font-size:.3472222222em}.katex .fontsize-ensurer.reset-size9.size3,.katex .sizing.reset-size9.size3{font-size:.4050925926em}.katex .fontsize-ensurer.reset-size9.size4,.katex .sizing.reset-size9.size4{font-size:.462962963em}.katex .fontsize-ensurer.reset-size9.size5,.katex .sizing.reset-size9.size5{font-size:.5208333333em}.katex .fontsize-ensurer.reset-size9.size6,.katex .sizing.reset-size9.size6{font-size:.5787037037em}.katex .fontsize-ensurer.reset-size9.size7,.katex .sizing.reset-size9.size7{font-size:.6944444444em}.katex .fontsize-ensurer.reset-size9.size8,.katex .sizing.reset-size9.size8{font-size:.8333333333em}.katex .fontsize-ensurer.reset-size9.size9,.katex .sizing.reset-size9.size9{font-size:1em}.katex .fontsize-ensurer.reset-size9.size10,.katex .sizing.reset-size9.size10{font-size:1.2002314815em}.katex .fontsize-ensurer.reset-size9.size11,.katex .sizing.reset-size9.size11{font-size:1.4398148148em}.katex .fontsize-ensurer.reset-size10.size1,.katex .sizing.reset-size10.size1{font-size:.2410800386em}.katex .fontsize-ensurer.reset-size10.size2,.katex .sizing.reset-size10.size2{font-size:.2892960463em}.katex .fontsize-ensurer.reset-size10.size3,.katex .sizing.reset-size10.size3{font-size:.337512054em}.katex .fontsize-ensurer.reset-size10.size4,.katex .sizing.reset-size10.size4{font-size:.3857280617em}.katex .fontsize-ensurer.reset-size10.size5,.katex .sizing.reset-size10.size5{font-size:.4339440694em}.katex .fontsize-ensurer.reset-size10.size6,.katex .sizing.reset-size10.size6{font-size:.4821600771em}.katex .fontsize-ensurer.reset-size10.size7,.katex .sizing.reset-size10.size7{font-size:.5785920926em}.katex .fontsize-ensurer.reset-size10.size8,.katex .sizing.reset-size10.size8{font-size:.6943105111em}.katex .fontsize-ensurer.reset-size10.size9,.katex .sizing.reset-size10.size9{font-size:.8331726133em}.katex .fontsize-ensurer.reset-size10.size10,.katex .sizing.reset-size10.size10{font-size:1em}.katex .fontsize-ensurer.reset-size10.size11,.katex .sizing.reset-size10.size11{font-size:1.1996142719em}.katex .fontsize-ensurer.reset-size11.size1,.katex .sizing.reset-size11.size1{font-size:.2009646302em}.katex .fontsize-ensurer.reset-size11.size2,.katex .sizing.reset-size11.size2{font-size:.2411575563em}.katex .fontsize-ensurer.reset-size11.size3,.katex .sizing.reset-size11.size3{font-size:.2813504823em}.katex .fontsize-ensurer.reset-size11.size4,.katex .sizing.reset-size11.size4{font-size:.3215434084em}.katex .fontsize-ensurer.reset-size11.size5,.katex .sizing.reset-size11.size5{font-size:.3617363344em}.katex .fontsize-ensurer.reset-size11.size6,.katex .sizing.reset-size11.size6{font-size:.4019292605em}.katex .fontsize-ensurer.reset-size11.size7,.katex .sizing.reset-size11.size7{font-size:.4823151125em}.katex .fontsize-ensurer.reset-size11.size8,.katex .sizing.reset-size11.size8{font-size:.578778135em}.katex .fontsize-ensurer.reset-size11.size9,.katex .sizing.reset-size11.size9{font-size:.6945337621em}.katex .fontsize-ensurer.reset-size11.size10,.katex .sizing.reset-size11.size10{font-size:.8336012862em}.katex .fontsize-ensurer.reset-size11.size11,.katex .sizing.reset-size11.size11{font-size:1em}.katex .delimsizing.size1{font-family:KaTeX_Size1}.katex .delimsizing.size2{font-family:KaTeX_Size2}.katex .delimsizing.size3{font-family:KaTeX_Size3}.katex .delimsizing.size4{font-family:KaTeX_Size4}.katex .delimsizing.mult .delim-size1>span{font-family:KaTeX_Size1}.katex .delimsizing.mult .delim-size4>span{font-family:KaTeX_Size4}.katex .nulldelimiter{display:inline-block;width:.12em}.katex .delimcenter,.katex .op-symbol{position:relative}.katex .op-symbol.small-op{font-family:KaTeX_Size1}.katex .op-symbol.large-op{font-family:KaTeX_Size2}.katex .accent>.vlist-t,.katex .op-limits>.vlist-t{text-align:center}.katex .accent .accent-body{position:relative}.katex .accent .accent-body:not(.accent-full){width:0}.katex .overlay{display:block}.katex .mtable .vertical-separator{display:inline-block;min-width:1px}.katex .mtable .arraycolsep{display:inline-block}.katex .mtable .col-align-c>.vlist-t{text-align:center}.katex .mtable .col-align-l>.vlist-t{text-align:left}.katex .mtable .col-align-r>.vlist-t{text-align:right}.katex .svg-align{text-align:left}.katex svg{fill:currentColor;stroke:currentColor;display:block;height:inherit;position:absolute;width:100%}.katex svg path{stroke:none}.katex svg{fill-rule:nonzero;fill-opacity:1;stroke-width:1;stroke-linecap:butt;stroke-linejoin:miter;stroke-miterlimit:4;stroke-dasharray:none;stroke-dashoffset:0;stroke-opacity:1}.katex img{border-style:none;max-height:none;max-width:none;min-height:0;min-width:0}.katex .stretchy{display:block;overflow:hidden;position:relative;width:100%}.katex .stretchy:after,.katex .stretchy:before{content:""}.katex .hide-tail{overflow:hidden;position:relative;width:100%}.katex .halfarrow-left{left:0;overflow:hidden;position:absolute;width:50.2%}.katex .halfarrow-right{overflow:hidden;position:absolute;right:0;width:50.2%}.katex .brace-left{left:0;overflow:hidden;position:absolute;width:25.1%}.katex .brace-center{left:25%;overflow:hidden;position:absolute;width:50%}.katex .brace-right{overflow:hidden;position:absolute;right:0;width:25.1%}.katex .x-arrow-pad{padding:0 .5em}.katex .cd-arrow-pad{padding:0 .55556em 0 .27778em}.katex .mover,.katex .munder,.katex .x-arrow{text-align:center}.katex .boxpad{padding:0 .3em}.katex .fbox,.katex .fcolorbox{border:.04em solid;box-sizing:border-box}.katex .cancel-pad{padding:0 .2em}.katex .cancel-lap{margin-left:-.2em;margin-right:-.2em}.katex .sout{border-bottom-style:solid;border-bottom-width:.08em}.katex .angl{border-right:.049em solid;border-top:.049em solid;box-sizing:border-box;margin-right:.03889em}.katex .anglpad{padding:0 .03889em}.katex .eqn-num:before{content:"(" counter(katexEqnNo) ")";counter-increment:katexEqnNo}.katex .mml-eqn-num:before{content:"(" counter(mmlEqnNo) ")";counter-increment:mmlEqnNo}.katex .mtr-glue{width:50%}.katex .cd-vert-arrow{display:inline-block;position:relative}.katex .cd-label-left{display:inline-block;position:absolute;right:calc(50% + .3em);text-align:left}.katex .cd-label-right{display:inline-block;left:calc(50% + .3em);position:absolute;text-align:right}.katex-display{display:block;margin:1em 0;text-align:center}.katex-display>.katex{display:block;text-align:center;white-space:nowrap}.katex-display>.katex>.katex-html{display:block;position:relative}.katex-display>.katex>.katex-html>.tag{position:absolute;right:0}.katex-display.leqno>.katex>.katex-html>.tag{left:0;right:auto}.katex-display.fleqn>.katex{padding-left:2em;text-align:left}body{counter-reset:katexEqnNo mmlEqnNo}

/* kpress: katex/katex-text-face.css */
/* KPress Math Text -- the reading face inside KaTeX mathematics.
 *
 * WHAT THIS IS. One composite CSS family, `KPress Math Text`, in four
 * style/weight slots. Each slot is two @font-face rules that share the same
 * descriptors and carve out DISJOINT `unicode-range`s:
 *
 *   1. the reading face (PT Serif) for Latin letters, and digits in the
 *      upright slots -- the glyphs a reader recognizes as "the text face";
 *   2. the KaTeX face this slot replaces, restricted to Greek and scaled by
 *      `size-adjust` so Computer Modern's Greek reaches PT Serif's height.
 *
 * Everything else -- operators, relations, punctuation, accents, arrows, every
 * other script -- is deliberately claimed by no face here. CSS Fonts 4 moves a
 * code point no face of a composite covers to the NEXT FAMILY in the stack,
 * and every rule below names the KaTeX face the slot replaces right after the
 * composite, so those glyphs come from the same face they always did. Declaring
 * them here as well would only duplicate the KaTeX faces: no bytes in hosted
 * modes, but a second copy of each face in a page that inlines everything.
 *
 * Delimiters, big operators, AMS, calligraphic, fraktur, script, sans and
 * typewriter stay on their own KaTeX families and are not touched here.
 *
 * WHY IT IS KPRESS-AUTHORED AND LAZY. `katex.min.css` next to this file is a
 * pinned upstream bundle that stays byte-identical through the next KaTeX bump,
 * so the correction lives in its own stylesheet rather than as a patch to it.
 * It sits under `katex/` because it belongs to the KaTeX lazy closure: it is
 * emitted only for documents that contain math, next to the faces it names, and
 * a document without math loads none of it. Everything under `katex/` keeps
 * stable, unhashed names in every asset mode and is always linked (never
 * inlined), so the relative `../fonts/` and `../katex/fonts/` URLs below resolve
 * in `hosted`, `linked`, `hashed` and `inline` alike.
 *
 * `font-display: block` on every screen face of BOTH composites -- the serif
 * `KPress Math Text` and the sans `KPress Math Text Sans` below -- as on the
 * prose PT Serif faces in style-tokens.css and unlike the vendored KaTeX
 * bundle's `swap`. A late slot can visibly repaint the letters and digits.
 * `katex-math-runtime.js` waits for the glyphs used by each hidden rendered
 * formula, including its composite slots and KaTeX construct
 * families. The formula is revealed only when its required faces are ready;
 * `block` also briefly suppresses fallback glyphs when the CSS is used without
 * that JavaScript boundary.
 *
 * The four static instances inside the `@media print` block keep `swap`, and
 * deliberately: there is no first paint to protect in a printed page, the print
 * path has already resolved its fonts before it composes a page, and `block`
 * blanks a whole run rather than the code points the face claims -- a cost worth
 * paying against a flash on screen and not worth paying against a blank run in a
 * PDF.
 *
 * THE CONTRACT FOR A HOST WITH ANOTHER READING FACE. Two hooks, both additive:
 *
 *   - Declare your own `KPress Math Text` @font-face rules AFTER this
 *     stylesheet, covering the ranges your face should draw. CSS Fonts 4 checks
 *     the last-defined face first, so your ranges win and the KaTeX fallbacks
 *     below keep everything you did not claim.
 *   - Ship your own `globalThis.kpressKatexTextMetrics` (same shape as
 *     `katex/katex-text-metrics.js`, generated by the same devtool) before
 *     `katex-math-runtime.js` runs, so KaTeX lays out from the metrics of the glyphs it
 *     actually draws.
 *
 * Supplying the faces without the metrics leaves KaTeX measuring Computer
 * Modern while drawing your face; supplying the metrics without the faces does
 * the reverse. They are one contract.
 *
 * SPECIFICITY. This stylesheet is linked after `katex.min.css`, but nothing
 * below relies on that: upstream's rules are `.katex` (0,1,0) and
 * `.katex .mathnormal` (0,2,0), and every selector here carries at least one
 * extra class or attribute, exactly as the "KaTeX sizing" block in
 * components.css does and for the same reason. The opt-out reverts add one more
 * attribute on top of the feature rules, so they win in both directions.
 */

/* ===================== SLOT 1: normal 400 (KaTeX_Main-Regular) ===================== */

@font-face {
  font-family: "KPress Math Text";
  font-style: normal;
  font-weight: 400;
  font-display: block;
  src: url("../fonts/pt-serif-latin-400-normal.4271064a37f3ffc0.woff2") format("woff2");
  unicode-range: U+0030-0039, U+0041-005A, U+0061-007A;
}

@font-face {
  font-family: "KPress Math Text";
  font-style: normal;
  font-weight: 400;
  font-display: block;
  /* Greek to PT Serif's cap height; `katex_text_metrics --print-scale` (Main-Regular). */
  size-adjust: 102.5%;
  src: url("../fonts/KaTeX_Main-Regular.c2342cd8b869e017.woff2") format("woff2");
  unicode-range: U+0391-03A9;
}

/* ====================== SLOT 2: italic 400 (KaTeX_Math-Italic) ===================== */

@font-face {
  font-family: "KPress Math Text";
  font-style: italic;
  font-weight: 400;
  font-display: block;
  src: url("../fonts/pt-serif-latin-400-italic.cb373bde18855c82.woff2") format("woff2");
  unicode-range: U+0041-005A, U+0061-007A;
}

@font-face {
  font-family: "KPress Math Text";
  font-style: italic;
  font-weight: 400;
  font-display: block;
  /* Greek to PT Serif's x-height; `katex_text_metrics --print-scale` (Math-Italic). */
  size-adjust: 115%;
  src: url("../fonts/KaTeX_Math-Italic.7af58c5ec8f132a2.woff2") format("woff2");
  unicode-range: U+0370-03FF;
}

/* ======================= SLOT 3: normal 700 (KaTeX_Main-Bold) ====================== */

@font-face {
  font-family: "KPress Math Text";
  font-style: normal;
  font-weight: 700;
  font-display: block;
  src: url("../fonts/pt-serif-latin-700-normal.bf23a7a4eebedbb8.woff2") format("woff2");
  unicode-range: U+0030-0039, U+0041-005A, U+0061-007A;
}

@font-face {
  font-family: "KPress Math Text";
  font-style: normal;
  font-weight: 700;
  font-display: block;
  /* Greek to PT Serif's cap height; `katex_text_metrics --print-scale` (Main-Bold). */
  size-adjust: 102%;
  src: url("../fonts/KaTeX_Main-Bold.0f60d1b897938ec9.woff2") format("woff2");
  unicode-range: U+0391-03A9;
}

/* ==================== SLOT 4: italic 700 (KaTeX_Math-BoldItalic) =================== */





/* ============================== THE FEATURE RULES ================================== */

/* Scoped positively, so there is nothing to revert: every rule below applies to a
   `.kpress` that has not opted out, and one that has keeps upstream's `.katex`
   rules and style-tokens.css's 1.05em exactly as they are. Three ways out, each
   honoured on the wrapper itself and on any ancestor:

   - `data-kpress-math-text="katex"`. The page shell stamps <html> from
     `RenderOptions.math_text_font`; an embedding host stamps its own root; a
     fragment under neither gets the face.
   - `data-kpress-fonts="system"`, the wrapper's baked font mode.
   - `data-kpress-font-set="system"`, the reader's persisted choice, which
     theme-bootstrap.js stamps on <html> before first paint.

   In either system mode the vendored reading face is not loaded, so the composite
   would have nothing to draw the Latin ranges with. The shared runtime applies the
   metric tables under the same three conditions -- read with `closest()`, which
   is why each one appears twice below, once for the element and once for its
   descendants -- and reverts the face itself when the tables cannot be applied,
   so what KaTeX measures and what it draws agree. A nested per-node opt-out is
   marked `data-kpress-math-face="katex"`; the rules at the end restore its stock
   families even inside a wrapper that uses the custom face.

   THE SECOND SCOPE ROOT is the footnote/section preview overlay. It carries a
   clone of already-rendered math, and tooltips.js mounts it on the viewport pane
   or the body, outside every `.kpress`. The metric tables are page-global, so the
   clone is laid out from whichever mode the document is in; the overlay therefore
   has to be drawn and sized in that same mode or the two disagree. tooltips.js
   resolves the originating wrapper's mode against the same three opt-outs and
   stamps it as `data-kpress-math-text`, so the overlay opts in explicitly rather
   than by position. `.kpress-tooltip[data-kpress-math-text="prose"]` is (0,2,0),
   the same as `.kpress:not(...)`, and `:is()` takes the higher of its arguments,
   so the specificity notes below hold for both roots.

   `:not()` with a selector list and descendant combinators inside it: Chrome 88,
   Firefox 84, Safari 9. `:is()`: Chrome 88, Firefox 88, Safari 14. The scope is
   (0,2,0), so the family rules land at (0,3,0) and (0,4,0) against upstream's
   (0,1,0) and (0,2,0), and the size token at (0,2,0) against style-tokens.css's
   (0,1,0): link order decides nothing here. */

/* With the letters and digits in the reading face, mathematics is the prose
   size: upstream's 1.21em lift exists to seat Computer Modern beside a
   Times-like body face, and there is nothing left to seat. That goes for
   display math too: TeX sets a displayed equation at the text size, and the
   1.1em the display token carries for Computer Modern read, once the letters
   were the reading face, as a paragraph set a size larger. The sans token
   (1em) already agrees; the consumers are in components.css, which applies them
   inside the preview overlay as well as inside the document. */
:is(
  .kpress:not(
    [data-kpress-fonts="system"],
    [data-kpress-font-set="system"],
    [data-kpress-math-text="katex"],
    [data-kpress-fonts="system"] *,
    [data-kpress-font-set="system"] *,
    [data-kpress-math-text="katex"] *
  ),
  .kpress-tooltip[data-kpress-math-text="prose"]
) {
  --kpress-katex-size-prose: 1em;
  --kpress-katex-size-display: 1em;
}

/* The root rule reaches digits, operator names, `\text{}` and `\mathrm{}`,
   which carry no font class of their own. The family after the composite is not a
   fallback for a missing download: it is where every code point the composite
   does not claim is drawn, so each rule names the KaTeX face its slot replaces. */
:is(
    .kpress:not(
      [data-kpress-fonts="system"],
      [data-kpress-font-set="system"],
      [data-kpress-math-text="katex"],
      [data-kpress-fonts="system"] *,
      [data-kpress-font-set="system"] *,
      [data-kpress-math-text="katex"] *
    ),
    .kpress-tooltip[data-kpress-math-text="prose"]
  )
  .katex {
  font-family: "KPress Math Text", KaTeX_Main, "Times New Roman", serif;
}

/* Variables (`n`, `t_k`): upstream draws them from KaTeX_Math. */
:is(
    .kpress:not(
      [data-kpress-fonts="system"],
      [data-kpress-font-set="system"],
      [data-kpress-math-text="katex"],
      [data-kpress-fonts="system"] *,
      [data-kpress-font-set="system"] *,
      [data-kpress-math-text="katex"] *
    ),
    .kpress-tooltip[data-kpress-math-text="prose"]
  )
  .katex
  .mathnormal {
  font-family: "KPress Math Text", KaTeX_Math, serif;
  font-style: italic;
}

/* `\mathit`: upstream draws it from KaTeX_Main italic and lays it out from the
   Main-Italic table, so KaTeX_Main follows the composite here, not KaTeX_Math.
   Its Greek is drawn by the italic slot's Math-Italic face, so the generator
   copies the Greek rows from the Math-Italic table -- not Main-Italic's, whose
   advances and skews are a different face's -- and scales them by that face's
   factor. */
:is(
    .kpress:not(
      [data-kpress-fonts="system"],
      [data-kpress-font-set="system"],
      [data-kpress-math-text="katex"],
      [data-kpress-fonts="system"] *,
      [data-kpress-font-set="system"] *,
      [data-kpress-math-text="katex"] *
    ),
    .kpress-tooltip[data-kpress-math-text="prose"]
  )
  .katex
  .mathit {
  font-family: "KPress Math Text", KaTeX_Main, serif;
  font-style: italic;
}

:is(
    .kpress:not(
      [data-kpress-fonts="system"],
      [data-kpress-font-set="system"],
      [data-kpress-math-text="katex"],
      [data-kpress-fonts="system"] *,
      [data-kpress-font-set="system"] *,
      [data-kpress-math-text="katex"] *
    ),
    .kpress-tooltip[data-kpress-math-text="prose"]
  )
  .katex
  .mathbf {
  font-family: "KPress Math Text", KaTeX_Main, serif;
  font-weight: 700;
}

:is(
    .kpress:not(
      [data-kpress-fonts="system"],
      [data-kpress-font-set="system"],
      [data-kpress-math-text="katex"],
      [data-kpress-fonts="system"] *,
      [data-kpress-font-set="system"] *,
      [data-kpress-math-text="katex"] *
    ),
    .kpress-tooltip[data-kpress-math-text="prose"]
  )
  .katex
  .boldsymbol {
  font-family: "KPress Math Text", KaTeX_Math, serif;
  font-style: italic;
  font-weight: 700;
}

/* `\textrm{}` and `\text{}` take the family only. Upstream gives `.textrm` no
   `font-style`: the upright default reaches it from the root `.katex` `font`
   shorthand at (0,1,0), which leaves an explicit `\textit` nested inside --
   KaTeX emits one `.mord.textrm.textit` leaf for `\textrm{\textit{x}}` -- free to
   win at (0,2,0). Pinning `font-style: normal` here would outrank `.textit` and
   draw the upright slot over a run KaTeX laid out from the italic table. Only
   `.mainrm` gets the pin, because upstream pins it too. */
:is(
    .kpress:not(
      [data-kpress-fonts="system"],
      [data-kpress-font-set="system"],
      [data-kpress-math-text="katex"],
      [data-kpress-fonts="system"] *,
      [data-kpress-font-set="system"] *,
      [data-kpress-math-text="katex"] *
    ),
    .kpress-tooltip[data-kpress-math-text="prose"]
  )
  .katex
  .textrm {
  font-family: "KPress Math Text", KaTeX_Main, serif;
}

:is(
    .kpress:not(
      [data-kpress-fonts="system"],
      [data-kpress-font-set="system"],
      [data-kpress-math-text="katex"],
      [data-kpress-fonts="system"] *,
      [data-kpress-font-set="system"] *,
      [data-kpress-math-text="katex"] *
    ),
    .kpress-tooltip[data-kpress-math-text="prose"]
  )
  .katex
  .mainrm {
  font-family: "KPress Math Text", KaTeX_Main, serif;
  font-style: normal;
}

/* ============================ KPRESS MATH TEXT SANS ================================ */

/* A second composite, for the sans roles of a serif document -- a caption, a footnote,
 * a table, the dialect boxes -- and for the reader's sans reading face. Same idea and
 * same slot structure as `KPress Math Text` above; Source Sans 3 draws the Latin ranges
 * instead of PT Serif, and the KaTeX faces are scaled to Source Sans's own measures.
 * The mathematics in a caption is then set in the caption's face rather than the
 * document's, which is what the size token beside it (`--kpress-katex-size-sans`, 1em)
 * has always assumed.
 *
 * PINNED WEIGHTS. Each slot declares a SINGLE `font-weight`, not the variable face's
 * whole 200-900 axis, and its metric table is built at that weight. A KaTeX metric
 * table describes one face and one weight, and Source Sans's advances travel along the
 * axis -- a median 7.1% and a worst 20.5% between 370 and 700, against 0.035em of
 * movement in the tallest ink height. CSS Fonts 4 clamps a variable face to the range
 * its `@font-face` declares, so a single value draws the weight the table was built at
 * whatever the context asks for, and KaTeX never lays out glyphs it has no numbers for.
 *
 * The regular weight comes from `--kpress-font-weight-sans-regular` in
 * style-tokens.css. instance_sans.py and katex_text_metrics.py generate its static
 * instances, fixed face descriptors, private CSS weight and matching tables together.
 * The regular CSS rule below overrides KaTeX's shorthand weight reset with that fixed
 * value. A host changing the source token must regenerate both tools; overriding only
 * the live prose token does not change the baked mathematics.
 *
 * Bold stays at 650. Its rules use a literal because a host may override the public
 * sans-bold prose token, whereas the bold metric tables describe only the 650 face.
 * CSS Fonts 4's weight matching can otherwise choose a regular face for a host's
 * lower bold request, drawing regular outlines over bold metrics.
 *
 * PRINT. The screen draws the Latin ranges from the variable faces; a printed page
 * cannot, because Chromium's PDF writer turns a variable face away from its default
 * position into Type3 outline paths (see css/print-fonts.css, which does the same for
 * the plain sans role). The `@media print` block at the end of this section layers the
 * static instances at the same two weights over the same ranges, LAST, so CSS Fonts 4's
 * last-defined-face rule gives them to print and leaves the screen alone. The two agree
 * to the unit: instancing the variable face at the generated weights reproduces every Latin
 * advance of the shipped instance exactly, so one metric table is true of both.
 *
 * The rules are separate from the ones above rather than folded into them, and each
 * scope is its own rule, to keep every selector well inside the 400-character budget a
 * consuming host's stylesheet check applies.
 */

/* BEGIN GENERATED SANS FACES: devtools.katex_text_metrics */
:root {
  --_kpress-math-sans-regular-weight: 410;
}

@font-face {
  font-family: "KPress Math Text Sans";
  font-style: normal;
  font-weight: 410;
  font-display: block;
  src: url("../fonts/source-sans-3-latin-wght-normal.7a19a7027e125257.woff2") format("woff2");
  unicode-range: U+0030-0039, U+0041-005A, U+0061-007A;
}

@font-face {
  font-family: "KPress Math Text Sans";
  font-style: normal;
  font-weight: 410;
  font-display: block;
  size-adjust: 96%;
  src: url("../fonts/KaTeX_Main-Regular.c2342cd8b869e017.woff2") format("woff2");
  unicode-range: U+0391-03A9;
}

@font-face {
  font-family: "KPress Math Text Sans";
  font-style: italic;
  font-weight: 410;
  font-display: block;
  src: url("../fonts/source-sans-3-latin-wght-italic.9a15dafc2c2b2414.woff2") format("woff2");
  unicode-range: U+0041-005A, U+0061-007A;
}

@font-face {
  font-family: "KPress Math Text Sans";
  font-style: italic;
  font-weight: 410;
  font-display: block;
  size-adjust: 110.2%;
  src: url("../fonts/KaTeX_Math-Italic.7af58c5ec8f132a2.woff2") format("woff2");
  unicode-range: U+0370-03FF;
}

@font-face {
  font-family: "KPress Math Text Sans";
  font-style: normal;
  font-weight: 650;
  font-display: block;
  src: url("../fonts/source-sans-3-latin-wght-normal.7a19a7027e125257.woff2") format("woff2");
  unicode-range: U+0030-0039, U+0041-005A, U+0061-007A;
}

@font-face {
  font-family: "KPress Math Text Sans";
  font-style: normal;
  font-weight: 650;
  font-display: block;
  size-adjust: 95.2%;
  src: url("../fonts/KaTeX_Main-Bold.0f60d1b897938ec9.woff2") format("woff2");
  unicode-range: U+0391-03A9;
}





@media print {
  @font-face {
    font-family: "KPress Math Text Sans";
    font-style: normal;
    font-weight: 410;
    font-display: swap;
    src: url("../fonts/kpress-print-sans-latin-410-normal.bf059edc7dd4843b.woff2") format("woff2");
    unicode-range: U+0030-0039, U+0041-005A, U+0061-007A;
  }

  @font-face {
    font-family: "KPress Math Text Sans";
    font-style: italic;
    font-weight: 410;
    font-display: swap;
    src: url("../fonts/kpress-print-sans-latin-410-italic.298817be3c07f0d3.woff2") format("woff2");
    unicode-range: U+0041-005A, U+0061-007A;
  }

  @font-face {
    font-family: "KPress Math Text Sans";
    font-style: normal;
    font-weight: 650;
    font-display: swap;
    src: url("../fonts/kpress-print-sans-latin-650-normal.8cd1aee8d860fe72.woff2") format("woff2");
    unicode-range: U+0030-0039, U+0041-005A, U+0061-007A;
  }

  
}
/* END GENERATED SANS FACES */

/* ---------------------------- THE SANS FEATURE RULES ------------------------------ */

/* Two scopes, one composite. The first is the document itself, reached by the mark
   `katex-init.js` stamps on every math node it installs the sans metric tables for:
   a caption, a footnote, a table cell, one of the semantic containers, a `<details>`,
   a tab button -- and, when the reader has chosen the sans reading face, every node in
   the document. The second is the footnote preview overlay, at the end of this section.

   THE MARK RATHER THAN A ROLE LIST. These rules used to spell the twelve sans roles out,
   once per repointed class and a second seven times for the reading face: fourteen copies
   of a selector `katex-init.js` also has to spell, in a language where it cannot be
   shared. Both costs were real. A role dropped from one of the fourteen drew Source Sans
   over Computer Modern's numbers in that one role with the whole suite still green, since
   only the first copy was ever pinned against the script. And the seven role selectors
   ran to 477 characters against the 400 a consuming host's stylesheet check allows, so
   the next role could not be added at all. Keying on the mark costs one attribute per
   rendered math node and leaves ONE list, in the file that must have it anyway, since
   only a script can install a metric table.

   A page without JavaScript is unaffected. There is no `.katex` for any of these rules to
   match until the script has rendered one, only the semantic MathML fallback.

   The mark says nothing about the opt-outs, so the `:not()` stays, spelled the way the
   serif rules above spell it: each attribute twice, once for the wrapper itself and once
   for an ancestor, because `closest()` reads both. `katex-init.js` marks a node wherever
   the sans set is what it installs, which includes a wrapper that opted out inside a page
   that did not, so dropping the guard here would draw Source Sans over the Computer
   Modern numbers that wrapper asked to keep.

   Specificity is what it was before the mark: `.kpress:not(...)` at (0,2,0), plus the
   mark, plus `.katex` lands the root rule at (0,4,0) against the serif root rule's
   (0,3,0), and each leaf class one higher again, (0,5,0) against (0,4,0). Margin +1
   everywhere, so the sans composite wins inside a sans context, does not exist outside
   one, and neither result is a matter of source order.

   Headings and the TOC are sans roles and are deliberately NOT marked, which
   `katex-init.js` decides by leaving them out of `SANS_CONTEXT`, for two different
   reasons. A heading sits a weight step away from the words around it -- `h3` at 550,
   `h4` at 540, `h2` in the serif italic -- and a table built at the regular weight describes none of
   those, so its mathematics would be a step off its own text whichever composite drew it.
   The TOC carries no mathematics at all: `render.py` escapes entry titles when it builds
   the TOC, so no `.katex` ever reaches it.

   `.textrm` takes the family only here, for the reason the serif rule above records:
   pinning `font-style: normal` at (0,5,0) would outrank the `.textit` nested inside a
   `\textrm{\textit{x}}` leaf and draw the upright slot over an italic-measured run.
   `.mainrm` keeps the pin, because upstream pins it too. */

/* --- the document, by the mark katex-init.js stamps --- */

.kpress:not(
    [data-kpress-fonts="system"],
    [data-kpress-font-set="system"],
    [data-kpress-math-text="katex"],
    [data-kpress-fonts="system"] *,
    [data-kpress-font-set="system"] *,
    [data-kpress-math-text="katex"] *
  ) [data-kpress-math-face="sans"]
  .katex {
  font-family: "KPress Math Text Sans", KaTeX_Main, "Times New Roman", serif;
  font-weight: var(--_kpress-math-sans-regular-weight);
}

.kpress:not(
    [data-kpress-fonts="system"],
    [data-kpress-font-set="system"],
    [data-kpress-math-text="katex"],
    [data-kpress-fonts="system"] *,
    [data-kpress-font-set="system"] *,
    [data-kpress-math-text="katex"] *
  )
  [data-kpress-math-face="sans"]
  .katex
  .mathnormal {
  font-family: "KPress Math Text Sans", KaTeX_Math, serif;
  font-style: italic;
}

.kpress:not(
    [data-kpress-fonts="system"],
    [data-kpress-font-set="system"],
    [data-kpress-math-text="katex"],
    [data-kpress-fonts="system"] *,
    [data-kpress-font-set="system"] *,
    [data-kpress-math-text="katex"] *
  )
  [data-kpress-math-face="sans"]
  .katex
  .mathit {
  font-family: "KPress Math Text Sans", KaTeX_Main, serif;
  font-style: italic;
}

/* Pin the generated bold slot, independently of a host's prose weight override.
   A request inside [400, 500] can otherwise choose the regular face under bold metrics. */
.kpress:not(
    [data-kpress-fonts="system"],
    [data-kpress-font-set="system"],
    [data-kpress-math-text="katex"],
    [data-kpress-fonts="system"] *,
    [data-kpress-font-set="system"] *,
    [data-kpress-math-text="katex"] *
  ) [data-kpress-math-face="sans"]
  .katex
  .mathbf {
  font-family: "KPress Math Text Sans", KaTeX_Main, serif;
  font-weight: 650;
}

.kpress:not(
    [data-kpress-fonts="system"],
    [data-kpress-font-set="system"],
    [data-kpress-math-text="katex"],
    [data-kpress-fonts="system"] *,
    [data-kpress-font-set="system"] *,
    [data-kpress-math-text="katex"] *
  )
  [data-kpress-math-face="sans"]
  .katex
  .boldsymbol {
  font-family: "KPress Math Text Sans", KaTeX_Math, serif;
  font-style: italic;
  font-weight: 650;
}

.kpress:not(
    [data-kpress-fonts="system"],
    [data-kpress-font-set="system"],
    [data-kpress-math-text="katex"],
    [data-kpress-fonts="system"] *,
    [data-kpress-font-set="system"] *,
    [data-kpress-math-text="katex"] *
  )
  [data-kpress-math-face="sans"]
  .katex
  .textrm {
  font-family: "KPress Math Text Sans", KaTeX_Main, serif;
}

.kpress:not(
    [data-kpress-fonts="system"],
    [data-kpress-font-set="system"],
    [data-kpress-math-text="katex"],
    [data-kpress-fonts="system"] *,
    [data-kpress-font-set="system"] *,
    [data-kpress-math-text="katex"] *
  )
  [data-kpress-math-face="sans"]
  .katex
  .mainrm {
  font-family: "KPress Math Text Sans", KaTeX_Main, serif;
  font-style: normal;
}

/* --- the footnote preview overlay --- */

/* THE SECOND SCOPE. tooltips.js mounts a preview on the viewport pane or the body,
   outside every `.kpress`, and stamps the originating wrapper's math mode on it so the
   serif rules above can reach it by attribute rather than by position. But a preview is
   a CLONE of math KaTeX has already typeset, and the only preview kind that carries
   rendered math is the footnote one: every other kind is escaped text
   (`internalTooltipContent` in js/tooltips.js), so no `.katex` reaches it at all.

   A footnote is a sans role in every mode -- `.kpress-footnotes` is in `SANS_CONTEXT`,
   and under the reader's sans reading face the whole document is sans -- so the clone's
   boxes were measured from the SANS tables. Drawing it in the serif composite would put
   PT Serif glyphs on Source Sans metrics, which is the same disagreement between what
   KaTeX measures and what it draws that the whole file exists to prevent. The overlay
   therefore takes the sans composite.

   This scope keys on position and the mode stamp rather than on the mark the document
   scope uses, and deliberately. The clone does carry the mark out of the document, since
   `katex-init.js` writes it on the math node the overlay copies. But the clone is mounted
   outside every `.kpress`, so the document rule cannot reach it whatever it carries, and
   a rule that trusted the mark alone would draw the sans composite in any preview an
   embedding host happened to mount -- including one whose serif original had never been
   marked. Reaching the overlay by what it is keeps the third-party surface narrow.

   `.kpress-tooltip[data-kpress-math-text="prose"].kpress-tooltip-footnote` is (0,3,0),
   one class above the serif overlay scope's (0,2,0), so these land at (0,5,0) against
   (0,4,0) -- the same margin the document scope keeps, and again not a matter of order.
   The mode stamp stays in the selector so the three opt-outs still apply: an overlay
   opened from an opted-out wrapper is stamped `katex` and matches nothing here.

   The size token needs no rule of its own: `--kpress-katex-size-sans` and the
   `--kpress-katex-size-prose` the serif overlay scope sets are both 1em. */

.kpress-tooltip[data-kpress-math-text="prose"].kpress-tooltip-footnote .katex {
  font-family: "KPress Math Text Sans", KaTeX_Main, "Times New Roman", serif;
  font-weight: var(--_kpress-math-sans-regular-weight);
}

.kpress-tooltip[data-kpress-math-text="prose"].kpress-tooltip-footnote .katex .mathnormal {
  font-family: "KPress Math Text Sans", KaTeX_Math, serif;
  font-style: italic;
}

.kpress-tooltip[data-kpress-math-text="prose"].kpress-tooltip-footnote .katex .mathit {
  font-family: "KPress Math Text Sans", KaTeX_Main, serif;
  font-style: italic;
}

.kpress-tooltip[data-kpress-math-text="prose"].kpress-tooltip-footnote .katex .mathbf {
  font-family: "KPress Math Text Sans", KaTeX_Main, serif;
  font-weight: 650;
}

.kpress-tooltip[data-kpress-math-text="prose"].kpress-tooltip-footnote .katex .boldsymbol {
  font-family: "KPress Math Text Sans", KaTeX_Math, serif;
  font-style: italic;
  font-weight: 650;
}

.kpress-tooltip[data-kpress-math-text="prose"].kpress-tooltip-footnote .katex .textrm {
  font-family: "KPress Math Text Sans", KaTeX_Main, serif;
}

.kpress-tooltip[data-kpress-math-text="prose"].kpress-tooltip-footnote .katex .mainrm {
  font-family: "KPress Math Text Sans", KaTeX_Main, serif;
  font-style: normal;
}

/* A per-node opt-out inside a custom-face wrapper needs stock families as well
   as stock metrics. The runtime chooses both through the same mark, including
   when a host creates its first formula after the native loop has finished.
   Repeating `.katex` matches the specificity of the sans ancestor and footnote
   preview rules, so these later rules also win in an already-rendered clone. */
:is(.kpress, .kpress-tooltip) [data-kpress-math-face="katex"] {
  --kpress-katex-size-prose: 1.05em;
  --kpress-katex-size-display: 1.1em;
}

:is(.kpress, .kpress-tooltip) [data-kpress-math-face="katex"] .katex.katex {
  font-family: KaTeX_Main, "Times New Roman", serif;
  font-weight: 400;
}

:is(.kpress, .kpress-tooltip) [data-kpress-math-face="katex"] .katex.katex .mathnormal,
:is(.kpress, .kpress-tooltip) [data-kpress-math-face="katex"] .katex.katex .boldsymbol {
  font-family: KaTeX_Math, serif;
}

:is(.kpress, .kpress-tooltip) [data-kpress-math-face="katex"] .katex.katex .mathit,
:is(.kpress, .kpress-tooltip) [data-kpress-math-face="katex"] .katex.katex .mathbf,
:is(.kpress, .kpress-tooltip) [data-kpress-math-face="katex"] .katex.katex .textrm,
:is(.kpress, .kpress-tooltip) [data-kpress-math-face="katex"] .katex.katex .mainrm {
  font-family: KaTeX_Main, serif;
}

/* The workbench's design tokens: every colour, space, type size, weight, line height, radius,
   border width, shadow, layer and duration the page uses is declared here and nowhere else.
   `tests/design-system.test.ts` refuses a raw value for any of those properties outside this
   block, checks the text and component colour pairs below against WCAG AA, and
   `workbench_tools.check_layout` measures the page structure they produce in Chromium.

   Three families of token, kept apart because they answer to different owners:
   - UI chrome (`--color-*`, `--space-*`, `--font-*`, `--radius-*`, `--control-*`, `--layout-*`):
     the controls around the stage. A 4 px spacing scale and a five-step type scale.
   - The stage (`--stage-*`): the 1920 x 1080 poster the video is captured from. Its sizes are
     stage pixels, chosen and measured for video, and do not follow the UI scale.
   - Scene and plot colours (`--scene-*`, `--plot-*`): what is drawn, not chrome. Square fills
     come from `sqpack.render` through the corpus and are not tokens at all. */
:root {
  /* Colour: surfaces. */
  --color-page: #e6e8eb;
  --color-surface: #ffffff;
  --color-surface-hover: #f3f5f7;
  --color-surface-selected: #eef1f4;
  /* Colour: text. `muted` is the quietest text the chrome sets: 4.75:1 on the page. */
  --color-text: #17202a;
  --color-text-label: #47525f;
  --color-text-muted: #5c6673;
  --color-text-inverse: var(--color-surface);
  /* Colour: lines. A control's own border has to read against the page it can sit on (WCAG
     1.4.11, 3:1); a panel's border and a divider only group, and are quieter. */
  --color-border: #d5d9de;
  --color-border-control: #7d8590;
  --color-divider: #dfe3e7;
  /* Colour: accent and selection. The chrome's one accent is ink: a primary action, a chosen
     segment or chip, the tab that is showing. */
  --color-accent: var(--color-text);
  --color-accent-hover: #2b3947;
  --color-selected: var(--color-accent);
  --color-selected-text: var(--color-text-inverse);
  /* Colour: status. Scarlet is a recent result and the proved lower bound; green is
     the best known arrangement, and nothing else on the page is green. */
  --color-status-new: #a3123f;
  --color-status-best: #17794a;
  /* Colour: focus. Scarlet for every control and the stage; the separator keeps metabrowser's
     accent, which its resize handle is drawn in. */
  --color-focus: var(--color-status-new);
  --color-focus-separator: oklch(54.14% 0.1337 246.71);

  /* Scene: what the stage draws besides the squares. */
  --scene-paper: var(--color-surface);
  --scene-ink: var(--color-text);
  --scene-black: #000000;
  --scene-rule: #0c1116;
  --scene-track: var(--color-divider);
  --scene-open: #8a939e;
  --scene-reference: #9aa3ad;
  --scene-ghost: var(--color-text-muted);
  --scene-proved: var(--color-status-new);
  --scene-best: var(--color-status-best);
  --scene-heading: #8a939e;
  --scene-label: var(--color-text-label);
  --scene-badge: var(--color-text-muted);
  --scene-badge-query: #c9cfd5;
  --scene-shadow: 0 8px 40px rgb(23 32 42 / 18%);
  /* Scene: the frames around the packing, all one width (the owner, 2026-09-17). The catalogue's
     box is green where it locks at the best known side and medium grey on its way; the container
     Pack and the animation studio draw is that grey too; the trace of where the box just was is
     the lightest grey the page draws a line in. */
  --scene-frame-width: 4px;
  --scene-frame: var(--color-border-control);
  --scene-frame-locked: var(--scene-best);
  --scene-trace: var(--color-divider);
  /* Plot: the force-law editor's drawing. */
  --plot-field: #fbfcfd;
  --plot-zero: var(--scene-reference);
  --plot-axis: #c8ced4;
  --plot-pull: #7a5aa8;
  --plot-text: var(--color-text-muted);
  --plot-font-size: 9px;

  /* Type: families. The names and stacks are kpress's (`--font-sans`, `--font-serif`,
     `--font-mono`). "Atlas Symbols" is KaTeX_Main restricted to the relation code points
     (≤ ≥ √ ≈ …) that the latin subsets do not carry; it follows each text face so those glyphs
     never fall back to Georgia. */
  --font-sans:
    "Source Sans 3", "Atlas Symbols", system-ui, -apple-system, BlinkMacSystemFont, "Segoe UI",
    sans-serif;
  --font-serif: "PT Serif", "Atlas Symbols", Georgia, "Times New Roman", serif;
  --font-mono: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;
  /* Type: the chrome's scale. */
  --font-size-caps: 11px;
  --font-size-xs: 12px;
  --font-size-sm: 13px;
  --font-size-body: 14px;
  --font-size-heading: 18px;
  --font-weight-strong: 600;
  --font-weight-bold: 700;
  --line-height-body: normal;
  --line-height-readout: 16px;
  --letter-spacing-caps: 0.1em;

  /* Space: a 4 px scale. */
  --space-1: 4px;
  --space-2: 8px;
  --space-3: 12px;
  --space-4: 16px;
  --space-8: 32px;
  --space-12: 48px;

  /* Shape. */
  --radius-sm: 4px;
  --radius-md: 6px;
  --border-width: 1px;
  --border-width-strong: 2px;
  --focus-ring-width: 2px;
  --focus-ring-offset: 2px;

  /* Layout: one page structure for every mode. The controls sit inside `--layout-gutter`; every
     block in them, and every panel in a row of panels, is `--layout-stack-gap` from the next. */
  --layout-gutter: var(--space-4);
  --layout-stack-gap: var(--space-2);
  --panel-padding-block: var(--space-2);
  --panel-padding-inline: var(--space-3);
  --panel-gap: var(--space-2);
  --field-gap: var(--space-1);
  /* The published page's note is fixed over the bottom of the window; the controls end this far
     above it when scrolled to the end. A narrow window sets it on two lines (see `#site-note`). */
  --site-note-clearance: var(--space-8);

  /* Controls: one height for every button, select, text field and segmented group. */
  --control-height: 28px;
  --control-padding-inline: var(--space-2);
  --control-border: var(--border-width) solid var(--color-border-control);
  --tab-height: 32px;

  /* Elevation and layers. */
  --z-separator: 2;
  --z-note: 30;
  /* Startup and loading errors remain above the application and its fixed note. */
  --z-startup: 1000;

  /* Motion. */
  --duration-fast: 150ms;
  --easing-standard: ease;

  /* The stage's type, in stage pixels, large enough to read on video: 26 the gap bar's numbers;
     28 the PROVEN and OPEN heads, the badge labels and the open group; 38 the bound line; 64 the
     headline, `n = 17`, set by KaTeX. */
  --stage-text-number: 26px;
  /* The note under the facts: the composite's own legend, a step below the bar's numbers. */
  --stage-text-note: 22px;
  /* The legend's rhythm: between a swatch row and its sentence, between swatches, and the
     hairline outline that keeps a pale shade reading as a square. */
  --stage-note-gap: 10px;
  --stage-note-swatch-border: 1px;
  --stage-text-label: 28px;
  --stage-text-bound: 38px;
  --stage-text-headline: 58px;
  --stage-badge-glyph: 15px;
  /* KaTeX inherits the line it is set in, as kpress's `--kpress-katex-size-sans` does. */
  --stage-katex-size: 1em;
  /* The legend's mathematics, sized so its x-height matches the sentence beside it. */
  --stage-katex-note: 1.18em;
  --stage-weight-regular: 400;
  --stage-weight-quiet: 450;
  --stage-weight-label: 500;
  --stage-weight-glyph: 650;
  --stage-weight-bold: 700;
  --stage-line-height-head: 34px;
  --stage-line-height-bound: 1.2;
  --stage-line-height-headline: 84px;
  --stage-line-height-facts: 1.35;
  /* The tracking on the uppercase section heads -- PROVEN, KNOWN BOUNDS, CITATION, OPEN. Uppercase
     needs a little to stop the letters closing up, and 0.16em was enough to read as spacing rather
     than as a word; the owner asked for less on 2026-09-22, once CITATION put three of them in the
     column at once. 0.06em, a little under the chrome's own 0.1em, because the stage's heads are
     set larger than any chrome label and tracking is felt at the size it is set. */
  --stage-tracking-head: 0.06em;
  --stage-tracking-label: 0.01em;
  --stage-tracking-numeral: -0.02em;
  /* A badge row: the gap between items, and between an item's icon and its label. The open row
     is the same shape a step quieter, with a smaller icon and proportionally smaller gaps. */
  --stage-badge-gap: 34px;
  --stage-badge-icon-gap: 11px;
  --stage-open-gap: 28px;
  --stage-open-icon-gap: 10px;
  /* A citation line: the gap between which bound it is, its reference, and `reported`. The line is
     set in the legend's type, a step below the badges, because it annotates the bound line rather
     than stating a fact of its own. */
  --stage-cite-gap: 12px;
  /* The head's line: CITATION, then the frontier record the n's bounds are held in, set apart by
     the badges' gap and read as one quiet phrase with a word space inside it. */
  --stage-cite-record-gap: var(--stage-badge-icon-gap);
  --stage-cite-word-gap: 5px;
  /* Where the headline's rolling numbers start; `layoutHeadline` measures and sets it. */
  --stage-numeral-left: 152px;
}

/* ============================================================================ base */
html,
body {
  margin: 0;
  padding: 0;
  height: 100%;
}
body {
  background: var(--color-page);
  color: var(--color-text);
  font-family: var(--font-sans);
  font-size: var(--font-size-body);
  line-height: var(--line-height-body);
  overflow: hidden;
}
body.capture {
  background: var(--scene-paper);
}
/* A rule later in the sheet that sets `display` wins over this at equal specificity, so a
   component that is shown and hidden by the attribute sets its own display only while it is not
   hidden (see `.workspace`). */
[hidden] {
  display: none;
}
.sr-only {
  position: absolute;
  width: 1px;
  height: 1px;
  overflow: hidden;
  clip: rect(0 0 0 0);
  white-space: nowrap;
}
@media (prefers-reduced-motion: reduce) {
  *,
  *::before,
  *::after {
    scroll-behavior: auto;
    transition: none;
  }
}

/* ============================================================================ the stage */
#viewport {
  position: absolute;
  inset: 0;
  display: flex;
  flex-direction: column;
  align-items: center;
}
/* The published page carries the site's navigation bar above `#viewport` (`build_site`; the bar's
   own box is `site-nav.css`'s). The page is then a column: the bar at its top at its own height,
   and the workbench in the rest, which is the height `layout` shares between the stage and the
   controls. A capture hides the bar, as it hides the note, and the workbench has the window. */
body:has(> .site-app-shell) {
  display: flex;
  flex-direction: column;
}
body:has(> .site-app-shell) > #viewport {
  position: relative;
  inset: auto;
  flex: 1 1 0;
  min-height: 0;
  width: 100%;
}
body.capture > .site-app-shell {
  display: none;
}
/* The stage is a 1920 x 1080 poster drawn at `--stage-scale`, which `layout` sets on `#viewport`
   from the window and the controls. Until it first does, the property is unset, the wrapper has
   no size and the stage no transform. */
#stage-wrap {
  position: relative;
  flex: none;
  overflow: hidden;
  width: calc(1920px * var(--stage-scale));
  height: calc(1080px * var(--stage-scale));
}
#stage {
  position: absolute;
  left: 0;
  top: 0;
  width: 1920px;
  height: 1080px;
  background: var(--scene-paper);
  transform: scale(var(--stage-scale));
  transform-origin: 0 0;
  box-shadow: var(--scene-shadow);
  /* A poster, not a text surface. A click, drag or double-click on it selected the facts' text,
     and the browser went on painting that selection -- grey while the window is unfocused --
     over every frame of the animation after it (the owner, 2026-09-21). The link in the
     attribution still takes its click; only selection is refused. */
  -webkit-user-select: none;
  user-select: none;
}
body.capture #stage {
  box-shadow: none;
}
/* Revision 9: the squares can be picked up, so the surface takes pointer gestures rather than the
   browser's pan and zoom, and says so with the cursor. */
#packing-svg {
  position: absolute;
  left: 30px;
  top: 12px;
  width: 1056px;
  /* 971, not 940: the owner asked for the box to be bigger, with even space above and below
     the headline under it, and saw and accepted this size. The square view fits this height,
     so the settled box's path sits at 12 + 971 x 1.045 / 1.09 = 942.9 at every n, and its
     4 px stroke draws to 945. The headline's ink runs 990 to 1035, measured in pixels: 45
     above, 45 below.
     A MOVING drawing reaches lower than the settled box. The SVG clips it (`overflow:
     hidden`), so nothing is drawn below the SVG's own floor, at 983: on the corpus's deepest
     steps, a square swinging in a rigid block under the bodies style at n = 293 and 302, the
     drawing is cut flat there, 7 px above the headline's ink, and `check_animate_view`
     requires at least 5. The page was shrunk to 954 and then 949 on element boxes, which
     ignore the clip and put that square 8 px into the headline's ink at this size; drawn,
     it never reaches it. The stage itself stays 1920 x 1080, which the 1080p capture
     depends on. */
  height: 1056px;
  display: block;
  touch-action: none;
}
#packing-svg #squares {
  cursor: grab;
}
body.dragging #packing-svg #squares {
  cursor: grabbing;
}
#links line {
  stroke: var(--scene-paper);
  stroke-opacity: 0.85;
  stroke-width: 2;
}
/* Revision 11: the relationship graph drawn on the stage — a faint line on every pair the
   attraction is actually reaching. It rides the correspondence overlay's own control rather than
   adding a second one, and a general relationship (every pair attracts) draws nothing, there being
   no mask to show. */
#mask-links line {
  stroke: var(--scene-paper);
  stroke-opacity: 0.9;
  stroke-width: 2.5;
  stroke-dasharray: 5 4;
}
/* Revision 12: a target contact graph is drawn in two classes, because the difference between them
   is the measurement. An edge whose two squares share a whole side right now is solid and white —
   it lies across the pair it joins, so white reads against the fill. One that is only wanted is
   dashed and dark: it is usually long and crosses paper, where white would be invisible. */
#mask-links line.met {
  stroke: var(--scene-paper);
  stroke-opacity: 1;
  stroke-width: 4.5;
  stroke-dasharray: none;
}
#mask-links line.unmet {
  stroke: var(--scene-ink);
  stroke-opacity: 0.62;
  stroke-width: 3;
  stroke-dasharray: 7 6;
}
/* The edge being drawn, following the cursor from the square it started on. */
#draw-line {
  stroke: var(--scene-ink);
  stroke-opacity: 0.75;
  stroke-width: 3.5;
  stroke-dasharray: 2 7;
}
/* Drawing mode: no square is ever picked up, and the cursor says which gesture is live. */
body.drawing #packing-svg #squares {
  cursor: crosshair;
}
/* The frames around the packing, one width whatever draws them. The box's colour is its lock, which
   `drawBounds` sets as `is-locked`; `#container` keeps its `stroke="none"` in the catalogue, which
   draws the box and trace instead, and is stroked by the mode rules below where it is drawn. */
#bound-box,
#bound-trace,
#container {
  stroke-width: var(--scene-frame-width);
}
#bound-box {
  stroke: var(--scene-frame);
}
#bound-box.is-locked {
  stroke: var(--scene-frame-locked);
}
#bound-trace {
  stroke: var(--scene-trace);
}
#ghost rect {
  stroke: var(--scene-ghost);
}
#mark rect {
  stroke: none;
}
#squares .sq[tabindex="0"]:focus-visible,
#pack-squares .pack-sq:focus-visible {
  outline: none;
}
#squares .sq[tabindex="0"]:focus-visible rect,
#pack-squares .pack-sq:focus-visible rect {
  stroke: var(--color-focus);
  stroke-width: 3;
}
#pack-squares .pack-sq {
  cursor: grab;
}
#facts {
  position: absolute;
  left: 1110px;
  top: 0;
  width: 780px;
  height: 1080px;
}
.facts-layer {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
  will-change: opacity;
}
/* Revision 8, feature 4: how close the arrangement on the stage is to the best known, drawn on a
   scale that runs from the proved lower bound to comfortably past the record. The panel's top 200 px
   were empty, and this is what goes in them.
   Revision 9 folds the two tabs into one view, so the bar is always drawn: the range is the spine and
   its `to` end is the n the bar measures.
   The two numbers are the ones the panel itself prints, s(n) <= and s(n) >=, read from the record. */
.gapbar {
  position: absolute;
  left: 6px;
  top: 164px;
  width: 768px;
  height: 268px;
}
/* The bar sits under the headline, so the first thing in the column is the n it is all about. */
.gapbar-plot {
  position: absolute;
  left: 0;
  top: 60px;
  width: 760px;
  height: 150px;
  display: block;
}
.gapbar-plot .track {
  fill: var(--scene-track);
}
/* The scale's two ends: the formula the end IS, and the value it takes at this n, on one line.
   HTML rather than SVG text, because KaTeX sets HTML: a radical it draws is an inline SVG inside a
   span, which cannot be nested in a `<text>`. Quiet, because they are the bar rather than a claim
   about this packing. Under the value each names: `left` is set per n by `gapbarSetup`, and the
   translate is what centres it on the mark. */
.gapbar-end {
  position: absolute;
  top: 210px;
  transform: translateX(-50%);
  font-family: var(--font-sans);
  font-size: var(--stage-text-number);
  color: var(--scene-ink);
  white-space: nowrap;
}
.gapbar-area {
  left: 34px;
}
.gapbar-grid {
  left: 646px;
}
/* The end's formula is the one piece of mathematics on the bar, so it is set as mathematics --
   at the size every other number here is set at, because it names one of them. */
.gapbar-end .katex {
  font-size: var(--stage-text-number);
}
/* The open territory: everything between what is proved and what is known.
   Named `gap-open`, not `open`: `height` is a CSS property on an SVG rect, so the panel's own
   `.open` group (a 76 px slot) silently stretched this band to 76 px when it shared the name. */
.gapbar-plot .gap-open {
  fill: var(--scene-open);
  opacity: 0.62;
}
/* The scale's reference marks -- its two ends, and any integer inside the span. A step
   darker than the rail so they read as marks rather than as part of it, and a step lighter
   than the bounds so the eye sorts them without being told. Not black: an earlier revision
   drew these in ink and the bar read as though every mark on it were a claim. */
.gapbar-plot .ref-tick {
  stroke: var(--scene-reference);
  stroke-width: 2.5;
}
/* The two bounds. Bold and black, because these are the two values the panel below states
   and the only two a reader is asked to compare the arrangement against. */
.gapbar-plot .bound-rule {
  stroke: var(--scene-rule);
  stroke-width: 4;
}
/* Where the arrangement on the stage actually is: a line through the track, not a third arrow.
   It is the only mark here that moves, so it does not need a shape to argue for it. */
.gapbar-plot .hand-stem {
  stroke: var(--scene-ink);
  stroke-width: 3;
}
.gapbar.is-met .gapbar-plot .hand-stem {
  stroke: var(--scene-best);
}
/* The stage's box, pointed at from above the rail: black while it moves, green once it locks at
   the best known side, when the box itself turns green. On its way the box is drawn grey and the
   pointer stays black, a mark on the bar beside the bold black bound rules. */
.gapbar-plot .box-pointer {
  fill: var(--scene-black);
}
.gapbar-plot .box-pointer.is-locked {
  fill: var(--scene-best);
}
/* Every number on this bar is the same size, and what differs is the colour and the weight.
   Scarlet and green at 700 are the two bounds, the values the panel below states. Ink at 400
   is a reference mark -- the scale's ends, and the integers inside it -- which is a place on
   the scale rather than a claim about this n.
   The modifiers are `is-lower` and `is-record`, not `lower` and `record`: a bare class selector
   reaches into the SVG as readily as into a div, and a `.lower` row once won by source order. */
.gapbar-num {
  font-family: var(--font-sans);
  font-size: var(--stage-text-number);
  font-weight: var(--stage-weight-bold);
  font-variant-numeric: tabular-nums;
  fill: var(--scene-ink);
}
.gapbar-num.is-lower {
  fill: var(--scene-proved);
}
.gapbar-num.is-record {
  fill: var(--scene-best);
}
.gapbar-ref-num {
  font-family: var(--font-sans);
  font-size: var(--stage-text-number);
  font-weight: var(--stage-weight-regular);
  font-variant-numeric: tabular-nums;
  fill: var(--scene-ink);
}
/* The headline, on one line: `n = 11`, under the packing it names. `#headline` holds three copies
   of the same KaTeX expression at the same place: a still one that draws only `n =` and never
   fades, and the two rolling layers' copies, which draw only the number. The script centres the
   expression on the widest number the corpus holds, through `--stage-numeral-left`, so `n =` does
   not move as a digit is gained.
   Anchored to the stage's floor with `bottom`: the numeral's ink runs 990 to 1035, 45 below the
   container's drawn edge and 45 above the stage's own. */
/* The headline sits a little below the packing's top edge (the owner, 2026-09-21: lower, with
   more room above it). Level with that edge, at 41, its ink started at 55.6 -- KaTeX's strut
   opens 15 px above the digits, measured rather than computed, since the strut is the face's
   business -- and read as crowding the frame's top. 24 px lower its ink starts near 80, and it
   still clears the gap bar under it, which `gapbar/clearance` holds. */
#headline {
  position: absolute;
  left: 1116px;
  top: 65px;
  width: 768px;
  height: 96px;
}
.numeral-slot {
  position: absolute;
  left: 0;
  top: 0;
  width: 100%;
  height: 100%;
}
.numeral {
  position: absolute;
  left: var(--stage-numeral-left);
  top: 0;
  font-family: var(--font-serif);
  color: var(--scene-ink);
  line-height: var(--stage-line-height-headline);
  white-space: nowrap;
}
/* Recency colors only the changing case number; `n =` stays in the shared ink. */
#numeral-a .numeral.is-new-result,
#numeral-b .numeral.is-new-result {
  color: var(--scene-proved);
}
.numeral .n-val {
  font-weight: var(--stage-weight-bold);
  font-size: var(--stage-text-headline);
  letter-spacing: var(--stage-tracking-numeral);
  font-variant-numeric: tabular-nums;
}
/* The headline is an equation, so KaTeX sets it and this is the one place its size is chosen,
   in the same `\boldsymbol` the panel's bound line is set in. */
.numeral .katex {
  font-size: var(--stage-text-headline);
}
/* `n =` never moves: the owner asked that a step change the number and nothing else. All three
   slots render the whole expression; the rolling two hide `n` and `=`, and the still one hides
   the digits. `visibility` rather than `display`, so every copy keeps KaTeX's own spacing. */
#numeral-a .katex .boldsymbol,
#numeral-a .katex .mrel,
#numeral-b .katex .boldsymbol,
#numeral-b .katex .mrel,
#numeral-static .katex .mord.mathbf {
  visibility: hidden;
}
/* An empty inline block on the headline's line sits on its baseline, so its top is where the
   headline's letters stand. `placeAttribution` reads it; it draws nothing. */
.numeral .baseline {
  display: inline-block;
}
/* The composite's legend, at the foot of the facts column and above the attribution. It is a
   child of the STAGE rather than of `#facts`, like the attribution it sits above, so its `left` is
   the stage's coordinate for the column's own inset (1110 + 6) rather than the inset itself --
   written at 6 it drew across the packing. Aligned with every other row in the column, so the
   column reads as one edge, and the attribution below it keeps the same left edge.
   It is text and takes no pointer: in Pack, where the packing is drawn further right, it sat over
   the drawing's lower right and swallowed the press that picks a square up. */
.stage-note {
  position: absolute;
  pointer-events: none;
  left: 1116px;
  top: 906px;
  width: 768px;
  font-family: var(--font-sans);
  font-size: var(--stage-text-note);
  font-weight: var(--stage-weight-quiet);
  line-height: var(--stage-line-height-facts);
  color: var(--scene-heading);
  white-space: nowrap;
}
/* A swatch row: the swatches beside the line of text they explain. */
.note-row {
  display: flex;
  align-items: baseline;
  gap: var(--stage-note-gap);
}
/* The legend's sentence is ordinary inline text with its math in the flow, which is how KaTeX
   is made to be set, so each formula stands on the line's own baseline. It was a flex row, and
   the sentence's `n` could not be math there without the row's gap on both sides of it.
   `check_layout` measures the baselines and the letters' ink; neither rests on this comment. */
.note-sentence {
  display: block;
}
/* An empty inline block at the end of each row's words stands on the row's baseline, so its top is
   where the row's letters stand. `placeAttribution` reads the last two to set the attribution one
   legend line below the last row; it draws nothing. */
.note-baseline {
  display: inline-block;
}
.note-swatches {
  display: block;
  flex: none;
  /* The row aligns type on its baseline; the swatches are not type and keep to its middle. */
  align-self: center;
}
/* The swatch's own outline, as the composite figure draws it: a hairline so a pale shade still
   reads as a square rather than as a smudge. Its `fill` is the corpus's palette, set as an
   attribute per rect, so the stylesheet says nothing about it. */
.note-swatch {
  stroke: var(--scene-ink);
  stroke-width: var(--stage-note-swatch-border);
}
/* Matched by x-height, not by em. At the line's own size KaTeX_Math's `s` inks 11 px against
   the text's 13 -- measured on a captured frame -- so the letters look small and float even
   though their baselines agree exactly. 13/11 is 1.18, which is why KaTeX's own default is
   1.21em: its faces carry a smaller x-height per em than a text face does. */
.note-math .katex {
  font-size: var(--stage-katex-note);
}
.note-math {
  font-family: var(--font-serif);
}
/* The attribution, the owner's (2026-09-17): the repository's address, just under the legend at
   its left edge (the owner, 2026-09-21), or on the same line at the column's right edge where
   Pack and the studio center their drawing. It is SVG text because SVG text is placed by its
   baseline and one end, which are the two things said about it: `placeAttribution` measures the
   legend once the faces land and writes them as the text's `y` and `x` in stage pixels. Hidden
   until then, rather than drawn at a guess. It is on the stage in every mode, so a captured frame
   carries it; the overlay takes no pointer events but the link's own. */
#stage-attribution {
  position: absolute;
  left: 0;
  top: 0;
  width: 1920px;
  height: 1080px;
  overflow: visible;
  pointer-events: none;
}
#stage-attribution:not(.is-placed) {
  visibility: hidden;
}
#stage-attribution a {
  cursor: pointer;
  pointer-events: auto;
}
#stage-attribution text {
  font-family: var(--font-sans);
  font-size: var(--stage-text-note);
  font-weight: var(--stage-weight-regular);
  fill: var(--scene-ink);
}
#stage-attribution a:hover text,
#stage-attribution a:focus-visible text {
  text-decoration: underline;
}
/* The panel says what is proved about n and, when anything is, what is open, under headings in
   the gap bar's head style. Every slot is fixed, so nothing jumps between n: PROVEN's bound and
   badges hold their places at every n, and OPEN, which is left out when nothing is open, starts
   at the same place whenever it is drawn.
   The rhythm, in stage pixels: a head is 6 above what it heads; a row of content is 28 above
   the next head. */
.section-head {
  position: absolute;
  left: 6px;
  height: var(--stage-line-height-head);
  line-height: var(--stage-line-height-head);
  font-family: var(--font-sans);
  font-size: var(--stage-text-label);
  font-weight: var(--stage-weight-label);
  letter-spacing: var(--stage-tracking-head);
  text-transform: uppercase;
  color: var(--scene-heading);
  white-space: nowrap;
}
.head-proved {
  top: 444px;
}
.head-open {
  top: 618px;
}
/* The two bounds as one chained statement, at one size: a best known side and a proved lower
   bound are the same kind of fact about the same quantity. Measured over the whole corpus at the
   old 48 px, the widest -- `10.055385 <= s(101) <= 10.535534` -- came to 812 against a 694 column;
   38 px brings that to 643. */
.side {
  position: absolute;
  left: 6px;
  top: 484px;
  height: 62px;
  font-family: var(--font-serif);
  font-size: var(--stage-text-bound);
  line-height: var(--stage-line-height-bound);
  color: var(--scene-ink);
  white-space: nowrap;
}
/* KaTeX owns the setting inside the line; the stylesheet owns only where it sits and how big it
   is. KaTeX's own stylesheet sets `white-space: normal` and breaks an expression into one `.base`
   span per relation; this line is a fixed-height slot in a poster and must not wrap. */
.side .katex {
  font-size: var(--stage-katex-size);
}
.side .katex,
.side .katex-html {
  white-space: nowrap;
}
/* Mathematical status badges, in a fixed-height row with short labels. */
.badges {
  position: absolute;
  left: 6px;
  top: 550px;
  height: 40px;
  display: flex;
  align-items: center;
  gap: var(--stage-badge-gap);
  white-space: nowrap;
}
.badge-item {
  display: inline-flex;
  align-items: center;
  gap: var(--stage-badge-icon-gap);
  font-family: var(--font-sans);
  font-size: var(--stage-text-label);
  font-weight: var(--stage-weight-label);
  color: var(--scene-label);
  letter-spacing: var(--stage-tracking-label);
}
.badge-item svg {
  width: 36px;
  height: 36px;
  display: block;
  flex: none;
}
.badge .box {
  fill: none;
  stroke: var(--scene-badge);
  stroke-width: 1.2;
}
.badge-solid .box {
  fill: var(--scene-badge);
  stroke: none;
}
.badge-query .box {
  stroke: var(--scene-badge-query);
}
.badge .glyph {
  font-family: var(--font-sans);
  font-weight: var(--stage-weight-glyph);
  font-size: var(--stage-badge-glyph);
  fill: var(--scene-badge);
}
.badge-solid .glyph {
  fill: var(--scene-paper);
}
.badge-query .glyph {
  fill: var(--scene-heading);
}
/* The approximately-equal sign is KaTeX_Main's outline in font units, filled and thickened by a
   stroke in the same units (the stroke width scales with the path), as the slideshow draws it. */
.badge .glyph-path {
  fill: var(--scene-badge);
  stroke: var(--scene-badge);
  stroke-linejoin: round;
}
/* OPEN: what the record leaves unsettled for this n, in the same badge row shape, a step quieter. */
.open-items {
  position: absolute;
  left: 6px;
  top: 658px;
  height: 40px;
  display: flex;
  align-items: center;
  gap: var(--stage-open-gap);
  white-space: nowrap;
}
.open-item {
  display: inline-flex;
  align-items: center;
  gap: var(--stage-open-icon-gap);
  font-family: var(--font-sans);
  font-size: var(--stage-text-label);
  font-weight: var(--stage-weight-quiet);
  color: var(--scene-heading);
}
.open-item svg {
  width: 32px;
  height: 32px;
  display: block;
  flex: none;
}
/* CITATION, under PROVEN while the setting is on (the owner, 2026-09-21): where each bound on the
   bound line comes from, one line per cited bound. Its head takes the place OPEN has with the
   setting off, and its two lines are fixed slots -- the lower bound's source on the first, the
   upper bound's on the second, at every n -- so nothing moves between n; a line with nothing to
   cite is an empty slot. OPEN moves below them for as long as the setting is on, to the same
   place at every n, in the same rhythm: a head 6 above what it heads, the last row 28 above the
   next head. The legend's 30 px pitch sets the lines, so the section reads at the legend's size.
   With the setting off none of this is built and OPEN is where it always was. */
.head-cite {
  position: absolute;
  left: 6px;
  top: 618px;
}
/* The head's own word keeps the heads' type, the record beside it the legend's: it names where the
   lines under it are kept rather than heading them, so it is not set in capitals or tracked. */
.head-cite.section-head {
  display: flex;
  align-items: baseline;
  gap: var(--stage-cite-record-gap);
}
.cite-record {
  display: flex;
  gap: var(--stage-cite-word-gap);
  font-size: var(--stage-text-note);
  font-weight: var(--stage-weight-quiet);
  letter-spacing: var(--stage-tracking-label);
  text-transform: none;
  font-variant-numeric: tabular-nums;
}
.cite-line {
  position: absolute;
  left: 6px;
  height: 30px;
  display: flex;
  align-items: baseline;
  gap: var(--stage-cite-gap);
  font-family: var(--font-sans);
  font-size: var(--stage-text-note);
  font-weight: var(--stage-weight-quiet);
  line-height: var(--stage-line-height-facts);
  color: var(--scene-label);
  white-space: nowrap;
}
.cite-lower {
  top: 658px;
}
.cite-upper {
  top: 688px;
}
/* Which bound, in that bound's colour on the bound line: scarlet for the proved lower bound, green
   for the best known upper one. One width for both words, so the two references start together. */
.cite-bound {
  flex: none;
  width: 58px;
  font-weight: var(--stage-weight-label);
}
.cite-bound.is-lower {
  color: var(--scene-proved);
}
.cite-bound.is-upper {
  color: var(--scene-best);
}
/* Everything this project has to say about a bound -- that the register reports it without
   certifying, that a result of ours confirms it, or both -- is one parenthesis after the
   reference, in OPEN's quieter grey: an aside about the bound rather than part of its source
   (the owner, 2026-09-22, think-qzmf). The words come from the record, not from here. */
.cite-note {
  color: var(--scene-heading);
  font-weight: var(--stage-weight-label);
}
/* The published work a lower bound corrects, `corrects Nagamochi 2005`, between the reference
   and the note, in the note's quieter grey: like the note it is said about the bound rather than
   part of its source (the owner, 2026-10-02). */
.cite-corrects {
  color: var(--scene-heading);
  font-weight: var(--stage-weight-label);
}
#facts.shows-citations .head-open {
  top: 746px;
}
#facts.shows-citations .open-items {
  top: 786px;
}
#pack-stage-facts {
  position: absolute;
  left: 1480px;
  top: 210px;
  width: 370px;
  font-family: var(--font-sans);
  font-size: var(--stage-text-label);
  line-height: var(--stage-line-height-facts);
  font-variant-numeric: tabular-nums;
  white-space: pre-line;
}

/* ============================================================================ page structure */
/* The separator between the stage and the controls, after metabrowser's `.resize-handle`
   (src/metabrowser/static/styles.css), turned for a stacked layout: a 4 px strip that takes
   no layout space, a 12 px hit area, transparent at rest and metabrowser's accent while
   hovered, focused or dragged, with its 2 px focus ring. */
.resize-handle {
  flex: none;
  align-self: stretch;
  height: var(--space-1);
  margin-bottom: calc(var(--space-1) * -1);
  position: relative;
  z-index: var(--z-separator);
  cursor: row-resize;
  background: transparent;
  touch-action: none;
  transition: background var(--duration-fast) var(--easing-standard);
}
.resize-handle::after {
  content: "";
  position: absolute;
  left: 0;
  right: 0;
  top: calc(var(--space-1) * -1);
  bottom: calc(var(--space-1) * -1);
  cursor: row-resize;
}
.resize-handle:hover,
.resize-handle:focus-visible,
body.resizing .resize-handle {
  background: var(--color-focus-separator);
}
.resize-handle:focus-visible {
  outline: var(--focus-ring-width) solid var(--color-focus-separator);
  outline-offset: calc(var(--focus-ring-offset) / 2);
}
body.resizing {
  cursor: row-resize;
  user-select: none;
}
body.capture .resize-handle,
body.search-active .resize-handle {
  display: none;
}
@media print {
  .resize-handle {
    display: none;
  }
}
/* The controls are the page's one column: every block in them -- the mode's panel, a row of
   panels, a workspace -- spans the same two edges inside `--layout-gutter`, and sits
   `--layout-stack-gap` from the next. Past the share `layout` allows it, the column scrolls rather
   than pushing the stage out: `max-height` here and `CONTROLS_SHARE` there are the same number, a share
   of `#viewport`'s height, which is the window's less the site's navigation bar where there is one. */
#controls {
  max-height: 58%;
  overflow-y: auto;
  flex: none;
  width: 100%;
  box-sizing: border-box;
  padding: var(--layout-stack-gap) var(--layout-gutter) var(--site-note-clearance);
  background: var(--color-page);
  border-top: var(--border-width) solid var(--color-border);
  display: flex;
  flex-direction: column;
  gap: var(--layout-stack-gap);
}
body.capture #controls {
  display: none;
}
#panel {
  display: flex;
  flex-direction: column;
  gap: var(--layout-stack-gap);
}
/* The published page's one note, injected by `build_site`: fixed to the bottom right, quiet, and
   clear of a drag everywhere but its link. */
#site-note {
  position: fixed;
  right: var(--space-3);
  bottom: var(--space-2);
  z-index: var(--z-note);
  font-family: var(--font-sans);
  font-size: var(--font-size-caps);
  line-height: var(--line-height-body);
  color: var(--color-text-muted);
  text-align: right;
  pointer-events: none;
}
#site-note a {
  color: inherit;
  text-decoration: underline;
  pointer-events: auto;
}
body.capture #site-note {
  display: none;
}
@media (max-width: 720px) {
  :root {
    --site-note-clearance: var(--space-12);
  }
}

/* ============================================================================ primitives */
/* Panel: a white surface with a quiet border, grouping one thing's controls. A workspace is a
   panel too, and a flush panel (the mode tabs) lets its own parts meet its edges. */
.subpanel {
  box-sizing: border-box;
  min-width: 0;
  padding: var(--panel-padding-block) var(--panel-padding-inline);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
  background: var(--color-surface);
}
.subpanel.is-flush {
  padding: 0;
}
/* A row of panels fills the column: each panel grows to share the line, so the last one on every
   line ends at the column's right edge, and the panels on a line share one height. */
.panel-row {
  display: flex;
  flex-wrap: wrap;
  align-items: stretch;
  gap: var(--layout-stack-gap);
}
.panel-row > .subpanel {
  flex: 1 1 auto;
}
/* Section header: the name of a panel, in small capitals. */
.box-title {
  display: block;
  margin-bottom: var(--space-1);
  font-size: var(--font-size-caps);
  font-weight: var(--font-weight-strong);
  letter-spacing: var(--letter-spacing-caps);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
/* Control row: controls and their labels on one line that wraps, centred on the control height. */
.row {
  display: flex;
  align-items: center;
  gap: var(--panel-gap);
  flex-wrap: wrap;
}
/* Field: a label and the control it names. */
.row label,
.group-body label,
.workspace label {
  display: inline-flex;
  align-items: center;
  gap: var(--field-gap);
  color: var(--color-text-label);
  white-space: nowrap;
}
/* Controls: one height, one border, one radius. The site's navigation bar is not a control of the
   workbench, and its gear keeps the bar's own look, so the element rules below pass it by; the
   `:where` keeps their specificity a bare `button`'s. */
button:not(:where(.site-app-shell *)),
select,
input[type="number"],
input[type="text"],
textarea {
  box-sizing: border-box;
  font: inherit;
  color: var(--color-text);
  background: var(--color-surface);
  border: var(--control-border);
  border-radius: var(--radius-sm);
}
button:not(:where(.site-app-shell *)),
select,
input[type="number"],
input[type="text"] {
  height: var(--control-height);
  padding: 0 var(--control-padding-inline);
}
button:not(:where(.site-app-shell *)) {
  font-size: calc(var(--font-size-body) * var(--paper-button-label-scale, 0.9));
  cursor: pointer;
}
button:not(:where(.site-app-shell *)):hover {
  background: var(--color-surface-hover);
}
button:disabled {
  cursor: not-allowed;
}
input[type="number"] {
  width: 64px;
}
input[type="range"] {
  accent-color: var(--color-accent);
}
textarea {
  display: block;
  width: 100%;
  padding: var(--space-1) var(--space-2);
  font-family: var(--font-mono);
  font-size: var(--font-size-xs);
}
button:not(:where(.site-app-shell *)):focus-visible,
select:focus-visible,
input:focus-visible,
textarea:focus-visible,
summary:focus-visible,
#stage:focus-visible,
#stage-attribution a:focus-visible {
  outline: var(--focus-ring-width) solid var(--color-focus);
  outline-offset: var(--focus-ring-offset);
}
button.primary {
  min-width: 84px;
  background: var(--color-accent);
  color: var(--color-selected-text);
  border-color: var(--color-accent);
}
button.primary:hover {
  background: var(--color-accent-hover);
}
/* Button group: segments share one border, and the chosen one is filled. At a narrow width the
   group wraps rather than running out of the column. */
.seg {
  display: inline-flex;
  flex-wrap: wrap;
  box-sizing: border-box;
  min-height: var(--control-height);
  border: var(--control-border);
  border-radius: var(--radius-sm);
  overflow: hidden;
}
.seg button {
  height: calc(var(--control-height) - var(--border-width) * 2);
  border: 0;
  border-radius: 0;
}
.seg button + button {
  border-left: var(--control-border);
}
.seg button.on,
.chips button.on {
  background: var(--color-selected);
  color: var(--color-selected-text);
  border-color: var(--color-selected);
}
.chips {
  display: inline-flex;
  gap: var(--space-1);
  flex-wrap: wrap;
}
.chips button {
  min-width: 38px;
  font-size: calc(var(--font-size-sm) * var(--paper-button-label-scale, 0.9));
  text-align: center;
}
/* Readout: a live figure in a fixed slot. **A readout that changes at runtime never changes
   size** (revision 12): every one takes a slot wide enough for the widest value it can hold, or
   moves onto its own line *below* the control it belongs to. Figures are tabular, so a slot's
   width is a character count, and anything that overruns is clipped rather than allowed to push.
   `check_animate_view` compares every button's box across a step and a setting change. A slot is
   never wider than the column, so a narrow window clips rather than scrolls sideways. */
.readout {
  display: inline-block;
  max-width: 100%;
  overflow: hidden;
  white-space: nowrap;
  text-overflow: ellipsis;
  font-variant-numeric: tabular-nums;
  vertical-align: middle;
  box-sizing: border-box;
}
.readout-line {
  display: block;
  flex: 0 0 100%;
  width: 100%;
  height: var(--line-height-readout);
  line-height: var(--line-height-readout);
}
.hint {
  color: var(--color-text-muted);
  font-size: var(--font-size-xs);
}
.hint.readout-line {
  font-style: italic;
}
/* Details: a disclosure's summary reads as a control. */
summary {
  cursor: pointer;
  font-weight: var(--font-weight-strong);
  color: var(--color-text-label);
}
/* Workspace: a mode's own panel -- a heading, its rows, and what it reports -- stacked at one gap. */
.workspace:not([hidden]) {
  display: flex;
  flex-direction: column;
  gap: var(--panel-gap);
}
.workspace h2 {
  margin: 0;
  font-size: var(--font-size-heading);
  font-weight: var(--font-weight-strong);
}
.workspace p {
  margin: 0;
}
.workspace details[open] > * + * {
  margin-top: var(--panel-gap);
}
.workspace output {
  display: block;
  font-variant-numeric: tabular-nums;
}
.workspace fieldset {
  display: flex;
  flex-direction: column;
  gap: var(--panel-gap);
  margin: 0;
  padding: var(--panel-padding-block) var(--panel-padding-inline);
  border: var(--border-width) solid var(--color-border);
  border-radius: var(--radius-md);
}
.workspace legend {
  padding: 0 var(--space-1);
  font-size: var(--font-size-caps);
  font-weight: var(--font-weight-strong);
  letter-spacing: var(--letter-spacing-caps);
  text-transform: uppercase;
  color: var(--color-text-muted);
}
/* Table: tabular figures, a rule under each row. */
#search-table {
  border-collapse: collapse;
  width: 100%;
  font-variant-numeric: tabular-nums;
}
#search-table th,
#search-table td {
  border-bottom: var(--border-width) solid var(--color-border);
  padding: var(--space-1) var(--space-2);
  text-align: left;
}
#search-table th {
  font-weight: var(--font-weight-strong);
}

/* ============================================================================ the controls */
/* Revision 10: a small tabbed sub-panel naming which aspect the page is showing. It is drawn as
   tabs and exposed as `aria-pressed` buttons inside a group, not as ARIA tabs: revision 9's
   property that no tab role survives anywhere on the page still holds. It spans the column on
   every mode, so the tabs sit in the same place whatever is under them. */
.mode-tabs {
  display: flex;
  border-bottom: var(--border-width) solid var(--color-border);
}
.mode-tabs button {
  height: var(--tab-height);
  margin-bottom: calc(var(--border-width) * -1);
  padding: 0 var(--space-4);
  border: 0;
  border-bottom: var(--border-width-strong) solid transparent;
  border-radius: 0;
  background: transparent;
  font-weight: var(--font-weight-strong);
  color: var(--color-text-label);
}
.mode-tabs button + button {
  border-left: var(--border-width) solid var(--color-divider);
}
.mode-tabs button.on {
  color: var(--color-text);
  border-bottom-color: var(--color-accent);
  background: var(--color-surface-selected);
}
.mode-body {
  padding: var(--panel-padding-block) var(--panel-padding-inline);
}
.mode-body + .mode-body {
  border-top: var(--border-width) solid var(--color-divider);
}
/* Revision 9: the transport is the tape convention — a right-pointing triangle to play, two bars to
   pause — drawn as inline SVG on one button that toggles. The glyphs are `fill: currentColor`, so
   they take the button's ink in both states. Previous and next are `-` and `+`. */
button.transport {
  min-width: 44px;
  padding: 0 var(--space-3);
  display: inline-flex;
  align-items: center;
  justify-content: center;
}
button.transport svg {
  width: 18px;
  height: 18px;
  display: block;
  fill: currentColor;
}
button.transport .glyph-pause {
  display: none;
}
button.transport.is-playing .glyph-play {
  display: none;
}
button.transport.is-playing .glyph-pause {
  display: inline;
}
button.step-nudge {
  min-width: 36px;
  font-weight: var(--font-weight-bold);
  text-align: center;
}
.step-label {
  font-weight: var(--font-weight-strong);
  color: var(--color-text);
  white-space: nowrap;
}
#range-from,
#range-to {
  width: 72px;
  font-weight: var(--font-weight-strong);
}
.range-sep,
.range-figure {
  color: var(--color-text-label);
  white-space: nowrap;
}
.range-figure strong {
  color: var(--color-text);
  font-variant-numeric: tabular-nums;
}
/* Revision 9: how fast the virtual clock runs during playback, 0.05x to 2x on a logarithmic slider.
   It scales playback only — `seek(t)` is still a pure function of its argument. */
#speed {
  width: 130px;
}
#speed-info {
  color: var(--color-text-label);
  width: 54px;
}
#clock {
  font-family: var(--font-mono);
  font-size: var(--font-size-sm);
  color: var(--color-text-label);
  width: 200px;
  text-align: right;
}
/* 'Optimize' becomes 'Restart optimize' the moment a run starts: one slot holds both. */
#optimize {
  width: 152px;
}
#range-duration {
  width: 292px;
}
#range-position {
  width: 252px;
}
#step-label {
  width: 216px;
}
/* The one-line note about the n on show, on its own line at a fixed height, so appearing and
   disappearing cannot change how tall the controls are and therefore how big the stage is. */
#step-note {
  flex: 0 0 100%;
  width: 100%;
  height: var(--line-height-readout);
  line-height: var(--line-height-readout);
}
#continuous-info {
  color: var(--color-text-muted);
}
/* A line of its own, but a fixed one: the annealing readout gains '(styles B and C only)'
   under style A, and with no width of its own that text widened the box it sits in. */
#anneal-info {
  color: var(--color-text-muted);
  width: 396px;
}
#anneal {
  width: 130px;
}
/* A flex row's intrinsic width is the sum of its items whether they wrap or not, so a line placed
   *below* the controls still widens the box that holds it unless the box has a width of its own. */
#shake-box,
#motion-advanced-box {
  flex-basis: 478px;
  max-width: 100%;
}
#law-info,
#rel-info,
#grow-info,
#solver-note {
  height: var(--line-height-readout);
  line-height: var(--line-height-readout);
}
#law-info,
#rel-info,
#grow-info {
  width: 300px;
}
/* Revision 14: **controls sit with the axis they belong to.** Which solver runs is strategy, not
   animation. The select has a width of its own because a `select` is as wide as its widest
   option, and Pack offers one option fewer. */
#solver-box {
  flex-basis: 264px;
}
#solver-note {
  white-space: normal;
}
#style-select {
  width: 118px;
}
#motion-scope-note {
  height: calc(var(--line-height-readout) * 2);
  line-height: var(--line-height-readout);
  white-space: normal;
}
/* A strategy control that cannot affect the current step is visibly and mechanically off. The
   fixed opacity and note slot keep switching solvers from reflowing the panel. */
[data-motion-control="physics"].is-inert {
  opacity: 0.56;
}
[data-motion-control="physics"].is-inert details {
  pointer-events: none;
}
/* Revision 15: the step animation is a whole group in its own row, so removing it in Pack moves
   nothing beside it. */
#step-anim-box.is-off,
#motion-advanced-box.is-off,
.panel-row:has(> #step-anim-box.is-off) {
  display: none;
}
/* Panel bodies: a wrapping line of fields, or a stack of labelled rows. */
.group-body {
  display: flex;
  align-items: center;
  gap: var(--panel-gap);
  flex-wrap: wrap;
}
.group-body.stack,
.rel-body,
.law-body {
  display: flex;
  flex-direction: column;
  align-items: stretch;
  gap: var(--space-1);
}
.law-row {
  display: flex;
  align-items: center;
  gap: var(--panel-gap);
  font-size: var(--font-size-sm);
  color: var(--color-text-label);
}
.law-row > span:first-child {
  min-width: 42px;
}
.law-body .law-row > span:first-child {
  min-width: 88px;
  text-align: right;
}
.group-body.stack .law-row > span:first-child {
  width: 66px;
  text-align: right;
}
.law-row input[type="range"] {
  width: 118px;
}
.rel-body label {
  font-size: var(--font-size-sm);
}
.law-val {
  display: inline-block;
  width: 56px;
  font-variant-numeric: tabular-nums;
  color: var(--color-text);
}
/* Revision 11: the force law, drawn and edited. The plot is the law itself — force against the
   signed gap, both sides of zero, the crossing marked — and its two handles are the four numbers.
   The sliders and the handles are two views of one state. */
/* The plot and its sliders sit side by side, and stack in a narrow window. */
.lawbox {
  display: flex;
  flex-wrap: wrap;
  align-items: flex-start;
  gap: var(--panel-gap) var(--space-4);
}
#law-plot {
  display: block;
  width: 264px;
  height: 116px;
  touch-action: none;
  cursor: crosshair;
}
[data-motion-control="physics"].is-inert #law-plot {
  pointer-events: none;
  cursor: default;
}
#law-plot .lp-field {
  fill: var(--plot-field);
}
#law-plot .lp-zero {
  stroke: var(--plot-zero);
  stroke-width: 1;
}
#law-plot .lp-axis {
  stroke: var(--plot-axis);
  stroke-width: 1;
}
#law-plot .lp-curve {
  fill: none;
  stroke: var(--scene-ink);
  stroke-width: 2;
  stroke-linejoin: round;
}
#law-plot .lp-cross {
  fill: var(--scene-proved);
}
#law-plot .lp-handle {
  fill: var(--scene-paper);
  stroke: var(--scene-ink);
  stroke-width: 2;
  cursor: grab;
}
#law-plot .lp-handle.is-pull {
  stroke: var(--plot-pull);
}
#law-plot text {
  font-family: var(--font-sans);
  font-size: var(--plot-font-size);
  fill: var(--plot-text);
}
#law-plot text.lp-side {
  fill: var(--color-text-label);
  font-weight: var(--font-weight-strong);
}
.law-presets {
  display: flex;
  align-items: center;
  gap: var(--panel-gap);
  flex-wrap: wrap;
}
.motion-advanced {
  color: var(--color-text-label);
  font-size: var(--font-size-sm);
}
.motion-advanced-body,
.motion-response-controls {
  display: flex;
  align-items: center;
  gap: var(--panel-gap);
  flex-wrap: wrap;
}
.motion-advanced-body {
  padding-top: var(--space-1);
}
.motion-advanced-body label {
  display: inline-flex;
  align-items: center;
  gap: var(--field-gap);
  white-space: nowrap;
}
.motion-advanced-body input[type="range"] {
  width: 100px;
}
#motion-response-info {
  color: var(--color-text-muted);
}
#pack-seed {
  width: 112px;
}

/* ============================================================================ modes */
/* Pack: its own workspace under the tabs, and its own facts on the stage. */
body.pack-independent #facts,
body.pack-independent #headline,
body.pack-independent #mask-links,
body.pack-independent #mode-panel,
body.pack-independent #transport-row,
body.pack-independent #panel > .panel-row {
  display: none;
}
body.pack-independent #packing-svg {
  left: 460px;
}
/* The legend explains the catalogue's picture, and Pack and the studio draw their own, centered,
   under where it would sit. Hidden rather than removed, so `placeAttribution` still has its box
   to set the attribution's line by. */
body.pack-independent #stage-note,
body.trace-active #stage-note {
  visibility: hidden;
}
body.pack-independent #pack-stage-facts {
  display: block;
}
/* The box and its trace are the catalogue's drawing of its container (`drawBounds`), and only the
   catalogue's scene updates them. Pack and the animation studio draw into the same stage and the
   same `#container` and draw no box, so while either owns the stage the bounds are hidden and the
   container is drawn. */
body.pack-independent #bound-box,
body.pack-independent #bound-trace,
body.trace-active #bound-box,
body.trace-active #bound-trace {
  display: none;
}
body.pack-independent #container,
body.trace-active #container {
  stroke: var(--scene-frame);
}
/* Search: no stage, and only its own workspace under the tabs. */
body.search-active #stage-wrap,
body.search-active #mode-panel,
body.search-active #transport-row,
body.search-active #panel > .panel-row,
body.search-active #controls > .panel-row {
  display: none;
}
body.search-active #controls {
  max-height: 100vh;
}
/* The animation studio: the trace on the stage and the studio's workspace under the tabs. */
body.trace-active #controls {
  max-height: calc(100vh - min(56.25vw, 42vh));
}
body.trace-active #facts,
body.trace-active #headline,
body.trace-active #mask-links,
body.trace-active #mode-panel,
body.trace-active #transport-row,
body.trace-active #panel > .panel-row,
body.trace-active #controls > .panel-row {
  display: none;
}
body.trace-active #packing-svg {
  left: 50%;
  transform: translateX(-50%);
}
/* A share chosen with the separator fixes the column's height, whatever the mode's own cap. Last,
   so it outranks the modes' `max-height` at equal specificity. */
body #controls.is-sized {
  height: var(--controls-height);
  max-height: none;
}

/* Published data loading must remain visible above the application's fixed viewport. */
#workbench-startup {
  position: fixed;
  inset: 5rem 1rem auto;
  z-index: var(--z-startup);
  max-width: 42rem;
  margin-inline: auto;
  padding: var(--space-4);
  border: var(--border-width) solid currentColor;
  background: var(--bg, #fff);
  color: var(--fg, #222);
}
