11<!DOCTYPE html>
2- < html lang ="en ">
2+ < html lang ="en " data-theme =" light " >
33< head >
44< meta charset ="UTF-8 ">
55< meta name ="viewport " content ="width=device-width, initial-scale=1.0 ">
88< link rel ="preconnect " href ="https://fonts.gstatic.com " crossorigin >
99< link href ="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700&display=swap " rel ="stylesheet ">
1010< style >
11+ /* ── Light theme (default) ────────────── */
1112 : root {
13+ --bg : # F8FAFC ;
14+ --bg-card : # FFFFFF ;
15+ --bg-elevated : # F1F5F9 ;
16+ --text : # 0F172A ;
17+ --text-dim : # 64748B ;
18+ --accent : # 16A34A ;
19+ --accent-glow : rgba (22 , 163 , 74 , 0.2 );
20+ --red : # DC2626 ;
21+ --yellow : # D97706 ;
22+ --blue : # 2563EB ;
23+ --purple : # 9333EA ;
24+ --cyan : # 0891B2 ;
25+ --border : # E2E8F0 ;
26+ --nav-bg : rgba (248 , 250 , 252 , 0.85 );
27+ --nav-border : rgba (226 , 232 , 240 , 0.7 );
28+ --code-bg : # F1F5F9 ;
29+ --code-border : # E2E8F0 ;
30+ --glow-hero : rgba (22 , 163 , 74 , 0.08 );
31+ --glow-cta : rgba (22 , 163 , 74 , 0.06 );
32+ --radius : 12px ;
33+ --spring : cubic-bezier (0.175 , 0.885 , 0.32 , 1.275 );
34+ --ease-out : cubic-bezier (0.16 , 1 , 0.3 , 1 );
35+ --ease-in-out : cubic-bezier (0.65 , 0 , 0.35 , 1 );
36+ --shadow-sm : 0 1px 3px rgba (0 , 0 , 0 , 0.06 );
37+ --shadow-md : 0 4px 20px rgba (0 , 0 , 0 , 0.08 );
38+ --shadow-hover : 0 8px 30px rgba (22 , 163 , 74 , 0.12 );
39+ }
40+
41+ /* ── Dark theme ───────────────────────── */
42+ [data-theme = "dark" ] {
1243 --bg : # 0F172A ;
1344 --bg-card : # 1E293B ;
1445 --bg-elevated : # 334155 ;
2253 --purple : # A855F7 ;
2354 --cyan : # 06B6D4 ;
2455 --border : # 334155 ;
25- --radius : 12px ;
26- --spring : cubic-bezier (0.175 , 0.885 , 0.32 , 1.275 );
27- --ease-out : cubic-bezier (0.16 , 1 , 0.3 , 1 );
28- --ease-in-out : cubic-bezier (0.65 , 0 , 0.35 , 1 );
56+ --nav-bg : rgba (15 , 23 , 42 , 0.85 );
57+ --nav-border : rgba (51 , 65 , 85 , 0.5 );
58+ --code-bg : # 0F172A ;
59+ --code-border : # 334155 ;
60+ --glow-hero : rgba (34 , 197 , 94 , 0.06 );
61+ --glow-cta : rgba (34 , 197 , 94 , 0.06 );
62+ --shadow-sm : 0 1px 3px rgba (0 , 0 , 0 , 0.3 );
63+ --shadow-md : 0 4px 20px rgba (0 , 0 , 0 , 0.3 );
64+ --shadow-hover : 0 8px 30px rgba (34 , 197 , 94 , 0.12 );
2965 }
66+
3067 * { margin : 0 ; padding : 0 ; box-sizing : border-box; }
3168 html { scroll-behavior : smooth; }
3269 body {
3572 color : var (--text );
3673 line-height : 1.6 ;
3774 overflow-x : hidden;
75+ transition : background 0.4s var (--ease-out ), color 0.4s var (--ease-out );
3876 }
3977 ::selection { background : var (--accent-glow ); }
4078
79+ /* ── Theme transition ─────────────────── */
80+ * , * ::before , * ::after {
81+ transition : background-color 0.4s var (--ease-out ),
82+ border-color 0.4s var (--ease-out ),
83+ color 0.4s var (--ease-out ),
84+ box-shadow 0.4s var (--ease-out );
85+ }
86+
4187 /* ── Scroll reveal ─────────────────────── */
4288 .reveal {
4389 opacity : 0 ;
4995 /* ── Nav ──────────────────────────────── */
5096 nav {
5197 position : fixed; top : 0 ; left : 0 ; right : 0 ; z-index : 100 ;
52- background : rgba ( 15 , 23 , 42 , 0.85 ); backdrop-filter : blur (12px );
53- border-bottom : 1px solid rgba ( 51 , 65 , 85 , 0.5 );
98+ background : var ( --nav-bg ); backdrop-filter : blur (12px );
99+ border-bottom : 1px solid var ( --nav-border );
54100 padding : 0 2rem ; height : 56px ;
55101 display : flex; align-items : center; justify-content : space-between;
56102 }
59105 background : linear-gradient (135deg , var (--accent ), var (--cyan ));
60106 -webkit-background-clip : text; -webkit-text-fill-color : transparent;
61107 }
108+ nav .nav-links { display : flex; align-items : center; gap : 0.5rem ; }
62109 nav a {
63110 color : var (--text-dim ); text-decoration : none; font-size : 0.875rem ;
64111 transition : color 0.2s ; margin-left : 1.5rem ;
65112 }
66113 nav a : hover { color : var (--text ); }
67114
115+ /* ── Theme toggle ─────────────────────── */
116+ .theme-toggle {
117+ background : var (--bg-elevated );
118+ border : 1px solid var (--border );
119+ border-radius : 100px ;
120+ padding : 0.4rem ;
121+ display : flex; align-items : center; gap : 0.25rem ;
122+ cursor : pointer;
123+ margin-left : 1rem ;
124+ transition : border-color 0.3s ;
125+ }
126+ .theme-toggle : hover { border-color : var (--accent ); }
127+ .theme-toggle .toggle-option {
128+ width : 32px ; height : 28px ;
129+ display : flex; align-items : center; justify-content : center;
130+ border-radius : 100px ;
131+ font-size : 0.85rem ;
132+ transition : background 0.3s var (--spring );
133+ }
134+ .theme-toggle .toggle-option .active {
135+ background : var (--accent );
136+ color : # fff ;
137+ }
138+ [data-theme = "dark" ] .theme-toggle .toggle-option .active {
139+ background : var (--accent );
140+ color : # 0F172A ;
141+ }
142+
68143 /* ── Container ────────────────────────── */
69144 .container { max-width : 1100px ; margin : 0 auto; padding : 0 2rem ; }
70145 section { padding : 6rem 0 ; }
74149 .hero ::before {
75150 content : '' ; position : absolute; top : -100px ; left : 50% ; transform : translateX (-50% );
76151 width : 600px ; height : 600px ;
77- background : radial-gradient (circle, rgba ( 34 , 197 , 94 , 0.06 ) 0% , transparent 70% );
152+ background : radial-gradient (circle, var ( --glow-hero ) 0% , transparent 70% );
78153 pointer-events : none;
79154 }
80155 .hero .badge {
81156 display : inline-flex; align-items : center; gap : 0.5rem ;
82- background : rgba (34 , 197 , 94 , 0.1 ); border : 1px solid rgba (34 , 197 , 94 , 0.2 );
157+ background : rgba (34 , 197 , 94 , 0.08 ); border : 1px solid rgba (34 , 197 , 94 , 0.2 );
83158 padding : 0.4rem 1rem ; border-radius : 100px ; font-size : 0.85rem ;
84159 color : var (--accent ); margin-bottom : 1.5rem ;
85160 animation : badge-pulse 3s ease-in-out infinite;
86161 }
87162 .hero .badge .dot { width : 8px ; height : 8px ; background : var (--accent ); border-radius : 50% ; }
88163 @keyframes badge-pulse {
89- 0% , 100% { box-shadow : 0 0 0 0 rgba ( 34 , 197 , 94 , 0.3 ); }
164+ 0% , 100% { box-shadow : 0 0 0 0 var ( --accent-glow ); }
90165 50% { box-shadow : 0 0 0 10px rgba (34 , 197 , 94 , 0 ); }
91166 }
92167 .hero h1 {
106181 display : inline-flex; align-items : center; gap : 0.5rem ;
107182 padding : 0.75rem 1.75rem ; border-radius : 100px ; font-weight : 600 ;
108183 font-size : 0.95rem ; text-decoration : none;
109- transition : transform 0.2s var (--spring ), box-shadow 0.2s ;
184+ transition : transform 0.2s var (--spring ), box-shadow 0.2s var ( --spring ) ;
110185 }
111186 .btn-primary {
112- background : var (--accent ); color : # 0F172A ;
113- box-shadow : 0 0 20px rgba ( 34 , 197 , 94 , 0.25 );
187+ background : var (--accent ); color : # fff ;
188+ box-shadow : 0 0 20px var ( --accent-glow );
114189 }
115- .btn-primary : hover { transform : scale (1.05 ); box-shadow : 0 0 35px rgba (34 , 197 , 94 , 0.4 ); }
190+ [data-theme = "light" ] .btn-primary { color : # fff ; }
191+ [data-theme = "dark" ] .btn-primary { color : # 0F172A ; }
192+ .btn-primary : hover { transform : scale (1.05 ); box-shadow : 0 0 35px var (--accent-glow ); }
116193 .btn-ghost {
117194 border : 1px solid var (--border ); color : var (--text );
195+ background : transparent;
118196 }
119- .btn-ghost : hover { transform : scale (1.05 ); border-color : var (--text-dim ); }
197+ .btn-ghost : hover { transform : scale (1.05 ); border-color : var (--accent ); }
120198
121199 /* ── Stats grid ──────────────────────── */
122200 .stats-grid {
127205 background : var (--bg-card ); border : 1px solid var (--border );
128206 border-radius : var (--radius ); padding : 1.5rem ; text-align : center;
129207 cursor : default;
130- transition : transform 0.3s var (--spring ), border-color 0.3s , box-shadow 0.3s ;
208+ box-shadow : var (--shadow-sm );
209+ transition : transform 0.3s var (--spring ), border-color 0.3s , box-shadow 0.3s var (--spring );
131210 }
132211 .stat-card : hover {
133212 transform : translateY (-4px ) scale (1.03 );
134213 border-color : var (--accent );
135- box-shadow : 0 8 px 30 px rgba ( 34 , 197 , 94 , 0.1 );
214+ box-shadow : var ( --shadow-hover );
136215 }
137216 .stat-card .number {
138217 font-size : 2rem ; font-weight : 700 ; font-variant-numeric : tabular-nums;
149228 .step {
150229 background : var (--bg-card ); border : 1px solid var (--border );
151230 border-radius : var (--radius ); padding : 2rem ; position : relative; overflow : hidden;
152- transition : transform 0.3s var (--spring ), border-color 0.3s ;
231+ box-shadow : var (--shadow-sm );
232+ transition : transform 0.3s var (--spring ), border-color 0.3s , box-shadow 0.3s var (--spring );
153233 }
154- .step : hover { transform : translateY (-3px ); border-color : var (--accent ); }
234+ .step : hover { transform : translateY (-3px ); border-color : var (--accent ); box-shadow : var ( --shadow-hover ); }
155235 .step .step-num {
156- font-size : 3.5rem ; font-weight : 800 ; color : rgba ( 34 , 197 , 94 , 0.08 );
236+ font-size : 3.5rem ; font-weight : 800 ; color : var ( --accent-glow );
157237 position : absolute; top : -8px ; right : 16px ; line-height : 1 ;
238+ opacity : 0.35 ;
158239 }
159240 .step code {
160- display : block; background : # 0F172A ; padding : 0.75rem 1rem ;
241+ display : block; background : var ( --code-bg ) ; padding : 0.75rem 1rem ;
161242 border-radius : 8px ; margin-top : 1rem ; font-size : 0.85rem ;
162- color : var (--accent ); border : 1px solid var (--border );
163- font-family : 'SF Mono' , 'Fira Code' , monospace;
243+ color : var (--accent ); border : 1px solid var (--code- border );
244+ font-family : 'SF Mono' , 'Fira Code' , 'Cascadia Code' , monospace;
164245 transition : box-shadow 0.3s ;
165246 }
166- .step : hover code { box-shadow : 0 0 15px rgba ( 34 , 197 , 94 , 0.1 ); }
247+ .step : hover code { box-shadow : 0 0 15px var ( --accent-glow ); }
167248 .step h3 { font-size : 1.15rem ; margin-bottom : 0.5rem ; }
168249
169250 /* ── Comparison ──────────────────────── */
172253 .comp-col {
173254 background : var (--bg-card ); border : 1px solid var (--border );
174255 border-radius : var (--radius ); padding : 2rem ;
256+ box-shadow : var (--shadow-sm );
257+ transition : box-shadow 0.3s var (--spring );
175258 }
259+ .comp-col : hover { box-shadow : var (--shadow-md ); }
176260 .comp-col .basic { border-top : 3px solid var (--red ); }
177261 .comp-col .pro { border-top : 3px solid var (--accent ); }
178262 .comp-col h3 { font-size : 1.1rem ; margin-bottom : 1rem ; }
189273 .arch-block {
190274 background : var (--bg-card ); border : 1px solid var (--border );
191275 border-radius : var (--radius ); padding : 1.25rem 1.5rem ; text-align : center;
192- transition : transform 0.3s var (--spring ), box-shadow 0.3s ;
276+ box-shadow : var (--shadow-sm );
277+ transition : transform 0.3s var (--spring ), box-shadow 0.3s var (--spring );
193278 min-width : 110px ;
194279 }
195- .arch-block : hover { transform : scale (1.08 ); box-shadow : 0 4 px 25 px rgba ( 34 , 197 , 94 , 0.15 ); }
280+ .arch-block : hover { transform : scale (1.08 ); box-shadow : var ( --shadow-hover ); }
196281 .arch-block .icon { font-size : 1.8rem ; margin-bottom : 0.25rem ; }
197282 .arch-block .name { font-weight : 600 ; font-size : 0.9rem ; }
198283 .arch-arrow { color : var (--accent ); font-size : 1.5rem ; font-weight : 300 ; }
199284
200285 /* ── CTA ─────────────────────────────── */
201- .cta-section { text-align : center; background : radial-gradient (ellipse at center, rgba (34 , 197 , 94 , 0.06 ) 0% , transparent 70% ); border-radius : var (--radius ); padding : 4rem 2rem ; }
286+ .cta-section {
287+ text-align : center;
288+ background : radial-gradient (ellipse at center, var (--glow-cta ) 0% , transparent 70% );
289+ border-radius : var (--radius ); padding : 4rem 2rem ;
290+ border : 1px solid var (--border );
291+ }
202292 .cta-section h2 { font-size : 2rem ; margin-bottom : 0.75rem ; }
203293 .cta-section p { color : var (--text-dim ); margin-bottom : 2rem ; font-size : 1.1rem ; }
204294
230320 .hero { padding-top : 7rem ; }
231321 .arch { flex-direction : column; }
232322 .arch-arrow { transform : rotate (90deg ); }
323+ nav { padding : 0 1rem ; }
324+ nav a { margin-left : 0.75rem ; font-size : 0.8rem ; }
233325 }
234326</ style >
235327</ head >
236328< body >
237329
238330< nav >
239331 < div class ="logo "> ⚡ BenchmarkFlow</ div >
240- < div >
332+ < div class =" nav-links " >
241333 < a href ="#how "> How</ a >
242334 < a href ="#compare "> Compare</ a >
243335 < a href ="https://github.com/SecureBananaLabs/bug-bounty/pull/68 " target ="_blank "> PR #68 ↗</ a >
336+ <!-- Theme toggle -->
337+ < button class ="theme-toggle " id ="themeToggle " aria-label ="Toggle theme ">
338+ < span class ="toggle-option " data-theme-val ="light " id ="lightOpt "> ☀️</ span >
339+ < span class ="toggle-option " data-theme-val ="dark " id ="darkOpt "> 🌙</ span >
340+ </ button >
244341 </ div >
245342</ nav >
246343
@@ -284,7 +381,7 @@ <h3>Run the benchmark</h3>
284381 < div class ="step ">
285382 < div class ="step-num "> 03</ div >
286383 < h3 > View the dashboard</ h3 >
287- < p style ="color:var(--text-dim);font-size:0.9rem; "> Dark-themed HTML report with color-coded metrics.</ p >
384+ < p style ="color:var(--text-dim);font-size:0.9rem; "> Interactive HTML report with color-coded metrics. Light & dark mode .</ p >
288385 < code > make bench-report</ code >
289386 </ div >
290387 </ div >
@@ -344,7 +441,7 @@ <h2>Architecture</h2>
344441< section id ="compare ">
345442 < div class ="container ">
346443 < div class ="section-header reveal ">
347- < h2 > Why this over < code style ="color:var(--red);background:rgba(239,68,68,0.1 );padding:0.15rem 0.5rem;border-radius:4px; "> autocannon</ code > </ h2 >
444+ < h2 > Why this over < code style ="color:var(--red);background:rgba(239,68,68,0.08 );padding:0.15rem 0.5rem;border-radius:4px; "> autocannon</ code > </ h2 >
348445 < p > The bounty asked for a CSV. Here's why this delivers more.</ p >
349446 </ div >
350447 < div class ="comparison stagger " id ="comparison ">
@@ -368,7 +465,7 @@ <h3 style="color:var(--accent);">This PR</h3>
368465 < li > Auto on every push & PR</ li >
369466 < li > GitHub Actions CI</ li >
370467 < li > PR comment with diff</ li >
371- < li > Dark-themed dashboard</ li >
468+ < li > Light & dark dashboard</ li >
372469 < li > Docker Compose reproducible</ li >
373470 </ ul >
374471 </ div >
@@ -381,7 +478,7 @@ <h3 style="color:var(--accent);">This PR</h3>
381478 < div class ="container ">
382479 < div class ="cta-section reveal ">
383480 < h2 > Ready to benchmark your API?</ h2 >
384- < p > Fork, run < code style ="background:rgba(34,197,94,0.1 );padding:0.2rem 0.6rem;border-radius:4px; "> make bench</ code > , and see the dashboard in 30 seconds.</ p >
481+ < p > Fork, run < code style ="background:rgba(34,197,94,0.08 );padding:0.2rem 0.6rem;border-radius:4px;color:var(--accent) ; "> make bench</ code > , and see the dashboard in 30 seconds.</ p >
385482 < div style ="display:flex;gap:1rem;justify-content:center;flex-wrap:wrap; ">
386483 < a href ="https://github.com/SecureBananaLabs/bug-bounty/pull/68 " target ="_blank " class ="btn btn-primary "> View PR #68 on GitHub</ a >
387484 < a href ="https://github.com/AtlasNexusOps/bug-bounty " target ="_blank " class ="btn btn-ghost "> Fork the repo</ a >
@@ -396,6 +493,31 @@ <h2>Ready to benchmark your API?</h2>
396493</ footer >
397494
398495< script >
496+ // ── Theme toggle ─────────────────────────
497+ ( function ( ) {
498+ const html = document . documentElement ;
499+ const lightOpt = document . getElementById ( 'lightOpt' ) ;
500+ const darkOpt = document . getElementById ( 'darkOpt' ) ;
501+
502+ // Load saved preference (default: light)
503+ const saved = localStorage . getItem ( 'benchmarkflow-theme' ) || 'light' ;
504+ html . setAttribute ( 'data-theme' , saved ) ;
505+ updateToggle ( saved ) ;
506+
507+ document . getElementById ( 'themeToggle' ) . addEventListener ( 'click' , ( ) => {
508+ const current = html . getAttribute ( 'data-theme' ) ;
509+ const next = current === 'dark' ? 'light' : 'dark' ;
510+ html . setAttribute ( 'data-theme' , next ) ;
511+ localStorage . setItem ( 'benchmarkflow-theme' , next ) ;
512+ updateToggle ( next ) ;
513+ } ) ;
514+
515+ function updateToggle ( theme ) {
516+ lightOpt . classList . toggle ( 'active' , theme === 'light' ) ;
517+ darkOpt . classList . toggle ( 'active' , theme === 'dark' ) ;
518+ }
519+ } ) ( ) ;
520+
399521// ── Scroll-triggered reveals ─────────────
400522const observer = new IntersectionObserver ( ( entries ) => {
401523 entries . forEach ( entry => {
@@ -426,7 +548,6 @@ <h2>Ready to benchmark your API?</h2>
426548
427549 function tick ( now ) {
428550 const progress = Math . min ( ( now - start ) / duration , 1 ) ;
429- // spring-like easing
430551 const eased = 1 - Math . pow ( 1 - progress , 4 ) ;
431552 current = Math . round ( target * eased ) ;
432553 el . textContent = isCurrency ? current + '$' : current + suffix ;
@@ -436,7 +557,6 @@ <h2>Ready to benchmark your API?</h2>
436557 } ) ;
437558}
438559
439- // Trigger counters when hero stats become visible
440560const heroStats = document . getElementById ( 'hero-stats' ) ;
441561const heroObs = new IntersectionObserver ( ( entries ) => {
442562 if ( entries [ 0 ] . isIntersecting ) {
0 commit comments