OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
HASH      849542ce02a9
DATE      2026-07-18
SUBJECT   web: git header becomes navigation, clickable paths, recent commit bar, prod
          repo root env
FILES     14 CHANGED
HASH      849542ce02a9
DATE      2026-07-18
SUBJECT   web: git header becomes navigation,
          clickable paths, recent commit bar,
          prod repo root env
FILES     14 CHANGED
 

diff --git a/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/re
sults.json b/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/re
sults.json
new file mode 100644
index 0000000..7c4663b
--- /dev/null
+++ b/node_modules/.vite/vitest/da39a3ee5e6b4b0d3255bfef95601890afd80709/results.j
son
@@ -0,0 +1 @@
+{"version":"4.1.10","results":[[":src/components/GitPath/GitPath.test.ts",{"durat
ion":0,"failed":true}]]}
\ No newline at end of file

diff --git a/node_modules/.vite/vitest/da39a
3ee5e6b4b0d3255bfef95601890afd80709/results.
json b/node_modules/.vite/vitest/da39a3ee5e6
b4b0d3255bfef95601890afd80709/results.json
new file mode 100644
index 0000000..7c4663b
--- /dev/null
+++ b/node_modules/.vite/vitest/da39a3ee5e6b
4b0d3255bfef95601890afd80709/results.json
@@ -0,0 +1 @@
+{"version":"4.1.10","results":[[":src/compo
nents/GitPath/GitPath.test.ts",{"duration":0
,"failed":true}]]}
\ No newline at end of file
 

diff --git a/ooknet-design/src/components/GitHeader/GitHeader.astro b/ooknet-desig
n/src/components/GitHeader/GitHeader.astro
new file mode 100644
index 0000000..801f06e
--- /dev/null
+++ b/ooknet-design/src/components/GitHeader/GitHeader.astro
@@ -0,0 +1,20 @@
+---
+import Pre from "../Pre/Pre.astro";
+import Frame from "../Frame/Frame.astro";
+import { rule } from "../../lib/ascii";
+import { FRAME_W, MOBILE_FRAME_W } from "../../lib/config";
+import { GIT_LEFT, REPO_KEY, headerGap, type Props } from "./GitHeader";
+import "./GitHeader.scss";
+
+const { name, slug } = Astro.props as Props;
+const variants: [string, number][] = [
+  ["frame-wide", FRAME_W],
+  ["frame-narrow", MOBILE_FRAME_W],
+];
+---
+<nav class="git-header" aria-label="Repository">
+  {variants.map(([cls, w]) => (
+    <Pre class={cls}><a class="git-link strong" href="/git/">{GIT_LEFT}</a>{heade
rGap(name, w)}{REPO_KEY}<a class="git-link" href={`/git/${slug}/`}>{name.toUpperCa
se()}</a></Pre>
+  ))}
+  <Frame build={(w) => rule(w)} />
+</nav>

diff --git a/ooknet-design/src/components/Gi
tHeader/GitHeader.astro b/ooknet-design/src/
components/GitHeader/GitHeader.astro
new file mode 100644
index 0000000..801f06e
--- /dev/null
+++ b/ooknet-design/src/components/GitHeader
/GitHeader.astro
@@ -0,0 +1,20 @@
+---
+import Pre from "../Pre/Pre.astro";
+import Frame from "../Frame/Frame.astro";
+import { rule } from "../../lib/ascii";
+import { FRAME_W, MOBILE_FRAME_W } from "..
/../lib/config";
+import { GIT_LEFT, REPO_KEY, headerGap, typ
e Props } from "./GitHeader";
+import "./GitHeader.scss";
+
+const { name, slug } = Astro.props as Props
;
+const variants: [string, number][] = [
+  ["frame-wide", FRAME_W],
+  ["frame-narrow", MOBILE_FRAME_W],
+];
+---
+<nav class="git-header" aria-label="Reposit
ory">
+  {variants.map(([cls, w]) => (
+    <Pre class={cls}><a class="git-link str
ong" href="/git/">{GIT_LEFT}</a>{headerGap(n
ame, w)}{REPO_KEY}<a class="git-link" href={
`/git/${slug}/`}>{name.toUpperCase()}</a></P
re>
+  ))}
+  <Frame build={(w) => rule(w)} />
+</nav>
 

diff --git a/ooknet-design/src/components/GitHeader/GitHeader.scss b/ooknet-design
/src/components/GitHeader/GitHeader.scss
new file mode 100644
index 0000000..48a5c73
--- /dev/null
+++ b/ooknet-design/src/components/GitHeader/GitHeader.scss
@@ -0,0 +1,22 @@
+.git-header {
+  display: block;
+}
+
+.git-link {
+  color: var(--ink);
+  text-decoration: none;
+
+  &.strong {
+    font-weight: 600;
+  }
+
+  &:hover {
+    text-decoration: underline;
+    text-underline-offset: 3px;
+  }
+
+  &:focus-visible {
+    outline: 1px dashed var(--ink);
+    outline-offset: 1px;
+  }
+}

diff --git a/ooknet-design/src/components/Gi
tHeader/GitHeader.scss b/ooknet-design/src/c
omponents/GitHeader/GitHeader.scss
new file mode 100644
index 0000000..48a5c73
--- /dev/null
+++ b/ooknet-design/src/components/GitHeader
/GitHeader.scss
@@ -0,0 +1,22 @@
+.git-header {
+  display: block;
+}
+
+.git-link {
+  color: var(--ink);
+  text-decoration: none;
+
+  &.strong {
+    font-weight: 600;
+  }
+
+  &:hover {
+    text-decoration: underline;
+    text-underline-offset: 3px;
+  }
+
+  &:focus-visible {
+    outline: 1px dashed var(--ink);
+    outline-offset: 1px;
+  }
+}
 

diff --git a/ooknet-design/src/components/GitHeader/GitHeader.ts b/ooknet-design/s
rc/components/GitHeader/GitHeader.ts
new file mode 100644
index 0000000..2249c1d
--- /dev/null
+++ b/ooknet-design/src/components/GitHeader/GitHeader.ts
@@ -0,0 +1,19 @@
+// Git navigation header: OOKNET GIT on the left links to the index,
+// the repo name on the right links to the repo home. Layout math only;
+// the anchors live in the astro file.
+import { len } from "../../lib/ascii";
+
+export interface Props {
+  /** Display name, e.g. "ooknet.org". */
+  name: string;
+  slug: string;
+}
+
+export const GIT_LEFT = "OOKNET GIT";
+export const REPO_KEY = "REPO: ";
+
+export function headerGap(name: string, width: number): string {
+  return " ".repeat(
+    Math.max(1, width - len(GIT_LEFT) - len(REPO_KEY) - len(name.toUpperCase())),
+  );
+}

diff --git a/ooknet-design/src/components/Gi
tHeader/GitHeader.ts b/ooknet-design/src/com
ponents/GitHeader/GitHeader.ts
new file mode 100644
index 0000000..2249c1d
--- /dev/null
+++ b/ooknet-design/src/components/GitHeader
/GitHeader.ts
@@ -0,0 +1,19 @@
+// Git navigation header: OOKNET GIT on the
 left links to the index,
+// the repo name on the right links to the 
repo home. Layout math only;
+// the anchors live in the astro file.
+import { len } from "../../lib/ascii";
+
+export interface Props {
+  /** Display name, e.g. "ooknet.org". */
+  name: string;
+  slug: string;
+}
+
+export const GIT_LEFT = "OOKNET GIT";
+export const REPO_KEY = "REPO: ";
+
+export function headerGap(name: string, wid
th: number): string {
+  return " ".repeat(
+    Math.max(1, width - len(GIT_LEFT) - len
(REPO_KEY) - len(name.toUpperCase())),
+  );
+}
 

diff --git a/ooknet-design/src/components/GitPath/GitPath.astro b/ooknet-design/sr
c/components/GitPath/GitPath.astro
new file mode 100644
index 0000000..f53c769
--- /dev/null
+++ b/ooknet-design/src/components/GitPath/GitPath.astro
@@ -0,0 +1,34 @@
+---
+import Pre from "../Pre/Pre.astro";
+import { FRAME_W, MOBILE_FRAME_W } from "../../lib/config";
+import { layoutPath, pathSegs, type PathSeg, type Props } from "./GitPath";
+import "../GitHeader/GitHeader.scss";
+
+const { repo, branch, path, linkLeaf = false } = Astro.props as Props;
+const segs = pathSegs(repo, branch, path, linkLeaf);
+const variants: [string, PathSeg[][]][] = [
+  ["frame-wide", layoutPath(segs, FRAME_W)],
+  ["frame-narrow", layoutPath(segs, MOBILE_FRAME_W)],
+];
+---
+<nav class="git-path" aria-label="Path">
+  {variants.map(([cls, rows]) =>
+    rows.map((row, i) => (
+      <Pre class={cls}>{i > 0 ? "  " : ""}{row.map((s, j) => (
+        <Fragment>{j > 0 || i > 0 ? " / " : ""}{s.href
+          ? <a class="git-link" href={s.href}>{s.label}</a>
+          : <span class="git-path-leaf">{s.label}</span>}</Fragment>
+      ))}</Pre>
+    ))
+  )}
+</nav>
+
+<style lang="scss">
+  .git-path {
+    display: block;
+
+    .git-path-leaf {
+      font-weight: 600;
+    }
+  }
+</style>

diff --git a/ooknet-design/src/components/Gi
tPath/GitPath.astro b/ooknet-design/src/comp
onents/GitPath/GitPath.astro
new file mode 100644
index 0000000..f53c769
--- /dev/null
+++ b/ooknet-design/src/components/GitPath/G
itPath.astro
@@ -0,0 +1,34 @@
+---
+import Pre from "../Pre/Pre.astro";
+import { FRAME_W, MOBILE_FRAME_W } from "..
/../lib/config";
+import { layoutPath, pathSegs, type PathSeg
, type Props } from "./GitPath";
+import "../GitHeader/GitHeader.scss";
+
+const { repo, branch, path, linkLeaf = fals
e } = Astro.props as Props;
+const segs = pathSegs(repo, branch, path, l
inkLeaf);
+const variants: [string, PathSeg[][]][] = [
+  ["frame-wide", layoutPath(segs, FRAME_W)]
,
+  ["frame-narrow", layoutPath(segs, MOBILE_
FRAME_W)],
+];
+---
+<nav class="git-path" aria-label="Path">
+  {variants.map(([cls, rows]) =>
+    rows.map((row, i) => (
+      <Pre class={cls}>{i > 0 ? "  " : ""}{
row.map((s, j) => (
+        <Fragment>{j > 0 || i > 0 ? " / " :
 ""}{s.href
+          ? <a class="git-link" href={s.hre
f}>{s.label}</a>
+          : <span class="git-path-leaf">{s.
label}</span>}</Fragment>
+      ))}</Pre>
+    ))
+  )}
+</nav>
+
+<style lang="scss">
+  .git-path {
+    display: block;
+
+    .git-path-leaf {
+      font-weight: 600;
+    }
+  }
+</style>
 

diff --git a/ooknet-design/src/components/GitPath/GitPath.test.ts b/ooknet-design/
src/components/GitPath/GitPath.test.ts
new file mode 100644
index 0000000..ca68143
--- /dev/null
+++ b/ooknet-design/src/components/GitPath/GitPath.test.ts
@@ -0,0 +1,29 @@
+import { describe, expect, it } from "vitest";
+import { layoutPath, pathSegs } from "./GitPath";
+
+const repo = { name: "ooknet.org", slug: "ooknet-org" };
+
+describe("pathSegs", () => {
+  it("links every segment but the leaf", () => {
+    const segs = pathSegs(repo, "master", "src/lib/git.ts");
+    expect(segs.map((s) => s.label)).toEqual(["ooknet.org", "src", "lib", "git.ts
"]);
+    expect(segs[0].href).toBe("/git/ooknet-org/");
+    expect(segs[1].href).toBe("/git/ooknet-org/tree/master/src/");
+    expect(segs[2].href).toBe("/git/ooknet-org/tree/master/src/lib/");
+    expect(segs[3].href).toBeUndefined();
+  });
+
+  it("links the leaf on tree pages", () => {
+    const segs = pathSegs(repo, "master", "src/lib", true);
+    expect(segs[2].href).toBe("/git/ooknet-org/tree/master/src/lib/");
+  });
+});
+
+describe("layoutPath", () => {
+  it("wraps long paths at segment boundaries", () => {
+    const segs = pathSegs(repo, "master", "a-long-directory/another-long-one/deep
er/file.ts");
+    const rows = layoutPath(segs, 30);
+    expect(rows.length).toBeGreaterThan(1);
+    expect(rows.flat().map((s) => s.label)).toEqual(segs.map((s) => s.label));
+  });
+});

diff --git a/ooknet-design/src/components/Gi
tPath/GitPath.test.ts b/ooknet-design/src/co
mponents/GitPath/GitPath.test.ts
new file mode 100644
index 0000000..ca68143
--- /dev/null
+++ b/ooknet-design/src/components/GitPath/G
itPath.test.ts
@@ -0,0 +1,29 @@
+import { describe, expect, it } from "vites
t";
+import { layoutPath, pathSegs } from "./Git
Path";
+
+const repo = { name: "ooknet.org", slug: "o
oknet-org" };
+
+describe("pathSegs", () => {
+  it("links every segment but the leaf", ()
 => {
+    const segs = pathSegs(repo, "master", "
src/lib/git.ts");
+    expect(segs.map((s) => s.label)).toEqua
l(["ooknet.org", "src", "lib", "git.ts"]);
+    expect(segs[0].href).toBe("/git/ooknet-
org/");
+    expect(segs[1].href).toBe("/git/ooknet-
org/tree/master/src/");
+    expect(segs[2].href).toBe("/git/ooknet-
org/tree/master/src/lib/");
+    expect(segs[3].href).toBeUndefined();
+  });
+
+  it("links the leaf on tree pages", () => 
{
+    const segs = pathSegs(repo, "master", "
src/lib", true);
+    expect(segs[2].href).toBe("/git/ooknet-
org/tree/master/src/lib/");
+  });
+});
+
+describe("layoutPath", () => {
+  it("wraps long paths at segment boundarie
s", () => {
+    const segs = pathSegs(repo, "master", "
a-long-directory/another-long-one/deeper/fil
e.ts");
+    const rows = layoutPath(segs, 30);
+    expect(rows.length).toBeGreaterThan(1);
+    expect(rows.flat().map((s) => s.label))
.toEqual(segs.map((s) => s.label));
+  });
+});
 

diff --git a/ooknet-design/src/components/GitPath/GitPath.ts b/ooknet-design/src/c
omponents/GitPath/GitPath.ts
new file mode 100644
index 0000000..5547942
--- /dev/null
+++ b/ooknet-design/src/components/GitPath/GitPath.ts
@@ -0,0 +1,56 @@
+// Clickable file path, github-style: repo / dir / dir / leaf. Every
+// segment but the last links to its tree page; long paths wrap at
+// segment boundaries.
+import { checkGrid, len } from "../../lib/ascii";
+
+export interface PathSeg {
+  label: string;
+  href?: string;
+}
+
+export interface Props {
+  repo: { name: string; slug: string };
+  branch: string;
+  /** Path within the repo; the leaf gets no link. */
+  path: string;
+  /** Link the leaf too (tree pages: current dir is the leaf). */
+  linkLeaf?: boolean;
+}
+
+export function pathSegs(
+  repo: { name: string; slug: string },
+  branch: string,
+  path: string,
+  linkLeaf = false,
+): PathSeg[] {
+  const segs: PathSeg[] = [{ label: repo.name, href: `/git/${repo.slug}/` }];
+  const parts = path.split("/").filter(Boolean);
+  parts.forEach((part, i) => {
+    const isLeaf = i === parts.length - 1;
+    const sub = parts.slice(0, i + 1).join("/");
+    segs.push({
+      label: part,
+      href: !isLeaf || linkLeaf ? `/git/${repo.slug}/tree/${branch}/${sub}/` : un
defined,
+    });
+  });
+  if (!linkLeaf && segs.length > 1) delete segs[segs.length - 1].href;
+  return segs;
+}
+
+/** Rows of segments fitting `width`; each costs " / " after the first. */
+export function layoutPath(segs: PathSeg[], width: number): PathSeg[][] {
+  const rows: PathSeg[][] = [[]];
+  let used = 0;
+  for (const s of segs) {
+    checkGrid(s.label, width, "git path segment");
+    const w = len(s.label) + (rows[rows.length - 1].length ? 3 : 0);
+    if (rows[rows.length - 1].length && used + w > width) {
+      rows.push([s]);
+      used = len(s.label);
+    } else {
+      rows[rows.length - 1].push(s);
+      used += w;
+    }
+  }
+  return rows;
+}

diff --git a/ooknet-design/src/components/Gi
tPath/GitPath.ts b/ooknet-design/src/compone
nts/GitPath/GitPath.ts
new file mode 100644
index 0000000..5547942
--- /dev/null
+++ b/ooknet-design/src/components/GitPath/G
itPath.ts
@@ -0,0 +1,56 @@
+// Clickable file path, github-style: repo 
/ dir / dir / leaf. Every
+// segment but the last links to its tree p
age; long paths wrap at
+// segment boundaries.
+import { checkGrid, len } from "../../lib/a
scii";
+
+export interface PathSeg {
+  label: string;
+  href?: string;
+}
+
+export interface Props {
+  repo: { name: string; slug: string };
+  branch: string;
+  /** Path within the repo; the leaf gets n
o link. */
+  path: string;
+  /** Link the leaf too (tree pages: curren
t dir is the leaf). */
+  linkLeaf?: boolean;
+}
+
+export function pathSegs(
+  repo: { name: string; slug: string },
+  branch: string,
+  path: string,
+  linkLeaf = false,
+): PathSeg[] {
+  const segs: PathSeg[] = [{ label: repo.na
me, href: `/git/${repo.slug}/` }];
+  const parts = path.split("/").filter(Bool
ean);
+  parts.forEach((part, i) => {
+    const isLeaf = i === parts.length - 1;
+    const sub = parts.slice(0, i + 1).join(
"/");
+    segs.push({
+      label: part,
+      href: !isLeaf || linkLeaf ? `/git/${r
epo.slug}/tree/${branch}/${sub}/` : undefine
d,
+    });
+  });
+  if (!linkLeaf && segs.length > 1) delete 
segs[segs.length - 1].href;
+  return segs;
+}
+
+/** Rows of segments fitting `width`; each 
costs " / " after the first. */
+export function layoutPath(segs: PathSeg[],
 width: number): PathSeg[][] {
+  const rows: PathSeg[][] = [[]];
+  let used = 0;
+  for (const s of segs) {
+    checkGrid(s.label, width, "git path seg
ment");
+    const w = len(s.label) + (rows[rows.len
gth - 1].length ? 3 : 0);
+    if (rows[rows.length - 1].length && use
d + w > width) {
+      rows.push([s]);
+      used = len(s.label);
+    } else {
+      rows[rows.length - 1].push(s);
+      used += w;
+    }
+  }
+  return rows;
+}
 

diff --git a/ooknet-design/src/git.config.ts b/ooknet-design/src/git.config.ts
index e9795bd..e5811a7 100644
--- a/ooknet-design/src/git.config.ts
+++ b/ooknet-design/src/git.config.ts
@@ -1,14 +1,18 @@
 import type { GitRepo } from "./lib/git";
 
-// Repos rendered by /git/. Paths resolve from ooknet-design/ at build
-// time; missing paths are skipped so any machine can build the site.
-// On ooknode these point at forgejo's bare repositories
-// (.../forgejo/data/forgejo-repositories/<owner>/<repo>.git).
+// Repos rendered by /git/. In production the builder sets
+// OOKNET_GIT_ROOT and paths resolve to bare mirrors
+// ($OOKNET_GIT_ROOT/<slug>.git); on dev machines the fallback paths
+// point at local checkouts. Missing paths are skipped either way, so
+// any machine builds. See .internal/deploy-plan.md.
+const ROOT = process.env.OOKNET_GIT_ROOT;
+const at = (slug: string, dev: string) => (ROOT ? `${ROOT}/${slug}.git` : dev);
+
 export const REPOS: GitRepo[] = [
   {
     slug: "ooknet-org",
     name: "ooknet.org",
-    path: "..",
+    path: at("ooknet-org", ".."),
     desc: "personal website - a text-mode knowledge base and the ascii design sys
tem that renders it",
     clone: "https://git.ooknet.org/ooks/ooknet.org.git",
   },

diff --git a/ooknet-design/src/git.config.ts
 b/ooknet-design/src/git.config.ts
index e9795bd..e5811a7 100644
--- a/ooknet-design/src/git.config.ts
+++ b/ooknet-design/src/git.config.ts
@@ -1,14 +1,18 @@
 import type { GitRepo } from "./lib/git";
 
-// Repos rendered by /git/. Paths resolve f
rom ooknet-design/ at build
-// time; missing paths are skipped so any m
achine can build the site.
-// On ooknode these point at forgejo's bare
 repositories
-// (.../forgejo/data/forgejo-repositories/<
owner>/<repo>.git).
+// Repos rendered by /git/. In production t
he builder sets
+// OOKNET_GIT_ROOT and paths resolve to bar
e mirrors
+// ($OOKNET_GIT_ROOT/<slug>.git); on dev ma
chines the fallback paths
+// point at local checkouts. Missing paths 
are skipped either way, so
+// any machine builds. See .internal/deploy
-plan.md.
+const ROOT = process.env.OOKNET_GIT_ROOT;
+const at = (slug: string, dev: string) => (
ROOT ? `${ROOT}/${slug}.git` : dev);
+
 export const REPOS: GitRepo[] = [
   {
     slug: "ooknet-org",
     name: "ooknet.org",
-    path: "..",
+    path: at("ooknet-org", ".."),
     desc: "personal website - a text-mode k
nowledge base and the ascii design system th
at renders it",
     clone: "https://git.ooknet.org/ooks/ook
net.org.git",
   },
 

diff --git a/ooknet-design/src/pages/git/[repo]/blob/[...rest].astro b/ooknet-desi
gn/src/pages/git/[repo]/blob/[...rest].astro
index 2c3a758..34d8762 100644
--- a/ooknet-design/src/pages/git/[repo]/blob/[...rest].astro
+++ b/ooknet-design/src/pages/git/[repo]/blob/[...rest].astro
@@ -1,9 +1,9 @@
 ---
 import ArticleLayout from "../../../../layouts/ArticleLayout/ArticleLayout.astro"
;
 import TopHeader from "../../../../components/TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../../components/ArticleHeader/ArticleHeader.ast
ro";
+import GitHeader from "../../../../components/GitHeader/GitHeader.astro";
+import GitPath from "../../../../components/GitPath/GitPath.astro";
 import Pre from "../../../../components/Pre/Pre.astro";
-import KeyValue from "../../../../components/KeyValue/KeyValue.astro";
 import CodeFrame from "../../../../components/CodeFrame/CodeFrame.astro";
 import Button from "../../../../components/Button/Button.astro";
 import ArticleFooter from "../../../../components/ArticleFooter/ArticleFooter.ast
ro";
@@ -26,23 +26,14 @@ const { repo, branch, file } = Astro.props as { repo: GitRepo;
 branch: string; f
 const blob = readBlob(repo.path, file, branch);
 const name = file.split("/").pop()!;
 const dir = file.includes("/") ? file.slice(0, file.lastIndexOf("/")) : "";
-const chunk = (s: string, n: number) => {
-  const cps = [...s];
-  return Array.from({ length: Math.ceil(cps.length / n) }, (_, i) =>
-    cps.slice(i * n, (i + 1) * n).join(""));
-};
-const pathRows = chunk(toGrid(file), 38);
 ---
 <ArticleLayout title={`GIT - ${repo.name} - ${name}`} description={`${file} in ${
repo.name}.`}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`REPO: ${repo.name.toUpperCase()}`} />
+  <GitHeader name={repo.name} slug={repo.slug} />
   <Pre>{" "}</Pre>
-  <KeyValue entries={[
-    ["FILE", pathRows[0]],
-    ...pathRows.slice(1).map((c) => ["", c] as [string, string]),
-    ["BRANCH", branch],
-    ["LINES", blob.binary ? "BINARY" : `${blob.lines}`],
-  ]} />
+  <GitPath repo={{ name: repo.name, slug: repo.slug }} branch={branch} path={file
} />
+  <Pre>{" "}</Pre>
+  <Pre>{branch} @ {blob.binary ? "BINARY" : `${blob.lines} LINES`}</Pre>
   <Pre>{" "}</Pre>
   <Pre><Button label="HISTORY" href={`/git/${repo.slug}/history/${branch}/${file}
/`} />{"  "}<Button label="UP" href={dir ? `/git/${repo.slug}/tree/${branch}/${dir
}/` : `/git/${repo.slug}/`} /></Pre>
   <Pre>{" "}</Pre>

diff --git a/ooknet-design/src/pages/git/[re
po]/blob/[...rest].astro b/ooknet-design/src
/pages/git/[repo]/blob/[...rest].astro
index 2c3a758..34d8762 100644
--- a/ooknet-design/src/pages/git/[repo]/blo
b/[...rest].astro
+++ b/ooknet-design/src/pages/git/[repo]/blo
b/[...rest].astro
@@ -1,9 +1,9 @@
 ---
 import ArticleLayout from "../../../../layo
uts/ArticleLayout/ArticleLayout.astro";
 import TopHeader from "../../../../componen
ts/TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../../comp
onents/ArticleHeader/ArticleHeader.astro";
+import GitHeader from "../../../../componen
ts/GitHeader/GitHeader.astro";
+import GitPath from "../../../../components
/GitPath/GitPath.astro";
 import Pre from "../../../../components/Pre
/Pre.astro";
-import KeyValue from "../../../../component
s/KeyValue/KeyValue.astro";
 import CodeFrame from "../../../../componen
ts/CodeFrame/CodeFrame.astro";
 import Button from "../../../../components/
Button/Button.astro";
 import ArticleFooter from "../../../../comp
onents/ArticleFooter/ArticleFooter.astro";
@@ -26,23 +26,14 @@ const { repo, branch, fi
le } = Astro.props as { repo: GitRepo; branc
h: string; f
 const blob = readBlob(repo.path, file, bran
ch);
 const name = file.split("/").pop()!;
 const dir = file.includes("/") ? file.slice
(0, file.lastIndexOf("/")) : "";
-const chunk = (s: string, n: number) => {
-  const cps = [...s];
-  return Array.from({ length: Math.ceil(cps
.length / n) }, (_, i) =>
-    cps.slice(i * n, (i + 1) * n).join(""))
;
-};
-const pathRows = chunk(toGrid(file), 38);
 ---
 <ArticleLayout title={`GIT - ${repo.name} -
 ${name}`} description={`${file} in ${repo.n
ame}.`}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`
REPO: ${repo.name.toUpperCase()}`} />
+  <GitHeader name={repo.name} slug={repo.sl
ug} />
   <Pre>{" "}</Pre>
-  <KeyValue entries={[
-    ["FILE", pathRows[0]],
-    ...pathRows.slice(1).map((c) => ["", c]
 as [string, string]),
-    ["BRANCH", branch],
-    ["LINES", blob.binary ? "BINARY" : `${b
lob.lines}`],
-  ]} />
+  <GitPath repo={{ name: repo.name, slug: r
epo.slug }} branch={branch} path={file} />
+  <Pre>{" "}</Pre>
+  <Pre>{branch} @ {blob.binary ? "BINARY" :
 `${blob.lines} LINES`}</Pre>
   <Pre>{" "}</Pre>
   <Pre><Button label="HISTORY" href={`/git/
${repo.slug}/history/${branch}/${file}/`} />
{"  "}<Button label="UP" href={dir ? `/git/$
{repo.slug}/tree/${branch}/${dir}/` : `/git/
${repo.slug}/`} /></Pre>
   <Pre>{" "}</Pre>
 

diff --git a/ooknet-design/src/pages/git/[repo]/commit/[hash].astro b/ooknet-desig
n/src/pages/git/[repo]/commit/[hash].astro
index a262295..cf95bad 100644
--- a/ooknet-design/src/pages/git/[repo]/commit/[hash].astro
+++ b/ooknet-design/src/pages/git/[repo]/commit/[hash].astro
@@ -1,7 +1,7 @@
 ---
 import ArticleLayout from "../../../../layouts/ArticleLayout/ArticleLayout.astro"
;
 import TopHeader from "../../../../components/TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../../components/ArticleHeader/ArticleHeader.ast
ro";
+import GitHeader from "../../../../components/GitHeader/GitHeader.astro";
 import Pre from "../../../../components/Pre/Pre.astro";
 import KeyValue from "../../../../components/KeyValue/KeyValue.astro";
 import CodeFrame from "../../../../components/CodeFrame/CodeFrame.astro";
@@ -27,7 +27,7 @@ const branch = defaultBranch(repo.path);
 ---
 <ArticleLayout title={`GIT - ${repo.name} @ ${hash}`} description={commit.subject
}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`COMMIT: ${hash!.toUpperCase()}`} date=
{commit.date} />
+  <GitHeader name={repo.name} slug={repo.slug} />
   <Pre>{" "}</Pre>
   <KeyValue entries={[
     ["HASH", commit.hash.slice(0, 12)],

diff --git a/ooknet-design/src/pages/git/[re
po]/commit/[hash].astro b/ooknet-design/src/
pages/git/[repo]/commit/[hash].astro
index a262295..cf95bad 100644
--- a/ooknet-design/src/pages/git/[repo]/com
mit/[hash].astro
+++ b/ooknet-design/src/pages/git/[repo]/com
mit/[hash].astro
@@ -1,7 +1,7 @@
 ---
 import ArticleLayout from "../../../../layo
uts/ArticleLayout/ArticleLayout.astro";
 import TopHeader from "../../../../componen
ts/TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../../comp
onents/ArticleHeader/ArticleHeader.astro";
+import GitHeader from "../../../../componen
ts/GitHeader/GitHeader.astro";
 import Pre from "../../../../components/Pre
/Pre.astro";
 import KeyValue from "../../../../component
s/KeyValue/KeyValue.astro";
 import CodeFrame from "../../../../componen
ts/CodeFrame/CodeFrame.astro";
@@ -27,7 +27,7 @@ const branch = defaultBran
ch(repo.path);
 ---
 <ArticleLayout title={`GIT - ${repo.name} @
 ${hash}`} description={commit.subject}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`
COMMIT: ${hash!.toUpperCase()}`} date={commi
t.date} />
+  <GitHeader name={repo.name} slug={repo.sl
ug} />
   <Pre>{" "}</Pre>
   <KeyValue entries={[
     ["HASH", commit.hash.slice(0, 12)],
 

diff --git a/ooknet-design/src/pages/git/[repo]/history/[...rest].astro b/ooknet-d
esign/src/pages/git/[repo]/history/[...rest].astro
index b303792..28fc3cf 100644
--- a/ooknet-design/src/pages/git/[repo]/history/[...rest].astro
+++ b/ooknet-design/src/pages/git/[repo]/history/[...rest].astro
@@ -1,13 +1,12 @@
 ---
 import ArticleLayout from "../../../../layouts/ArticleLayout/ArticleLayout.astro"
;
 import TopHeader from "../../../../components/TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../../components/ArticleHeader/ArticleHeader.ast
ro";
+import GitHeader from "../../../../components/GitHeader/GitHeader.astro";
+import GitPath from "../../../../components/GitPath/GitPath.astro";
 import Pre from "../../../../components/Pre/Pre.astro";
-import KeyValue from "../../../../components/KeyValue/KeyValue.astro";
 import Timeline from "../../../../components/Timeline/Timeline.astro";
 import Button from "../../../../components/Button/Button.astro";
 import ArticleFooter from "../../../../components/ArticleFooter/ArticleFooter.ast
ro";
-import { toGrid } from "../../../../lib/ascii";
 import { REPOS } from "../../../../git.config";
 import { repoAvailable, branches, repoFiles, pathLog, type GitRepo } from "../../
../../lib/git";
 
@@ -24,22 +23,14 @@ export function getStaticPaths() {
 
 const { repo, branch, file } = Astro.props as { repo: GitRepo; branch: string; fi
le: string };
 const log = pathLog(repo.path, file, 200, `/git/${repo.slug}/`, branch);
-const chunk = (s: string, n: number) => {
-  const cps = [...s];
-  return Array.from({ length: Math.ceil(cps.length / n) }, (_, i) =>
-    cps.slice(i * n, (i + 1) * n).join(""));
-};
-const pathRows = chunk(toGrid(file), 38);
 ---
 <ArticleLayout title={`GIT - ${repo.name} - history of ${file}`} description={`Co
mmits touching ${file} in ${repo.name}.`}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`HISTORY @ ${branch.toUpperCase()}`} />
+  <GitHeader name={repo.name} slug={repo.slug} />
   <Pre>{" "}</Pre>
-  <KeyValue entries={[
-    ["FILE", pathRows[0]],
-    ...pathRows.slice(1).map((c) => ["", c] as [string, string]),
-    ["COMMITS", `${log.length}`],
-  ]} />
+  <GitPath repo={{ name: repo.name, slug: repo.slug }} branch={branch} path={file
} />
+  <Pre>{" "}</Pre>
+  <Pre>HISTORY @ {branch} - {log.length} COMMITS</Pre>
   <Pre>{" "}</Pre>
   <Timeline entries={log} />
   <Pre>{" "}</Pre>

diff --git a/ooknet-design/src/pages/git/[re
po]/history/[...rest].astro b/ooknet-design/
src/pages/git/[repo]/history/[...rest].astro
index b303792..28fc3cf 100644
--- a/ooknet-design/src/pages/git/[repo]/his
tory/[...rest].astro
+++ b/ooknet-design/src/pages/git/[repo]/his
tory/[...rest].astro
@@ -1,13 +1,12 @@
 ---
 import ArticleLayout from "../../../../layo
uts/ArticleLayout/ArticleLayout.astro";
 import TopHeader from "../../../../componen
ts/TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../../comp
onents/ArticleHeader/ArticleHeader.astro";
+import GitHeader from "../../../../componen
ts/GitHeader/GitHeader.astro";
+import GitPath from "../../../../components
/GitPath/GitPath.astro";
 import Pre from "../../../../components/Pre
/Pre.astro";
-import KeyValue from "../../../../component
s/KeyValue/KeyValue.astro";
 import Timeline from "../../../../component
s/Timeline/Timeline.astro";
 import Button from "../../../../components/
Button/Button.astro";
 import ArticleFooter from "../../../../comp
onents/ArticleFooter/ArticleFooter.astro";
-import { toGrid } from "../../../../lib/asc
ii";
 import { REPOS } from "../../../../git.conf
ig";
 import { repoAvailable, branches, repoFiles
, pathLog, type GitRepo } from "../../../../
lib/git";
 
@@ -24,22 +23,14 @@ export function getStati
cPaths() {
 
 const { repo, branch, file } = Astro.props 
as { repo: GitRepo; branch: string; file: st
ring };
 const log = pathLog(repo.path, file, 200, `
/git/${repo.slug}/`, branch);
-const chunk = (s: string, n: number) => {
-  const cps = [...s];
-  return Array.from({ length: Math.ceil(cps
.length / n) }, (_, i) =>
-    cps.slice(i * n, (i + 1) * n).join(""))
;
-};
-const pathRows = chunk(toGrid(file), 38);
 ---
 <ArticleLayout title={`GIT - ${repo.name} -
 history of ${file}`} description={`Commits 
touching ${file} in ${repo.name}.`}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`
HISTORY @ ${branch.toUpperCase()}`} />
+  <GitHeader name={repo.name} slug={repo.sl
ug} />
   <Pre>{" "}</Pre>
-  <KeyValue entries={[
-    ["FILE", pathRows[0]],
-    ...pathRows.slice(1).map((c) => ["", c]
 as [string, string]),
-    ["COMMITS", `${log.length}`],
-  ]} />
+  <GitPath repo={{ name: repo.name, slug: r
epo.slug }} branch={branch} path={file} />
+  <Pre>{" "}</Pre>
+  <Pre>HISTORY @ {branch} - {log.length} CO
MMITS</Pre>
   <Pre>{" "}</Pre>
   <Timeline entries={log} />
   <Pre>{" "}</Pre>
 

diff --git a/ooknet-design/src/pages/git/[repo]/index.astro b/ooknet-design/src/pa
ges/git/[repo]/index.astro
index 469f7e3..84a8dbe 100644
--- a/ooknet-design/src/pages/git/[repo]/index.astro
+++ b/ooknet-design/src/pages/git/[repo]/index.astro
@@ -1,17 +1,17 @@
 ---
 import ArticleLayout from "../../../layouts/ArticleLayout/ArticleLayout.astro";
 import TopHeader from "../../../components/TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../components/ArticleHeader/ArticleHeader.astro"
;
+import GitHeader from "../../../components/GitHeader/GitHeader.astro";
 import Frame from "../../../components/Frame/Frame.astro";
 import Pre from "../../../components/Pre/Pre.astro";
-import ArticleMeta from "../../../components/ArticleMeta/ArticleMeta.astro";
 import Menu from "../../../components/Menu/Menu.astro";
 import GitListing from "../../../components/GitListing/GitListing.astro";
 import Timeline from "../../../components/Timeline/Timeline.astro";
 import Button from "../../../components/Button/Button.astro";
 import Prose from "../../../components/Prose/Prose.astro";
 import ArticleFooter from "../../../components/ArticleFooter/ArticleFooter.astro"
;
-import { row2, ruleD } from "../../../lib/ascii";
+import { len, row2, ruleD } from "../../../lib/ascii";
+import { FRAME_W, MOBILE_FRAME_W } from "../../../lib/config";
 import { renderMarkdown } from "../../../lib/markdown";
 import { REPOS } from "../../../git.config";
 import { repoAvailable, repoInfo, branches, dirEntries, repoLog, readReadme, type
 GitRepo } from "../../../lib/git";
@@ -34,25 +34,47 @@ const readmeHtml = readme ? renderMarkdown(readme) : null;
 
 const section = (title: string, right: string) => (w: number) =>
   [row2(title, right, w), ruleD(w)].join("\n");
+
+// recent-commit bar: [hash] subject ... date
+const recentRow = (w: number) => {
+  const hash = `[${info.lastHash}]`;
+  const avail = w - len(hash) - 1 - 12;
+  const subject =
+    len(info.lastSubject) > avail
+      ? [...info.lastSubject].slice(0, avail - 3).join("") + "..."
+      : info.lastSubject;
+  const gap = " ".repeat(Math.max(2, w - len(hash) - 1 - len(subject) - len(info.
lastDate)));
+  return { hash, subject, gap };
+};
+const commitsLabel = `COMMITS: ${info.commits}`;
+const variants: [string, number][] = [
+  ["frame-wide", FRAME_W],
+  ["frame-narrow", MOBILE_FRAME_W],
+];
 ---
 <ArticleLayout title={`GIT - ${repo.name}`} description={repo.desc}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`REPO: ${repo.name.toUpperCase()}`} dat
e={info.lastDate} />
-  <Pre>{" "}</Pre>
-  <ArticleMeta entries={[
-    { key: "COMMITS", value: `${info.commits}`, href: `/git/${repo.slug}/log/${br
anch}/` },
-    { key: "RECENT", value: `${info.lastHash} ${info.lastSubject}`, href: `/git/$
{repo.slug}/commit/${info.lastHash}/` },
-    ...(repo.clone ? [{ key: "CLONE", value: repo.clone.replace(/^https?:\/\//, "
") }] : []),
-  ]} />
+  <GitHeader name={repo.name} slug={repo.slug} />
+  {repo.clone && <Pre>CLONE  {repo.clone.replace(/^https?:\/\//, "")}</Pre>}
   <Pre>{" "}</Pre>
 
-  <Frame build={section("FILES", `${entries.length} ENTRIES`)} />
+  {variants.map(([cls, w]) => (
+    <Pre class={cls}>FILES{" ".repeat(Math.max(1, w - 5 - len(commitsLabel)))}<a 
class="git-link" href={`/git/${repo.slug}/log/${branch}/`}>{commitsLabel}</a></Pre
>
+  ))}
+  <Frame build={(w) => ruleD(w)} />
   <Pre>{" "}</Pre>
   <Pre><Menu label={`BRANCH: ${branch}`} items={allBranches.map((b) => ({
     label: b,
     href: b === branch ? `/git/${repo.slug}/` : `/git/${repo.slug}/tree/${b}/`,
   }))} /></Pre>
   <Pre>{" "}</Pre>
+  {variants.map(([cls, w]) => {
+    const r = recentRow(w);
+    return (
+      <Pre class={cls}><a class="git-link" href={`/git/${repo.slug}/commit/${info
.lastHash}/`}>{r.hash}</a>{" "}{r.subject}{r.gap}{info.lastDate}</Pre>
+    );
+  })}
+  <Pre>{" "}</Pre>
   <GitListing entries={entries}
     treeBase={`/git/${repo.slug}/tree/${branch}/`}
     blobBase={`/git/${repo.slug}/blob/${branch}/`}

diff --git a/ooknet-design/src/pages/git/[re
po]/index.astro b/ooknet-design/src/pages/gi
t/[repo]/index.astro
index 469f7e3..84a8dbe 100644
--- a/ooknet-design/src/pages/git/[repo]/ind
ex.astro
+++ b/ooknet-design/src/pages/git/[repo]/ind
ex.astro
@@ -1,17 +1,17 @@
 ---
 import ArticleLayout from "../../../layouts
/ArticleLayout/ArticleLayout.astro";
 import TopHeader from "../../../components/
TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../compone
nts/ArticleHeader/ArticleHeader.astro";
+import GitHeader from "../../../components/
GitHeader/GitHeader.astro";
 import Frame from "../../../components/Fram
e/Frame.astro";
 import Pre from "../../../components/Pre/Pr
e.astro";
-import ArticleMeta from "../../../component
s/ArticleMeta/ArticleMeta.astro";
 import Menu from "../../../components/Menu/
Menu.astro";
 import GitListing from "../../../components
/GitListing/GitListing.astro";
 import Timeline from "../../../components/T
imeline/Timeline.astro";
 import Button from "../../../components/But
ton/Button.astro";
 import Prose from "../../../components/Pros
e/Prose.astro";
 import ArticleFooter from "../../../compone
nts/ArticleFooter/ArticleFooter.astro";
-import { row2, ruleD } from "../../../lib/a
scii";
+import { len, row2, ruleD } from "../../../
lib/ascii";
+import { FRAME_W, MOBILE_FRAME_W } from "..
/../../lib/config";
 import { renderMarkdown } from "../../../li
b/markdown";
 import { REPOS } from "../../../git.config"
;
 import { repoAvailable, repoInfo, branches,
 dirEntries, repoLog, readReadme, type GitRe
po } from "../../../lib/git";
@@ -34,25 +34,47 @@ const readmeHtml = readm
e ? renderMarkdown(readme) : null;
 
 const section = (title: string, right: stri
ng) => (w: number) =>
   [row2(title, right, w), ruleD(w)].join("\
n");
+
+// recent-commit bar: [hash] subject ... da
te
+const recentRow = (w: number) => {
+  const hash = `[${info.lastHash}]`;
+  const avail = w - len(hash) - 1 - 12;
+  const subject =
+    len(info.lastSubject) > avail
+      ? [...info.lastSubject].slice(0, avai
l - 3).join("") + "..."
+      : info.lastSubject;
+  const gap = " ".repeat(Math.max(2, w - le
n(hash) - 1 - len(subject) - len(info.lastDa
te)));
+  return { hash, subject, gap };
+};
+const commitsLabel = `COMMITS: ${info.commi
ts}`;
+const variants: [string, number][] = [
+  ["frame-wide", FRAME_W],
+  ["frame-narrow", MOBILE_FRAME_W],
+];
 ---
 <ArticleLayout title={`GIT - ${repo.name}`}
 description={repo.desc}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`
REPO: ${repo.name.toUpperCase()}`} date={inf
o.lastDate} />
-  <Pre>{" "}</Pre>
-  <ArticleMeta entries={[
-    { key: "COMMITS", value: `${info.commit
s}`, href: `/git/${repo.slug}/log/${branch}/
` },
-    { key: "RECENT", value: `${info.lastHas
h} ${info.lastSubject}`, href: `/git/${repo.
slug}/commit/${info.lastHash}/` },
-    ...(repo.clone ? [{ key: "CLONE", value
: repo.clone.replace(/^https?:\/\//, "") }] 
: []),
-  ]} />
+  <GitHeader name={repo.name} slug={repo.sl
ug} />
+  {repo.clone && <Pre>CLONE  {repo.clone.re
place(/^https?:\/\//, "")}</Pre>}
   <Pre>{" "}</Pre>
 
-  <Frame build={section("FILES", `${entries
.length} ENTRIES`)} />
+  {variants.map(([cls, w]) => (
+    <Pre class={cls}>FILES{" ".repeat(Math.
max(1, w - 5 - len(commitsLabel)))}<a class=
"git-link" href={`/git/${repo.slug}/log/${br
anch}/`}>{commitsLabel}</a></Pre>
+  ))}
+  <Frame build={(w) => ruleD(w)} />
   <Pre>{" "}</Pre>
   <Pre><Menu label={`BRANCH: ${branch}`} it
ems={allBranches.map((b) => ({
     label: b,
     href: b === branch ? `/git/${repo.slug}
/` : `/git/${repo.slug}/tree/${b}/`,
   }))} /></Pre>
   <Pre>{" "}</Pre>
+  {variants.map(([cls, w]) => {
+    const r = recentRow(w);
+    return (
+      <Pre class={cls}><a class="git-link" 
href={`/git/${repo.slug}/commit/${info.lastH
ash}/`}>{r.hash}</a>{" "}{r.subject}{r.gap}{
info.lastDate}</Pre>
+    );
+  })}
+  <Pre>{" "}</Pre>
   <GitListing entries={entries}
     treeBase={`/git/${repo.slug}/tree/${bra
nch}/`}
     blobBase={`/git/${repo.slug}/blob/${bra
nch}/`}
 

diff --git a/ooknet-design/src/pages/git/[repo]/log/[...branch].astro b/ooknet-des
ign/src/pages/git/[repo]/log/[...branch].astro
index 9453807..4e3363c 100644
--- a/ooknet-design/src/pages/git/[repo]/log/[...branch].astro
+++ b/ooknet-design/src/pages/git/[repo]/log/[...branch].astro
@@ -1,11 +1,13 @@
 ---
 import ArticleLayout from "../../../../layouts/ArticleLayout/ArticleLayout.astro"
;
 import TopHeader from "../../../../components/TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../../components/ArticleHeader/ArticleHeader.ast
ro";
+import GitHeader from "../../../../components/GitHeader/GitHeader.astro";
+import Frame from "../../../../components/Frame/Frame.astro";
 import Pre from "../../../../components/Pre/Pre.astro";
 import Timeline from "../../../../components/Timeline/Timeline.astro";
 import Button from "../../../../components/Button/Button.astro";
 import ArticleFooter from "../../../../components/ArticleFooter/ArticleFooter.ast
ro";
+import { row2, ruleD } from "../../../../lib/ascii";
 import { REPOS } from "../../../../git.config";
 import { repoAvailable, branches, defaultBranch, repoInfo, repoLog, type GitRepo 
} from "../../../../lib/git";
 
@@ -26,7 +28,9 @@ const backHref = isDefault ? `/git/${repo.slug}/` : `/git/${repo
.slug}/tree/${br
 ---
 <ArticleLayout title={`GIT - ${repo.name} - log @ ${branch}`} description={`Commi
t log for ${repo.name} @ ${branch}.`}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`LOG: ${repo.name.toUpperCase()} @ ${br
anch.toUpperCase()}`} date={info.lastDate} />
+  <GitHeader name={repo.name} slug={repo.slug} />
+  <Pre>{" "}</Pre>
+  <Frame build={(w) => [row2(`LOG @ ${branch}`, `${info.commits} COMMITS`, w), ru
leD(w)].join("\n")} />
   <Pre>{" "}</Pre>
   <Timeline entries={log} />
   <Pre>{" "}</Pre>

diff --git a/ooknet-design/src/pages/git/[re
po]/log/[...branch].astro b/ooknet-design/sr
c/pages/git/[repo]/log/[...branch].astro
index 9453807..4e3363c 100644
--- a/ooknet-design/src/pages/git/[repo]/log
/[...branch].astro
+++ b/ooknet-design/src/pages/git/[repo]/log
/[...branch].astro
@@ -1,11 +1,13 @@
 ---
 import ArticleLayout from "../../../../layo
uts/ArticleLayout/ArticleLayout.astro";
 import TopHeader from "../../../../componen
ts/TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../../comp
onents/ArticleHeader/ArticleHeader.astro";
+import GitHeader from "../../../../componen
ts/GitHeader/GitHeader.astro";
+import Frame from "../../../../components/F
rame/Frame.astro";
 import Pre from "../../../../components/Pre
/Pre.astro";
 import Timeline from "../../../../component
s/Timeline/Timeline.astro";
 import Button from "../../../../components/
Button/Button.astro";
 import ArticleFooter from "../../../../comp
onents/ArticleFooter/ArticleFooter.astro";
+import { row2, ruleD } from "../../../../li
b/ascii";
 import { REPOS } from "../../../../git.conf
ig";
 import { repoAvailable, branches, defaultBr
anch, repoInfo, repoLog, type GitRepo } from
 "../../../../lib/git";
 
@@ -26,7 +28,9 @@ const backHref = isDefault
 ? `/git/${repo.slug}/` : `/git/${repo.slug}
/tree/${br
 ---
 <ArticleLayout title={`GIT - ${repo.name} -
 log @ ${branch}`} description={`Commit log 
for ${repo.name} @ ${branch}.`}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`
LOG: ${repo.name.toUpperCase()} @ ${branch.t
oUpperCase()}`} date={info.lastDate} />
+  <GitHeader name={repo.name} slug={repo.sl
ug} />
+  <Pre>{" "}</Pre>
+  <Frame build={(w) => [row2(`LOG @ ${branc
h}`, `${info.commits} COMMITS`, w), ruleD(w)
].join("\n")} />
   <Pre>{" "}</Pre>
   <Timeline entries={log} />
   <Pre>{" "}</Pre>
 

diff --git a/ooknet-design/src/pages/git/[repo]/tree/[...rest].astro b/ooknet-desi
gn/src/pages/git/[repo]/tree/[...rest].astro
index 570a4ff..64f5007 100644
--- a/ooknet-design/src/pages/git/[repo]/tree/[...rest].astro
+++ b/ooknet-design/src/pages/git/[repo]/tree/[...rest].astro
@@ -5,13 +5,14 @@
 // is no ambiguity to parse.
 import ArticleLayout from "../../../../layouts/ArticleLayout/ArticleLayout.astro"
;
 import TopHeader from "../../../../components/TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../../components/ArticleHeader/ArticleHeader.ast
ro";
+import GitHeader from "../../../../components/GitHeader/GitHeader.astro";
+import GitPath from "../../../../components/GitPath/GitPath.astro";
 import Frame from "../../../../components/Frame/Frame.astro";
 import Pre from "../../../../components/Pre/Pre.astro";
 import GitListing from "../../../../components/GitListing/GitListing.astro";
 import Button from "../../../../components/Button/Button.astro";
 import ArticleFooter from "../../../../components/ArticleFooter/ArticleFooter.ast
ro";
-import { row2, ruleD, toGrid } from "../../../../lib/ascii";
+import { row2, ruleD } from "../../../../lib/ascii";
 import { REPOS } from "../../../../git.config";
 import { repoAvailable, branches, defaultBranch, repoFiles, repoDirs, dirEntries,
 type GitRepo } from "../../../../lib/git";
 
@@ -39,16 +40,16 @@ const upHref = dir
       : `/git/${repo.slug}/tree/${branch}/`
   : `/git/${repo.slug}/`;
 
-const where = `/${toGrid(dir)}`;
-const section = (w: number) =>
-  [row2(`FILES @ ${branch}`, where.length > 30 ? "..." + where.slice(-27) : where
, w), ruleD(w)].join("\n");
+const section = (w: number) => [row2(`FILES @ ${branch}`, "", w), ruleD(w)].join(
"\n");
 ---
 <ArticleLayout title={`GIT - ${repo.name} - ${dir || branch}`} description={`${di
r || branch} in ${repo.name}.`}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`REPO: ${repo.name.toUpperCase()}`} />
+  <GitHeader name={repo.name} slug={repo.slug} />
   <Pre>{" "}</Pre>
   <Frame build={section} />
   <Pre>{" "}</Pre>
+  <GitPath repo={{ name: repo.name, slug: repo.slug }} branch={branch} path={dir}
 linkLeaf />
+  <Pre>{" "}</Pre>
   <Pre><Button label="UP" href={upHref} />{"  "}<Button label="LOG" href={`/git/$
{repo.slug}/log/${branch}/`} /></Pre>
   <Pre>{" "}</Pre>
   <GitListing entries={entries}

diff --git a/ooknet-design/src/pages/git/[re
po]/tree/[...rest].astro b/ooknet-design/src
/pages/git/[repo]/tree/[...rest].astro
index 570a4ff..64f5007 100644
--- a/ooknet-design/src/pages/git/[repo]/tre
e/[...rest].astro
+++ b/ooknet-design/src/pages/git/[repo]/tre
e/[...rest].astro
@@ -5,13 +5,14 @@
 // is no ambiguity to parse.
 import ArticleLayout from "../../../../layo
uts/ArticleLayout/ArticleLayout.astro";
 import TopHeader from "../../../../componen
ts/TopHeader/TopHeader.astro";
-import ArticleHeader from "../../../../comp
onents/ArticleHeader/ArticleHeader.astro";
+import GitHeader from "../../../../componen
ts/GitHeader/GitHeader.astro";
+import GitPath from "../../../../components
/GitPath/GitPath.astro";
 import Frame from "../../../../components/F
rame/Frame.astro";
 import Pre from "../../../../components/Pre
/Pre.astro";
 import GitListing from "../../../../compone
nts/GitListing/GitListing.astro";
 import Button from "../../../../components/
Button/Button.astro";
 import ArticleFooter from "../../../../comp
onents/ArticleFooter/ArticleFooter.astro";
-import { row2, ruleD, toGrid } from "../../
../../lib/ascii";
+import { row2, ruleD } from "../../../../li
b/ascii";
 import { REPOS } from "../../../../git.conf
ig";
 import { repoAvailable, branches, defaultBr
anch, repoFiles, repoDirs, dirEntries, type 
GitRepo } from "../../../../lib/git";
 
@@ -39,16 +40,16 @@ const upHref = dir
       : `/git/${repo.slug}/tree/${branch}/`
   : `/git/${repo.slug}/`;
 
-const where = `/${toGrid(dir)}`;
-const section = (w: number) =>
-  [row2(`FILES @ ${branch}`, where.length >
 30 ? "..." + where.slice(-27) : where, w), 
ruleD(w)].join("\n");
+const section = (w: number) => [row2(`FILES
 @ ${branch}`, "", w), ruleD(w)].join("\n");
 ---
 <ArticleLayout title={`GIT - ${repo.name} -
 ${dir || branch}`} description={`${dir || b
ranch} in ${repo.name}.`}>
   <TopHeader />
-  <ArticleHeader left="OOKNET GIT" right={`
REPO: ${repo.name.toUpperCase()}`} />
+  <GitHeader name={repo.name} slug={repo.sl
ug} />
   <Pre>{" "}</Pre>
   <Frame build={section} />
   <Pre>{" "}</Pre>
+  <GitPath repo={{ name: repo.name, slug: r
epo.slug }} branch={branch} path={dir} linkL
eaf />
+  <Pre>{" "}</Pre>
   <Pre><Button label="UP" href={upHref} />{
"  "}<Button label="LOG" href={`/git/${repo.
slug}/log/${branch}/`} /></Pre>
   <Pre>{" "}</Pre>
   <GitListing entries={entries}
 
[ BACK TO LOG ]
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET