NobGit
public anord read

Ledger

Why work hard when you can work easier?

Languages

Repository composition by tracked source files.

TypeScript
TypeScript 86% CSS 10% SQL 3% Shell 1% HTML 0%
Create file Wiki Documentation
Clone
https://nobgit.com/orgs/anord/ledger.git
ssh://[email protected]:2222/orgs/anord/ledger.git

Commit

Continues UI Fixes part 3

bf8ab75
Alex Nord <[email protected]> 3 months ago
apps/web/src/components/DocsSidebar.tsx |  20 +-
 apps/web/src/components/DraftsPage.tsx  |  22 +-
 apps/web/src/components/EmptyState.tsx  |   4 +-
 apps/web/src/components/PageHeader.tsx  |   2 +-
 apps/web/src/components/SearchBar.tsx   |   6 +-
 apps/web/src/components/SearchPage.tsx  |  26 ++-
 apps/web/src/components/SpacesPage.tsx  |  18 +-
 apps/web/src/docs-theme.css             | 359 +++++++++++++++++++++++++-------
 8 files changed, 350 insertions(+), 107 deletions(-)

Diff

diff --git a/apps/web/src/components/DocsSidebar.tsx b/apps/web/src/components/DocsSidebar.tsx
index d0f0aae..dfcd2c8 100644
--- a/apps/web/src/components/DocsSidebar.tsx
+++ b/apps/web/src/components/DocsSidebar.tsx
@@ -123,10 +123,12 @@ export function DocsSidebar({
       <div className={`sidebar-overlay${isOpen ? " is-open" : ""}`} onClick={onClose} />
       <aside className={`sidebar${isOpen ? " is-open" : ""}`}>
         <div className="sidebar__top">
-          <div>
-            <p className="eyebrow">Workspace</p>
-            <h2 className="sidebar__workspace">Ledger</h2>
-            <p className="muted">{user ? `${user.displayName} - ${user.role}` : "Public knowledge base"}</p>
+          <div className="sidebar__brand">
+            <span className="sidebar__brand-mark">L</span>
+            <div>
+              <h2 className="sidebar__workspace">Ledger</h2>
+              <p className="muted">{user ? "Documentation workspace" : "Public knowledge base"}</p>
+            </div>
           </div>
           <button type="button" className="mobile-only button-ghost" onClick={onClose} aria-label="Close navigation">
             <Icon name="chevronRight" className="icon" />
@@ -261,6 +263,16 @@ export function DocsSidebar({
             })}
           </div>
         </section>
+
+        <div className="sidebar__footer">
+          <div className="sidebar__account">
+            <div className="sidebar__avatar">{user ? user.displayName.slice(0, 1).toUpperCase() : "P"}</div>
+            <div className="sidebar__account-body">
+              <strong>{user?.displayName ?? "Public visitor"}</strong>
+              <span>{user?.role ?? "public"}</span>
+            </div>
+          </div>
+        </div>
       </aside>
     </>
   );
diff --git a/apps/web/src/components/DraftsPage.tsx b/apps/web/src/components/DraftsPage.tsx
index 75a0787..6dcd98a 100644
--- a/apps/web/src/components/DraftsPage.tsx
+++ b/apps/web/src/components/DraftsPage.tsx
@@ -3,6 +3,7 @@ import { Link } from "react-router-dom";
 import type { PageSummary, SessionUser } from "@ledger/shared";
 import { api } from "../lib/api";
 import { EmptyState } from "./EmptyState";
