-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathkernel-overview.html
More file actions
225 lines (215 loc) · 28.7 KB
/
Copy pathkernel-overview.html
File metadata and controls
225 lines (215 loc) · 28.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
<!doctype html>
<html lang="en" class="scroll-smooth">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>Kernel Overview - Forge Kernel Documentation</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/components/prism-core.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css" rel="stylesheet" />
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet" />
<link rel="stylesheet" href="assets/css/docs.css" />
</head>
<body class="bg-gray-50 text-gray-900">
<!-- Navigation -->
<nav class="bg-white shadow-sm border-b">
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8">
<div class="flex justify-between h-16">
<div class="flex items-center">
<div class="flex-shrink-0"><h1 class="text-xl font-bold text-gray-900">Forge Kernel</h1></div>
<div class="hidden sm:ml-6 sm:flex sm:space-x-8">
<a href="index.html" class="text-gray-900 inline-flex items-center px-1 pt-1 text-sm font-medium hover:text-blue-600">Home</a>
<div class="relative" id="kernel-menu-wrap">
<button id="kernel-menu-button" aria-expanded="false" aria-haspopup="true" class="text-blue-600 inline-flex items-center px-1 pt-1 text-sm font-medium border-b-2 border-blue-600">Kernel <i class="fas fa-chevron-down ml-1 text-xs"></i></button>
<div id="kernel-dropdown" class="absolute left-0 top-full hidden w-64 bg-white rounded-md shadow-lg border z-50 py-1">
<a href="kernel-overview.html" class="block px-4 py-2 text-sm bg-blue-50 text-blue-700">Overview — What's in / What's NOT</a>
<a href="anatomy.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 hover:text-blue-600">Anatomy & Folder Structure</a>
<a href="lifecycle.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 hover:text-blue-600">Lifecycle & Bootstrap</a>
<a href="forging-your-own.html" class="block px-4 py-2 text-sm text-gray-700 hover:bg-gray-50 hover:text-blue-600">Forging Your Own</a>
</div>
</div>
<a href="getting-started.html" class="text-gray-900 inline-flex items-center px-1 pt-1 text-sm font-medium hover:text-blue-600">Getting Started</a>
<a href="core-concepts.html" class="text-gray-900 inline-flex items-center px-1 pt-1 text-sm font-medium hover:text-blue-600">Core Concepts</a>
<a href="capabilities.html" class="text-gray-900 inline-flex items-center px-1 pt-1 text-sm font-medium hover:text-blue-600">Capabilities</a>
<a href="api-reference.html" class="text-gray-900 inline-flex items-center px-1 pt-1 text-sm font-medium hover:text-blue-600">API Reference</a>
<a href="tutorial.html" class="text-gray-900 inline-flex items-center px-1 pt-1 text-sm font-medium hover:text-blue-600">Tutorials</a>
<a href="https://github.com/forge-kernel" target="_blank" class="text-gray-900 inline-flex items-center px-1 pt-1 text-sm font-medium hover:text-blue-600"><i class="fab fa-github mr-2"></i> GitHub</a>
</div>
</div>
<div class="flex items-center sm:hidden"><button id="mobile-menu-button" class="text-gray-700 hover:text-blue-600 p-2"><i class="fas fa-bars text-xl"></i></button></div>
</div>
</div>
<div id="mobile-menu" class="sm:hidden hidden bg-white border-t border-gray-200">
<div class="px-2 pt-2 pb-3 space-y-1">
<a href="index.html" class="block px-3 py-2 text-gray-900 hover:text-blue-600">Home</a>
<div class="border-t border-gray-100 my-1 pt-1"><span class="block px-3 py-1 text-xs font-semibold text-blue-600 uppercase tracking-wider">Kernel</span>
<a href="kernel-overview.html" class="block px-3 py-2 pl-6 text-blue-600 font-medium">Overview — In / NOT in Kernel</a>
<a href="anatomy.html" class="block px-3 py-2 pl-6 text-gray-900 hover:text-blue-600">Anatomy & Structure</a>
<a href="lifecycle.html" class="block px-3 py-2 pl-6 text-gray-900 hover:text-blue-600">Lifecycle & Bootstrap</a>
<a href="forging-your-own.html" class="block px-3 py-2 pl-6 text-gray-900 hover:text-blue-600">Forging Your Own</a></div>
<a href="getting-started.html" class="block px-3 py-2 text-gray-900 hover:text-blue-600">Getting Started</a>
<a href="core-concepts.html" class="block px-3 py-2 text-gray-900 hover:text-blue-600">Core Concepts</a>
<a href="capabilities.html" class="block px-3 py-2 text-gray-900 hover:text-blue-600">Capabilities</a>
<a href="api-reference.html" class="block px-3 py-2 text-gray-900 hover:text-blue-600">API Reference</a>
<a href="tutorial.html" class="block px-3 py-2 text-gray-900 hover:text-blue-600">Tutorials</a>
</div>
</div>
</nav>
<!-- Main Content -->
<div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 py-8">
<div class="flex flex-col lg:flex-row gap-8">
<!-- Sidebar -->
<div id="sidebar-nav" class="lg:w-1/4">
<div class="bg-white rounded-lg shadow-sm p-6 sticky top-8">
<h3 class="text-lg font-semibold text-gray-900 mb-4">Kernel Overview</h3>
<nav class="space-y-2">
<a href="#what-is-kernel" class="nav-link block px-3 py-2 text-sm text-gray-700 rounded-md hover:text-blue-600">What is the Kernel</a>
<a href="#whats-in" class="nav-link block px-3 py-2 text-sm text-gray-700 rounded-md hover:text-blue-600">What's In the Kernel</a>
<a href="#whats-not" class="nav-link block px-3 py-2 text-sm text-gray-700 rounded-md hover:text-blue-600">What's NOT in the Kernel</a>
<a href="#contracts" class="nav-link block px-3 py-2 text-sm text-gray-700 rounded-md hover:text-blue-600">Contracts vs Implementations</a>
<a href="#philosophy" class="nav-link block px-3 py-2 text-sm text-gray-700 rounded-md hover:text-blue-600">Philosophy</a>
<a href="#capabilities-vs-modules" class="nav-link block px-3 py-2 text-sm text-gray-700 rounded-md hover:text-blue-600">Capabilities vs Modules</a>
<a href="#custom-structure" class="nav-link block px-3 py-2 text-sm text-gray-700 rounded-md hover:text-blue-600">Custom Structure</a>
</nav>
<div class="mt-6 pt-6 border-t border-gray-200">
<h4 class="font-semibold text-sm mb-3 text-blue-600">Next</h4>
<nav class="space-y-2">
<a href="anatomy.html" class="block text-gray-600 hover:text-blue-600 py-1 text-sm">Anatomy & Structure →</a>
<a href="lifecycle.html" class="block text-gray-600 hover:text-blue-600 py-1 text-sm">Lifecycle & Bootstrap →</a>
</nav>
</div>
</div>
</div>
<!-- Content -->
<div class="lg:w-3/4">
<div class="bg-white rounded-lg shadow-sm p-8">
<h1 class="text-4xl font-bold text-gray-900 mb-2">Kernel Overview</h1>
<p class="text-xl text-gray-600 mb-8">The minimal, no-magic core. Everything else is a capability you plug in when you need it.</p>
<div class="bg-blue-50 border-l-4 border-blue-500 p-4 mb-8">
<p class="text-sm text-blue-800"><strong>In short:</strong> The Kernel handles bootstrapping, dependency injection, module loading, CLI and config. Router, view, database, ORM, auth, storage — those live in capabilities. You assemble: <strong>Kernel + Capabilities + Your Code = Your App.</strong></p>
</div>
<section id="what-is-kernel" class="section-anchor mb-12">
<h2 class="text-2xl font-bold text-gray-900 mb-4">What is the Kernel</h2>
<p class="text-gray-600 mb-4">The minimal, no-magic core of Forge. It handles bootstrapping, dependency injection, module loading, configuration, and CLI infrastructure. Everything else — database, routing, authentication, storage, templating — is a capability you plug in when you need it.</p>
<p class="text-gray-600 mb-4">You don't build a “Forge app”. You build <em>your app</em> on top of the Kernel. The Kernel stays lean. You stay in control. No baked-in opinions about databases, routers, or templating.</p>
<div class="code-block p-6 text-white rounded-lg mb-6 overflow-x-auto"><pre><code class="language-php">final class Kernel {
public static function init(): void {
if (FileExistenceCache::exists(BASE_PATH . "/.env")) {
EnvParser::load(BASE_PATH . "/.env");
}
Bootstrap::getInstance();
}
}</code></pre></div>
<p class="text-gray-600">That's the whole entry point. Both the web request and the CLI go through it. The details live in the <a href="lifecycle.html" class="text-blue-600 underline">Lifecycle</a> page.</p>
</section>
<section id="whats-in" class="section-anchor mb-12">
<h2 class="text-2xl font-bold text-gray-900 mb-4">What's In the Kernel</h2>
<p class="text-gray-600 mb-6">A small set of essentials. If it's not here, it's a capability.</p>
<div class="grid md:grid-cols-2 gap-4 mb-6">
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">DI Container</h4><p class="text-sm text-gray-600 break-words">Automatic wiring. Add a type-hint to your constructor and it resolves. Supports singletons and interface binding.</p></div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">Module System</h4><p class="text-sm text-gray-600 break-words">Discovers modules in <code class="break-all">modules/</code> and <code class="break-all">capabilities/</code>, orders them, and runs lifecycle hooks.</p></div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">CLI Kernel</h4><p class="text-sm text-gray-600 break-words">Command routing, generators, and the interactive browser you get with <code>php forge.php</code>.</p></div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">Configuration</h4><p class="text-sm text-gray-600 break-words">Simple config files plus environment variables. Helpers <code>config()</code> and <code>env()</code> everywhere.</p></div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">Bootstrap</h4><p class="text-sm text-gray-600 break-words">Creates storage folders, loads <code>.env</code>, sets timezone and secure session defaults.</p></div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">Autoloader</h4><p class="text-sm text-gray-600 break-words">PSR-4, with a cache so it doesn't scan the filesystem on every request.</p></div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">Cache & Session</h4><p class="text-sm text-gray-600 break-words">Driver-based cache with transparent proxy, and session handling with secure cookies.</p></div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">Validation</h4><p class="text-sm text-gray-600 break-words">Small, explicit validation rules you can use anywhere.</p></div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">Contracts</h4><p class="text-sm text-gray-600 break-words">Interfaces for things like database and views — the Kernel defines the shape, capabilities provide the code.</p></div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">Helpers & Traits</h4><p class="text-sm text-gray-600 break-words">Small helpers like <code>env()</code>, <code>cache()</code>, <code>e()</code> and shared traits you can reuse.</p></div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">Debug & Observability</h4><p class="text-sm text-gray-600 break-words">Metrics and small utilities to understand what's happening.</p></div>
<div class="bg-gray-50 border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-1">Structure</h4><p class="text-sm text-gray-600 break-words">Where files live and what namespace they use — and you can change it if you want. See <a href="anatomy.html" class="text-blue-600 underline">Anatomy</a>.</p></div>
</div>
</section>
<section id="whats-not" class="section-anchor mb-12">
<h2 class="text-2xl font-bold text-gray-900 mb-4">What's NOT in the Kernel</h2>
<p class="text-gray-600 mb-4">If it touches HTTP, HTML, or the database — it's a capability. The Kernel only provides the contract. The capability provides the implementation.</p>
<div class="bg-yellow-50 border border-yellow-200 rounded-lg p-4 mb-6">
<p class="text-sm text-yellow-800"><strong>Not built-in. Install when you need it:</strong> Every item below needs <code class="break-all">php forge.php package:install-module --module=Name</code>. If you don't install it, nothing breaks — it just isn't there.</p>
</div>
<div class="grid md:grid-cols-2 gap-4 mb-6">
<div class="border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-2">HTTP & Rendering</h4><ul class="text-sm text-gray-600 list-disc list-inside space-y-1 break-words"><li>Router & <code>#[Route]</code> — <a href="capabilities.html" class="text-blue-600 underline">ForgeRouter</a></li><li>View engine & layouts — ForgeView</li><li>Middleware — ForgeRouter</li><li>HTMX / Tailwind — <a href="forge-htmx.html" class="text-blue-600 underline">ForgeHtmx</a>, <a href="forge-tailwind.html" class="text-blue-600 underline">ForgeTailwind</a></li><li>Reactive islands — <a href="forge-wire.html" class="text-blue-600 underline">ForgeWire</a></li></ul></div>
<div class="border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-2">Data & Auth</h4><ul class="text-sm text-gray-600 list-disc list-inside space-y-1 break-words"><li>Database — <a href="forge-database-sql.html" class="text-blue-600 underline">ForgeDatabaseSql</a></li><li>ORM — <a href="forge-sql-orm.html" class="text-blue-600 underline">ForgeSqlOrm</a></li><li>Authentication — <a href="forge-auth.html" class="text-blue-600 underline">ForgeAuth</a></li><li>Storage — ForgeStorage</li><li>Multi-tenancy — <a href="forge-multi-tenant.html" class="text-blue-600 underline">ForgeMultiTenant</a></li></ul></div>
<div class="border border-gray-200 rounded-lg p-4 overflow-hidden"><h4 class="font-semibold text-sm mb-2">Infra & Tooling</h4><ul class="text-sm text-gray-600 list-disc list-inside space-y-1 break-words"><li>Events & Queues — <a href="forge-events.html" class="text-blue-600 underline">ForgeEvents</a></li><li>Deployment — <a href="forge-deployment.html" class="text-blue-600 underline">ForgeDeployment</a></li><li>Package Manager — <a href="forge-package-manager.html" class="text-blue-600 underline">ForgePackageManager</a></li><li>Testing / DebugBar / ErrorHandler</li></ul></div>
<div class="border border-gray-200 rounded-lg p-4 bg-blue-50 border-blue-200 overflow-hidden"><h4 class="font-semibold text-sm mb-2">Kernel stays lean</h4><p class="text-sm text-gray-600 break-words">Capabilities, not built-ins. Database, ORM, authentication, storage — they aren't in the kernel. They're capabilities you plug in when you need them. No hidden dependencies.</p></div>
</div>
</section>
<section id="contracts" class="section-anchor mb-12">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Contracts vs Implementations</h2>
<p class="text-gray-600 mb-4">The Kernel defines interfaces. Capabilities implement them. Your code depends on the interface, so you can swap the implementation or write your own.</p>
<div class="code-block p-6 text-white rounded-lg mb-4 overflow-x-auto"><pre><code class="language-php">interface DatabaseConnectionInterface {
public function getPdo(): PDO;
public function exec(string $statement): int|false;
public function prepare(string $statement): PDOStatement;
public function query(string $statement): PDOStatement;
public function beginTransaction(): bool;
public function commit(): bool;
public function rollBack(): bool;
public function getDriver(): string; // sqlite | mysql | pgsql
}</code></pre></div>
<div class="grid md:grid-cols-2 gap-4 mb-6">
<div class="bg-red-50 border border-red-200 rounded p-4 overflow-hidden"><p class="text-xs font-semibold text-red-800 mb-1">Without the capability</p><pre class="text-xs text-red-700 whitespace-pre-wrap break-words"><code>Container::get(DatabaseConnectionInterface::class)
→ MissingServiceException
// Kernel has the interface, no implementation</code></pre></div>
<div class="bg-green-50 border border-green-200 rounded p-4 overflow-hidden"><p class="text-xs font-semibold text-green-800 mb-1">After installing it</p><pre class="text-xs text-green-700 whitespace-pre-wrap break-words"><code>php forge.php package:install-module --module=ForgeDatabaseSQL
Container::get(DatabaseConnectionInterface::class)
→ PDO-backed Connection</code></pre></div>
</div>
<p class="text-gray-600 mb-4">Same pattern for views, cache, and events. If you want your own database layer, implement the interface and bind it in your module's <code>register()</code> — the Kernel doesn't need to know which one you chose.</p>
</section>
<section id="philosophy" class="section-anchor mb-12">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Philosophy</h2>
<p class="text-gray-600 mb-4">This isn't a product. There's no company behind it. No support SLA. No roadmap you should depend on.</p>
<p class="text-gray-600 mb-4">Forge exists because I like to understand and own my stack. If others find value in it — awesome. If not — that's cool too.</p>
<h3 class="text-lg font-semibold mb-3 text-gray-900">You're not a user here. You're a builder.</h3>
<ul class="list-disc list-inside space-y-2 text-gray-600 mb-4">
<li>If you use Forge, it's yours now. Your rules. Your path.</li>
<li>If I publish updates, they're for my use case. Pull them in if they help.</li>
<li>If my direction doesn't match yours, fork it. Change everything. That's the point.</li>
</ul>
<p class="text-gray-600">MIT licensed. Take what helps, ignore what doesn't. See <a href="forging-your-own.html" class="text-blue-600 underline">Forging Your Own</a> for how to fork the whole thing.</p>
</section>
<section id="capabilities-vs-modules" class="section-anchor mb-12">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Capabilities vs Modules</h2>
<p class="text-gray-600 mb-4">To the Kernel they're the same. It scans both <code>modules/</code> and <code>capabilities/</code>. The difference is just convention and namespace.</p>
<div class="overflow-x-auto mb-6">
<table class="min-w-full divide-y divide-gray-200 text-sm">
<thead class="bg-gray-50"><tr><th class="px-4 py-2 text-left font-semibold">Location</th><th class="px-4 py-2 text-left font-semibold">Namespace</th><th class="px-4 py-2 text-left font-semibold">Use for</th><th class="px-4 py-2 text-left font-semibold">Example</th></tr></thead>
<tbody class="divide-y divide-gray-200 bg-white">
<tr><td class="px-4 py-2 font-mono">capabilities/</td><td class="px-4 py-2 font-mono">Capability\</td><td class="px-4 py-2">Primitives, reusable building blocks</td><td class="px-4 py-2"><code>capabilities/ForgeHtmx</code></td></tr>
<tr><td class="px-4 py-2 font-mono">modules/</td><td class="px-4 py-2 font-mono">Modules\</td><td class="px-4 py-2">Your app features</td><td class="px-4 py-2"><code>modules/Blog</code></td></tr>
</tbody>
</table>
</div>
<div class="bg-blue-50 border-l-4 border-blue-500 p-4 mb-6">
<p class="text-sm text-blue-800"><strong>Your choice.</strong> Follow the convention, or put everything in <code>modules/</code>, or everything in <code>capabilities/</code>, or mix them. The Kernel doesn't enforce it. It's a slow migration — most primitives still live in <code>modules/</code> and will move over time. <code>ForgeHtmx</code> is already in <code>capabilities/</code> as the reference.</p>
</div>
<p class="text-gray-600">Put your services in the <code>injectable</code> folders — <code>app/Services</code> or <code>app/Listeners</code> for your app, <code>src/Services</code>, <code>src/Listeners</code> or <code>src/Providers</code> inside a module — and they are found automatically. No attribute needed. If you want a custom id or non-singleton, you can add <code>#[Injectable]</code> — it's optional and just a leftover from before the refactor. Only those folders are scanned — not every folder — which keeps things fast. You can change the folders if you want (see <a href="anatomy.html" class="text-blue-600 underline">Anatomy</a>).</p>
</section>
<section id="custom-structure" class="section-anchor mb-12">
<h2 class="text-2xl font-bold text-gray-900 mb-4">Customizing Folder Structure</h2>
<p class="text-gray-600 mb-4">Don't like the defaults? Change them. You don't have to create the file by hand — run the wizard and it will make it for you:</p>
<div class="code-block p-4 text-white rounded-lg mb-4 overflow-x-auto"><pre><code class="language-bash">php forge.php structure:init # wizard: pick app / modules / roots, or partial
php forge.php structure:info # see current config (interactive)</code></pre></div>
<p class="text-gray-600 mb-4">That's the easy path. If you prefer, you can still create <code>forge_structure.php</code> by hand at the project root and override any path or namespace — app root, module roots, or where controllers, views, and models live. The wizard just writes the same file for you.</p>
<p class="text-gray-600 mb-4">A quick warning from the wizard itself: changing paths won't move your files for you, and deleting the file won't move them back. Back up first, and make sure your filesystem matches what you configure. Modules that define their own structure with <code>#[Structure]</code> have the final say — they aren't affected by this file.</p>
<p class="text-gray-600 mb-4">Each capability or module can also define its own internal layout. The details for that live in the capability's own page, not here.</p>
<p class="text-gray-600">Full examples and the interactive viewer are in <a href="anatomy.html#custom-structure" class="text-blue-600 underline">Anatomy → Customizing Folder Structure & Namespaces</a>.</p>
<div class="flex gap-4 mt-6">
<a href="anatomy.html" class="bg-blue-600 text-white px-6 py-3 rounded-lg hover:bg-blue-700 font-medium">Next: Anatomy & Structure →</a>
<a href="lifecycle.html" class="bg-white border border-gray-300 text-gray-700 px-6 py-3 rounded-lg hover:bg-gray-50 font-medium">Lifecycle →</a>
</div>
</section>
</div>
</div>
</div>
</div>
<footer class="bg-gray-900 text-white py-8 mt-16"><div class="max-w-7xl mx-auto px-4 sm:px-6 lg:px-8 text-center"><span class="text-lg font-bold">Forge Kernel</span><p class="text-gray-400 text-sm mt-2">A toolbox for builders · <a href="https://github.com/forge-kernel" class="text-gray-400 underline">github.com/forge-kernel</a></p></div></footer>
<script>
(function(){const wrap=document.getElementById('kernel-menu-wrap'),btn=document.getElementById('kernel-menu-button'),dd=document.getElementById('kernel-dropdown');if(!wrap||!btn||!dd)return;let t=null;function open(){dd.classList.remove('hidden');dd.classList.add('block');btn.setAttribute('aria-expanded','true');}function close(){dd.classList.add('hidden');dd.classList.remove('block');btn.setAttribute('aria-expanded','false');}function scheduleClose(){clearTimeout(t);t=setTimeout(close,180);}function cancelClose(){clearTimeout(t);}btn.addEventListener('click',e=>{e.stopPropagation();dd.classList.contains('hidden')?open():close();});wrap.addEventListener('mouseenter',()=>{cancelClose();open();});wrap.addEventListener('mouseleave',scheduleClose);dd.addEventListener('mouseenter',cancelClose);dd.addEventListener('mouseleave',scheduleClose);btn.addEventListener('focus',open);document.addEventListener('click',e=>{if(!wrap.contains(e.target)) close();});document.addEventListener('keydown',e=>{if(e.key==='Escape') close();});})();
const mb=document.getElementById('mobile-menu-button'),mm=document.getElementById('mobile-menu');if(mb&&mm)mb.addEventListener('click',()=>mm.classList.toggle('hidden'));
document.querySelectorAll('a[href^="#"]').forEach(a=>{a.addEventListener('click',function(e){e.preventDefault();const t=document.querySelector(this.getAttribute('href'));if(t) t.scrollIntoView({behavior:'smooth',block:'start'});});});
window.addEventListener('scroll',()=>{const s=document.querySelectorAll('.section-anchor'),l=document.querySelectorAll('.nav-link');let c='';s.forEach(e=>{if(window.pageYOffset>=e.offsetTop-100) c=e.getAttribute('id');});l.forEach(a=>{a.classList.remove('active','bg-blue-50','text-blue-600');if(a.getAttribute('href')==='#'+c) a.classList.add('active','bg-blue-50','text-blue-600');});});
</script>
</body>
</html>