diff --git a/USER_GUIDE.md b/USER_GUIDE.md
index 3304ae9..fb5c728 100644
--- a/USER_GUIDE.md
+++ b/USER_GUIDE.md
@@ -638,7 +638,7 @@ STATIC_CACHE_PRELOAD=true STATIC_CACHE_GC_PERCENT=400 ./bin/static-web
### GC tuning
-`gc_percent` sets the Go runtime `GOGC` target. A higher value means the GC runs less often, trading memory for throughput. The handler's hot path is allocation-free, and fasthttp reuses per-connection buffers (unlike net/http which allocates per-request). Recommended values:
+`gc_percent` sets the Go runtime `GOGC` target. A higher value means the GC runs less often, trading memory for throughput. The handler's hot path has near-zero allocations, and fasthttp reuses per-connection buffers (unlike net/http which allocates per-request). Recommended values:
| `gc_percent` | Behaviour |
|---|---|
diff --git a/docs/index.html b/docs/index.html
index 40980f9..82addb0 100644
--- a/docs/index.html
+++ b/docs/index.html
@@ -48,7 +48,7 @@
@@ -298,12 +298,14 @@
-
โก
+
Near-Zero Alloc Hot Path
~141k req/sec โ 55% faster than Bun. Built on fasthttp with direct ctx.SetBody() and pre-formatted headers โ no formatting allocations on cache hits.
-
๐๏ธ
+
gzip + Brotli
On-the-fly gzip via pooled writers, plus pre-compressed .gz/.br sidecar file
@@ -311,7 +313,7 @@
gzip + Brotli
-
๐
+
TLS 1.2 / 1.3
Modern cipher suites, automatic HTTPโHTTPS redirects, HSTS, and HTTP/2 via ALPN negotiation โ just set
@@ -319,7 +321,7 @@
TLS 1.2 / 1.3
-
๐ก๏ธ
+
Security Hardened
Path traversal prevention, dotfile blocking, CSP, HSTS, Referrer-Policy, Permissions-Policy โ set on
@@ -327,12 +329,12 @@
Security Hardened
-
๐ฆ
+
Smart Caching
Byte-accurate LRU cache with startup preloading, configurable max size, per-file size cap, optional TTL expiry, ETag, and live flush via SIGHUP without downtime.
-
๐
+
HTTP/2 & Range Requests
Full HTTP/2 support, byte-range serving for video / large files, conditional requests (ETag,
@@ -340,7 +342,7 @@
HTTP/2 & Range Requests
-
๐
+
CORS Built-In
Wildcard or per-origin CORS. Preflight returns 204 with proper headers. Wildcard emits literal
@@ -348,7 +350,7 @@
CORS Built-In
-
๐ณ
+
Container Ready
Most settings overridable via environment variables. Graceful shutdown on SIGTERM/SIGINT with
@@ -356,7 +358,7 @@
Container Ready
-
๐
+
Directory Listing
Optional HTML directory index with breadcrumb nav, sorted entries, human-readable sizes, and automatic
@@ -511,7 +513,7 @@
Request Pipeline
-
๐
+
HTTP Request
Incoming GET / HEAD / OPTIONS
@@ -523,7 +525,7 @@
HTTP Request
-
๐ก๏ธ
+
Recovery Middleware
Panic โ 500, log stack trace
@@ -535,7 +537,7 @@
Recovery Middleware
-
๐
+
Logging Middleware
Pooled status writer, method / path / status / bytes / duration
@@ -547,7 +549,7 @@
Logging Middleware
-
๐
+
Security Middleware
Method whitelist ยท security headers ยท path safety (cached) ยท dotfile block ยท CORS
@@ -559,7 +561,7 @@
Security Middleware
-
๐๏ธ
+
Compress Middleware
Post-processing gzip via pooled writers ยท content-type / size gating
@@ -571,7 +573,7 @@
Compress Middleware
-
โก
+
File Handler
@@ -603,19 +605,19 @@
- โก static-web (fasthttp)
+ static-web (fasthttp)
~141,000
619 µs
2.46 ms
- ๐ฅ Bun (native static)
+ Bun (native static)
~90,000
1.05 ms
2.33 ms
- ๐ฆ static-web (old net/http)
+ static-web (old net/http)
~76,000
1.25 ms
3.15 ms
@@ -627,24 +629,24 @@
-
๐ง
+
fasthttp + Preload
- Built on fasthttp with zero per-request allocations. --preload loads all files into RAM at startup. Cache hits use direct ctx.SetBody() with pre-formatted headers.
+ Built on fasthttp with near-zero per-request allocations. --preload loads all files into RAM at startup. Cache hits use direct ctx.SetBody() with pre-formatted headers.
-
๐ค
+
55% Faster Than Bun
With fasthttp + preload, static-web reaches ~141k req/sec โ 55% faster than Bun at ~90k req/sec , while offering full security headers, TLS, and compression out of the box.
-
โป๏ธ
+
GC tuned
- gc_percent = 400 reduces GC frequency by 4x. The hot path is allocation-free โ fasthttp reuses per-connection buffers, eliminating the per-request allocations of net/http.
+ gc_percent = 400 reduces GC frequency by 4x. The hot path has near-zero allocations โ fasthttp reuses per-connection buffers, eliminating the per-request allocations of net/http.
@@ -669,7 +671,7 @@ Configuration Reference
- ๐ฅ๏ธ server
+ server
Configuration Reference
- ๐ files
+ files
Configuration Reference
- ๐ฆ cache
+ cache
Configuration Reference
- ๐๏ธ compression
+ compression
Configuration Reference
- ๐ headers
+ headers
Configuration Reference
- ๐ก๏ธ security
+ security
@@ -1018,7 +1020,7 @@ Security Model
aria-controls="sec-panel-path"
id="sec-tab-path"
>
- ๐ Path Safety
+ Path Safety
Security Model
aria-controls="sec-panel-headers"
id="sec-tab-headers"
>
- ๐ Headers
+ Headers
- ๐ก๏ธ DoS
+ DoS
- ๐ CORS
+ CORS
- ๐ TLS
+ TLS
Security Model
aria-controls="sec-panel-runtime"
id="sec-tab-runtime"
>
- โก Runtime
+ Runtime
@@ -1303,7 +1305,7 @@ Legal
diff --git a/docs/script.js b/docs/script.js
index c6649bf..d04fd57 100644
--- a/docs/script.js
+++ b/docs/script.js
@@ -332,7 +332,7 @@ document.querySelectorAll('a[href^="#"]').forEach(function (link) {
โ Groups elements by parent section for incremental delays
=========================== */
(function initReveal() {
- var selectors = '.feature-card, .pipeline-step, .perf-card';
+ var selectors = ".feature-card, .pipeline-step, .perf-card, .section-title, .section-description, .cta-card";
var targets = document.querySelectorAll(selectors);
if (!targets.length) return;
diff --git a/docs/styles.css b/docs/styles.css
index 3be82c8..4dce2dd 100644
--- a/docs/styles.css
+++ b/docs/styles.css
@@ -2,24 +2,24 @@
CSS Variables & Design System
=========================== */
:root {
- --color-bg: #0a0a0f;
- --color-bg-secondary: #12121a;
- --color-bg-tertiary: #1a1a25;
- --color-text: #e4e4e7;
+ --color-bg: #000000;
+ --color-bg-secondary: #0a0a0a;
+ --color-bg-tertiary: #111111;
+ --color-text: #ededed;
--color-text-secondary: #a1a1aa;
--color-text-muted: #71717a;
- --color-primary: #6366f1;
- --color-primary-light: #818cf8;
+ --color-primary: #ffffff;
+ --color-primary-light: #e4e4e7;
--color-secondary: #8b5cf6;
--color-accent: #22d3ee;
--color-accent-green: #34d399;
--color-border: #27272a;
--color-border-light: #3f3f46;
- --gradient-primary: linear-gradient(135deg, #6366f1 0%, #8b5cf6 50%, #a855f7 100%);
+ --gradient-primary: linear-gradient(135deg, #ffffff 0%, #a1a1aa 100%);
--gradient-accent: linear-gradient(135deg, #22d3ee 0%, #34d399 100%);
- --gradient-glow: linear-gradient(135deg, rgba(99,102,241,0.3) 0%, rgba(139,92,246,0.3) 100%);
- --shadow-glow: 0 0 60px rgba(99,102,241,0.3);
- --font-sans: 'Outfit', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
+ --gradient-glow: linear-gradient(135deg, rgba(255,255,255,0.1) 0%, rgba(255,255,255,0.05) 100%);
+ --shadow-glow: 0 0 60px rgba(255,255,255,0.05);
+ --font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
--font-mono: 'JetBrains Mono', 'Fira Code', monospace;
--radius-sm: 6px;
--radius-md: 12px;
@@ -73,6 +73,20 @@ a { color: inherit; text-decoration: none; }
top: 16px;
}
+/* ===========================
+ Scroll-Reveal (injected by JS but base defined here for no-FOUC)
+ =========================== */
+.reveal {
+ opacity: 0;
+ transform: translateY(24px);
+ transition: opacity 0.6s cubic-bezier(0.4, 0, 0.2, 1), transform 0.6s cubic-bezier(0.4, 0, 0.2, 1);
+}
+
+.reveal.visible {
+ opacity: 1;
+ transform: translateY(0);
+}
+
/* ===========================
Navigation
=========================== */
@@ -80,7 +94,7 @@ a { color: inherit; text-decoration: none; }
display: flex;
justify-content: space-between;
align-items: center;
- padding: 20px 40px;
+ padding: 16px 40px;
max-width: 1400px;
margin: 0 auto;
position: relative;
@@ -134,7 +148,7 @@ a { color: inherit; text-decoration: none; }
display: inline-flex;
align-items: center;
gap: 8px;
- padding: 9px 18px;
+ padding: 8px 16px;
background: var(--color-bg-tertiary);
border: 1px solid var(--color-border);
border-radius: var(--radius-full);
@@ -150,7 +164,7 @@ a { color: inherit; text-decoration: none; }
.nav-cta:hover {
border-color: var(--color-primary);
color: var(--color-text);
- background: rgba(99,102,241,0.1);
+ background: rgba(255,255,255,0.1);
}
/* Hamburger Button */
@@ -202,7 +216,7 @@ a { color: inherit; text-decoration: none; }
position: relative;
display: flex;
flex-direction: column;
- min-height: 100vh;
+ min-height: 65vh;
overflow: hidden;
background: var(--color-bg);
}
@@ -224,20 +238,20 @@ a { color: inherit; text-decoration: none; }
align-items: center;
justify-content: center;
text-align: center;
- padding: 20px 20px 48px;
+ padding: 16px 16px 24px;
position: relative;
z-index: 2;
}
.hero-logo {
- margin-bottom: 16px;
+ margin-bottom: 12px;
animation: float 6s ease-in-out infinite;
}
.hero-logo-svg {
width: 80px;
height: 80px;
- filter: drop-shadow(0 0 40px rgba(99,102,241,0.45));
+ filter: drop-shadow(0 0 40px rgba(255,255,255,0.45));
}
@keyframes float {
@@ -246,13 +260,13 @@ a { color: inherit; text-decoration: none; }
}
.hero-title {
- font-size: clamp(2.8rem, 6vw, 4.2rem);
+ font-size: clamp(2.6rem, 5vw, 4rem);
font-weight: 800;
background: var(--gradient-primary);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
- margin-bottom: 8px;
+ margin-bottom: 4px;
letter-spacing: -0.03em;
}
@@ -260,15 +274,15 @@ a { color: inherit; text-decoration: none; }
font-size: clamp(1rem, 2.5vw, 1.3rem);
color: var(--color-text-secondary);
font-weight: 500;
- margin-bottom: 12px;
+ margin-bottom: 8px;
}
.hero-description {
font-size: 1rem;
color: var(--color-text-muted);
max-width: 620px;
- margin-bottom: 28px;
- line-height: 1.75;
+ margin-bottom: 16px;
+ line-height: 1.6;
}
.hero-description strong { color: var(--color-accent); }
@@ -279,11 +293,11 @@ a { color: inherit; text-decoration: none; }
grid-template-columns: repeat(4, auto);
align-items: center;
column-gap: 0;
- margin-bottom: 24px;
+ margin-bottom: 16px;
background: var(--color-bg-tertiary);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
- padding: 14px 24px;
+ padding: 12px 20px;
}
.stat {
@@ -323,7 +337,7 @@ a { color: inherit; text-decoration: none; }
.hero-actions {
display: flex;
gap: 12px;
- margin-bottom: 20px;
+ margin-bottom: 16px;
flex-wrap: wrap;
justify-content: center;
}
@@ -332,27 +346,31 @@ a { color: inherit; text-decoration: none; }
display: inline-flex;
align-items: center;
gap: 8px;
- padding: 14px 28px;
+ padding: 12px 24px;
border-radius: var(--radius-md);
font-weight: 600;
- font-size: 0.95rem;
- transition: all 0.3s ease;
+ font-size: 0.9rem;
+ transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1);
border: none;
cursor: pointer;
font-family: var(--font-sans);
+ position: relative;
+ overflow: hidden;
}
-.btn-icon { width: 18px; height: 18px; }
+.btn-icon { width: 18px; height: 18px; transition: transform 0.3s ease; }
+
+.btn:hover .btn-icon { transform: scale(1.1); }
.btn-primary {
background: var(--gradient-primary);
- color: white;
- box-shadow: 0 4px 20px rgba(99,102,241,0.4);
+ color: #000;
+ box-shadow: 0 4px 20px rgba(255,255,255,0.2);
}
.btn-primary:hover {
- transform: translateY(-2px);
- box-shadow: 0 6px 32px rgba(99,102,241,0.55);
+ transform: translateY(-2px) scale(1.02);
+ box-shadow: 0 8px 32px rgba(255,255,255,0.4);
}
.btn-secondary {
@@ -362,8 +380,10 @@ a { color: inherit; text-decoration: none; }
}
.btn-secondary:hover {
- background: var(--color-border);
- border-color: var(--color-border-light);
+ background: var(--color-bg-secondary);
+ border-color: var(--color-primary-light);
+ transform: translateY(-2px);
+ box-shadow: 0 8px 24px rgba(255,255,255,0.1);
}
/* Install bar (hero + CTA shared) */
@@ -410,7 +430,7 @@ a { color: inherit; text-decoration: none; }
transform: translate(-50%, -50%);
width: 900px;
height: 900px;
- background: radial-gradient(circle, rgba(99,102,241,0.13) 0%, transparent 65%);
+ background: radial-gradient(circle, rgba(255,255,255,0.13) 0%, transparent 65%);
pointer-events: none;
z-index: 1;
}
@@ -425,7 +445,7 @@ a { color: inherit; text-decoration: none; }
.section-inner {
max-width: 1200px;
margin: 0 auto;
- padding: 56px 20px;
+ padding: 40px 20px;
}
.section-inner--narrow {
@@ -447,7 +467,7 @@ a { color: inherit; text-decoration: none; }
text-align: center;
color: var(--color-text-secondary);
font-size: 1rem;
- margin-bottom: 36px;
+ margin-bottom: 24px;
max-width: 600px;
margin-left: auto;
margin-right: auto;
@@ -506,14 +526,14 @@ a { color: inherit; text-decoration: none; }
background: var(--color-bg-tertiary);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
- padding: 22px;
+ padding: 20px;
transition: all 0.3s ease;
}
.feature-card:hover {
- border-color: var(--color-primary);
- transform: translateY(-3px);
- box-shadow: 0 8px 30px rgba(99,102,241,0.15);
+ border-color: var(--color-secondary);
+ transform: translateY(-4px);
+ box-shadow: 0 12px 40px rgba(139, 92, 246, 0.15), 0 0 20px rgba(139, 92, 246, 0.1);
}
.feature-icon { font-size: 1.8rem; margin-bottom: 10px; }
@@ -536,7 +556,7 @@ a { color: inherit; text-decoration: none; }
.feature-card p code {
font-family: var(--font-mono);
font-size: 0.82em;
- background: rgba(99,102,241,0.15);
+ background: rgba(255,255,255,0.15);
padding: 1px 5px;
border-radius: 4px;
color: var(--color-primary-light);
@@ -574,7 +594,7 @@ a { color: inherit; text-decoration: none; }
.tab-btn[aria-selected="true"] {
background: var(--gradient-primary);
border-color: transparent;
- color: white;
+ color: #000;
}
.tab-btn:focus-visible {
@@ -622,7 +642,7 @@ a { color: inherit; text-decoration: none; }
}
.code-block pre {
- padding: 18px 20px;
+ padding: 16px 20px;
overflow-x: auto;
font-family: var(--font-mono);
font-size: 0.85rem;
@@ -661,15 +681,15 @@ a { color: inherit; text-decoration: none; }
background: var(--color-bg-tertiary);
border: 1px solid var(--color-border);
border-radius: var(--radius-md);
- padding: 14px 18px;
+ padding: 12px 16px;
transition: all 0.25s;
}
.pipeline-step:hover { border-color: var(--color-border-light); }
.pipeline-step--highlight {
- border-color: rgba(99,102,241,0.4);
- background: rgba(99,102,241,0.07);
+ border-color: rgba(255,255,255,0.4);
+ background: rgba(255,255,255,0.07);
}
.pipeline-step--highlight:hover { border-color: var(--color-primary); }
@@ -704,7 +724,7 @@ a { color: inherit; text-decoration: none; }
/* Benchmark table wrapper โ border-radius fix (border-collapse: collapse kills border-radius) */
.benchmark-table-wrap {
max-width: 760px;
- margin: 0 auto 28px;
+ margin: 0 auto 20px;
overflow-x: auto;
}
@@ -740,7 +760,7 @@ a { color: inherit; text-decoration: none; }
}
.benchmark-table tr.highlight td {
- background: rgba(99,102,241,0.08);
+ background: rgba(255,255,255,0.08);
color: var(--color-text);
}
@@ -761,10 +781,14 @@ a { color: inherit; text-decoration: none; }
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
padding: 20px;
- transition: all 0.25s;
+ transition: all 0.3s ease;
}
-.perf-card:hover { border-color: var(--color-border-light); }
+.perf-card:hover {
+ border-color: var(--color-accent);
+ transform: translateY(-4px);
+ box-shadow: 0 12px 40px rgba(34, 211, 238, 0.15), 0 0 20px rgba(34, 211, 238, 0.1);
+}
.perf-card-icon { font-size: 1.6rem; margin-bottom: 8px; }
@@ -784,7 +808,7 @@ a { color: inherit; text-decoration: none; }
.perf-card p code {
font-family: var(--font-mono);
font-size: 0.82em;
- background: rgba(99,102,241,0.15);
+ background: rgba(255,255,255,0.15);
padding: 1px 5px;
border-radius: 4px;
color: var(--color-primary-light);
@@ -876,7 +900,7 @@ a { color: inherit; text-decoration: none; }
.security-panel-lead code {
font-family: var(--font-mono);
font-size: 0.88em;
- background: rgba(99,102,241,0.12);
+ background: rgba(255,255,255,0.12);
padding: 1px 5px;
border-radius: 4px;
color: var(--color-primary-light);
@@ -910,7 +934,7 @@ a { color: inherit; text-decoration: none; }
content: counter(sec-counter);
min-width: 22px;
height: 22px;
- background: rgba(99,102,241,0.2);
+ background: rgba(255,255,255,0.2);
color: var(--color-primary-light);
border-radius: 50%;
display: flex;
@@ -925,7 +949,7 @@ a { color: inherit; text-decoration: none; }
.security-list li code {
font-family: var(--font-mono);
font-size: 0.82em;
- background: rgba(99,102,241,0.12);
+ background: rgba(255,255,255,0.12);
padding: 1px 5px;
border-radius: 4px;
color: var(--color-primary-light);
@@ -943,7 +967,7 @@ a { color: inherit; text-decoration: none; }
.security-note code {
font-family: var(--font-mono);
font-size: 0.88em;
- background: rgba(99,102,241,0.12);
+ background: rgba(255,255,255,0.12);
padding: 1px 5px;
border-radius: 4px;
color: var(--color-primary-light);
@@ -990,7 +1014,7 @@ a { color: inherit; text-decoration: none; }
background: var(--color-bg-tertiary);
border: 1px solid var(--color-border);
border-radius: var(--radius-lg);
- padding: 44px 36px;
+ padding: 32px 36px;
position: relative;
overflow: hidden;
}
@@ -1044,7 +1068,7 @@ a { color: inherit; text-decoration: none; }
.footer {
background: var(--color-bg-secondary);
border-top: 1px solid var(--color-border);
- padding: 40px 20px 24px;
+ padding: 32px 20px 24px;
}
.footer-content {
@@ -1122,28 +1146,16 @@ a { color: inherit; text-decoration: none; }
.footer-bottom a:hover { color: var(--color-primary); }
-/* ===========================
- Scroll-Reveal (injected by JS but base defined here for no-FOUC)
- =========================== */
-.reveal {
- opacity: 0;
- transform: translateY(24px);
- transition: opacity 0.5s ease, transform 0.5s ease;
-}
-
-.reveal.visible {
- opacity: 1;
- transform: none;
-}
-
/* ===========================
Responsive
=========================== */
@media (max-width: 768px) {
- .nav { padding: 16px 20px; }
+ .nav { padding: 12px 16px; gap: 16px; }
+ .nav-logo { gap: 8px; }
+ .logo-text { font-size: 1.1rem; }
.nav-links { display: none; }
.nav-cta { display: none; }
- .nav-hamburger { display: flex; }
+ .nav-hamburger { display: flex; width: 36px; height: 36px; }
/* Mobile nav overlay */
.nav-open .nav-links {
@@ -1152,7 +1164,7 @@ a { color: inherit; text-decoration: none; }
position: fixed;
inset: 0;
z-index: 100;
- background: rgba(10, 10, 15, 0.97);
+ background: rgba(10, 10, 15, 0.98);
backdrop-filter: blur(12px);
align-items: center;
justify-content: center;
@@ -1167,41 +1179,47 @@ a { color: inherit; text-decoration: none; }
}
.hero { min-height: auto; }
- .hero-content { padding: 20px 16px 40px; }
- .hero-logo-svg { width: 72px; height: 72px; }
+ .hero-content { padding: 12px 12px 24px; }
+ .hero-logo-svg { width: 64px; height: 64px; }
+ .hero-title { font-size: 2.2rem; }
+ .hero-subtitle { font-size: 1rem; }
.hero-stats {
grid-template-columns: repeat(2, auto);
- padding: 16px;
- gap: 8px;
- row-gap: 12px;
+ padding: 12px;
+ gap: 12px;
+ row-gap: 16px;
+ width: 100%;
+ margin-bottom: 16px;
}
/* Hide dividers on mobile 2ร2 grid */
.stat-divider { display: none; }
- .stat { padding: 0 12px; }
+ .stat { padding: 0 8px; }
.stat-value { font-size: 1.05rem; }
.hero-install,
.cta-install {
- padding: 12px 12px 12px 16px;
+ padding: 8px 8px 8px 16px;
+ width: 100%;
}
- .install-code { font-size: 0.75rem; }
+ .install-code { font-size: 0.75rem; overflow-x: auto; flex: 1; }
- .section-inner { padding: 44px 16px; }
+ .section-inner { padding: 48px 16px; }
- .features-grid { grid-template-columns: 1fr; }
+ .features-grid { grid-template-columns: 1fr; gap: 12px; }
- .pipeline { padding: 0 4px; }
- .pipeline-step { padding: 14px 16px; }
- .pipeline-info p { font-size: 0.78rem; }
+ .pipeline { padding: 0; }
+ .pipeline-step { padding: 14px 16px; flex-direction: column; text-align: center; gap: 10px; }
+ .pipeline-icon { width: auto; }
+ .pipeline-info p { font-size: 0.8rem; }
- .perf-cards { grid-template-columns: 1fr; }
+ .perf-cards { grid-template-columns: 1fr; gap: 12px; }
.cta-card { padding: 32px 16px; }
- .cta-install { padding: 10px 12px; }
+ .cta-install { padding: 8px 12px; }
.footer-content { flex-direction: column; gap: 32px; }
.footer-links-group { gap: 28px; }
@@ -1232,4 +1250,4 @@ a { color: inherit; text-decoration: none; }
::-webkit-scrollbar-thumb { background: var(--color-border); border-radius: 4px; }
::-webkit-scrollbar-thumb:hover { background: var(--color-border-light); }
-::selection { background: rgba(99,102,241,0.3); color: var(--color-text); }
+::selection { background: rgba(255,255,255,0.3); color: var(--color-text); }