summaryrefslogtreecommitdiff
path: root/themes/magical
diff options
context:
space:
mode:
Diffstat (limited to 'themes/magical')
-rw-r--r--themes/magical/home.html352
-rw-r--r--themes/magical/layout.html775
2 files changed, 1127 insertions, 0 deletions
diff --git a/themes/magical/home.html b/themes/magical/home.html
new file mode 100644
index 0000000..bb0e936
--- /dev/null
+++ b/themes/magical/home.html
@@ -0,0 +1,352 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <title>{{ .SiteTitle }}</title>
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
+ <link
+ href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
+ rel="stylesheet"
+ />
+ <style>
+ :root {
+ --bg: #fafafa;
+ --bg-elevated: #ffffff;
+ --text: #0a0a0a;
+ --text-secondary: #525252;
+ --text-muted: #737373;
+ --border: #e5e5e5;
+ --accent: #6366f1;
+ --accent-light: #e0e7ff;
+ --sans:
+ "Inter", -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
+ --mono: "JetBrains Mono", "Fira Code", monospace;
+ --max-width: 720px;
+ --ease: cubic-bezier(0.16, 1, 0.3, 1);
+ }
+
+ *,
+ *::before,
+ *::after {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+
+ html {
+ scroll-behavior: smooth;
+ }
+
+ body {
+ font-family: var(--sans);
+ background: var(--bg);
+ color: var(--text);
+ line-height: 1.6;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ min-height: 100vh;
+ }
+
+ /* ── Layout ── */
+ .page {
+ max-width: var(--max-width);
+ margin: 0 auto;
+ padding: 0 2rem;
+ }
+
+ /* ── Nav ── */
+ nav {
+ display: flex;
+ justify-content: flex-end;
+ align-items: center;
+ padding: 2rem 0 0;
+ gap: 2rem;
+ }
+
+ nav a {
+ font-family: var(--mono);
+ font-size: 0.68rem;
+ letter-spacing: 0.08em;
+ text-transform: uppercase;
+ color: var(--text-muted);
+ text-decoration: none;
+ transition: color 120ms ease;
+ }
+
+ nav a:hover {
+ color: var(--text);
+ }
+
+ /* ── Hero ── */
+ .hero {
+ padding: 5rem 0 4rem;
+ border-bottom: 1px solid var(--border);
+ }
+
+ .hero-name {
+ font-size: clamp(2.2rem, 6vw, 3.5rem);
+ font-weight: 700;
+ line-height: 1.1;
+ letter-spacing: -0.03em;
+ margin-bottom: 1rem;
+ color: var(--text);
+ animation: fadeUp 0.6s var(--ease) both;
+ }
+
+ .hero-role {
+ font-family: var(--mono);
+ font-size: 0.7rem;
+ letter-spacing: 0.1em;
+ text-transform: uppercase;
+ color: var(--text-muted);
+ margin-bottom: 1.25rem;
+ animation: fadeUp 0.6s 0.08s var(--ease) both;
+ }
+
+ .hero-bio {
+ font-size: 1rem;
+ line-height: 1.7;
+ color: var(--text-secondary);
+ max-width: 480px;
+ animation: fadeUp 0.6s 0.15s var(--ease) both;
+ }
+
+ /* ── Writing Header ── */
+ .writing-header {
+ display: flex;
+ align-items: center;
+ gap: 1rem;
+ padding: 2.5rem 0 1.5rem;
+ }
+
+ .writing-label {
+ font-family: var(--mono);
+ font-size: 0.65rem;
+ letter-spacing: 0.12em;
+ text-transform: uppercase;
+ color: var(--text-muted);
+ white-space: nowrap;
+ }
+
+ .writing-rule {
+ flex: 1;
+ height: 1px;
+ background: var(--border);
+ }
+
+ /* ── Post List ── */
+ .post-list {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ }
+
+ .post-item {
+ display: flex;
+ align-items: baseline;
+ gap: 2rem;
+ padding: 1.25rem 0;
+ text-decoration: none;
+ color: inherit;
+ border-bottom: 1px solid var(--border);
+ transition: opacity 140ms ease;
+ animation: fadeUp 0.5s var(--ease) both;
+ }
+
+ .post-item:hover {
+ opacity: 0.6;
+ }
+
+ .post-date {
+ font-family: var(--mono);
+ font-size: 0.65rem;
+ letter-spacing: 0.05em;
+ color: var(--text-muted);
+ white-space: nowrap;
+ flex-shrink: 0;
+ padding-top: 0.15em;
+ min-width: 6rem;
+ }
+
+ .post-right {
+ flex: 1;
+ min-width: 0;
+ }
+
+ .post-title {
+ font-size: 1.1rem;
+ font-weight: 500;
+ color: var(--text);
+ line-height: 1.4;
+ display: block;
+ }
+
+ .post-tags {
+ display: flex;
+ gap: 0.35rem;
+ margin-top: 0.4rem;
+ flex-wrap: wrap;
+ }
+
+ .pill {
+ display: inline-block;
+ font-family: var(--mono);
+ font-size: 0.58rem;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ padding: 0.15rem 0.5rem;
+ background: transparent;
+ border: 1px solid var(--border);
+ border-radius: 100px;
+ color: var(--text-muted);
+ }
+
+ /* ── Empty State ── */
+ .empty {
+ font-family: var(--mono);
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ letter-spacing: 0.06em;
+ padding: 2.5rem 0;
+ }
+
+ /* ── Footer ── */
+ footer {
+ padding: 2.5rem 0 3rem;
+ display: flex;
+ justify-content: space-between;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 0.8rem;
+ font-family: var(--mono);
+ font-size: 0.65rem;
+ letter-spacing: 0.05em;
+ color: var(--text-muted);
+ }
+
+ footer a {
+ color: inherit;
+ text-decoration: underline;
+ text-underline-offset: 3px;
+ text-decoration-color: var(--border);
+ transition: color 120ms ease;
+ }
+
+ footer a:hover {
+ color: var(--text);
+ }
+
+ /* ── Animations ── */
+ @keyframes fadeUp {
+ from {
+ opacity: 0;
+ transform: translateY(10px);
+ }
+ to {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+
+ .post-item:nth-child(1) {
+ animation-delay: 0.2s;
+ }
+ .post-item:nth-child(2) {
+ animation-delay: 0.27s;
+ }
+ .post-item:nth-child(3) {
+ animation-delay: 0.34s;
+ }
+ .post-item:nth-child(4) {
+ animation-delay: 0.41s;
+ }
+ .post-item:nth-child(5) {
+ animation-delay: 0.48s;
+ }
+ .post-item:nth-child(6) {
+ animation-delay: 0.55s;
+ }
+
+ /* ── Mobile ── */
+ @media (max-width: 500px) {
+ .page {
+ padding: 0 1.25rem;
+ }
+ .hero {
+ padding: 3.5rem 0 3rem;
+ }
+ .post-item {
+ flex-direction: column;
+ gap: 0.3rem;
+ }
+ .post-date {
+ min-width: unset;
+ }
+ footer {
+ flex-direction: column;
+ }
+ }
+
+ :focus-visible {
+ outline: 2px solid var(--accent);
+ outline-offset: 2px;
+ border-radius: 4px;
+ }
+ </style>
+ </head>
+ <body>
+ <div class="page">
+ <nav>
+ <a href="#">About</a>
+ <a href="#">Contact</a>
+ </nav>
+
+ <header class="hero">
+ <h1 class="hero-name">{{ .AuthorName }}</h1>
+ <p class="hero-role">{{ .AuthorRole }}</p>
+ <p class="hero-bio">{{ .AuthorBio }}</p>
+ </header>
+
+ <main>
+ <div class="writing-header">
+ <span class="writing-label">Writing</span>
+ <span class="writing-rule"></span>
+ </div>
+
+ {{ if .Posts }}
+ <ul class="post-list">
+ {{ range .Posts }}
+ <li>
+ <a class="post-item" href="/{{ .Slug }}/">
+ <span class="post-date">{{ .Date }}</span>
+ <span class="post-right">
+ <span class="post-title">{{ .Title }}</span>
+ {{ if .Tags }}
+ <span class="post-tags">
+ {{ range .Tags }}
+ <span class="pill">{{ . }}</span>
+ {{ end }}
+ </span>
+ {{ end }}
+ </span>
+ </a>
+ </li>
+ {{ end }}
+ </ul>
+ {{ else }}
+ <p class="empty">No posts yet.</p>
+ {{ end }}
+ </main>
+
+ <footer>
+ <span>&copy; {{ .Year }} {{ .AuthorName }}</span>
+ <span
+ >Built with
+ <a href="https://github.com/HimanshuSardana/kite">kite</a></span
+ >
+ </footer>
+ </div>
+ </body>
+</html>
diff --git a/themes/magical/layout.html b/themes/magical/layout.html
new file mode 100644
index 0000000..bce6818
--- /dev/null
+++ b/themes/magical/layout.html
@@ -0,0 +1,775 @@
+<!doctype html>
+<html lang="en">
+ <head>
+ <meta charset="UTF-8" />
+ <meta name="viewport" content="width=device-width, initial-scale=1.0" />
+ <meta name="description" content="{{ .Title }}" />
+ <title>{{ .Title }}</title>
+
+ <!-- Google Fonts: Playfair Display (Serif) + Inter/Geist (Sans) -->
+ <link rel="preconnect" href="https://fonts.googleapis.com" />
+ <link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
+ <link
+ href="https://fonts.googleapis.com/css2?family=Playfair+Display:ital,wght@0,400..800;1,400..800&family=Inter:wght@300;400;500;600;700&family=JetBrains+Mono:wght@400;500&display=swap"
+ rel="stylesheet"
+ />
+
+ <!-- Prism for Syntax Highlighting -->
+ <link
+ rel="stylesheet"
+ href="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/themes/prism-tomorrow.min.css"
+ />
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/prism.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-go.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-javascript.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-typescript.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-css.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/components/prism-bash.min.js"></script>
+ <script src="https://cdn.jsdelivr.net/npm/prismjs@1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
+
+ <style>
+ /* ── Modern Dark Theme — Editorial + Micro-interactions ── */
+
+ :root {
+ --bg: #09090b; /* Deep zinc */
+ --bg-elevated: rgba(24, 24, 27, 0.65); /* Glassmorphic base */
+ --bg-subtle: rgba(39, 39, 42, 0.5);
+ --bg-hover: rgba(63, 63, 70, 0.4);
+
+ --text: #fafafa;
+ --text-secondary: #a1a1aa;
+ --text-muted: #71717a;
+
+ --border: rgba(63, 63, 70, 0.4);
+ --border-light: rgba(82, 82, 91, 0.5);
+
+ --accent: #818cf8; /* Indigo accent */
+ --accent-glow: rgba(129, 140, 248, 0.4);
+ --accent-dim: rgba(129, 140, 248, 0.08);
+ --code-bg: #111113;
+
+ --serif: "Playfair Display", Georgia, serif;
+ --sans: "Inter", -apple-system, BlinkMacSystemFont, sans-serif;
+ --mono: "JetBrains Mono", monospace;
+
+ --max-width: 700px;
+ --ease-spring: cubic-bezier(
+ 0.25,
+ 1.2,
+ 0.5,
+ 1
+ ); /* Bouncy micro-interaction */
+ --ease-smooth: cubic-bezier(0.16, 1, 0.3, 1);
+ }
+
+ /* ── Base ── */
+ *,
+ *::before,
+ *::after {
+ box-sizing: border-box;
+ margin: 0;
+ padding: 0;
+ }
+ html {
+ scroll-behavior: smooth;
+ }
+
+ body {
+ font-family: var(--sans);
+ background: var(--bg);
+ color: var(--text);
+ line-height: 1.8;
+ font-size: 16px;
+ -webkit-font-smoothing: antialiased;
+ -moz-osx-font-smoothing: grayscale;
+ overflow-x: hidden;
+ }
+
+ /* ── Initial Load Animation ── */
+ @keyframes fadeInSlideUp {
+ 0% {
+ opacity: 0;
+ transform: translateY(20px);
+ }
+ 100% {
+ opacity: 1;
+ transform: translateY(0);
+ }
+ }
+
+ /* ── Article Layout ── */
+ .article {
+ max-width: var(--max-width);
+ margin: 0 auto;
+ padding: 0 2rem 8rem;
+ animation: fadeInSlideUp 0.8s var(--ease-smooth) forwards;
+ }
+
+ /* ── Article Title (h1) ── */
+ h1 {
+ font-family: var(--serif);
+ font-size: clamp(2.2rem, 5vw, 3.5rem);
+ font-weight: 600;
+ line-height: 1.15;
+ letter-spacing: -0.02em;
+ margin-bottom: 2.5rem;
+ color: var(--text);
+ }
+
+ /* ════════════════════════════════════════
+ TOC — Sticky dropdown pill (Glassmorphism)
+ ════════════════════════════════════════ */
+
+ .toc-toggle {
+ display: none !important;
+ }
+ .toc-overlay {
+ display: none !important;
+ }
+
+ .toc {
+ position: sticky;
+ top: 1.5rem;
+ display: flex;
+ justify-content: center;
+ align-items: top;
+ z-index: 50;
+ width: 100%;
+ max-width: 100%;
+ background: transparent;
+ margin-bottom: 3.5rem;
+ }
+
+ /* Pill trigger */
+ .toc-pill {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.6rem;
+ background: var(--bg-elevated);
+ backdrop-filter: blur(12px);
+ -webkit-backdrop-filter: blur(12px);
+ border: 1px solid var(--border);
+ border-radius: 999px;
+ padding: 0.5rem 1rem 0.5rem 0.75rem;
+ cursor: pointer;
+ user-select: none;
+ max-width: 100%;
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2);
+ transition:
+ transform 0.3s var(--ease-spring),
+ border-color 0.3s var(--ease-smooth),
+ box-shadow 0.3s var(--ease-smooth),
+ background 0.3s var(--ease-smooth);
+ }
+
+ /* Pill Hover & Active Micro-interactions */
+ .toc-pill:hover {
+ border-color: var(--border-light);
+ background: rgba(39, 39, 42, 0.7);
+ transform: translateY(-2px);
+ box-shadow:
+ 0 8px 30px rgba(0, 0, 0, 0.4),
+ 0 0 0 1px rgba(129, 140, 248, 0.2);
+ }
+
+ .toc-pill:active {
+ transform: translateY(1px) scale(0.97);
+ }
+
+ /* Spinner */
+ .toc-progress {
+ width: 16px;
+ height: 16px;
+ flex-shrink: 0;
+ overflow: visible;
+ transform: rotate(
+ -90deg
+ ); /* Reset handled in JS too, but good for initial paint */
+ }
+ .toc-progress-track {
+ fill: none;
+ stroke: var(--border);
+ stroke-width: 2.5;
+ }
+ .toc-progress-fill {
+ fill: none;
+ stroke: var(--accent);
+ stroke-width: 2.5;
+ stroke-linecap: round;
+ transition: stroke-dashoffset 0.2s var(--ease-smooth);
+ filter: drop-shadow(0 0 2px var(--accent-glow));
+ }
+
+ .toc-current {
+ font-size: 0.85rem;
+ font-weight: 500;
+ color: var(--text-secondary);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ max-width: 32ch;
+ transition: color 0.3s ease;
+ }
+
+ .toc-pill:hover .toc-current {
+ color: var(--text);
+ }
+
+ .toc-chevron {
+ margin-left: 0.2rem;
+ flex-shrink: 0;
+ color: var(--text-muted);
+ transition:
+ transform 0.4s var(--ease-spring),
+ color 0.3s ease;
+ width: 14px;
+ height: 14px;
+ }
+
+ .toc-pill:hover .toc-chevron {
+ color: var(--text-secondary);
+ }
+
+ .toc[open] .toc-chevron,
+ .toc.open .toc-chevron {
+ transform: rotate(180deg);
+ }
+
+ /* Dropdown panel */
+ .toc-panel {
+ position: absolute;
+ top: calc(100% + 0.75rem);
+ left: 50%;
+ transform: translateX(-50%) translateY(-10px) scale(0.95);
+ min-width: 300px;
+ max-width: min(420px, calc(100vw - 2rem));
+ background: rgba(24, 24, 27, 0.85);
+ backdrop-filter: blur(16px);
+ -webkit-backdrop-filter: blur(16px);
+ border: 1px solid var(--border-light);
+ border-radius: 16px;
+ padding: 0.75rem;
+ box-shadow:
+ 0 10px 40px rgba(0, 0, 0, 0.6),
+ 0 0 0 1px rgba(255, 255, 255, 0.02);
+ opacity: 0;
+ pointer-events: none;
+ transition:
+ opacity 0.3s var(--ease-smooth),
+ transform 0.4s var(--ease-spring);
+ }
+
+ .toc-panel-header {
+ display: flex;
+ align-items: flex-start;
+ gap: 0.7rem;
+ padding: 0.5rem 0.5rem 1rem;
+ border-bottom: 1px solid var(--border);
+ margin-bottom: 0.75rem;
+ }
+
+ .toc-panel-title {
+ font-family: var(--serif);
+ font-size: 1rem;
+ font-weight: 500;
+ color: var(--text);
+ line-height: 1.3;
+ letter-spacing: 0.01em;
+ }
+
+ .toc[open] .toc-panel,
+ .toc.open .toc-panel {
+ opacity: 1;
+ transform: translateX(-50%) translateY(0) scale(1);
+ pointer-events: auto;
+ }
+
+ .toc-list {
+ list-style: none;
+ }
+ .toc-item {
+ margin: 2px 0;
+ }
+
+ .toc-link {
+ display: flex;
+ align-items: center;
+ gap: 0.55rem;
+ padding: 0.5rem 0.75rem;
+ font-size: 0.85rem;
+ color: var(--text-secondary);
+ text-decoration: none;
+ border-radius: 10px;
+ transition: all 0.25s var(--ease-smooth);
+ line-height: 1.4;
+ }
+
+ /* Hover Micro-interaction on List */
+ .toc-link:hover {
+ background: var(--bg-hover);
+ color: var(--text);
+ transform: translateX(4px);
+ }
+
+ .toc-link.active {
+ color: var(--text);
+ background: var(--bg-subtle);
+ font-weight: 500;
+ }
+
+ .toc-link.active::before {
+ content: "";
+ width: 6px;
+ height: 6px;
+ border-radius: 50%;
+ background: var(--accent);
+ box-shadow: 0 0 8px var(--accent-glow);
+ flex-shrink: 0;
+ }
+
+ .toc-level-3 .toc-link {
+ padding-left: 1.75rem;
+ font-size: 0.8rem;
+ color: var(--text-muted);
+ }
+ .toc-level-4 .toc-link {
+ padding-left: 2.5rem;
+ font-size: 0.75rem;
+ color: var(--text-muted);
+ }
+
+ /* ════════════════════════════════════════
+ Content Typography & Playfair Display
+ ════════════════════════════════════════ */
+
+ .content h2 {
+ font-family: var(--serif);
+ font-size: 2rem;
+ font-weight: 500;
+ margin-top: 4rem;
+ margin-bottom: 1.25rem;
+ letter-spacing: -0.01em;
+ color: var(--text);
+ padding-bottom: 0.75rem;
+ border-bottom: 1px solid var(--border);
+ }
+
+ .content h3 {
+ font-family: var(--serif);
+ font-size: 1.5rem;
+ font-weight: 500;
+ margin-top: 3rem;
+ margin-bottom: 1rem;
+ color: var(--text);
+ }
+
+ .content h4 {
+ font-family: var(--serif);
+ font-size: 1.2rem;
+ font-weight: 600;
+ margin-top: 2rem;
+ margin-bottom: 0.75rem;
+ color: var(--text-secondary);
+ }
+
+ .content p {
+ margin-bottom: 1.5rem;
+ color: var(--text-secondary);
+ font-size: 1.05rem;
+ font-weight: 300;
+ }
+
+ /* Inline Link Hover Animation */
+ .content a {
+ color: var(--text);
+ font-weight: 500;
+ text-decoration: none;
+ background-image: linear-gradient(var(--accent), var(--accent));
+ background-size: 0% 1px;
+ background-position: 0 100%;
+ background-repeat: no-repeat;
+ transition:
+ background-size 0.3s var(--ease-smooth),
+ color 0.3s var(--ease-smooth);
+ padding-bottom: 1px;
+ }
+
+ .content a:hover {
+ background-size: 100% 1px;
+ color: var(--accent);
+ }
+
+ .content strong {
+ font-weight: 600;
+ color: var(--text);
+ }
+ .content em {
+ font-style: italic;
+ color: var(--text-secondary);
+ }
+
+ .content ul,
+ .content ol {
+ margin-bottom: 1.5rem;
+ padding-left: 0;
+ color: var(--text-secondary);
+ font-size: 1.05rem;
+ font-weight: 300;
+ list-style: none;
+ }
+
+ .content ul li,
+ .content ol li {
+ position: relative;
+ padding-left: 1.75rem;
+ margin-bottom: 0.6rem;
+ line-height: 1.7;
+ }
+
+ .content ul li::before {
+ content: "";
+ position: absolute;
+ left: 0.25rem;
+ top: 0.65rem;
+ width: 5px;
+ height: 5px;
+ border-radius: 50%;
+ background: var(--accent);
+ opacity: 0.8;
+ }
+
+ .content ol {
+ counter-reset: ol-counter;
+ }
+ .content ol li {
+ counter-increment: ol-counter;
+ }
+ .content ol li::before {
+ content: counter(ol-counter) ".";
+ position: absolute;
+ left: 0;
+ color: var(--accent);
+ font-size: 0.85em;
+ font-weight: 600;
+ font-family: var(--mono);
+ top: 0.1em;
+ background: transparent;
+ width: auto;
+ height: auto;
+ }
+
+ .content code {
+ font-family: var(--mono);
+ font-size: 0.85em;
+ background: var(--bg-subtle);
+ border: 1px solid var(--border);
+ padding: 0.2em 0.4em;
+ border-radius: 6px;
+ color: #c4b5fd;
+ }
+
+ .content pre {
+ margin: 2rem 0;
+ border-radius: 12px;
+ overflow: hidden;
+ border: 1px solid var(--border);
+ background: var(--code-bg);
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.4);
+ transition:
+ border-color 0.3s ease,
+ box-shadow 0.3s ease;
+ }
+
+ .content pre:hover {
+ border-color: var(--border-light);
+ box-shadow: 0 8px 30px rgba(0, 0, 0, 0.6);
+ }
+
+ .content pre code {
+ font-family: var(--mono);
+ font-size: 0.85rem;
+ line-height: 1.7;
+ background: transparent;
+ color: #e2e8f0;
+ padding: 1.5rem;
+ border: none;
+ display: block;
+ overflow-x: auto;
+ }
+
+ .content blockquote {
+ position: relative;
+ padding: 1.5rem 2rem;
+ margin: 2.5rem 0;
+ background: var(--accent-dim);
+ border-left: 3px solid var(--accent);
+ border-radius: 0 12px 12px 0;
+ }
+
+ /* Playfair emphasis for blockquotes */
+ .content blockquote p {
+ font-family: var(--serif);
+ font-size: 1.25rem;
+ color: var(--text);
+ font-style: italic;
+ line-height: 1.6;
+ margin-bottom: 0;
+ }
+
+ .content hr {
+ border: none;
+ height: 1px;
+ background: linear-gradient(
+ 90deg,
+ transparent,
+ var(--border),
+ transparent
+ );
+ margin: 3.5rem 0;
+ }
+
+ .content img {
+ max-width: 100%;
+ border-radius: 12px;
+ margin: 2.5rem 0;
+ border: 1px solid var(--border);
+ box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3);
+ transition:
+ transform 0.4s var(--ease-spring),
+ box-shadow 0.4s var(--ease-smooth);
+ }
+
+ .content img:hover {
+ transform: scale(1.01);
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.5);
+ }
+
+ :focus-visible {
+ outline: 2px solid var(--accent);
+ outline-offset: 4px;
+ border-radius: 6px;
+ }
+
+ @media (max-width: 640px) {
+ .article {
+ padding: 0 1.25rem 5rem;
+ }
+ h1 {
+ font-size: 2rem;
+ margin-bottom: 2rem;
+ }
+ .content h2 {
+ font-size: 1.6rem;
+ margin-top: 3rem;
+ }
+ .content h3 {
+ font-size: 1.3rem;
+ }
+ .toc-current {
+ max-width: 20ch;
+ }
+ .toc-panel {
+ max-width: calc(100vw - 2.5rem);
+ }
+ .content blockquote {
+ padding: 1.2rem 1.5rem;
+ }
+ }
+ </style>
+ </head>
+ <body>
+ <main class="article">
+ <div class="toc" id="toc">
+ <!-- Pill trigger -->
+ <div
+ class="toc-pill"
+ id="toc-pill"
+ role="button"
+ aria-expanded="false"
+ aria-controls="toc-panel"
+ tabindex="0"
+ >
+ <!-- Section progress ring -->
+ <svg class="toc-progress" viewBox="0 0 16 16" aria-hidden="true">
+ <circle class="toc-progress-track" cx="8" cy="8" r="6" />
+ <circle
+ class="toc-progress-fill"
+ cx="8"
+ cy="8"
+ r="6"
+ id="toc-progress-fill"
+ />
+ </svg>
+ <span class="toc-current" id="toc-current"
+ >{{ (index .TOC 0).Text }}</span
+ >
+ <svg
+ class="toc-chevron"
+ viewBox="0 0 16 16"
+ fill="none"
+ stroke="currentColor"
+ stroke-width="2"
+ stroke-linecap="round"
+ stroke-linejoin="round"
+ aria-hidden="true"
+ >
+ <polyline points="4 6 8 10 12 6" />
+ </svg>
+ </div>
+
+ <!-- Dropdown panel -->
+ <div class="toc-panel" id="toc-panel" role="listbox">
+ <div class="toc-panel-header">
+ <svg
+ class="toc-progress"
+ viewBox="0 0 16 16"
+ aria-hidden="true"
+ style="margin-top: 3px; flex-shrink: 0"
+ >
+ <circle class="toc-progress-track" cx="8" cy="8" r="6" />
+ <circle
+ class="toc-progress-fill"
+ cx="8"
+ cy="8"
+ r="6"
+ id="toc-progress-fill-panel"
+ />
+ </svg>
+ <span class="toc-panel-title">{{ .Title }}</span>
+ </div>
+
+ <ul class="toc-list">
+ {{ range .TOC }}
+ <li class="toc-item toc-level-{{ .Level }}">
+ <a class="toc-link" href="#{{ .ID }}">{{ .Text }}</a>
+ </li>
+ {{ end }}
+ </ul>
+ </div>
+ </div>
+
+ <h1>{{ .Title }}</h1>
+ <div class="content">{{ .Content }}</div>
+ </main>
+
+ <script>
+ (function () {
+ const toc = document.getElementById("toc");
+ const pill = document.getElementById("toc-pill");
+ const panel = document.getElementById("toc-panel");
+ const currentLabel = document.getElementById("toc-current");
+ const fillPill = document.getElementById("toc-progress-fill");
+ const fillPanel = document.getElementById("toc-progress-fill-panel");
+
+ if (!toc || !pill) return;
+
+ // ── Circle geometry ──
+ const CIRCUMFERENCE = 2 * Math.PI * 6;
+
+ [fillPill, fillPanel].forEach((el) => {
+ if (!el) return;
+ el.style.strokeDasharray = CIRCUMFERENCE;
+ el.style.strokeDashoffset = CIRCUMFERENCE;
+ el.style.transform = "rotate(-90deg)";
+ el.style.transformOrigin = "50% 50%";
+ });
+
+ function setProgress(ratio) {
+ const offset = CIRCUMFERENCE * (1 - Math.min(1, Math.max(0, ratio)));
+ [fillPill, fillPanel].forEach((el) => {
+ if (el) el.style.strokeDashoffset = offset;
+ });
+ }
+
+ // ── Toggle open/close ──
+ function openToc() {
+ toc.classList.add("open");
+ pill.setAttribute("aria-expanded", "true");
+ }
+ function closeToc() {
+ toc.classList.remove("open");
+ pill.setAttribute("aria-expanded", "false");
+ }
+ function toggle() {
+ toc.classList.contains("open") ? closeToc() : openToc();
+ }
+
+ pill.addEventListener("click", toggle);
+ pill.addEventListener("keydown", (e) => {
+ if (e.key === "Enter" || e.key === " ") {
+ e.preventDefault();
+ toggle();
+ }
+ });
+
+ document.addEventListener("click", (e) => {
+ if (!toc.contains(e.target)) closeToc();
+ });
+
+ panel.querySelectorAll(".toc-link").forEach((link) => {
+ link.addEventListener("click", () => closeToc());
+ });
+
+ // ── Section tracking ──
+ const links = Array.from(panel.querySelectorAll(".toc-link"));
+ if (!links.length) return;
+
+ const ids = links.map((a) =>
+ decodeURIComponent(a.getAttribute("href").slice(1)),
+ );
+ const headings = ids
+ .map((id) => document.getElementById(id))
+ .filter(Boolean);
+
+ let activeIndex = 0;
+
+ function getActiveIndex() {
+ const scrollY = window.scrollY + window.innerHeight * 0.25;
+ let idx = 0;
+ for (let i = 0; i < headings.length; i++) {
+ if (
+ headings[i].getBoundingClientRect().top + window.scrollY <=
+ scrollY
+ )
+ idx = i;
+ else break;
+ }
+ return idx;
+ }
+
+ function getSectionProgress(idx) {
+ const sectionTop =
+ headings[idx].getBoundingClientRect().top + window.scrollY;
+ const nextTop =
+ idx + 1 < headings.length
+ ? headings[idx + 1].getBoundingClientRect().top + window.scrollY
+ : document.documentElement.scrollHeight;
+ const sectionHeight = nextTop - sectionTop;
+ const scrolled =
+ window.scrollY + window.innerHeight * 0.25 - sectionTop;
+ return scrolled / sectionHeight;
+ }
+
+ function update() {
+ activeIndex = getActiveIndex();
+ const progress = getSectionProgress(activeIndex);
+
+ setProgress(progress);
+
+ links.forEach((link, i) => {
+ const on = i === activeIndex;
+ link.classList.toggle("active", on);
+ if (on && currentLabel)
+ currentLabel.textContent = link.textContent.trim();
+ });
+ }
+
+ window.addEventListener("scroll", update, { passive: true });
+ window.addEventListener("resize", update, { passive: true });
+
+ // Initial call
+ setTimeout(update, 100);
+ })();
+ </script>
+ </body>
+</html>