OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      e19417749051
DATE      2026-07-17
SUBJECT   web: restore symbols2 subset for box glyphs; fix masthead cell drift
FILES     3 CHANGED
HASH      e19417749051
DATE      2026-07-17
SUBJECT   web: restore symbols2 subset for box
          glyphs; fix masthead cell drift
FILES     3 CHANGED
 

diff --git a/ooknet-design/src/components/ThemeToggle/ThemeToggle.astro b/ooknet-d
esign/src/components/ThemeToggle/ThemeToggle.astro
index 521b7cb..b22beda 100644
--- a/ooknet-design/src/components/ThemeToggle/ThemeToggle.astro
+++ b/ooknet-design/src/components/ThemeToggle/ThemeToggle.astro
@@ -1,4 +1,9 @@
 ---
+// Click handler is delegated in ArticleLayout: this component renders
+// twice (wide + narrow frame), so a per-instance script would bind
+// twice and the toggles would cancel out.
+// NB: nothing may follow the button - this renders inside the masthead
+// <pre>, where a trailing newline or comment becomes a visible cell.
 import "./ThemeToggle.scss";
 ---
 <button
@@ -7,7 +12,3 @@ import "./ThemeToggle.scss";
   aria-label="Toggle dark mode"
   title="Toggle dark mode"
 >[ <span class="theme-toggle-icon" aria-hidden="true">?</span> ]</button>
-
-<!-- Click handler is delegated in ArticleLayout: this component renders
-     twice (wide + narrow frame), so a per-instance script would bind
-     twice and the toggles would cancel out. -->

diff --git a/ooknet-design/src/components/Th
emeToggle/ThemeToggle.astro b/ooknet-design/
src/components/ThemeToggle/ThemeToggle.astro
index 521b7cb..b22beda 100644
--- a/ooknet-design/src/components/ThemeTogg
le/ThemeToggle.astro
+++ b/ooknet-design/src/components/ThemeTogg
le/ThemeToggle.astro
@@ -1,4 +1,9 @@
 ---
+// Click handler is delegated in ArticleLay
out: this component renders
+// twice (wide + narrow frame), so a per-in
stance script would bind
+// twice and the toggles would cancel out.
+// NB: nothing may follow the button - this
 renders inside the masthead
+// <pre>, where a trailing newline or comme
nt becomes a visible cell.
 import "./ThemeToggle.scss";
 ---
 <button
@@ -7,7 +12,3 @@ import "./ThemeToggle.scss"
;
   aria-label="Toggle dark mode"
   title="Toggle dark mode"
 >[ <span class="theme-toggle-icon" aria-hid
den="true">?</span> ]</button>
-
-<!-- Click handler is delegated in ArticleL
ayout: this component renders
-     twice (wide + narrow frame), so a per-
instance script would bind
-     twice and the toggles would cancel out
. -->
 

diff --git a/ooknet-design/src/components/TopHeader/TopHeader.scss b/ooknet-design
/src/components/TopHeader/TopHeader.scss
index 95006c5..014855c 100644
--- a/ooknet-design/src/components/TopHeader/TopHeader.scss
+++ b/ooknet-design/src/components/TopHeader/TopHeader.scss
@@ -32,7 +32,10 @@
   padding: 0;
   margin: 0;
   caret-color: currentColor;
-  width: 20ch;
+  // cell units, not ch - ch resolves against the input's own font
+  // metrics and drifts a fraction of a pixel per cell, which is enough
+  // to overflow the masthead row by a full cell at 20 cells.
+  width: calc(var(--cell-w) * 20);
 
   &::placeholder {
     color: inherit;
@@ -44,7 +47,7 @@
     outline-offset: 2px;
   }
 }
-.frame-narrow .masthead-search-input { width: 18ch; }
+.frame-narrow .masthead-search-input { width: calc(var(--cell-w) * 18); }
 
 // Results dropdown - positioned beneath the masthead row, aligned with
 // the page's content gutter. Hidden until the input has matches.

diff --git a/ooknet-design/src/components/To
pHeader/TopHeader.scss b/ooknet-design/src/c
omponents/TopHeader/TopHeader.scss
index 95006c5..014855c 100644
--- a/ooknet-design/src/components/TopHeader
/TopHeader.scss
+++ b/ooknet-design/src/components/TopHeader
/TopHeader.scss
@@ -32,7 +32,10 @@
   padding: 0;
   margin: 0;
   caret-color: currentColor;
-  width: 20ch;
+  // cell units, not ch - ch resolves again
st the input's own font
+  // metrics and drifts a fraction of a pix
el per cell, which is enough
+  // to overflow the masthead row by a full
 cell at 20 cells.
+  width: calc(var(--cell-w) * 20);
 
   &::placeholder {
     color: inherit;
@@ -44,7 +47,7 @@
     outline-offset: 2px;
   }
 }
-.frame-narrow .masthead-search-input { widt
h: 18ch; }
+.frame-narrow .masthead-search-input { widt
h: calc(var(--cell-w) * 18); }
 
 // Results dropdown - positioned beneath th
e masthead row, aligned with
 // the page's content gutter. Hidden until 
the input has matches.
 

diff --git a/ooknet-design/src/layouts/ArticleLayout/ArticleLayout.astro b/ooknet-
design/src/layouts/ArticleLayout/ArticleLayout.astro
index b91d047..2eefd2b 100644
--- a/ooknet-design/src/layouts/ArticleLayout/ArticleLayout.astro
+++ b/ooknet-design/src/layouts/ArticleLayout/ArticleLayout.astro
@@ -1,12 +1,16 @@
 ---
