OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      67eeefa065ec
DATE      2026-07-17
SUBJECT   web: frame the docs index card
FILES     2 CHANGED
HASH      67eeefa065ec
DATE      2026-07-17
SUBJECT   web: frame the docs index card
FILES     2 CHANGED
 

diff --git a/ooknet-design/src/components/DocsNav/DocsNav.astro b/ooknet-design/sr
c/components/DocsNav/DocsNav.astro
index f0465e6..a69e9ac 100644
--- a/ooknet-design/src/components/DocsNav/DocsNav.astro
+++ b/ooknet-design/src/components/DocsNav/DocsNav.astro
@@ -1,12 +1,14 @@
 ---
 // Docs navigation, rendered twice from one tree: a fixed index card in
 // the backdrop margin when the viewport has room beside the paper, and
-// a collapsed accordion in the content flow everywhere else.
+// a collapsed accordion in the content flow everywhere else. The card
+// draws its own ┌─ INDEX ─┐ frame - like every framed unit on the
+// site - with the tree rows seated between │ rails, Menu-style.
 import Pre from "../Pre/Pre.astro";
 import Tree from "../Tree/Tree.astro";
 import Accordion from "../Accordion/Accordion.astro";
 import { layoutTree } from "../Tree/Tree";
-import { len, rule } from "../../lib/ascii";
+import { G, len, pad } from "../../lib/ascii";
 import { docsTree, type DocEntry } from "../../lib/docs";
 import "./DocsNav.scss";
 
@@ -16,12 +18,23 @@ interface Props {
 }
 const { docs, currentId } = Astro.props as Props;
 const nodes = docsTree(docs, currentId);
-const cardCells = Math.max(12, ...layoutTree(nodes).map((r) => len(r.prefix) + le
n(r.label)));
+const rows = layoutTree(nodes);
+const inner = Math.max(12, ...rows.map((r) => len(r.prefix) + len(r.label)));
+
+const top = `${G.TL}${G.H} INDEX ${G.H.repeat(Math.max(0, inner - 6))}${G.TR}`;
+const blank = `${G.V}${" ".repeat(inner + 2)}${G.V}`;
+const bottom = `${G.BL}${G.H.repeat(inner + 2)}${G.BR}`;
 ---
-<aside class="docs-nav-card" aria-label="Documentation index" style={`--card-cell
s: ${cardCells}`}>
-  <Pre class="docs-nav-title">INDEX</Pre>
-  <Pre class="docs-nav-rule">{rule(cardCells)}</Pre>
-  <Tree nodes={nodes} />
+<aside class="docs-nav-card" aria-label="Documentation index" style={`--card-cell
s: ${inner + 4}`}>
+  <Pre>{top}</Pre>
+  <Pre>{blank}</Pre>
+  {rows.map((r) => (
+    <Pre>{G.V}{" "}{r.prefix}{r.href
+      ? <a class:list={["tree-link", { "tree-current": r.current }]} href={r.href
} aria-current={r.current ? "page" : undefined}>{r.label}</a>
+      : r.label}{" ".repeat(Math.max(0, inner - len(r.prefix) - len(r.label)))}{"
 "}{G.V}</Pre>
+  ))}
+  <Pre>{blank}</Pre>
+  <Pre>{bottom}</Pre>
 </aside>
 <div class="docs-nav-inline">
   <Accordion label="DOC INDEX">

diff --git a/ooknet-design/src/components/Do
csNav/DocsNav.astro b/ooknet-design/src/comp
onents/DocsNav/DocsNav.astro
index f0465e6..a69e9ac 100644
--- a/ooknet-design/src/components/DocsNav/D
ocsNav.astro
+++ b/ooknet-design/src/components/DocsNav/D
ocsNav.astro
@@ -1,12 +1,14 @@
 ---
 // Docs navigation, rendered twice from one
 tree: a fixed index card in
 // the backdrop margin when the viewport ha
s room beside the paper, and
-// a collapsed accordion in the content flo
w everywhere else.
+// a collapsed accordion in the content flo
w everywhere else. The card
+// draws its own ┌─ INDEX ─┐ frame - like e
very framed unit on the
+// site - with the tree rows seated between
 │ rails, Menu-style.
 import Pre from "../Pre/Pre.astro";
 import Tree from "../Tree/Tree.astro";
 import Accordion from "../Accordion/Accordi
on.astro";
 import { layoutTree } from "../Tree/Tree";
-import { len, rule } from "../../lib/ascii"
;
+import { G, len, pad } from "../../lib/asci
i";
 import { docsTree, type DocEntry } from "..
/../lib/docs";
 import "./DocsNav.scss";
 
@@ -16,12 +18,23 @@ interface Props {
 }
 const { docs, currentId } = Astro.props as 
Props;
 const nodes = docsTree(docs, currentId);
-const cardCells = Math.max(12, ...layoutTre
e(nodes).map((r) => len(r.prefix) + len(r.la
bel)));
+const rows = layoutTree(nodes);
+const inner = Math.max(12, ...rows.map((r) 
=> len(r.prefix) + len(r.label)));
+
+const top = `${G.TL}${G.H} INDEX ${G.H.repe
at(Math.max(0, inner - 6))}${G.TR}`;
+const blank = `${G.V}${" ".repeat(inner + 2
)}${G.V}`;
+const bottom = `${G.BL}${G.H.repeat(inner +
 2)}${G.BR}`;
 ---
-<aside class="docs-nav-card" aria-label="Do
cumentation index" style={`--card-cells: ${c
ardCells}`}>
-  <Pre class="docs-nav-title">INDEX</Pre>
-  <Pre class="docs-nav-rule">{rule(cardCell
s)}</Pre>
-  <Tree nodes={nodes} />
+<aside class="docs-nav-card" aria-label="Do
cumentation index" style={`--card-cells: ${i
nner + 4}`}>
+  <Pre>{top}</Pre>
+  <Pre>{blank}</Pre>
+  {rows.map((r) => (
+    <Pre>{G.V}{" "}{r.prefix}{r.href
+      ? <a class:list={["tree-link", { "tre
e-current": r.current }]} href={r.href} aria
-current={r.current ? "page" : undefined}>{r
.label}</a>
+      : r.label}{" ".repeat(Math.max(0, inn
er - len(r.prefix) - len(r.label)))}{" "}{G.
V}</Pre>
+  ))}
+  <Pre>{blank}</Pre>
+  <Pre>{bottom}</Pre>
 </aside>
 <div class="docs-nav-inline">
   <Accordion label="DOC INDEX">
 

diff --git a/ooknet-design/src/components/DocsNav/DocsNav.scss b/ooknet-design/src
/components/DocsNav/DocsNav.scss
index 5580904..b6b8653 100644
--- a/ooknet-design/src/components/DocsNav/DocsNav.scss
+++ b/ooknet-design/src/components/DocsNav/DocsNav.scss
@@ -22,30 +22,21 @@
     display: block;
     position: fixed;
     top: 2.15em;
-    --card-w: calc(var(--cell-w) * var(--card-cells) + 2.4em);
+    // The glyph frame is the border; padding is just a thin paper edge.
+    --card-w: calc(var(--cell-w) * var(--card-cells) + 1em);
     left: calc((100vw - var(--page-w)) / 2 - var(--card-w) - 1.5em);
     width: var(--card-w);
     max-height: calc(100vh - 4.3em);
     overflow-y: auto;
-    padding: 1em 1.2em 1.2em;
+    padding: 0.4em 0.5em;
     background: var(--paper);
     color: var(--ink);
     font-size: var(--fs);
     line-height: var(--lh);
-    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.08), 0 8px 24px -12px rgba(0, 0, 0, 0.1
8);
 
     pre.ascii {
       width: auto;
     }
-
-    .docs-nav-title {
-      font-weight: 700;
-    }
-
-    .docs-nav-rule {
-      margin-bottom: 0.5em;
-      color: var(--ink-soft);
-    }
   }
 }
 

diff --git a/ooknet-design/src/components/Do
csNav/DocsNav.scss b/ooknet-design/src/compo
nents/DocsNav/DocsNav.scss
index 5580904..b6b8653 100644
--- a/ooknet-design/src/components/DocsNav/D
ocsNav.scss
+++ b/ooknet-design/src/components/DocsNav/D
ocsNav.scss
@@ -22,30 +22,21 @@
     display: block;
     position: fixed;
     top: 2.15em;
-    --card-w: calc(var(--cell-w) * var(--ca
rd-cells) + 2.4em);
+    // The glyph frame is the border; paddi
ng is just a thin paper edge.
+    --card-w: calc(var(--cell-w) * var(--ca
rd-cells) + 1em);
     left: calc((100vw - var(--page-w)) / 2 
- var(--card-w) - 1.5em);
     width: var(--card-w);
     max-height: calc(100vh - 4.3em);
     overflow-y: auto;
-    padding: 1em 1.2em 1.2em;
+    padding: 0.4em 0.5em;
     background: var(--paper);
     color: var(--ink);
     font-size: var(--fs);
     line-height: var(--lh);
-    box-shadow: 0 0 0 1px rgba(0, 0, 0, 0.0
8), 0 8px 24px -12px rgba(0, 0, 0, 0.18);
 
     pre.ascii {
       width: auto;
     }
-
-    .docs-nav-title {
-      font-weight: 700;
-    }
-
-    .docs-nav-rule {
-      margin-bottom: 0.5em;
-      color: var(--ink-soft);
-    }
   }
 }
 
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET