🎨 docs: sci-fi design system β€” 5 themes (dark/light/dracula/rose-pine/warm), light-mode fix, code highlighting, animated landing with terminal + stat matrix + SVG viz

swadhinbiswas committed 2 months ago
227afa4
1 parent 0436ae9
commit 227afa4
5 files changed
+808 -341
β–Όdocs_site/astro.config.mjs
+39-0
10
10
integrations: [
11
11
starlight({
12
12
title: 'JustAPI',
13
+ expressiveCode: {
14
+ themes: ['dracula', 'github-light'],
15
+ styleOverrides: {
16
+ borderRadius: '12px',
17
+ },
18
+ },
13
19
description: 'Python web framework. Rust engine underneath.',
14
20
logo: {
15
21
src: './src/assets/logo.svg',
24
30
baseUrl: 'https://github.com/swadhinbiswas/JustAPI/edit/main/docs_site',
25
31
},
26
32
head: [
33
+ {
34
+ tag: 'script',
35
+ attrs: { is: 'inline' },
36
+ content: `// JustAPI theme switcher (dark/light/dracula/rose-pine/warm)
37
+(function () {
38
+ var THEMES = ['dark', 'light', 'dracula', 'rose-pine', 'warm'];
39
+ function apply(t) {
40
+ document.documentElement.setAttribute('data-theme', t);
41
+ try { localStorage.setItem('ja-theme', t); } catch (e) {}
42
+ document.querySelectorAll('.ja-theme-btn').forEach(function (b) {
43
+ b.setAttribute('data-active', b.dataset.theme === t ? 'true' : 'false');
44
+ });
45
+ }
46
+ document.addEventListener('DOMContentLoaded', function () {
47
+ var saved = null;
48
+ try { saved = localStorage.getItem('ja-theme'); } catch (e) {}
49
+ if (saved && THEMES.indexOf(saved) !== -1) apply(saved);
50
+ var w = document.createElement('div');
51
+ w.className = 'ja-theme-switcher';
52
+ THEMES.forEach(function (t) {
53
+ var b = document.createElement('button');
54
+ b.className = 'ja-theme-btn ja-theme-btn--' + (t === 'rose-pine' ? 'rosepine' : t);
55
+ b.dataset.theme = t;
56
+ b.title = t;
57
+ b.setAttribute('aria-label', 'Theme: ' + t);
58
+ b.addEventListener('click', function () { apply(t); });
59
+ w.appendChild(b);
60
+ });
61
+ document.body.appendChild(w);
62
+ apply(saved || (window.matchMedia && window.matchMedia('(prefers-color-scheme: light)').matches ? 'light' : 'dark'));
63
+ });
64
+})();`,
65
+ },
27
66
{ tag: 'meta', attrs: { charset: 'utf-8' } },
28
67
{ tag: 'meta', attrs: { name: 'viewport', content: 'width=device-width, initial-scale=1' } },
29
68
{ tag: 'meta', attrs: { name: 'generator', content: 'Astro v7 + Starlight' } },
30
69
β–Όdocs_site/public/justapi-features.png
+0-0
Binary file not shown.
β–Όdocs_site/public/justapi-pipeline.svg
+150-0
1
+<svg width="1200" height="420" viewBox="0 0 1200 420" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <defs>
3
+ <linearGradient id="bg2" x1="0" y1="0" x2="1200" y2="420" gradientUnits="userSpaceOnUse">
4
+ <stop stop-color="#0b0e1a"/>
5
+ <stop offset="1" stop-color="#111631"/>
6
+ </linearGradient>
7
+ <linearGradient id="boxRust" x1="0" y1="0" x2="0" y2="1">
8
+ <stop offset="0" stop-color="#e6522c"/>
9
+ <stop offset="1" stop-color="#b03a1c"/>
10
+ </linearGradient>
11
+ <linearGradient id="boxPy" x1="0" y1="0" x2="0" y2="1">
12
+ <stop offset="0" stop-color="#22d3ee"/>
13
+ <stop offset="1" stop-color="#0e7490"/>
14
+ </linearGradient>
15
+ <filter id="glow2" x="-30%" y="-30%" width="160%" height="160%">
16
+ <feDropShadow dx="0" dy="0" stdDeviation="6" flood-color="#22d3ee" flood-opacity="0.5"/>
17
+ </filter>
18
+ </defs>
19
+
20
+ <rect width="1200" height="420" fill="url(#bg2)"/>
21
+
22
+ <text x="600" y="40" text-anchor="middle" font-family="'Segoe UI', Arial, sans-serif" font-size="24" font-weight="700" fill="#e2e8f0" letter-spacing="1">One request, end to end</text>
23
+
24
+ <!-- ============ ROW 1: Rust pipeline ============ -->
25
+ <g font-family="'Segoe UI', Arial, sans-serif">
26
+ <!-- boxes: x positions -->
27
+ <!-- Kernel -->
28
+ <rect x="20" y="80" width="150" height="62" rx="10" fill="#1e293b" stroke="#334155"/>
29
+ <text x="95" y="105" text-anchor="middle" font-size="14" font-weight="700" fill="#22d3ee">Kernel</text>
30
+ <text x="95" y="125" text-anchor="middle" font-size="11" fill="#94a3b8">epoll / io_uring</text>
31
+
32
+ <!-- tokio -->
33
+ <rect x="220" y="80" width="150" height="62" rx="10" fill="#1e293b" stroke="#334155"/>
34
+ <text x="295" y="105" text-anchor="middle" font-size="14" font-weight="700" fill="#22d3ee">tokio</text>
35
+ <text x="295" y="125" text-anchor="middle" font-size="11" fill="#94a3b8">async runtime</text>
36
+
37
+ <!-- TLS -->
38
+ <rect x="420" y="80" width="150" height="62" rx="10" fill="#1e293b" stroke="#334155"/>
39
+ <text x="495" y="105" text-anchor="middle" font-size="14" font-weight="700" fill="#22d3ee">TLS</text>
40
+ <text x="495" y="125" text-anchor="middle" font-size="11" fill="#94a3b8">rustls</text>
41
+
42
+ <!-- HTTP -->
43
+ <rect x="620" y="80" width="150" height="62" rx="10" fill="#1e293b" stroke="#334155"/>
44
+ <text x="695" y="105" text-anchor="middle" font-size="14" font-weight="700" fill="#22d3ee">HTTP/1.1 Β· 2</text>
45
+ <text x="695" y="125" text-anchor="middle" font-size="11" fill="#94a3b8">hyper</text>
46
+
47
+ <!-- Router -->
48
+ <rect x="820" y="80" width="150" height="62" rx="10" fill="#1e293b" stroke="#334155"/>
49
+ <text x="895" y="105" text-anchor="middle" font-size="14" font-weight="700" fill="#22d3ee">Router</text>
50
+ <text x="895" y="125" text-anchor="middle" font-size="11" fill="#94a3b8">matchit Β· 51ns</text>
51
+
52
+ <!-- Middleware -->
53
+ <rect x="1020" y="80" width="160" height="62" rx="10" fill="#1e293b" stroke="#334155"/>
54
+ <text x="1100" y="105" text-anchor="middle" font-size="14" font-weight="700" fill="#22d3ee">Middleware</text>
55
+ <text x="1100" y="125" text-anchor="middle" font-size="11" fill="#94a3b8">auth Β· CORS Β· rate-limit</text>
56
+
57
+ <!-- arrows row 1 -->
58
+ <line x1="170" y1="111" x2="218" y2="111" stroke="#22d3ee" stroke-width="2" marker-end="url(#arr)">
59
+ <animate attributeName="stroke-opacity" values="0.2;1;0.2" dur="2s" repeatCount="indefinite"/>
60
+ </line>
61
+ <line x1="370" y1="111" x2="418" y2="111" stroke="#22d3ee" stroke-width="2">
62
+ <animate attributeName="stroke-opacity" values="0.2;1;0.2" dur="2.3s" repeatCount="indefinite"/>
63
+ </line>
64
+ <line x1="570" y1="111" x2="618" y2="111" stroke="#22d3ee" stroke-width="2">
65
+ <animate attributeName="stroke-opacity" values="0.2;1;0.2" dur="2.6s" repeatCount="indefinite"/>
66
+ </line>
67
+ <line x1="770" y1="111" x2="818" y2="111" stroke="#22d3ee" stroke-width="2">
68
+ <animate attributeName="stroke-opacity" values="0.2;1;0.2" dur="2.9s" repeatCount="indefinite"/>
69
+ </line>
70
+ <line x1="970" y1="111" x2="1018" y2="111" stroke="#22d3ee" stroke-width="2">
71
+ <animate attributeName="stroke-opacity" values="0.2;1;0.2" dur="3.2s" repeatCount="indefinite"/>
72
+ </line>
73
+ <marker id="arr" viewBox="0 0 10 10" refX="8" refY="5" markerWidth="7" markerHeight="7" orient="auto-start-reverse">
74
+ <path d="M0 0 L10 5 L0 10 Z" fill="#22d3ee"/>
75
+ </marker>
76
+
77
+ <!-- moving packet dots -->
78
+ <circle cx="170" cy="111" r="4" fill="#22d3ee" filter="url(#glow2)">
79
+ <animateMotion dur="2s" repeatCount="indefinite" path="M170,111 L218,111"/>
80
+ </circle>
81
+ <circle cx="370" cy="111" r="4" fill="#22d3ee" filter="url(#glow2)">
82
+ <animateMotion dur="2.3s" repeatCount="indefinite" path="M370,111 L418,111"/>
83
+ </circle>
84
+ <circle cx="570" cy="111" r="4" fill="#22d3ee" filter="url(#glow2)">
85
+ <animateMotion dur="2.6s" repeatCount="indefinite" path="M570,111 L618,111"/>
86
+ </circle>
87
+ <circle cx="770" cy="111" r="4" fill="#22d3ee" filter="url(#glow2)">
88
+ <animateMotion dur="2.9s" repeatCount="indefinite" path="M770,111 L818,111"/>
89
+ </circle>
90
+ <circle cx="970" cy="111" r="4" fill="#22d3ee" filter="url(#glow2)">
91
+ <animateMotion dur="3.2s" repeatCount="indefinite" path="M970,111 L1018,111"/>
92
+ </circle>
93
+ </g>
94
+
95
+ <!-- down arrow from middleware -->
96
+ <path d="M1100,142 L1100,170 L1000,170 L1000,195" stroke="#8b5cf6" stroke-width="2.5" fill="none" stroke-dasharray="6 5">
97
+ <animate attributeName="stroke-dashoffset" values="0;-22" dur="1.5s" repeatCount="indefinite"/>
98
+ </path>
99
+
100
+ <!-- ============ PYTHON BOUNDARY (glowing) ============ -->
101
+ <g font-family="'Segoe UI', Arial, sans-serif">
102
+ <rect x="820" y="200" width="360" height="72" rx="12" fill="url(#boxPy)" filter="url(#glow2)">
103
+ <animate attributeName="opacity" values="0.85;1;0.85" dur="3s" repeatCount="indefinite"/>
104
+ </rect>
105
+ <text x="1000" y="228" text-anchor="middle" font-size="16" font-weight="700" fill="#03141f">Python boundary</text>
106
+ <text x="1000" y="250" text-anchor="middle" font-size="12" fill="#0b3a4d">zero-copy PyO3 Β· GIL pool Β· free-threaded ready</text>
107
+ </g>
108
+
109
+ <!-- down to handler -->
110
+ <path d="M1000,272 L1000,300 L700,300 L700,323" stroke="#8b5cf6" stroke-width="2.5" fill="none" stroke-dasharray="6 5">
111
+ <animate attributeName="stroke-dashoffset" values="0;-22" dur="1.8s" repeatCount="indefinite"/>
112
+ </path>
113
+
114
+ <!-- ============ YOUR CODE (highlighted) ============ -->
115
+ <g font-family="'Segoe UI', Arial, sans-serif">
116
+ <rect x="560" y="325" width="280" height="72" rx="12" fill="#ffffff" fill-opacity="0.05" stroke="#f5a524" stroke-width="2">
117
+ <animate attributeName="stroke-opacity" values="0.5;1;0.5" dur="2.2s" repeatCount="indefinite"/>
118
+ </rect>
119
+ <text x="700" y="350" text-anchor="middle" font-size="15" font-weight="700" fill="#f5a524">Your Python code</text>
120
+ <text x="700" y="372" text-anchor="middle" font-size="12" fill="#94a3b8">the only part that is yours</text>
121
+ </g>
122
+
123
+ <!-- path from handler to serializer -->
124
+ <path d="M700,325 L700,300 L300,300 L300,272" stroke="#e6522c" stroke-width="2.5" fill="none" stroke-dasharray="6 5">
125
+ <animate attributeName="stroke-dashoffset" values="0;-22" dur="1.6s" repeatCount="indefinite"/>
126
+ </path>
127
+
128
+ <!-- ============ ROW 2: response path ============ -->
129
+ <g font-family="'Segoe UI', Arial, sans-serif">
130
+ <rect x="20" y="200" width="240" height="62" rx="10" fill="#1e293b" stroke="#334155"/>
131
+ <text x="140" y="225" text-anchor="middle" font-size="14" font-weight="700" fill="#e6522c">Serializer</text>
132
+ <text x="140" y="245" text-anchor="middle" font-size="11" fill="#94a3b8">serde_json Β· simd-json</text>
133
+
134
+ <rect x="20" y="325" width="240" height="62" rx="10" fill="#1e293b" stroke="#334155"/>
135
+ <text x="140" y="350" text-anchor="middle" font-size="14" font-weight="700" fill="#22d3ee">Response write</text>
136
+ <text x="140" y="370" text-anchor="middle" font-size="11" fill="#94a3b8">back to the socket</text>
137
+
138
+ <line x1="140" y1="262" x2="140" y2="323" stroke="#e6522c" stroke-width="2" stroke-dasharray="6 5">
139
+ <animate attributeName="stroke-dashoffset" values="0;-22" dur="1.4s" repeatCount="indefinite"/>
140
+ </line>
141
+ </g>
142
+
143
+ <!-- side legend -->
144
+ <g font-family="'Segoe UI', Arial, sans-serif" font-size="12">
145
+ <rect x="420" y="225" width="16" height="16" rx="4" fill="#22d3ee"/>
146
+ <text x="445" y="238" fill="#94a3b8">Rust (everything except your code)</text>
147
+ <rect x="420" y="252" width="16" height="16" rx="4" fill="#f5a524"/>
148
+ <text x="445" y="265" fill="#94a3b8">Python (just your logic)</text>
149
+ </g>
150
+</svg>
0
151
β–Όdocs_site/src/content/docs/index.mdx
+121-94
1
1
---
2
2
title: JustAPI
3
-description: Python web framework powered by Rust. Handles 700k+ requests per second. FastAPI alternative with 20Γ— performance.
3
+description: Python web framework powered by Rust. 766k req/s. Built to handle real traffic.
4
4
template: splash
5
5
hero:
6
- tagline: Python web framework powered by Rust. Built to handle real traffic.
6
+ tagline: Python web framework. Rust engine underneath.
7
7
image:
8
8
file: ../../assets/logo.svg
9
9
actions:
11
11
link: /getting-started/overview/
12
12
icon: right-arrow
13
13
variant: primary
14
- - text: View on GitHub
14
+ - text: GitHub
15
15
link: https://github.com/swadhinbiswas/JustAPI
16
16
icon: external
17
17
variant: minimal
18
18
---
19
19
20
-import { Card, CardGrid } from '@astrojs/starlight/components';
21
-
22
-## Performance
23
-
24
-| Framework | Hello-world req/s | JSON echo | p99 latency | RSS |
25
-|---|--:|--:|--:|--:|
26
-| **JustAPI (native fast path)** | **766,000** | **782,000** | **0.48 ms** | **12 MB** |
27
-| Granian (ASGI) | 314,000 | 145,000 | 0.74 ms | 37 MB |
28
-| Robyn | 39,000 | β€” | β€” | β€” |
29
-| FastAPI + Uvicorn | 36,000 | 33,000 | 24.63 ms | 29 MB |
30
-
31
-All measurements on the same hardware, 100 concurrent connections, 30s duration. Full methodology in [BENCHMARKS.md](https://github.com/swadhinbiswas/JustAPI/blob/main/BENCHMARKS.md).
32
-
33
-## What It Does
34
-
35
-JustAPI runs your Python application logic on top of a Rust networking stack. Routing, TLS, serialization, compression β€” all handled in Rust before your code even runs.
36
-
37
-```python title="main.py"
38
-from justapi import JustAPIApp
39
-
40
-app = JustAPIApp()
41
-
42
-@app.get("/")
43
-def hello():
44
- return {"message": "Hello from JustAPI!"}
45
-```
46
-
47
-```bash title="Terminal"
48
-$ pip install justapi
49
-$ python main.py
50
-
51
-INFO: JustAPI running on http://127.0.0.1:8000
52
-```
53
-
54
-Open `/docs` for Swagger UI, `/redoc` for ReDoc, and the full OpenAPI schema β€” generated automatically from your code.
55
-
56
-## Features
57
-
58
-<CardGrid>
59
- <Card title="FastAPI-Compatible" icon="star">
60
- Same decorators, Pydantic models, dependency injection. Switch with one import.
61
- </Card>
62
- <Card title="Rust Under the Hood" icon="rocket">
63
- Networking, TLS, routing, serialization run in Rust. Python does the rest.
64
- </Card>
65
- <Card title="Zero GIL" icon="shield">
66
- GIL released during I/O. Works with free-threaded Python 3.13t/3.14t.
67
- </Card>
68
- <Card title="Production-Ready" icon="lock">
69
- JWT auth, rate limiting, circuit breakers, OpenTelemetry, health checks.
70
- </Card>
71
- <Card title="Multi-Protocol" icon="globe">
72
- REST, GraphQL, gRPC, JSON-RPC 2.0, WebSocket, SSE β€” all in one app.
73
- </Card>
74
- <Card title="Native Async DB" icon="rocket">
75
- `await app.db.query_async()` β€” SQL runs on Rust's tokio runtime, GIL released. 53Γ— faster on slow queries.
76
- </Card>
77
- <Card title="Rust-Native SSE" icon="activity">
20
+<div class="ja-hero">
21
+ <img src="/og-image.png" alt="JustAPI β€” Python writes the logic. Rust does everything else." width="100%" />
22
+</div>
23
+
24
+## Performance Matrix
25
+
26
+<div class="benchmark-card">
27
+ <div class="ja-stats">
28
+ <div class="ja-stat">
29
+ <div class="ja-stat-value">766k</div>
30
+ <div class="ja-stat-label">req/s hello-world</div>
31
+ </div>
32
+ <div class="ja-stat">
33
+ <div class="ja-stat-value">782k</div>
34
+ <div class="ja-stat-label">req/s JSON echo</div>
35
+ </div>
36
+ <div class="ja-stat">
37
+ <div class="ja-stat-value">2.4x</div>
38
+ <div class="ja-stat-label">vs Granian</div>
39
+ </div>
40
+ <div class="ja-stat">
41
+ <div class="ja-stat-value">53x</div>
42
+ <div class="ja-stat-label">native async DB</div>
43
+ </div>
44
+ <div class="ja-stat">
45
+ <div class="ja-stat-value">12MB</div>
46
+ <div class="ja-stat-label">resident memory</div>
47
+ </div>
48
+ <div class="ja-stat">
49
+ <div class="ja-stat-value">12.4x</div>
50
+ <div class="ja-stat-label">free-threaded CPU</div>
51
+ </div>
52
+ </div>
53
+</div>
54
+
55
+## Runtime
56
+
57
+<div class="ja-terminal">
58
+ <div class="ja-terminal-bar">
59
+ <span class="ja-terminal-dot"></span>
60
+ <span class="ja-terminal-dot"></span>
61
+ <span class="ja-terminal-dot"></span>
62
+ </div>
63
+ <div class="ja-terminal-body">
64
+ <span class="cm">$</span> pip install justapi<br/>
65
+ <span class="ok">βœ“ installed 2.0.9 (8 platforms)</span><br/>
66
+ <span class="cm">$</span> cat main.py<br/>
67
+ <span class="cm">from</span> justapi <span class="cm">import</span> JustAPIApp<br/>
68
+ <br/>
69
+ app = JustAPIApp()<br/>
70
+ <br/>
71
+ <span class="cm">@app.get</span>(<span class="ok">"/"</span>)<br/>
72
+ <span class="cm">def</span> hello():<br/>
73
+ &nbsp;&nbsp;&nbsp;&nbsp;<span class="cm">return</span> &#123;<span class="ok">"Hello"</span>: <span class="ok">"World"</span>&#125;<br/>
74
+ <br/>
75
+ app.run()<br/>
76
+ <span class="ok">βœ“ server started on http://127.0.0.1:8000</span>
77
+ </div>
78
+</div>
79
+
80
+## Feature Graph
81
+
82
+<div class="ja-graph">
83
+ <img src="/justapi-features.png" alt="JustAPI feature matrix" width="100%" />
84
+</div>
85
+
86
+## Pipeline
87
+
88
+<div class="ja-graph">
89
+ <img src="/justapi-pipeline.svg" alt="Request pipeline β€” Rust end to end" width="100%" />
90
+</div>
91
+
92
+## Why JustAPI
93
+
94
+<div class="feature-grid">
95
+ <div class="feature-card">
96
+ <h3>Rust Core</h3>
97
+ Networking, TLS, routing, serialization β€” all in Rust before your code runs.
98
+ </div>
99
+ <div class="feature-card">
100
+ <h3>Native Async DB</h3>
101
+ `await app.db.query_async()` β€” SQL on Rust's tokio runtime, loop never blocked.
102
+ </div>
103
+ <div class="feature-card">
104
+ <h3>Rust-Native SSE</h3>
78
105
`app.sse_native()` streams events with zero Python per event.
79
- </Card>
80
- <Card title="Free-Threathed 3.14t" icon="shield">
81
- CPU-bound Python scales with cores β€” 12.4Γ— measured.
82
- </Card>
83
- <Card title="Auto Docs" icon="document">
84
- Swagger UI, ReDoc, Scalar. Generated from your code.
85
- </Card>
86
-</CardGrid>
87
-
88
-## Install
89
-
90
-```bash title="Terminal"
91
-$ pip install justapi
92
-$ uv pip install justapi
93
-$ uvx justapi create my_app
94
-```
95
-
96
-## Learn
97
-
98
-<CardGrid>
99
- <Card title="Tutorial" icon="pencil">
100
- [36-step learning path β†’](/tutorials/python-types/)
101
- </Card>
102
- <Card title="Advanced" icon="rocket">
103
- [Rust internals, zero-GIL, native fast path β†’](/advanced/zero-gil-architecture/)
104
- </Card>
105
- <Card title="API Reference" icon="document">
106
- [Every class and function β†’](/api-reference/)
107
- </Card>
108
- <Card title="Deployment" icon="setting">
109
- [Docker, Kubernetes, cloud providers β†’](/deployment/docker/)
110
- </Card>
111
-</CardGrid>
106
+ </div>
107
+ <div class="feature-card">
108
+ <h3>Multi-Worker</h3>
109
+ `justapi serve --workers N --scale` β€” 1.88x throughput at 4 workers.
110
+ </div>
111
+ <div class="feature-card">
112
+ <h3>Free-Threaded</h3>
113
+ CPython 3.14t wheels β€” CPU-bound Python scales with cores.
114
+ </div>
115
+ <div class="feature-card">
116
+ <h3>Type-Checked</h3>
117
+ `py.typed` + complete stubs β€” mypy-clean on user code.
118
+ </div>
119
+</div>
120
+
121
+## Framework vs FastAPI
122
+
123
+| | FastAPI | JustAPI |
124
+|---|---|---|
125
+| **Server** | uvicorn (Python) | Rust (tokio + hyper) |
126
+| **Hello-world** | ~36k req/s | **~766k req/s** |
127
+| **JSON echo** | ~33k req/s | **~782k req/s** |
128
+| **Native DB SELECT** | Python driver | **181k req/s (Γ—125)** |
129
+| **Memory** | 29 MB | **12 MB** |
130
+| **OpenAPI docs** | /docs | /docs |
131
+
132
+<div class="ja-cta">
133
+ <div class="ja-cta-title">Ready to build?</div>
134
+ <p style={{ color: "var(--ja-muted)" }}>One import. Rust underneath. Zero config.</p>
135
+ <p>
136
+ <a href="/getting-started/overview/" class="ja-cta-btn" style={{ display: "inline-block", padding: "0.75rem 1.5rem", border: "1px solid var(--ja-accent)", borderRadius: "9999px", color: "var(--ja-accent)", fontWeight: 700 }}>Get Started β†’</a>
137
+ </p>
138
+</div>
112
139
β–Όdocs_site/src/styles/custom.css
+498-247
1
1
/* ═══════════════════════════════════════════════════════════════════
2
- JustAPI Documentation β€” Design System
3
- Premium, FastAPI-level documentation styling
2
+ JustAPI Documentation β€” Sci-Fi Design System
3
+ Themes: Sci-Fi Dark (default) Β· Light Β· Dracula Β· RosΓ© Pine Β· Warm
4
+ Palette: green #00ff9d Β· black #05080f Β· white #e6f1ff Β· red #ff2e4d
4
5
═══════════════════════════════════════════════════════════════════ */
5
6
6
-/* ─── Custom Properties ─── */
7
-:root {
8
- /* Accent palette */
9
- --sl-color-accent-low: #2a1147;
10
- --sl-color-accent: #8b5cf6;
11
- --sl-color-accent-high: #c4b5fd;
12
-
13
- /* Neutrals */
14
- --sl-color-white: #ffffff;
15
- --sl-color-gray-1: #f8fafc;
16
- --sl-color-gray-2: #f1f5f9;
17
- --sl-color-gray-3: #94a3b8;
18
- --sl-color-gray-4: #64748b;
19
- --sl-color-gray-5: #334155;
20
- --sl-color-gray-6: #1e293b;
21
- --sl-color-black: #020617;
22
-
23
- /* Brand */
24
- --sl-color-orange: #e6522c;
25
- --sl-color-blue: #3b82f6;
26
- --sl-color-green: #10b981;
27
- --sl-color-red: #ef4444;
28
- --sl-color-yellow: #f59e0b;
29
-
30
- /* Typography */
31
- --sl-font: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
32
- --sl-font-mono: 'JetBrains Mono', 'Fira Code', 'Cascadia Code', 'SF Mono', monospace;
33
-
34
- /* Spacing */
35
- --sl-content-width: 72rem;
36
- --sl-sidebar-width: 18rem;
37
- --sl-toc-width: 14rem;
38
-}
39
-
40
-/* ─── Dark Mode ─── */
7
+/* ─── Base palette (Sci-Fi Dark) ─── */
8
+:root,
41
9
[data-theme='dark'] {
42
- --sl-color-bg: #020617;
43
- --sl-color-bg-nav: #0f172a;
44
- --sl-color-bg-sidebar: #0f172a;
45
- --sl-color-bg-hover: #1e293b;
46
- --sl-color-text: #e2e8f0;
47
- --sl-color-text-muted: #94a3b8;
48
- --sl-color-border: #1e293b;
49
-}
50
-
51
-/* ─── Light Mode ─── */
10
+ --ja-bg: #05080f;
11
+ --ja-bg-2: #0a0f1c;
12
+ --ja-bg-3: #101830;
13
+ --ja-panel: rgba(10, 15, 28, 0.8);
14
+ --ja-border: #1a2440;
15
+ --ja-green: #00ff9d;
16
+ --ja-green-dim: #00c97d;
17
+ --ja-red: #ff2e4d;
18
+ --ja-white: #e6f1ff;
19
+ --ja-muted: #7d8db1;
20
+ --ja-accent: #00ff9d;
21
+ --ja-accent-2: #00d4ff;
22
+
23
+ --sl-color-accent-low: #003d26;
24
+ --sl-color-accent: #00ff9d;
25
+ --sl-color-accent-high: #66ffc4;
26
+ --sl-color-white: #e6f1ff;
27
+ --sl-color-gray-1: #e6f1ff;
28
+ --sl-color-gray-2: #b8c6e0;
29
+ --sl-color-gray-3: #7d8db1;
30
+ --sl-color-gray-4: #55648c;
31
+ --sl-color-gray-5: #2a3550;
32
+ --sl-color-gray-6: #141c30;
33
+ --sl-color-black: #05080f;
34
+ --sl-color-bg: #05080f;
35
+ --sl-color-bg-nav: #070b15;
36
+ --sl-color-bg-sidebar: #070b15;
37
+ --sl-color-bg-hover: #0d1526;
38
+ --sl-color-text: #e6f1ff;
39
+ --sl-color-text-muted: #7d8db1;
40
+ --sl-color-border: #1a2440;
41
+}
42
+
43
+/* ─── Light theme ─── */
52
44
[data-theme='light'] {
53
- --sl-color-bg: #ffffff;
54
- --sl-color-bg-nav: #f8fafc;
55
- --sl-color-bg-sidebar: #f8fafc;
56
- --sl-color-bg-hover: #f1f5f9;
57
- --sl-color-text: #1e293b;
58
- --sl-color-text-muted: #64748b;
59
- --sl-color-border: #e2e8f0;
60
-}
61
-
62
-/* ─── Global Typography ─── */
45
+ --ja-bg: #f4f7fb;
46
+ --ja-bg-2: #ffffff;
47
+ --ja-bg-3: #eef2f8;
48
+ --ja-panel: rgba(255, 255, 255, 0.92);
49
+ --ja-border: #d5dde8;
50
+ --ja-green: #00925c;
51
+ --ja-green-dim: #007a4c;
52
+ --ja-red: #d91f3c;
53
+ --ja-white: #0d1526;
54
+ --ja-muted: #5a6a8c;
55
+ --ja-accent: #00925c;
56
+ --ja-accent-2: #0077a8;
57
+
58
+ --sl-color-accent-low: #e0f7ee;
59
+ --sl-color-accent: #00925c;
60
+ --sl-color-accent-high: #00593a;
61
+ --sl-color-white: #0d1526;
62
+ --sl-color-gray-1: #0d1526;
63
+ --sl-color-gray-2: #2a3550;
64
+ --sl-color-gray-3: #5a6a8c;
65
+ --sl-color-gray-4: #7d8db1;
66
+ --sl-color-gray-5: #d5dde8;
67
+ --sl-color-gray-6: #eef2f8;
68
+ --sl-color-black: #ffffff;
69
+ --sl-color-bg: #f4f7fb;
70
+ --sl-color-bg-nav: #ffffff;
71
+ --sl-color-bg-sidebar: #ffffff;
72
+ --sl-color-bg-hover: #eef2f8;
73
+ --sl-color-text: #0d1526;
74
+ --sl-color-text-muted: #5a6a8c;
75
+ --sl-color-border: #d5dde8;
76
+}
77
+
78
+/* ─── Dracula theme ─── */
79
+[data-theme='dracula'] {
80
+ --ja-bg: #282a36;
81
+ --ja-bg-2: #21222c;
82
+ --ja-bg-3: #343746;
83
+ --ja-panel: rgba(33, 34, 44, 0.9);
84
+ --ja-border: #44475a;
85
+ --ja-green: #50fa7b;
86
+ --ja-green-dim: #3dd962;
87
+ --ja-red: #ff5555;
88
+ --ja-white: #f8f8f2;
89
+ --ja-muted: #6272a4;
90
+ --ja-accent: #bd93f9;
91
+ --ja-accent-2: #8be9fd;
92
+
93
+ --sl-color-accent-low: #3d3552;
94
+ --sl-color-accent: #bd93f9;
95
+ --sl-color-accent-high: #e3d5ff;
96
+ --sl-color-white: #f8f8f2;
97
+ --sl-color-gray-1: #f8f8f2;
98
+ --sl-color-gray-2: #bfc2d8;
99
+ --sl-color-gray-3: #6272a4;
100
+ --sl-color-gray-4: #4d5a80;
101
+ --sl-color-gray-5: #343746;
102
+ --sl-color-gray-6: #21222c;
103
+ --sl-color-black: #282a36;
104
+ --sl-color-bg: #282a36;
105
+ --sl-color-bg-nav: #21222c;
106
+ --sl-color-bg-sidebar: #21222c;
107
+ --sl-color-bg-hover: #343746;
108
+ --sl-color-text: #f8f8f2;
109
+ --sl-color-text-muted: #6272a4;
110
+ --sl-color-border: #44475a;
111
+}
112
+
113
+/* ─── RosΓ© Pine theme ─── */
114
+[data-theme='rose-pine'] {
115
+ --ja-bg: #191724;
116
+ --ja-bg-2: #1f1d2e;
117
+ --ja-bg-3: #26233a;
118
+ --ja-panel: rgba(31, 29, 46, 0.9);
119
+ --ja-border: #403d52;
120
+ --ja-green: #9ccfd8;
121
+ --ja-green-dim: #7fb4bd;
122
+ --ja-red: #eb6f92;
123
+ --ja-white: #e0def4;
124
+ --ja-muted: #908caa;
125
+ --ja-accent: #c4a7e7;
126
+ --ja-accent-2: #ebbcba;
127
+
128
+ --sl-color-accent-low: #3d3552;
129
+ --sl-color-accent: #c4a7e7;
130
+ --sl-color-accent-high: #e0def4;
131
+ --sl-color-white: #e0def4;
132
+ --sl-color-gray-1: #e0def4;
133
+ --sl-color-gray-2: #b5b1d6;
134
+ --sl-color-gray-3: #908caa;
135
+ --sl-color-gray-4: #6e6a86;
136
+ --sl-color-gray-5: #403d52;
137
+ --sl-color-gray-6: #26233a;
138
+ --sl-color-black: #191724;
139
+ --sl-color-bg: #191724;
140
+ --sl-color-bg-nav: #1f1d2e;
141
+ --sl-color-bg-sidebar: #1f1d2e;
142
+ --sl-color-bg-hover: #26233a;
143
+ --sl-color-text: #e0def4;
144
+ --sl-color-text-muted: #908caa;
145
+ --sl-color-border: #403d52;
146
+}
147
+
148
+/* ─── Warm theme ─── */
149
+[data-theme='warm'] {
150
+ --ja-bg: #1c1412;
151
+ --ja-bg-2: #241a17;
152
+ --ja-bg-3: #33241e;
153
+ --ja-panel: rgba(36, 26, 23, 0.9);
154
+ --ja-border: #4a362e;
155
+ --ja-green: #ffb454;
156
+ --ja-green-dim: #e89b3a;
157
+ --ja-red: #ff6b6b;
158
+ --ja-white: #f8ead9;
159
+ --ja-muted: #a88b7a;
160
+ --ja-accent: #ff9d5c;
161
+ --ja-accent-2: #ffd166;
162
+
163
+ --sl-color-accent-low: #4a2c1a;
164
+ --sl-color-accent: #ff9d5c;
165
+ --sl-color-accent-high: #ffd0a8;
166
+ --sl-color-white: #f8ead9;
167
+ --sl-color-gray-1: #f8ead9;
168
+ --sl-color-gray-2: #d4bca8;
169
+ --sl-color-gray-3: #a88b7a;
170
+ --sl-color-gray-4: #7d6353;
171
+ --sl-color-gray-5: #4a362e;
172
+ --sl-color-gray-6: #33241e;
173
+ --sl-color-black: #1c1412;
174
+ --sl-color-bg: #1c1412;
175
+ --sl-color-bg-nav: #241a17;
176
+ --sl-color-bg-sidebar: #241a17;
177
+ --sl-color-bg-hover: #33241e;
178
+ --sl-color-text: #f8ead9;
179
+ --sl-color-text-muted: #a88b7a;
180
+ --sl-color-border: #4a362e;
181
+}
182
+
183
+/* ─── Typography ─── */
63
184
html {
64
- font-family: var(--sl-font);
185
+ font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
65
186
-webkit-font-smoothing: antialiased;
66
- -moz-osx-font-smoothing: grayscale;
67
187
text-rendering: optimizeLegibility;
68
188
scroll-behavior: smooth;
69
189
}
73
193
letter-spacing: -0.011em;
74
194
}
75
195
76
-/* ─── Headings ─── */
77
196
.content h1 {
78
197
font-size: 2.25rem;
79
198
font-weight: 800;
80
199
letter-spacing: -0.025em;
81
200
line-height: 1.2;
82
201
margin-bottom: 1rem;
202
+ background: linear-gradient(90deg, var(--ja-white), var(--ja-accent));
203
+ -webkit-background-clip: text;
204
+ -webkit-text-fill-color: transparent;
205
+ background-clip: text;
206
+}
207
+
208
+[data-theme='light'] .content h1 {
209
+ background: linear-gradient(90deg, var(--ja-white), var(--ja-green));
210
+ -webkit-background-clip: text;
211
+ background-clip: text;
83
212
}
84
213
85
214
.content h2 {
86
215
font-size: 1.5rem;
87
216
font-weight: 700;
88
- letter-spacing: -0.02em;
89
217
margin-top: 3rem;
90
218
margin-bottom: 1rem;
91
219
padding-bottom: 0.75rem;
92
- border-bottom: 1px solid var(--sl-color-border, #e2e8f0);
220
+ border-bottom: 1px solid var(--sl-color-border);
93
221
}
94
222
95
223
.content h3 {
97
225
font-weight: 600;
98
226
margin-top: 2rem;
99
227
margin-bottom: 0.75rem;
100
- letter-spacing: -0.01em;
101
-}
102
-
103
-.content h4 {
104
- font-size: 1rem;
105
- font-weight: 600;
106
- margin-top: 1.5rem;
107
228
}
108
229
109
230
/* ─── Links ─── */
110
231
.content a {
111
- color: var(--sl-color-accent);
232
+ color: var(--ja-accent);
112
233
text-decoration: none;
113
- transition: color 0.15s ease;
234
+ transition: color 0.15s ease, text-shadow 0.15s ease;
114
235
}
115
236
116
237
.content a:hover {
117
- color: var(--sl-color-accent-high);
238
+ color: var(--ja-accent-high);
118
239
text-decoration: underline;
119
240
text-decoration-thickness: 2px;
120
241
text-underline-offset: 3px;
242
+ text-shadow: 0 0 12px rgba(0, 255, 157, 0.4);
121
243
}
122
244
123
245
/* ─── Code Blocks ─── */
124
246
code {
125
- font-family: var(--sl-font-mono);
247
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
126
248
font-size: 0.85em;
127
249
border-radius: 6px;
128
250
padding: 0.15em 0.4em;
129
- background: var(--sl-color-gray-2, #f1f5f9);
251
+ background: var(--sl-color-gray-5);
252
+ color: var(--ja-accent);
130
253
}
131
254
132
-[data-theme='dark'] code {
133
- background: rgba(139, 92, 246, 0.15);
134
- color: #c4b5fd;
255
+[data-theme='light'] code {
256
+ background: #e8f5ee;
257
+ color: #00925c;
135
258
}
136
259
137
260
pre {
138
- font-family: var(--sl-font-mono);
261
+ font-family: 'JetBrains Mono', 'Fira Code', monospace;
139
262
font-size: 0.875rem;
140
263
line-height: 1.6;
141
264
border-radius: 12px;
142
- border: 1px solid var(--sl-color-border, #e2e8f0);
265
+ border: 1px solid var(--ja-border);
143
266
padding: 1.25rem;
144
267
overflow-x: auto;
145
- background: #0f172a !important;
268
+ background: var(--ja-bg-2);
269
+ box-shadow: inset 0 0 30px rgba(0, 255, 157, 0.03);
146
270
}
147
271
148
-[data-theme='dark'] pre {
149
- background: #0b0f19 !important;
150
- border-color: #1e293b;
272
+[data-theme='light'] pre {
273
+ background: #0d1526;
274
+ color: #e6f1ff;
151
275
}
152
276
277
+[data-theme='dracula'] pre { background: #21222c; }
278
+[data-theme='rose-pine'] pre { background: #1f1d2e; }
279
+[data-theme='warm'] pre { background: #241a17; }
280
+
153
281
pre code {
154
282
background: none;
155
283
padding: 0;
156
284
border-radius: 0;
285
+ color: inherit;
157
286
}
158
287
288
+[data-theme='light'] pre code { color: #e6f1ff; }
289
+
159
290
/* ─── Tables ─── */
160
291
.content table {
161
292
width: 100%;
164
295
border-spacing: 0;
165
296
border-radius: 12px;
166
297
overflow: hidden;
167
- border: 1px solid var(--sl-color-border, #e2e8f0);
298
+ border: 1px solid var(--ja-border);
168
299
margin: 1.5rem 0;
169
300
}
170
301
171
302
.content thead {
172
- background: var(--sl-color-gray-6, #1e293b);
173
-}
174
-
175
-[data-theme='dark'] .content thead {
176
- background: #1e293b;
177
-}
178
-
179
-[data-theme='light'] .content thead {
180
- background: #f1f5f9;
303
+ background: var(--ja-bg-3);
181
304
}
182
305
183
306
.content th {
184
307
font-weight: 600;
185
308
text-align: left;
186
309
padding: 0.75rem 1rem;
187
- border-bottom: 2px solid var(--sl-color-border, #e2e8f0);
310
+ border-bottom: 2px solid var(--ja-border);
311
+ color: var(--ja-accent);
188
312
}
189
313
190
314
.content td {
191
315
padding: 0.75rem 1rem;
192
- border-bottom: 1px solid var(--sl-color-border, #e2e8f0);
316
+ border-bottom: 1px solid var(--ja-border);
193
317
}
194
318
195
-.content tbody tr:last-child td {
196
- border-bottom: none;
319
+.content tbody tr {
320
+ transition: background 0.15s ease;
197
321
}
198
322
199
323
.content tbody tr:hover {
200
- background: var(--sl-color-bg-hover, #f8fafc);
324
+ background: var(--ja-bg-3);
201
325
}
202
326
203
-/* ─── Callouts / Asides ─── */
327
+/* ─── Callouts ─── */
204
328
.starlight-aside {
205
329
border-radius: 12px;
206
330
border-left-width: 4px;
208
332
margin: 1.5rem 0;
209
333
}
210
334
211
-.starlight-aside--note {
212
- border-left-color: var(--sl-color-blue);
213
- background: rgba(59, 130, 246, 0.05);
335
+.starlight-aside--note { border-left-color: var(--ja-accent-2); background: rgba(0, 212, 255, 0.06); }
336
+.starlight-aside--tip { border-left-color: var(--ja-green); background: rgba(0, 255, 157, 0.06); }
337
+.starlight-aside--caution { border-left-color: #ffb454; background: rgba(255, 180, 84, 0.06); }
338
+.starlight-aside--danger { border-left-color: var(--ja-red); background: rgba(255, 46, 77, 0.06); }
339
+
340
+/* ─── Sci-Fi Background Grid ─── */
341
+.site-frame::before,
342
+body::before {
343
+ content: '';
344
+ position: fixed;
345
+ inset: 0;
346
+ z-index: -1;
347
+ pointer-events: none;
348
+ background-image:
349
+ linear-gradient(rgba(0, 255, 157, 0.03) 1px, transparent 1px),
350
+ linear-gradient(90deg, rgba(0, 255, 157, 0.03) 1px, transparent 1px);
351
+ background-size: 48px 48px;
352
+ animation: gridScroll 24s linear infinite;
353
+}
354
+
355
+[data-theme='light'] body::before {
356
+ background-image:
357
+ linear-gradient(rgba(0, 146, 92, 0.04) 1px, transparent 1px),
358
+ linear-gradient(90deg, rgba(0, 146, 92, 0.04) 1px, transparent 1px);
359
+}
360
+
361
+@keyframes gridScroll {
362
+ from { background-position: 0 0; }
363
+ to { background-position: 0 48px; }
214
364
}
215
365
216
-.starlight-aside--tip {
217
- border-left-color: var(--sl-color-green);
218
- background: rgba(16, 185, 129, 0.05);
366
+/* ─── Scanline sweep ─── */
367
+.main-frame::after,
368
+body::after {
369
+ content: '';
370
+ position: fixed;
371
+ left: 0;
372
+ right: 0;
373
+ height: 120px;
374
+ z-index: 9999;
375
+ pointer-events: none;
376
+ background: linear-gradient(180deg, transparent, rgba(0, 255, 157, 0.04), transparent);
377
+ animation: scanSweep 7s linear infinite;
219
378
}
220
379
221
-.starlight-aside--caution {
222
- border-left-color: var(--sl-color-yellow);
223
- background: rgba(245, 158, 11, 0.05);
380
+[data-theme='light'] body::after {
381
+ background: linear-gradient(180deg, transparent, rgba(0, 146, 92, 0.05), transparent);
224
382
}
225
383
226
-.starlight-aside--danger {
227
- border-left-color: var(--sl-color-red);
228
- background: rgba(239, 68, 68, 0.05);
384
+@keyframes scanSweep {
385
+ from { top: -120px; }
386
+ to { top: 100vh; }
229
387
}
230
388
231
-/* ─── Hero Gradient ─── */
232
-.hero-gradient {
233
- background: linear-gradient(135deg, #e6522c 0%, #8b5cf6 50%, #3b82f6 100%);
234
- -webkit-background-clip: text;
235
- -webkit-text-fill-color: transparent;
236
- background-clip: text;
389
+/* ─── Glow Effects ─── */
390
+.content h2::after {
391
+ content: '';
392
+ display: block;
393
+ width: 3rem;
394
+ height: 3px;
395
+ margin-top: 0.5rem;
396
+ background: linear-gradient(90deg, var(--ja-accent), transparent);
397
+ animation: glowPulse 3s ease-in-out infinite;
398
+}
399
+
400
+@keyframes glowPulse {
401
+ 0%, 100% { opacity: 0.6; }
402
+ 50% { opacity: 1; box-shadow: 0 0 12px rgba(0, 255, 157, 0.6); }
237
403
}
238
404
239
-/* ─── Feature Grid ─── */
405
+/* ─── Feature Cards ─── */
240
406
.feature-grid {
241
407
display: grid;
242
408
grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
245
411
}
246
412
247
413
.feature-card {
248
- border: 1px solid var(--sl-color-border, #e2e8f0);
414
+ border: 1px solid var(--ja-border);
249
415
border-radius: 16px;
250
416
padding: 1.75rem;
251
- background: var(--sl-color-bg, #ffffff);
417
+ background: var(--ja-panel);
418
+ backdrop-filter: blur(12px);
252
419
transition: all 0.25s cubic-bezier(0.4, 0, 0.2, 1);
253
420
position: relative;
254
421
overflow: hidden;
261
428
left: 0;
262
429
right: 0;
263
430
height: 3px;
264
- background: linear-gradient(90deg, var(--sl-color-accent), var(--sl-color-blue));
431
+ background: linear-gradient(90deg, var(--ja-accent), var(--ja-accent-2));
265
432
opacity: 0;
266
433
transition: opacity 0.25s ease;
267
434
}
268
435
269
436
.feature-card:hover {
270
- border-color: var(--sl-color-accent);
437
+ border-color: var(--ja-accent);
271
438
transform: translateY(-4px);
272
- box-shadow: 0 20px 40px -12px rgba(139, 92, 246, 0.15);
439
+ box-shadow: 0 0 30px rgba(0, 255, 157, 0.15);
273
440
}
274
441
275
-.feature-card:hover::before {
276
- opacity: 1;
277
-}
442
+.feature-card:hover::before { opacity: 1; }
278
443
279
444
.feature-card h3 {
280
445
margin-top: 0;
281
446
font-size: 1.1rem;
282
447
font-weight: 600;
448
+ color: var(--ja-white);
283
449
}
284
450
285
451
/* ─── Benchmark Card ─── */
286
452
.benchmark-card {
287
- border: 1px solid rgba(139, 92, 246, 0.3);
453
+ border: 1px solid rgba(0, 255, 157, 0.3);
288
454
border-radius: 16px;
289
455
padding: 1.75rem;
290
- background: rgba(17, 24, 39, 0.7);
456
+ background: var(--ja-panel);
291
457
backdrop-filter: blur(16px);
292
458
margin-bottom: 1.5rem;
293
459
position: relative;
301
467
left: 0;
302
468
right: 0;
303
469
height: 2px;
304
- background: linear-gradient(90deg, var(--sl-color-orange), var(--sl-color-accent), var(--sl-color-blue));
470
+ background: linear-gradient(90deg, var(--ja-green), var(--ja-accent), var(--ja-accent-2));
471
+ background-size: 200% 100%;
472
+ animation: gradientShift 4s linear infinite;
473
+}
474
+
475
+@keyframes gradientShift {
476
+ from { background-position: 0 0; }
477
+ to { background-position: 200% 0; }
305
478
}
306
479
307
480
/* ─── Performance Table ─── */
311
484
border-spacing: 0;
312
485
border-radius: 12px;
313
486
overflow: hidden;
314
- border: 1px solid var(--sl-color-border, #e2e8f0);
487
+ border: 1px solid var(--ja-border);
315
488
}
316
489
317
490
.performance-table th {
318
491
text-align: left;
319
492
padding: 1rem 1.25rem;
320
493
font-weight: 600;
321
- background: var(--sl-color-gray-6, #1e293b);
494
+ background: var(--ja-bg-3);
495
+ color: var(--ja-accent);
322
496
}
323
497
324
498
.performance-table td {
332
506
}
333
507
334
508
.performance-table .winner {
335
- color: var(--sl-color-accent-high);
509
+ color: var(--ja-green);
336
510
font-weight: 700;
337
511
font-size: 1.1em;
338
-}
339
-
340
-.performance-table tbody tr:hover {
341
- background: var(--sl-color-bg-hover, #f8fafc);
512
+ text-shadow: 0 0 10px rgba(0, 255, 157, 0.5);
342
513
}
343
514
344
515
/* ─── Sidebar ─── */
347
518
font-size: 0.8rem;
348
519
text-transform: uppercase;
349
520
letter-spacing: 0.05em;
350
- color: var(--sl-color-text-muted, #64748b);
521
+ color: var(--ja-muted);
351
522
}
352
523
353
-/* ─── Badge Styling ─── */
524
+/* ─── Badges ─── */
354
525
.badge--success {
355
- background: rgba(16, 185, 129, 0.15);
356
- color: var(--sl-color-green);
357
- border: 1px solid rgba(16, 185, 129, 0.3);
526
+ background: rgba(0, 255, 157, 0.15);
527
+ color: var(--ja-green);
528
+ border: 1px solid rgba(0, 255, 157, 0.3);
358
529
border-radius: 9999px;
359
530
padding: 0.15em 0.6em;
360
531
font-size: 0.75rem;
361
532
font-weight: 600;
362
533
}
363
534
364
-/* ─── Card Grid Overrides ─── */
365
-.sl-card-grid {
366
- gap: 1.25rem;
367
-}
368
-
535
+/* ─── Cards ─── */
369
536
.sl-card {
370
537
border-radius: 12px;
371
- border: 1px solid var(--sl-color-border, #e2e8f0);
538
+ border: 1px solid var(--ja-border);
372
539
transition: all 0.2s ease;
540
+ background: var(--ja-panel);
373
541
}
374
542
375
543
.sl-card:hover {
376
- border-color: var(--sl-color-accent);
377
- box-shadow: 0 8px 24px -8px rgba(139, 92, 246, 0.12);
544
+ border-color: var(--ja-accent);
545
+ box-shadow: 0 0 24px rgba(0, 255, 157, 0.15);
378
546
}
379
547
380
-/* ─── TOC (Table of Contents) ─── */
381
-.toc-panel {
382
- font-size: 0.85rem;
548
+/* ─── Search ─── */
549
+.search-input {
550
+ border-radius: 10px !important;
551
+ font-size: 0.9rem !important;
383
552
}
384
553
385
-.toc-panel a {
386
- transition: color 0.15s ease;
554
+/* ─── Mobile Responsive ─── */
555
+@media (max-width: 768px) {
556
+ .content h1 { font-size: 1.75rem; }
557
+ .content h2 { font-size: 1.3rem; }
558
+ .feature-grid { grid-template-columns: 1fr; }
559
+ .performance-table { font-size: 0.8rem; }
387
560
}
388
561
389
-/* ─── Breadcrumbs ─── */
390
-.breadcrumbs a {
391
- font-size: 0.85rem;
392
- color: var(--sl-color-text-muted, #64748b);
393
- transition: color 0.15s ease;
562
+/* ─── Print ─── */
563
+@media print {
564
+ .sidebar, .toc-panel, .edit-link, .prev-next-nav { display: none !important; }
565
+ .content { max-width: 100%; }
394
566
}
395
567
396
-.breadcrumbs a:hover {
397
- color: var(--sl-color-accent);
568
+/* ─── Accessibility ─── */
569
+:focus-visible {
570
+ outline: 2px solid var(--ja-accent);
571
+ outline-offset: 2px;
398
572
}
399
573
400
-/* ─── Navigation (Prev/Next) ─── */
401
-.prev-next-nav a {
402
- border-radius: 12px;
403
- transition: all 0.2s ease;
404
- border: 1px solid var(--sl-color-border, #e2e8f0);
574
+::selection {
575
+ background: rgba(0, 255, 157, 0.3);
576
+ color: var(--ja-white);
405
577
}
406
578
407
-.prev-next-nav a:hover {
408
- border-color: var(--sl-color-accent);
409
- box-shadow: 0 4px 12px -4px rgba(139, 92, 246, 0.15);
579
+[data-theme='light'] ::selection {
580
+ background: rgba(0, 146, 92, 0.2);
410
581
}
411
582
412
-/* ─── Search ─── */
413
-.search-input {
414
- border-radius: 10px !important;
415
- font-size: 0.9rem !important;
583
+/* ─── Scrollbar ─── */
584
+::-webkit-scrollbar { width: 8px; height: 8px; }
585
+::-webkit-scrollbar-track { background: transparent; }
586
+::-webkit-scrollbar-thumb {
587
+ background: var(--ja-border);
588
+ border-radius: 4px;
416
589
}
590
+::-webkit-scrollbar-thumb:hover { background: var(--ja-accent); }
417
591
418
-/* ─── Mobile Responsive ─── */
419
-@media (max-width: 768px) {
420
- .content h1 {
421
- font-size: 1.75rem;
422
- }
592
+/* ─── Animations ─── */
593
+@keyframes fadeInUp {
594
+ from { opacity: 0; transform: translateY(12px); }
595
+ to { opacity: 1; transform: translateY(0); }
596
+}
423
597
424
- .content h2 {
425
- font-size: 1.3rem;
426
- }
598
+.content > * {
599
+ animation: fadeInUp 0.3s ease-out;
600
+}
427
601
428
- .feature-grid {
429
- grid-template-columns: 1fr;
430
- }
602
+/* ─── Code Group Tabs ─── */
603
+.tab-label {
604
+ font-family: 'JetBrains Mono', monospace;
605
+ font-size: 0.8rem;
606
+}
431
607
432
- .performance-table {
433
- font-size: 0.8rem;
434
- }
608
+/* ─── Theme Switcher Widget ─── */
609
+.ja-theme-switcher {
610
+ position: fixed;
611
+ bottom: 1.25rem;
612
+ right: 1.25rem;
613
+ z-index: 1000;
614
+ display: flex;
615
+ gap: 0.35rem;
616
+ padding: 0.35rem;
617
+ border-radius: 9999px;
618
+ border: 1px solid var(--ja-border);
619
+ background: var(--ja-panel);
620
+ backdrop-filter: blur(12px);
621
+}
435
622
436
- .performance-table th,
437
- .performance-table td {
438
- padding: 0.5rem 0.75rem;
439
- }
623
+.ja-theme-btn {
624
+ width: 2rem;
625
+ height: 2rem;
626
+ border-radius: 9999px;
627
+ border: 1px solid transparent;
628
+ cursor: pointer;
629
+ transition: all 0.2s ease;
630
+ position: relative;
440
631
}
441
632
442
-/* ─── Print Styles ─── */
443
-@media print {
444
- .sidebar,
445
- .toc-panel,
446
- .edit-link,
447
- .prev-next-nav {
448
- display: none !important;
449
- }
633
+.ja-theme-btn:hover { transform: scale(1.15); }
634
+.ja-theme-btn[data-active='true'] {
635
+ border-color: var(--ja-white);
636
+ box-shadow: 0 0 12px currentColor;
637
+}
638
+
639
+.ja-theme-btn--dark { background: #05080f; color: #00ff9d; }
640
+.ja-theme-btn--light { background: #f4f7fb; color: #00925c; }
641
+.ja-theme-btn--dracula { background: #282a36; color: #bd93f9; }
642
+.ja-theme-btn--rosepine { background: #191724; color: #c4a7e7; }
643
+.ja-theme-btn--warm { background: #1c1412; color: #ff9d5c; }
450
644
451
- .content {
452
- max-width: 100%;
453
- }
645
+/* ─── Landing Page ─── */
646
+.ja-hero {
647
+ position: relative;
648
+ border: 1px solid var(--ja-border);
649
+ border-radius: 24px;
650
+ overflow: hidden;
651
+ margin: 1.5rem 0;
652
+ background: var(--ja-bg-2);
454
653
}
455
654
456
-/* ─── Focus Styles (Accessibility) ─── */
457
-:focus-visible {
458
- outline: 2px solid var(--sl-color-accent);
459
- outline-offset: 2px;
460
- border-radius: 4px;
655
+.ja-hero img {
656
+ display: block;
657
+ width: 100%;
658
+ height: auto;
461
659
}
462
660
463
-/* ─── Selection ─── */
464
-::selection {
465
- background: rgba(139, 92, 246, 0.3);
466
- color: var(--sl-color-white);
661
+.ja-stats {
662
+ display: grid;
663
+ grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
664
+ gap: 1rem;
665
+ margin: 2rem 0;
467
666
}
468
667
469
-[data-theme='light'] ::selection {
470
- background: rgba(139, 92, 246, 0.2);
471
- color: var(--sl-color-black);
668
+.ja-stat {
669
+ border: 1px solid var(--ja-border);
670
+ border-radius: 16px;
671
+ padding: 1.25rem;
672
+ text-align: center;
673
+ background: var(--ja-panel);
674
+ transition: all 0.25s ease;
472
675
}
473
676
474
-/* ─── Scrollbar ─── */
475
-::-webkit-scrollbar {
476
- width: 8px;
477
- height: 8px;
677
+.ja-stat:hover {
678
+ border-color: var(--ja-accent);
679
+ transform: translateY(-3px);
680
+ box-shadow: 0 0 24px rgba(0, 255, 157, 0.12);
478
681
}
479
682
480
-::-webkit-scrollbar-track {
481
- background: transparent;
683
+.ja-stat-value {
684
+ font-size: 2rem;
685
+ font-weight: 800;
686
+ color: var(--ja-accent);
687
+ font-family: 'JetBrains Mono', monospace;
688
+ text-shadow: 0 0 16px rgba(0, 255, 157, 0.4);
482
689
}
483
690
484
-::-webkit-scrollbar-thumb {
485
- background: var(--sl-color-gray-4, #64748b);
486
- border-radius: 4px;
691
+.ja-stat-label {
692
+ font-size: 0.85rem;
693
+ color: var(--ja-muted);
694
+ margin-top: 0.25rem;
487
695
}
488
696
489
-::-webkit-scrollbar-thumb:hover {
490
- background: var(--sl-color-gray-3, #94a3b8);
697
+/* ─── Landing: Code Terminal ─── */
698
+.ja-terminal {
699
+ border: 1px solid var(--ja-border);
700
+ border-radius: 16px;
701
+ overflow: hidden;
702
+ margin: 2rem 0;
703
+ background: var(--ja-bg-2);
491
704
}
492
705
493
-/* ─── Animations ─── */
494
-@keyframes fadeInUp {
495
- from {
496
- opacity: 0;
497
- transform: translateY(12px);
498
- }
499
- to {
500
- opacity: 1;
501
- transform: translateY(0);
502
- }
706
+.ja-terminal-bar {
707
+ display: flex;
708
+ align-items: center;
709
+ gap: 0.5rem;
710
+ padding: 0.6rem 1rem;
711
+ background: var(--ja-bg-3);
712
+ border-bottom: 1px solid var(--ja-border);
503
713
}
504
714
505
-.content > * {
506
- animation: fadeInUp 0.3s ease-out;
715
+.ja-terminal-dot {
716
+ width: 12px;
717
+ height: 12px;
718
+ border-radius: 9999px;
719
+}
720
+
721
+.ja-terminal-dot:nth-child(1) { background: #ff2e4d; }
722
+.ja-terminal-dot:nth-child(2) { background: #ffb454; }
723
+.ja-terminal-dot:nth-child(3) { background: #00ff9d; }
724
+
725
+.ja-terminal-body {
726
+ padding: 1.25rem;
727
+ font-family: 'JetBrains Mono', monospace;
728
+ font-size: 0.85rem;
729
+ color: var(--ja-green);
730
+ line-height: 1.7;
507
731
}
508
732
509
-/* ─── Starlight Overrides ─── */
510
-.starlight-sidebar > div {
511
- border-right: 1px solid var(--sl-color-border, #e2e8f0);
733
+.ja-terminal-body .cm { color: var(--ja-muted); }
734
+.ja-terminal-body .ok { color: var(--ja-green); }
735
+.ja-terminal-body .err { color: var(--ja-red); }
736
+
737
+/* ─── Landing: Feature Matrix Graph ─── */
738
+.ja-graph {
739
+ border: 1px solid var(--ja-border);
740
+ border-radius: 16px;
741
+ padding: 1rem;
742
+ background: var(--ja-bg-2);
743
+ margin: 2rem 0;
512
744
}
513
745
514
-/* ─── Code Group Tabs ─── */
515
-.tab-label {
516
- font-family: var(--sl-font-mono);
517
- font-size: 0.8rem;
746
+.ja-graph img {
747
+ display: block;
748
+ width: 100%;
749
+ height: auto;
750
+}
751
+
752
+/* ─── Landing: Call-to-Action ─── */
753
+.ja-cta {
754
+ border: 1px solid var(--ja-accent);
755
+ border-radius: 16px;
756
+ padding: 2rem;
757
+ text-align: center;
758
+ margin: 2rem 0;
759
+ background:
760
+ radial-gradient(ellipse at center, rgba(0, 255, 157, 0.08), transparent 70%),
761
+ var(--ja-panel);
762
+ animation: ctaGlow 4s ease-in-out infinite;
763
+}
764
+
765
+@keyframes ctaGlow {
766
+ 0%, 100% { box-shadow: 0 0 20px rgba(0, 255, 157, 0.1); }
767
+ 50% { box-shadow: 0 0 40px rgba(0, 255, 157, 0.25); }
518
768
}
519
769
520
-/* ─── Gradient Text Utility ─── */
521
-.gradient-text {
522
- background: linear-gradient(135deg, #e6522c, #8b5cf6, #3b82f6);
770
+.ja-cta-title {
771
+ font-size: 1.75rem;
772
+ font-weight: 800;
773
+ background: linear-gradient(90deg, var(--ja-white), var(--ja-accent));
523
774
-webkit-background-clip: text;
524
775
-webkit-text-fill-color: transparent;
525
776
background-clip: text;
526
777