+import { Icon } from "./Icon";
 import { PageHeader } from "./PageHeader";
 
 type Space = {
@@ -43,10 +44,10 @@ export function DraftsPage({
         eyebrow="Drafts"
         title="Work in progress"
         description="Draft pages are only visible to people with the right access. Use this space to review and publish content safely."
-        actions={user && user.role !== "viewer" && user.role !== "public" ? <Link to="/admin/general" className="button-secondary">Create draft</Link> : null}
+        actions={user && user.role !== "viewer" && user.role !== "public" ? <Link to="/spaces" className="button-secondary">New draft</Link> : null}
       />
 
-      <section className="panel">
+      <section className="content-section">
         {loading ? <p className="muted">Loading drafts...</p> : null}
         {!loading && (!user || user.role === "viewer" || user.role === "public") ? (
           <EmptyState
@@ -64,14 +65,19 @@ export function DraftsPage({
           />
         ) : null}
         {!loading && drafts.length > 0 ? (
-          <div className="article-list">
+          <div className="document-feed">
             {drafts.map((page) => (
-              <Link key={page.id} to={`/page/${page.slug}`} className="article-list__item">
-                <div className="article-list__meta">
-                  <strong>{page.title}</strong>
-                  <span>{spaces.find((space) => space.id === page.spaceId)?.name ?? "Collection"}</span>
+              <Link key={page.id} to={`/page/${page.slug}`} className="document-feed__item">
+                <div className="document-feed__icon">
+                  <Icon name="document" className="icon icon-sm" />
+                </div>
+                <div className="document-feed__body">
+                  <strong className="document-feed__title">{page.title}</strong>
+                  <p className="document-feed__meta">
+                    {spaces.find((space) => space.id === page.spaceId)?.name ?? "Collection"} - draft
+                  </p>
+                  <p className="document-feed__excerpt">{page.excerpt ?? "Draft page without an excerpt yet."}</p>
                 </div>
-                <p>{page.excerpt ?? "Draft page without an excerpt yet."}</p>
               </Link>
             ))}
           </div>
diff --git a/apps/web/src/components/EmptyState.tsx b/apps/web/src/components/EmptyState.tsx
index f57efe1..ff7d4b6 100644
--- a/apps/web/src/components/EmptyState.tsx
+++ b/apps/web/src/components/EmptyState.tsx
@@ -14,8 +14,8 @@ export function EmptyState({
   return (
     <section className="empty-state">
       {eyebrow ? <p className="eyebrow">{eyebrow}</p> : null}
-      <h2>{title}</h2>
-      <p className="muted">{description}</p>
+      <h2 className="empty-state__title">{title}</h2>
+      <p className="empty-state__description">{description}</p>
       {action ? <div className="empty-state__action">{action}</div> : null}
     </section>
   );
diff --git a/apps/web/src/components/PageHeader.tsx b/apps/web/src/components/PageHeader.tsx
index 4f47928..f7aea20 100644
--- a/apps/web/src/components/PageHeader.tsx
+++ b/apps/web/src/components/PageHeader.tsx
@@ -13,7 +13,7 @@ export function PageHeader({
 }) {
   return (
     <header className="page-header">
-      <div>
+      <div className="page-header__body">
         {eyebrow ? <p className="eyebrow">{eyebrow}</p> : null}
         <h1>{title}</h1>
         {description ? <p className="lede">{description}</p> : null}
diff --git a/apps/web/src/components/SearchBar.tsx b/apps/web/src/components/SearchBar.tsx
index 8132771..50e808c 100644
--- a/apps/web/src/components/SearchBar.tsx
+++ b/apps/web/src/components/SearchBar.tsx
@@ -21,14 +21,16 @@ export function SearchBar({
 
   return (
     <form className={`search-bar${compact ? " search-bar-compact" : ""}`} onSubmit={handleSubmit}>
-      <Icon name="search" className="icon" />
+      <span className="search-bar__icon">
+        <Icon name="search" className="icon" />
+      </span>
       <input
         value={query}
         onChange={(event) => setQuery(event.target.value)}
         placeholder={placeholder}
         aria-label={placeholder}
       />
-      <button type="submit">{compact ? "Go" : "Search"}</button>
+      <button type="submit" className="search-bar__submit">{compact ? "Go" : "Search"}</button>
     </form>
   );
 }
diff --git a/apps/web/src/components/SearchPage.tsx b/apps/web/src/components/SearchPage.tsx
index 89d6b61..f3aeef9 100644
--- a/apps/web/src/components/SearchPage.tsx
+++ b/apps/web/src/components/SearchPage.tsx
@@ -2,6 +2,7 @@ import { useState } from "react";
 import { Link } from "react-router-dom";
 import type { PageSummary } from "@ledger/shared";
 import { EmptyState } from "./EmptyState";
+import { Icon } from "./Icon";
 import { PageHeader } from "./PageHeader";
 import { SearchBar } from "./SearchBar";
 
@@ -35,10 +36,10 @@ export function SearchPage({
       <PageHeader
         eyebrow="Search"
         title="Find answers quickly"
-        description="Search across every page you’re allowed to read. Results respect the same visibility and group rules as the rest of Ledger."
+        description="Search across every page you're allowed to read. Results respect the same visibility and group rules as the rest of Ledger."
       />
 
-      <section className="panel">
+      <section className="content-section content-section-search">
         <SearchBar
           initialQuery={query}
           onSearch={handleSearch}
@@ -46,8 +47,8 @@ export function SearchPage({
         />
       </section>
 
-      <section className="panel">
-        <div className="panel__header">
+      <section className="content-section">
+        <div className="section-head">
           <div>
             <p className="eyebrow">Results</p>
             <h3>{query ? `Results for "${query}"` : "Search results"}</h3>
@@ -71,14 +72,19 @@ export function SearchPage({
         ) : null}
 
         {!isLoading && results.length > 0 ? (
-          <div className="article-list">
+          <div className="document-feed">
             {results.map((page) => (
-              <Link key={page.id} to={`/page/${page.slug}`} className="article-list__item">
-                <div className="article-list__meta">
-                  <strong>{page.title}</strong>
-                  <span>{spaces.find((space) => space.id === page.spaceId)?.name ?? "Collection"}</span>
+              <Link key={page.id} to={`/page/${page.slug}`} className="document-feed__item">
+                <div className="document-feed__icon">
+                  <Icon name="document" className="icon icon-sm" />
+                </div>
+                <div className="document-feed__body">
+                  <strong className="document-feed__title">{page.title}</strong>
+                  <p className="document-feed__meta">
+                    {spaces.find((space) => space.id === page.spaceId)?.name ?? "Collection"} - {page.visibility}
+                  </p>
+                  <p className="document-feed__excerpt">{page.excerpt ?? "Open this page to read more."}</p>
                 </div>
-                <p>{page.excerpt ?? "Open this page to read more."}</p>
               </Link>
             ))}
           </div>
diff --git a/apps/web/src/components/SpacesPage.tsx b/apps/web/src/components/SpacesPage.tsx
index 6a5f9ee..c09a4bd 100644
--- a/apps/web/src/components/SpacesPage.tsx
+++ b/apps/web/src/components/SpacesPage.tsx
@@ -2,6 +2,7 @@ import { useMemo, useState } from "react";
 import { Link } from "react-router-dom";
 import type { PageSummary } from "@ledger/shared";
 import { EmptyState } from "./EmptyState";
+import { Icon } from "./Icon";
 import { PageHeader } from "./PageHeader";
 
 type Space = {
@@ -68,17 +69,20 @@ export function SpacesPage({
             </button>
           </div>
 
-          <section className="home-stream">
+          <section className="document-feed">
             {visiblePages.map((page) => {
               const space = spaces.find((entry) => entry.id === page.spaceId);
               return (
-                <Link key={page.id} to={`/page/${page.slug}`} className="home-stream__item">
-                  <div className="home-stream__title">
-                    <strong>{page.title}</strong>
+                <Link key={page.id} to={`/page/${page.slug}`} className="document-feed__item">
+                  <div className="document-feed__icon">
+                    <Icon name="document" className="icon icon-sm" />
+                  </div>
+                  <div className="document-feed__body">
+                    <strong className="document-feed__title">{page.title}</strong>
+                    <p className="document-feed__meta">
+                      Updated {new Date(page.updatedAt).toLocaleDateString()} in {space?.name ?? "Collection"} - {page.visibility}
+                    </p>
                   </div>
-                  <p className="home-stream__meta">
-                    Updated {new Date(page.updatedAt).toLocaleDateString()} in {space?.name ?? "Collection"} - {page.visibility}
-                  </p>
                 </Link>
               );
             })}
diff --git a/apps/web/src/docs-theme.css b/apps/web/src/docs-theme.css
index 9c59639..5eea6b4 100644
--- a/apps/web/src/docs-theme.css
+++ b/apps/web/src/docs-theme.css
@@ -1,25 +1,63 @@
 :root {
-  --bg: #0f1115;
-  --bg-elevated: #12151b;
-  --bg-sidebar: #0a0c10;
-  --bg-panel: #12151b;
-  --bg-soft: #10141a;
-  --bg-soft-2: #171b22;
-  --text: #eef2f7;
-  --text-muted: #9aa4b2;
-  --text-soft: #697586;
-  --line: #1b2028;
-  --line-strong: #2a313d;
-  --brand: #f2a43a;
-  --brand-soft: rgba(242, 164, 58, 0.12);
-  --shadow: none;
-  --radius-lg: 2px;
-  --radius-md: 2px;
-  --radius-sm: 2px;
+  color-scheme: dark;
+  --bg: #0f1217;
+  --bg-sidebar: #0b0d12;
+  --bg-elevated: #12161d;
+  --bg-panel: #141922;
+  --bg-soft: #171d27;
+  --bg-soft-2: #1d2430;
+  --bg-hover: rgba(148, 163, 184, 0.08);
+  --bg-active: rgba(138, 160, 196, 0.12);
+  --text: #ebeff6;
+  --text-muted: #96a2b4;
+  --text-soft: #6b778a;
+  --line: rgba(148, 163, 184, 0.12);
+  --line-strong: rgba(148, 163, 184, 0.22);
+  --brand: #e9a23b;
+  --brand-soft: rgba(233, 162, 59, 0.14);
+  --brand-strong: #f4b45a;
+  --radius-lg: 6px;
+  --radius-md: 5px;
+  --radius-sm: 4px;
+  --space-1: 0.25rem;
+  --space-2: 0.5rem;
+  --space-3: 0.75rem;
+  --space-4: 1rem;
+  --space-5: 1.25rem;
+  --space-6: 1.5rem;
+  --space-8: 2rem;
+  --text-xs: 0.76rem;
+  --text-sm: 0.88rem;
+  --text-md: 0.95rem;
+  --text-lg: 1.05rem;
+  --text-xl: 1.35rem;
+  --text-2xl: 2.8rem;
   --sidebar-width: 272px;
   color: var(--text);
   background: var(--bg);
-  font-family: "Segoe UI", "Helvetica Neue", Arial, sans-serif;
+  font-family: Inter, "Segoe UI", "Helvetica Neue", Arial, sans-serif;
+}
+
+@media (prefers-color-scheme: light) {
+  :root {
+    color-scheme: light;
+    --bg: #f6f4ef;
+    --bg-sidebar: #efede7;
+    --bg-elevated: #fbfaf7;
+    --bg-panel: #faf8f4;
+    --bg-soft: #f2eee7;
+    --bg-soft-2: #ebe6dc;
+    --bg-hover: rgba(15, 23, 42, 0.04);
+    --bg-active: rgba(37, 99, 235, 0.08);
+    --text: #171b22;
+    --text-muted: #596579;
+    --text-soft: #7a8596;
+    --line: rgba(15, 23, 42, 0.08);
+    --line-strong: rgba(15, 23, 42, 0.16);
+    --brand: #c97b21;
+    --brand-soft: rgba(201, 123, 33, 0.12);
+    --brand-strong: #b86718;
+  }
 }
 
 * {
@@ -36,6 +74,8 @@ body {
   margin: 0;
   color: var(--text);
   background: var(--bg);
+  font-size: var(--text-md);
+  line-height: 1.5;
 }
 
 a {
@@ -61,9 +101,10 @@ textarea {
   width: 100%;
   border: 1px solid var(--line);
   border-radius: var(--radius-sm);
-  background: var(--bg-soft);
+  background: var(--bg-elevated);
   color: var(--text);
-  padding: 0.8rem 0.9rem;
+  padding: 0.72rem 0.82rem;
+  transition: border-color 140ms ease, background 140ms ease;
 }
 
 textarea {
@@ -93,7 +134,7 @@ a:focus {
 
 .eyebrow {
   margin: 0 0 0.55rem;
-  font-size: 0.7rem;
+  font-size: var(--text-xs);
   font-weight: 700;
   letter-spacing: 0.12em;
   text-transform: uppercase;
@@ -105,8 +146,8 @@ a:focus {
 }
 
 .lede {
-  font-size: 1.05rem;
-  line-height: 1.65;
+  font-size: var(--text-lg);
+  line-height: 1.7;
   color: var(--text-muted);
 }
 
@@ -120,6 +161,7 @@ a:focus {
   padding: 0.62rem 0.85rem;
   background: transparent;
   color: var(--text);
+  transition: background 140ms ease, border-color 140ms ease, color 140ms ease;
 }
 
 .button-secondary {
@@ -127,6 +169,11 @@ a:focus {
   background: transparent;
 }
 
+.button-ghost:hover,
+.button-secondary:hover {
+  background: var(--bg-hover);
+}
+
 .button-primary {
   display: inline-flex;
   align-items: center;
@@ -139,6 +186,10 @@ a:focus {
   font-weight: 600;
 }
 
+.button-primary:hover {
+  background: var(--brand-strong);
+}
+
 button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-link):not(.collection-card):not(.search-launcher):not(.home-tab) {
   border-radius: var(--radius-sm);
   padding: 0.78rem 1rem;
@@ -163,7 +214,10 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
   position: sticky;
   top: 0;
   height: 100vh;
-  padding: 0.75rem 0.65rem 1rem;
+  display: grid;
+  grid-template-rows: auto auto auto 1fr auto;
+  gap: var(--space-4);
+  padding: var(--space-4) var(--space-3) var(--space-4);
   background: var(--bg-sidebar);
   border-right: 1px solid var(--line);
   overflow-y: auto;
@@ -195,10 +249,28 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
 
 .sidebar__workspace {
   margin: 0;
-  font-size: 0.95rem;
+  font-size: var(--text-lg);
   font-weight: 600;
 }
 
+.sidebar__brand {
+  display: flex;
+  align-items: center;
+  gap: var(--space-3);
+}
+
+.sidebar__brand-mark {
+  width: 1.6rem;
+  height: 1.6rem;
+  display: grid;
+  place-items: center;
+  border-radius: 5px;
+  background: linear-gradient(180deg, rgba(255,255,255,0.04), rgba(255,255,255,0));
+  border: 1px solid var(--line);
+  font-size: var(--text-sm);
+  font-weight: 700;
+}
+
 .sidebar-nav,
 .sidebar-list,
 .sidebar-collections,
@@ -213,7 +285,7 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
 }
 
 .sidebar-nav {
-  margin: 0.8rem 0 1.25rem;
+  margin: 0;
 }
 
 .sidebar-nav__item,
@@ -222,22 +294,32 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
   display: flex;
   align-items: center;
   gap: 0.7rem;
-  padding: 0.5rem 0.6rem;
+  min-height: 2.25rem;
+  padding: 0.42rem 0.62rem;
   border-radius: var(--radius-sm);
   color: var(--text-muted);
-  font-size: 0.92rem;
+  font-size: var(--text-sm);
   transition: background 140ms ease, color 140ms ease;
 }
 
 .sidebar-nav__item.is-current,
 .sidebar-doc.is-current,
 .collection-link.is-current {
-  background: #171b22;
+  background: var(--bg-active);
+  color: var(--text);
+}
+
+.sidebar-nav__item:hover,
+.sidebar-doc:hover,
+.collection-link:hover,
+.tree-link:hover,
+.collection-group__header:hover {
+  background: var(--bg-hover);
   color: var(--text);
 }
 
 .sidebar-section {
-  margin-top: 1rem;
+  margin-top: 0;
 }
 
 .sidebar-section__header {
@@ -276,7 +358,8 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
 .collection-group__header {
   width: 100%;
   justify-content: space-between;
-  padding: 0.55rem 0.6rem;
+  min-height: 2.3rem;
+  padding: 0.38rem 0.55rem;
   background: transparent;
   border-top: 1px solid var(--line);
 }
@@ -306,13 +389,13 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
   align-items: center;
   justify-content: space-between;
   gap: 0.7rem;
-  padding: 0.34rem 0.55rem;
+  padding: 0.3rem 0.5rem;
   border-radius: var(--radius-sm);
   color: var(--text-muted);
 }
 
 .tree-item.is-active .tree-link {
-  background: #171b22;
+  background: var(--bg-active);
   color: var(--text);
   box-shadow: inset 2px 0 0 0 var(--brand);
 }
@@ -374,7 +457,7 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
 }
 
 .app-header {
-  padding: 0.72rem 0;
+  padding: var(--space-4) 0 var(--space-3);
   border-bottom: 1px solid var(--line);
 }
 
@@ -397,12 +480,12 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
 }
 
 .search-launcher {
-  min-width: min(520px, 100%);
+  min-width: min(560px, 100%);
   justify-content: space-between;
-  padding: 0.62rem 0.78rem;
+  padding: 0.7rem 0.82rem;
   border-radius: var(--radius-sm);
   border: 1px solid var(--line);
-  background: #0f1318;
+  background: var(--bg-elevated);
   color: var(--text-muted);
   transition: border-color 140ms ease, background 140ms ease, color 140ms ease;
 }
@@ -446,7 +529,7 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
 }
 
 .app-content {
-  padding: 1.1rem 0 2.2rem;
+  padding: var(--space-5) 0 var(--space-8);
 }
 
 .app-footer {
@@ -465,85 +548,105 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
 
 .home-page {
   display: grid;
-  gap: 1rem;
-  max-width: 840px;
+  gap: var(--space-4);
+  max-width: 860px;
   margin: 0 auto;
 }
 
 .home-tabs {
   display: flex;
   align-items: center;
-  gap: 1.35rem;
+  gap: var(--space-5);
   border-bottom: 1px solid var(--line);
 }
 
 .home-tab {
-  padding: 0 0 0.72rem;
+  padding: 0 0 var(--space-3);
   background: transparent;
   color: var(--text-soft);
   border-bottom: 2px solid transparent;
   font-weight: 500;
   border-radius: 0;
+  font-size: var(--text-sm);
 }
 
 .home-tab.is-active {
   color: var(--text);
-  border-bottom-color: #8aa0c4;
+  border-bottom-color: var(--brand-strong);
 }
 
-.home-stream {
+.document-feed {
   display: grid;
 }
 
-.home-stream__item {
+.document-feed__item {
   display: grid;
-  gap: 0.2rem;
+  grid-template-columns: auto 1fr;
+  align-items: start;
+  gap: var(--space-3);
   padding: 0.95rem 0;
   border-bottom: 1px solid var(--line);
-  transition: color 140ms ease, border-color 140ms ease;
+  transition: color 140ms ease, border-color 140ms ease, background 140ms ease;
 }
 
-.home-stream__item:hover {
-  color: #ffffff;
+.document-feed__item:hover {
+  color: var(--text);
   border-bottom-color: var(--line-strong);
 }
 
-.home-stream__title {
-  display: flex;
-  align-items: center;
-  gap: 0.6rem;
+.document-feed__icon {
+  width: 1.1rem;
+  height: 1.1rem;
+  display: grid;
+  place-items: center;
+  color: var(--text-soft);
+  margin-top: 0.18rem;
+}
+
+.document-feed__body {
+  display: grid;
+  gap: 0.2rem;
+}
+
+.document-feed__title {
   font-size: 1rem;
+  font-weight: 600;
+  letter-spacing: -0.01em;
 }
 
-.home-stream__meta {
+.document-feed__meta,
+.document-feed__excerpt {
   margin: 0;
   color: var(--text-muted);
-  font-size: 0.92rem;
+  font-size: var(--text-sm);
+}
+
+.document-feed__excerpt {
+  line-height: 1.55;
 }
 
 .panel-muted {
   background: transparent;
 }
 
-.overview-hero,
 .panel,
 .doc-card,
-.auth-panel,
-.rail-card,
-.auth-form,
-.setup-form {
-  border: 1px solid var(--line);
-  border-radius: var(--radius-lg);
-  background: #10141a;
+.rail-card {
+  border: 0;
+  border-top: 1px solid var(--line);
+  border-radius: 0;
+  background: transparent;
+  padding: var(--space-5) 0;
 }
 
 .overview-hero,
-.doc-card,
 .auth-panel,
-.panel,
 .auth-form,
 .setup-form {
-  padding: 1.05rem 1.1rem;
+  border: 1px solid var(--line);
+  border-radius: var(--radius-lg);
+  background: transparent;
+  padding: var(--space-5) var(--space-5);
 }
 
 .doc-card {
@@ -558,6 +661,11 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
   gap: 1rem;
   align-items: end;
   background: transparent;
+  border: 0;
+  border-bottom: 1px solid var(--line);
+  border-radius: 0;
+  padding-left: 0;
+  padding-right: 0;
 }
 
 .overview-hero h1,
@@ -960,11 +1068,25 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
 .search-bar {
   display: flex;
   align-items: center;
-  gap: 0.65rem;
-  padding: 0.3rem 0.3rem 0.3rem 0.75rem;
+  gap: var(--space-3);
+  padding: 0.35rem;
   border: 1px solid var(--line);
   border-radius: var(--radius-sm);
-  background: var(--bg-soft);
+  background: var(--bg-elevated);
+  transition: border-color 140ms ease, background 140ms ease;
+}
+
+.search-bar:focus-within {
+  border-color: var(--line-strong);
+  background: var(--bg-panel);
+}
+
+.search-bar__icon {
+  display: inline-flex;
+  align-items: center;
+  justify-content: center;
+  width: 1.75rem;
+  color: var(--text-soft);
 }
 
 .search-bar input {
@@ -973,8 +1095,51 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
   background: transparent;
 }
 
+.search-bar__submit {
+  padding: 0.55rem 0.8rem;
+  background: var(--bg-soft);
+  color: var(--text);
+  border: 1px solid var(--line);
+}
+
+.content-section {
+  max-width: 860px;
+  margin: 0 auto;
+  padding: 0;
+}
+
+.content-section-search {
+  padding-bottom: var(--space-2);
+}
+
+.section-head {
+  display: flex;
+  align-items: flex-end;
+  justify-content: space-between;
+  padding-bottom: var(--space-3);
+  border-bottom: 1px solid var(--line);
+  margin-bottom: var(--space-2);
+}
+
 .empty-state {
-  padding: 1rem 0;
+  padding: var(--space-6) 0;
+  max-width: 34rem;
+}
+
+.empty-state__title {
+  margin: 0;
+  font-size: 1.5rem;
+  letter-spacing: -0.02em;
+}
+
+.empty-state__description {
+  margin: 0.7rem 0 0;
+  color: var(--text-muted);
+  line-height: 1.65;
+}
+
+.empty-state__action {
+  margin-top: var(--space-4);
 }
 
 .skeleton {
@@ -1068,13 +1233,13 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
   justify-content: space-between;
   align-items: flex-start;
   gap: 1rem;
-  padding: 0.35rem 0 0.5rem;
+  padding: 0 0 var(--space-4);
   border-bottom: 1px solid var(--line);
 }
 
 .page-header h1 {
   margin: 0;
-  font-size: 3rem;
+  font-size: var(--text-2xl);
   line-height: 1.06;
   letter-spacing: -0.03em;
 }
@@ -1084,6 +1249,10 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
   margin: 0.85rem 0 0;
 }
 
+.page-header__body {
+  max-width: 760px;
+}
+
 .page-header__actions {
   display: flex;
   gap: 0.75rem;
@@ -1105,6 +1274,45 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
   border: 0;
 }
 
+.sidebar__footer {
+  align-self: end;
+  padding-top: var(--space-4);
+  border-top: 1px solid var(--line);
+}
+
+.sidebar__account {
+  display: flex;
+  align-items: center;
+  gap: var(--space-3);
+}
+
+.sidebar__avatar {
+  width: 2rem;
+  height: 2rem;
+  display: grid;
+  place-items: center;
+  border-radius: 999px;
+  background: var(--bg-soft-2);
+  color: var(--text);
+  font-size: var(--text-sm);
+  font-weight: 700;
+}
+
+.sidebar__account-body {
+  display: grid;
+  gap: 0.12rem;
+}
+
+.sidebar__account-body strong {
+  font-size: var(--text-sm);
+}
+
+.sidebar__account-body span {
+  color: var(--text-soft);
+  font-size: var(--text-xs);
+  text-transform: capitalize;
+}
+
 .admin-backlink {
   display: inline-flex;
   align-items: center;
@@ -1178,7 +1386,7 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
   grid-template-columns: minmax(0, 1fr) minmax(220px, 260px);
   gap: 2rem;
   align-items: center;
-  padding: 1rem 0;
+  padding: 1.05rem 0;
   border-bottom: 1px solid var(--line);
 }
 
@@ -1198,6 +1406,11 @@ button:not(.button-ghost):not(.button-secondary):not(.tree-toggle):not(.space-li
   width: 100%;
 }
 
+.settings-row__control :is(input, select) {
+  max-width: 260px;
+  margin-left: auto;
+}
+
 .settings-row__value {
   color: var(--text-muted);
   text-align: left;