-// latin-only: the full css ships every script's files into dist (~1MB
-// of fonts the site never uses). 500 dropped - nothing sets it.
-import "@fontsource/ibm-plex-mono/latin-400.css";
-import "@fontsource/ibm-plex-mono/latin-600.css";
-import "@fontsource/ibm-plex-mono/latin-700.css";
-import "@fontsource/ibm-plex-mono/latin-400-italic.css";
-import "@fontsource/cascadia-mono/latin-400.css";
-import "@fontsource/cascadia-mono/latin-700.css";
+// Full css, not the latin-*.css variants: the standalone subset files
+// carry no unicode-range, and box-drawing lives in the symbols2 subset
+// - latin-only imports bend every frame. unicode-range means browsers
+// only download the subsets a page uses (latin + symbols2 here), so
+// the extra files cost dist size, not transfer. 500 dropped - nothing
+// sets it.
+import "@fontsource/ibm-plex-mono/400.css";
+import "@fontsource/ibm-plex-mono/600.css";
+import "@fontsource/ibm-plex-mono/700.css";
+import "@fontsource/ibm-plex-mono/400-italic.css";
+import "@fontsource/cascadia-mono/400.css";
+import "@fontsource/cascadia-mono/700.css";
 import "../../styles/global.scss";
 import "./ArticleLayout.scss";
 import Toast from "../../components/Toast/Toast.astro";
@@ -15,9 +19,12 @@ import Toast from "../../components/Toast/Toast.astro";
 // snaps when the woff2 arrives: visible jitter on each navigation.
 import cascadia400 from "@fontsource/cascadia-mono/files/cascadia-mono-latin-400-
normal.woff2?url";
 import cascadia700 from "@fontsource/cascadia-mono/files/cascadia-mono-latin-700-
normal.woff2?url";
+import cascadiaSym from "@fontsource/cascadia-mono/files/cascadia-mono-symbols2-4
00-normal.woff2?url";
 import plex400 from "@fontsource/ibm-plex-mono/files/ibm-plex-mono-latin-400-norm
al.woff2?url";
 import plex600 from "@fontsource/ibm-plex-mono/files/ibm-plex-mono-latin-600-norm
al.woff2?url";
-const preloadFonts = [cascadia400, cascadia700, plex400, plex600];
+// symbols2 carries the box-drawing glyphs - every frame needs it at
+// first paint just as much as latin.
+const preloadFonts = [cascadia400, cascadia700, cascadiaSym, plex400, plex600];
 const { title = "OOKNET KB" } = Astro.props;
 ---
 <!doctype html>

diff --git a/ooknet-design/src/layouts/Artic
leLayout/ArticleLayout.astro b/ooknet-design
/src/layouts/ArticleLayout/ArticleLayout.ast
ro
index b91d047..2eefd2b 100644
--- a/ooknet-design/src/layouts/ArticleLayou
t/ArticleLayout.astro
+++ b/ooknet-design/src/layouts/ArticleLayou
t/ArticleLayout.astro
@@ -1,12 +1,16 @@
 ---
-// latin-only: the full css ships every scr
ipt's files into dist (~1MB
-// of fonts the site never uses). 500 dropp
ed - nothing sets it.
-import "@fontsource/ibm-plex-mono/latin-400
.css";
-import "@fontsource/ibm-plex-mono/latin-600
.css";
-import "@fontsource/ibm-plex-mono/latin-700
.css";
-import "@fontsource/ibm-plex-mono/latin-400
-italic.css";
-import "@fontsource/cascadia-mono/latin-400
.css";
-import "@fontsource/cascadia-mono/latin-700
.css";
+// Full css, not the latin-*.css variants: 
the standalone subset files
+// carry no unicode-range, and box-drawing 
lives in the symbols2 subset
+// - latin-only imports bend every frame. u
nicode-range means browsers
+// only download the subsets a page uses (l
atin + symbols2 here), so
+// the extra files cost dist size, not tran
sfer. 500 dropped - nothing
+// sets it.
+import "@fontsource/ibm-plex-mono/400.css";
+import "@fontsource/ibm-plex-mono/600.css";
+import "@fontsource/ibm-plex-mono/700.css";
+import "@fontsource/ibm-plex-mono/400-itali
c.css";
+import "@fontsource/cascadia-mono/400.css";
+import "@fontsource/cascadia-mono/700.css";
 import "../../styles/global.scss";
 import "./ArticleLayout.scss";
 import Toast from "../../components/Toast/T
oast.astro";
@@ -15,9 +19,12 @@ import Toast from "../../
components/Toast/Toast.astro";
 // snaps when the woff2 arrives: visible ji
tter on each navigation.
 import cascadia400 from "@fontsource/cascad
ia-mono/files/cascadia-mono-latin-400-normal
.woff2?url";
 import cascadia700 from "@fontsource/cascad
ia-mono/files/cascadia-mono-latin-700-normal
.woff2?url";
+import cascadiaSym from "@fontsource/cascad
ia-mono/files/cascadia-mono-symbols2-400-nor
mal.woff2?url";
 import plex400 from "@fontsource/ibm-plex-m
ono/files/ibm-plex-mono-latin-400-normal.wof
f2?url";
 import plex600 from "@fontsource/ibm-plex-m
ono/files/ibm-plex-mono-latin-600-normal.wof
f2?url";
-const preloadFonts = [cascadia400, cascadia
700, plex400, plex600];
+// symbols2 carries the box-drawing glyphs 
- every frame needs it at
+// first paint just as much as latin.
+const preloadFonts = [cascadia400, cascadia
700, cascadiaSym, plex400, plex600];
 const { title = "OOKNET KB" } = Astro.props
;
 ---
 <!doctype html>
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET