From d9f4e38222b1e23237053b503af16dc47935165a Mon Sep 17 00:00:00 2001 From: "russell@unturf.com" Date: Sun, 7 Jun 2026 10:23:01 -0400 Subject: [PATCH] whitepaper-html: left-rail TOC built at runtime from section ids inject-whitepaper-css.py adds CSS for a fixed 280px left sidebar plus a DOMContentLoaded script that walks `section[id] > h2, > h3` and builds a chapter/section nav. IntersectionObserver tracks active section as you scroll; the rail scrolls itself to keep the current entry in view. Below 1100px the rail hides behind a hamburger toggle with backdrop dismiss. Cancels docutils responsive.css `body > *` blanket padding on the rail via the same `all: revert` pattern already used for the uncloseai floating button. 59/59 source sections present in rendered DOM. --- whitepaper/inject-whitepaper-css.py | 223 ++++++++++++++++++++++++++++ whitepaper/lumbda-whitepaper.html | 223 ++++++++++++++++++++++++++++ 2 files changed, 446 insertions(+) diff --git a/whitepaper/inject-whitepaper-css.py b/whitepaper/inject-whitepaper-css.py index 8ff3b5b..ea488a9 100644 --- a/whitepaper/inject-whitepaper-css.py +++ b/whitepaper/inject-whitepaper-css.py @@ -76,6 +76,122 @@ main img, section img {{ object-fit: contain; box-shadow: 0 12px 48px rgba(0, 0, 0, 0.6); }} +/* Left-rail table of contents. Cancels the same docutils responsive.css + `body > *` blanket rule that broke the uncloseai button (padding / + margin / max-width / background / line-height) and then lays the + sidebar out as a fixed left rail on wide viewports. Below 1100px the + sidebar collapses behind a toggle button so it cannot crowd the + single-column reading flow on phones and narrow laptops. */ +body > .wp-toc {{ + all: revert; + position: fixed; + top: 0; + left: 0; + bottom: 0; + width: 280px; + padding: 1.25rem 1rem 1.25rem 1.5rem; + margin: 0; + background: #fafafa; + border-right: 1px solid #e5e5e5; + overflow-y: auto; + overflow-x: hidden; + z-index: 50; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, + Arial, sans-serif; + font-size: 0.82rem; + line-height: 1.4; + box-sizing: border-box; +}} +.wp-toc-title {{ + font-family: 'chunkfive', Georgia, serif; + font-size: 1.15rem; + margin: 0 0 0.6rem 0; + color: #227842; + letter-spacing: 0.02em; +}} +.wp-toc-title .period {{ color: #227842; }} +.wp-toc ol {{ + list-style: none; + padding: 0; + margin: 0; +}} +.wp-toc li {{ + margin: 0; +}} +.wp-toc a {{ + display: block; + padding: 0.22rem 0.4rem; + color: #333; + text-decoration: none; + border-left: 2px solid transparent; + border-radius: 0 3px 3px 0; + word-wrap: break-word; +}} +.wp-toc a:hover {{ + background: #efefef; + color: #000; +}} +.wp-toc a.active {{ + background: #e8f1ec; + color: #155c30; + border-left-color: #227842; + font-weight: 600; +}} +.wp-toc li.lvl-3 a {{ + padding-left: 1.2rem; + font-size: 0.78rem; + color: #555; +}} +.wp-toc li.lvl-3 a.active {{ + color: #155c30; +}} +/* Toggle button — hidden on wide viewports, shown when the sidebar + collapses. Same `all: revert` trick so docutils does not stretch it. */ +body > .wp-toc-toggle {{ + all: revert; + position: fixed; + top: 0.75rem; + left: 0.75rem; + z-index: 51; + width: 2.4rem; + height: 2.4rem; + border: 1px solid #cfcfcf; + border-radius: 4px; + background: #ffffff; + color: #227842; + font-size: 1.2rem; + line-height: 1; + cursor: pointer; + display: none; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); +}} +body > .wp-toc-backdrop {{ + all: revert; + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.35); + z-index: 49; + display: none; +}} +@media (min-width: 1100px) {{ + /* Push the centered docutils column right so it never slides under + the rail. The blanket `body > *` rule already centers content with + huge calc() padding, so we just add a left margin to body. */ + body {{ margin-left: 280px; }} + /* The uncloseai floating button is `position: fixed; left: ...`, so + it sits independent of body margin. No further adjustment. */ +}} +@media (max-width: 1099px) {{ + body > .wp-toc {{ + transform: translateX(-100%); + transition: transform 0.2s ease-out; + width: min(85vw, 320px); + box-shadow: 2px 0 8px rgba(0, 0, 0, 0.12); + }} + body > .wp-toc.open {{ transform: translateX(0); }} + body > .wp-toc-toggle {{ display: block; }} + body > .wp-toc-backdrop.open {{ display: block; }} +}} """ diff --git a/whitepaper/lumbda-whitepaper.html b/whitepaper/lumbda-whitepaper.html index ab00008..86bac0c 100644 --- a/whitepaper/lumbda-whitepaper.html +++ b/whitepaper/lumbda-whitepaper.html @@ -863,6 +863,122 @@ main img, section img { object-fit: contain; box-shadow: 0 12px 48px rgba(0, 0, 0, 0.6); } +/* Left-rail table of contents. Cancels the same docutils responsive.css + `body > *` blanket rule that broke the uncloseai button (padding / + margin / max-width / background / line-height) and then lays the + sidebar out as a fixed left rail on wide viewports. Below 1100px the + sidebar collapses behind a toggle button so it cannot crowd the + single-column reading flow on phones and narrow laptops. */ +body > .wp-toc { + all: revert; + position: fixed; + top: 0; + left: 0; + bottom: 0; + width: 280px; + padding: 1.25rem 1rem 1.25rem 1.5rem; + margin: 0; + background: #fafafa; + border-right: 1px solid #e5e5e5; + overflow-y: auto; + overflow-x: hidden; + z-index: 50; + font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Helvetica, + Arial, sans-serif; + font-size: 0.82rem; + line-height: 1.4; + box-sizing: border-box; +} +.wp-toc-title { + font-family: 'chunkfive', Georgia, serif; + font-size: 1.15rem; + margin: 0 0 0.6rem 0; + color: #227842; + letter-spacing: 0.02em; +} +.wp-toc-title .period { color: #227842; } +.wp-toc ol { + list-style: none; + padding: 0; + margin: 0; +} +.wp-toc li { + margin: 0; +} +.wp-toc a { + display: block; + padding: 0.22rem 0.4rem; + color: #333; + text-decoration: none; + border-left: 2px solid transparent; + border-radius: 0 3px 3px 0; + word-wrap: break-word; +} +.wp-toc a:hover { + background: #efefef; + color: #000; +} +.wp-toc a.active { + background: #e8f1ec; + color: #155c30; + border-left-color: #227842; + font-weight: 600; +} +.wp-toc li.lvl-3 a { + padding-left: 1.2rem; + font-size: 0.78rem; + color: #555; +} +.wp-toc li.lvl-3 a.active { + color: #155c30; +} +/* Toggle button — hidden on wide viewports, shown when the sidebar + collapses. Same `all: revert` trick so docutils does not stretch it. */ +body > .wp-toc-toggle { + all: revert; + position: fixed; + top: 0.75rem; + left: 0.75rem; + z-index: 51; + width: 2.4rem; + height: 2.4rem; + border: 1px solid #cfcfcf; + border-radius: 4px; + background: #ffffff; + color: #227842; + font-size: 1.2rem; + line-height: 1; + cursor: pointer; + display: none; + box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12); +} +body > .wp-toc-backdrop { + all: revert; + position: fixed; + inset: 0; + background: rgba(0, 0, 0, 0.35); + z-index: 49; + display: none; +} +@media (min-width: 1100px) { + /* Push the centered docutils column right so it never slides under + the rail. The blanket `body > *` rule already centers content with + huge calc() padding, so we just add a left margin to body. */ + body { margin-left: 280px; } + /* The uncloseai floating button is `position: fixed; left: ...`, so + it sits independent of body margin. No further adjustment. */ +} +@media (max-width: 1099px) { + body > .wp-toc { + transform: translateX(-100%); + transition: transform 0.2s ease-out; + width: min(85vw, 320px); + box-shadow: 2px 0 8px rgba(0, 0, 0, 0.12); + } + body > .wp-toc.open { transform: translateX(0); } + body > .wp-toc-toggle { display: block; } + body > .wp-toc-backdrop.open { display: block; } +}