Skip to main content

logicaffeine_web/ui/pages/
landing.rs

1//! Marketing landing page.
2//!
3//! The main entry point for new visitors showcasing the LOGOS platform with:
4//! - Hero section with animated gradient orbs
5//! - Feature highlights for Logic, Code, and Math modes
6//! - Call-to-action buttons for learning and the studio
7//! - Live interactive demos
8//!
9//! # Route
10//!
11//! Accessed via [`Route::Landing`].
12
13use dioxus::prelude::*;
14#[cfg(all(feature = "split", target_arch = "wasm32"))]
15use dioxus::wasm_split;
16use crate::ui::router::Route;
17use crate::ui::components::main_nav::{MainNav, ActivePage};
18use crate::ui::components::footer::Footer;
19use crate::ui::components::icon::{Icon, IconVariant, IconSize};
20use crate::ui::components::code_editor::{CodeEditor, Language};
21use crate::ui::seo::{JsonLdMultiple, PageHead, organization_schema, website_schema, faq_schema, pages as seo_pages};
22use crate::ui::state::StudioMode;
23use logicaffeine_compile::{compile_for_ui, compile_theorem_for_ui, interpret_for_ui, generate_rust_code};
24use logicaffeine_kernel::interface::Repl;
25use crate::ui::examples::{
26    CODE_HELLO, CODE_FIBONACCI, CODE_CRDT_COUNTERS, CODE_CRDT_TALLY,
27    LOGIC_LEIBNIZ, LOGIC_BARBER, LOGIC_SIMPLE, LOGIC_QUANTIFIERS,
28    MATH_GODEL_LITERATE, MATH_INCOMPLETENESS_LITERATE, MATH_AUTO, MATH_NAT, MATH_BOOL, MATH_PROP_LOGIC,
29};
30
31struct DemoExample {
32    filename: &'static str,
33    icon: &'static str,
34    content: &'static str,
35    output: &'static str,
36    compiled: &'static str,
37    studio_path: &'static str,
38}
39
40const CODE_DEMO_EXAMPLES: [DemoExample; 4] = [
41    DemoExample {
42        filename: "hello-world.logos",
43        icon: "λ",
44        content: CODE_HELLO,
45        output: "",
46        compiled: "",
47        studio_path: "examples/code/hello-world.logos",
48    },
49    DemoExample {
50        filename: "fibonacci.logos",
51        icon: "λ",
52        content: CODE_FIBONACCI,
53        output: "",
54        compiled: "",
55        studio_path: "examples/code/fibonacci.logos",
56    },
57    DemoExample {
58        filename: "counters.logos",
59        icon: "λ",
60        content: CODE_CRDT_COUNTERS,
61        output: "",
62        compiled: "",
63        studio_path: "examples/code/distributed/counters.logos",
64    },
65    DemoExample {
66        filename: "tally.logos",
67        icon: "λ",
68        content: CODE_CRDT_TALLY,
69        output: "",
70        compiled: "",
71        studio_path: "examples/code/distributed/tally.logos",
72    },
73];
74
75const LOGIC_DEMO_EXAMPLES: [DemoExample; 4] = [
76    DemoExample {
77        filename: "leibniz-identity.logic",
78        icon: "∀",
79        content: LOGIC_LEIBNIZ,
80        output: "",
81        compiled: "",
82        studio_path: "examples/logic/leibniz-identity.logic",
83    },
84    DemoExample {
85        filename: "barber-paradox.logic",
86        icon: "∀",
87        content: LOGIC_BARBER,
88        output: "",
89        compiled: "",
90        studio_path: "examples/logic/barber-paradox.logic",
91    },
92    DemoExample {
93        filename: "simple-sentences.logic",
94        icon: "∀",
95        content: LOGIC_SIMPLE,
96        output: "",
97        compiled: "",
98        studio_path: "examples/logic/simple-sentences.logic",
99    },
100    DemoExample {
101        filename: "quantifiers.logic",
102        icon: "∀",
103        content: LOGIC_QUANTIFIERS,
104        output: "",
105        compiled: "",
106        studio_path: "examples/logic/quantifiers.logic",
107    },
108];
109
110const MATH_DEMO_EXAMPLES: [DemoExample; 6] = [
111    DemoExample {
112        filename: "godel-literate.logos",
113        icon: "π",
114        content: MATH_GODEL_LITERATE,
115        output: "",
116        compiled: "",
117        studio_path: "examples/math/godel-literate.logos",
118    },
119    DemoExample {
120        filename: "incompleteness-literate.logos",
121        icon: "π",
122        content: MATH_INCOMPLETENESS_LITERATE,
123        output: "",
124        compiled: "",
125        studio_path: "examples/math/incompleteness-literate.logos",
126    },
127    DemoExample {
128        filename: "auto-tactic.logos",
129        icon: "π",
130        content: MATH_AUTO,
131        output: "",
132        compiled: "",
133        studio_path: "examples/math/auto-tactic.logos",
134    },
135    DemoExample {
136        filename: "natural-numbers.logos",
137        icon: "π",
138        content: MATH_NAT,
139        output: "",
140        compiled: "",
141        studio_path: "examples/math/natural-numbers.logos",
142    },
143    DemoExample {
144        filename: "boolean-logic.logos",
145        icon: "π",
146        content: MATH_BOOL,
147        output: "",
148        compiled: "",
149        studio_path: "examples/math/boolean-logic.logos",
150    },
151    DemoExample {
152        filename: "prop-logic.logos",
153        icon: "π",
154        content: MATH_PROP_LOGIC,
155        output: "",
156        compiled: "",
157        studio_path: "examples/math/prop-logic.logos",
158    },
159];
160
161fn execute_math_code(content: &str) -> (Vec<String>, Option<String>) {
162    let mut repl = Repl::new();
163    let mut lines = Vec::new();
164    let mut error = None;
165    let statements = parse_math_statements(content);
166    for stmt in statements {
167        match repl.execute(&stmt) {
168            Ok(output) => {
169                if !output.is_empty() {
170                    lines.push(output);
171                }
172            }
173            Err(e) => {
174                error = Some(e.to_string());
175                break;
176            }
177        }
178    }
179    (lines, error)
180}
181
182fn parse_math_statements(code: &str) -> Vec<String> {
183    let mut statements = Vec::new();
184    let lines: Vec<&str> = code.lines().collect();
185    let mut i = 0;
186
187    while i < lines.len() {
188        let line = lines[i];
189        let trimmed = line.trim();
190
191        if trimmed.is_empty() || trimmed.starts_with("--") {
192            i += 1;
193            continue;
194        }
195
196        if trimmed.starts_with("## To ") {
197            let mut block = String::new();
198            block.push_str(trimmed);
199            i += 1;
200            while i < lines.len() {
201                let next_line = lines[i];
202                let next_trimmed = next_line.trim();
203                if next_trimmed.is_empty() || next_trimmed.starts_with("--") {
204                    i += 1;
205                    continue;
206                }
207                let is_indented = next_line.starts_with(' ') || next_line.starts_with('\t');
208                let is_continuation = next_trimmed.starts_with("Consider ")
209                    || next_trimmed.starts_with("When ")
210                    || next_trimmed.starts_with("Yield ");
211                if is_indented || is_continuation {
212                    block.push(' ');
213                    block.push_str(next_trimmed);
214                    i += 1;
215                } else {
216                    break;
217                }
218            }
219            statements.push(block);
220            continue;
221        }
222
223        if trimmed.starts_with("## Theorem:") {
224            let mut block = String::new();
225            block.push_str(trimmed);
226            i += 1;
227            while i < lines.len() {
228                let next_line = lines[i];
229                let next_trimmed = next_line.trim();
230                if next_trimmed.is_empty() || next_trimmed.starts_with("--") {
231                    i += 1;
232                    continue;
233                }
234                let is_indented = next_line.starts_with(' ') || next_line.starts_with('\t');
235                let is_theorem_part = next_trimmed.starts_with("Statement:")
236                    || next_trimmed.starts_with("Proof:");
237                if is_indented || is_theorem_part {
238                    block.push('\n');
239                    block.push_str(next_line);
240                    i += 1;
241                    if next_trimmed.starts_with("Proof:") && next_trimmed.ends_with('.') {
242                        break;
243                    }
244                } else {
245                    break;
246                }
247            }
248            statements.push(block);
249            continue;
250        }
251
252        if (trimmed.starts_with("A ") || trimmed.starts_with("An ")) && trimmed.contains(" is either") {
253            if trimmed.ends_with('.') && !trimmed.trim_end_matches('.').ends_with(':') {
254                statements.push(trimmed.to_string());
255                i += 1;
256                continue;
257            }
258            let mut block = String::new();
259            block.push_str(trimmed);
260            i += 1;
261            while i < lines.len() {
262                let next_line = lines[i];
263                let next_trimmed = next_line.trim();
264                if next_trimmed.is_empty() || next_trimmed.starts_with("--") {
265                    i += 1;
266                    continue;
267                }
268                let is_indented = next_line.starts_with(' ') || next_line.starts_with('\t');
269                let looks_like_variant = next_trimmed.starts_with("a ")
270                    || next_trimmed.chars().next().map(|c| c.is_uppercase()).unwrap_or(false);
271                if is_indented || (looks_like_variant && !next_trimmed.starts_with("A ") && !next_trimmed.starts_with("An ")) {
272                    if !block.ends_with(':') {
273                        block.push_str(" or ");
274                    } else {
275                        block.push(' ');
276                    }
277                    block.push_str(next_trimmed.trim_end_matches('.'));
278                    i += 1;
279                } else {
280                    break;
281                }
282            }
283            if !block.ends_with('.') {
284                block.push('.');
285            }
286            statements.push(block);
287            continue;
288        }
289
290        let mut current_stmt = String::new();
291        while i < lines.len() {
292            let line = lines[i];
293            let trimmed = line.trim();
294            if trimmed.is_empty() || trimmed.starts_with("--") {
295                i += 1;
296                continue;
297            }
298            if !current_stmt.is_empty() {
299                current_stmt.push(' ');
300            }
301            current_stmt.push_str(trimmed);
302            i += 1;
303            if trimmed.ends_with('.') {
304                break;
305            }
306        }
307        if !current_stmt.is_empty() {
308            statements.push(current_stmt);
309        }
310    }
311
312    statements
313}
314
315fn examples_for_mode(mode: StudioMode) -> &'static [DemoExample] {
316    match mode {
317        StudioMode::Code => &CODE_DEMO_EXAMPLES,
318        // The landing carousel surfaces Logic/Code/Math; Hardware lives in the Studio.
319        StudioMode::Logic | StudioMode::Hardware => &LOGIC_DEMO_EXAMPLES,
320        StudioMode::Math => &MATH_DEMO_EXAMPLES,
321    }
322}
323
324const LANDING_STYLE: &str = r#"
325body:has(.landing) {
326  overflow: hidden;
327}
328
329.landing {
330  height: 100vh;
331  color: var(--text-primary);
332  background:
333    radial-gradient(1200px 600px at 50% -120px, rgba(167,139,250,0.18), transparent 60%),
334    radial-gradient(900px 500px at 15% 30%, rgba(96,165,250,0.18), transparent 60%),
335    radial-gradient(800px 450px at 90% 45%, rgba(34,197,94,0.10), transparent 62%),
336    linear-gradient(180deg, #070a12, #0b1022 55%, #070a12);
337  overflow-x: hidden;
338  overflow-y: auto;
339  font-family: var(--font-sans);
340  position: relative;
341}
342
343.bg-orb {
344  position: absolute;
345  inset: auto;
346  width: 520px;
347  height: 520px;
348  border-radius: var(--radius-full);
349  filter: blur(42px);
350  opacity: 0.22;
351  pointer-events: none;
352  animation: float 14s ease-in-out infinite, pulse-glow 10s ease-in-out infinite;
353}
354.orb1 { top: -220px; left: -160px; background: radial-gradient(circle at 30% 30%, var(--color-accent-blue), transparent 60%); animation-delay: 0s; }
355.orb2 { top: 120px; right: -200px; background: radial-gradient(circle at 40% 35%, var(--color-accent-purple), transparent 60%); animation-delay: -5s; }
356.orb3 { bottom: -260px; left: 20%; background: radial-gradient(circle at 40% 35%, rgba(34,197,94,0.9), transparent 60%); animation-delay: -10s; }
357
358@media (max-width: 640px) {
359  /* Purely decorative: shrink and stop animating the 520px blurred orbs on
360     phones — a continuous blur(42px) repaint is the most expensive thing on a
361     mobile GPU here, for zero content value. */
362  .bg-orb { width: 300px; height: 300px; filter: blur(32px); animation: none; }
363}
364
365.container {
366  width: 100%;
367  max-width: 1120px;
368  margin: 0 auto;
369  padding: 0 var(--spacing-xl);
370}
371
372/* Navigation now handled by MainNav component */
373
374.btn {
375  display: inline-flex;
376  align-items: center;
377  justify-content: center;
378  gap: 10px;
379  padding: var(--spacing-md) var(--spacing-lg);
380  border-radius: var(--radius-lg);
381  border: 1px solid rgba(255,255,255,0.10);
382  background: rgba(255,255,255,0.05);
383  text-decoration: none;
384  font-weight: 650;
385  font-size: var(--font-body-md);
386  transition: transform 0.18s ease, background 0.18s ease, border-color 0.18s ease;
387  will-change: transform;
388}
389.btn:hover { transform: translateY(-1px); background: rgba(255,255,255,0.07); border-color: rgba(255,255,255,0.18); }
390.btn:active { transform: translateY(0px); }
391
392.btn-primary {
393  background: linear-gradient(135deg, rgba(96,165,250,0.95), rgba(167,139,250,0.95));
394  border-color: rgba(255,255,255,0.20);
395  color: #060814;
396  box-shadow: 0 18px 40px rgba(96,165,250,0.18);
397}
398.btn-primary:hover {
399  background: linear-gradient(135deg, var(--color-accent-blue), var(--color-accent-purple));
400}
401
402.btn-ghost {
403  background: rgba(255,255,255,0.03);
404}
405
406.btn-icon {
407  padding: 10px;
408  background: rgba(255,255,255,0.03);
409}
410.btn-icon svg {
411  width: 20px;
412  height: 20px;
413  fill: currentColor;
414}
415
416.github-link {
417  display: inline-flex;
418  align-items: center;
419  gap: 6px;
420  color: inherit;
421  text-decoration: none;
422  transition: color 0.2s ease;
423}
424.github-link:hover {
425  color: var(--text-primary);
426}
427
428.hero {
429  padding: 64px 0 30px;
430}
431
432.hero-grid {
433  display: grid;
434  grid-template-columns: 1.05fr 0.95fr;
435  gap: 36px;
436  align-items: center;
437}
438
439.badge {
440  display: inline-flex;
441  align-items: center;
442  gap: 10px;
443  padding: 10px 14px;
444  border-radius: var(--radius-full);
445  background: rgba(255,255,255,0.06);
446  border: 1px solid rgba(255,255,255,0.10);
447  backdrop-filter: blur(18px);
448  box-shadow: 0 18px 40px rgba(0,0,0,0.25);
449  color: var(--text-primary);
450  font-size: var(--font-caption-md);
451  font-weight: 650;
452}
453.badge .dot {
454  width: 8px;
455  height: 8px;
456  border-radius: var(--radius-full);
457  background: var(--color-success);
458  box-shadow: 0 0 0 6px rgba(34,197,94,0.12);
459  animation: pulse-glow 2s ease-in-out infinite;
460}
461
462.hero .badge { animation: fadeInUp 0.6s ease both; }
463.hero .h-title { animation: fadeInUp 0.6s ease 0.08s both; }
464.hero .h-sub { animation: fadeInUp 0.6s ease 0.16s both; }
465.hero .hero-ctas { animation: fadeInUp 0.6s ease 0.24s both; }
466.hero .microcopy { animation: fadeInUp 0.6s ease 0.30s both; }
467.hero .demo { animation: fadeInUp 0.8s ease 0.44s both; }
468
469.h-title {
470  margin: 24px 0 var(--spacing-lg);
471  font-size: var(--font-display-xl);
472  line-height: 1.15;
473  letter-spacing: -2px;
474  font-weight: 900;
475  background: linear-gradient(180deg, #ffffff 0%, rgba(229,231,235,0.78) 65%, rgba(229,231,235,0.62) 100%);
476  -webkit-background-clip: text;
477  -webkit-text-fill-color: transparent;
478}
479
480.h-sub {
481  margin: 0 0 var(--spacing-xl);
482  max-width: 580px;
483  color: var(--text-secondary);
484  font-size: var(--font-body-lg);
485  line-height: 1.65;
486}
487
488.hero-ctas {
489  display: flex;
490  gap: var(--spacing-md);
491  flex-wrap: wrap;
492  margin: 18px 0 14px;
493}
494
495.microcopy {
496  font-size: var(--font-caption-md);
497  color: var(--text-tertiary);
498}
499
500.demo {
501  border-radius: var(--radius-xl);
502  border: 1px solid rgba(255,255,255,0.10);
503  background: linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.03));
504  backdrop-filter: blur(18px);
505  box-shadow: 0 30px 80px rgba(0,0,0,0.55);
506  overflow: hidden;
507  position: relative;
508}
509
510.demo::before {
511  content: "";
512  position: absolute;
513  inset: -2px;
514  background: radial-gradient(600px 280px at 10% 10%, rgba(96,165,250,0.22), transparent 55%),
515              radial-gradient(520px 240px at 90% 20%, rgba(167,139,250,0.22), transparent 55%);
516  opacity: 0.9;
517  pointer-events: none;
518}
519
520.demo-head {
521  position: relative;
522  display: flex;
523  align-items: center;
524  justify-content: space-between;
525  padding: 14px var(--spacing-lg);
526  border-bottom: 1px solid rgba(255,255,255,0.06);
527  background: rgba(0,0,0,0.10);
528}
529
530.win-dots { display: flex; gap: var(--spacing-sm); align-items: center; }
531.wdot { width: 11px; height: 11px; border-radius: var(--radius-full); opacity: 0.9; }
532.wr { background: #ef4444; } .wy { background: #fbbf24; } .wg { background: #22c55e; }
533
534.demo-label {
535  font-size: var(--font-caption-sm);
536  color: var(--text-secondary);
537  border: 1px solid rgba(255,255,255,0.10);
538  padding: 7px 10px;
539  border-radius: var(--radius-full);
540  background: rgba(255,255,255,0.04);
541}
542
543.demo-body {
544  position: relative;
545  display: grid;
546  grid-template-columns: 1fr 1fr;
547}
548
549.demo-col {
550  padding: 18px 18px 22px;
551  min-height: 240px;
552}
553
554.demo-col + .demo-col {
555  border-left: 1px solid rgba(255,255,255,0.06);
556  background: rgba(0,0,0,0.18);
557}
558
559.demo-kicker {
560  display: flex;
561  align-items: center;
562  justify-content: space-between;
563  margin-bottom: var(--spacing-md);
564  font-size: var(--font-caption-sm);
565  color: var(--text-secondary);
566}
567
568.pill {
569  border: 1px solid rgba(255,255,255,0.10);
570  background: rgba(255,255,255,0.04);
571  padding: 6px 10px;
572  border-radius: var(--radius-full);
573}
574
575.code {
576  font-family: var(--font-mono);
577  font-size: var(--font-caption-md);
578  line-height: 1.6;
579  color: var(--text-primary);
580  white-space: pre-wrap;
581}
582
583.code.logic { color: var(--color-accent-purple); }
584
585.demo-foot {
586  display: flex;
587  gap: 10px;
588  flex-wrap: wrap;
589  padding: 14px var(--spacing-lg);
590  border-top: 1px solid rgba(255,255,255,0.06);
591  background: rgba(0,0,0,0.12);
592  color: var(--text-secondary);
593  font-size: var(--font-caption-md);
594}
595
596.section {
597  padding: 74px 0;
598}
599
600.section-title {
601  font-size: var(--font-display-md);
602  letter-spacing: -1.2px;
603  margin: 0 0 14px;
604  font-weight: 800;
605}
606.section-sub {
607  margin: 0 0 var(--spacing-xl);
608  color: var(--text-secondary);
609  line-height: 1.65;
610  max-width: 760px;
611}
612.section-right .section-title,
613.section-right .section-sub {
614  text-align: right;
615}
616.section-right .section-sub {
617  margin-left: auto;
618}
619.section-center .section-title,
620.section-center .section-sub {
621  text-align: center;
622}
623.section-center .section-sub {
624  margin-left: auto;
625  margin-right: auto;
626}
627
628.grid3 {
629  display: grid;
630  grid-template-columns: repeat(3, 1fr);
631  gap: 18px;
632}
633.grid2 {
634  display: grid;
635  grid-template-columns: 1fr 1fr;
636  gap: 18px;
637}
638
639.card {
640  position: relative;
641  border-radius: var(--radius-xl);
642  border: 1px solid rgba(255,255,255,0.10);
643  background: rgba(255,255,255,0.04);
644  backdrop-filter: blur(18px);
645  padding: 18px;
646  transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease;
647  overflow: hidden;
648}
649.card::before {
650  content: "";
651  position: absolute;
652  inset: 0;
653  border-radius: var(--radius-xl);
654  background: linear-gradient(135deg, rgba(96,165,250,0.12), rgba(167,139,250,0.12));
655  opacity: 0;
656  transition: opacity 0.3s ease;
657  pointer-events: none;
658}
659.card:hover {
660  transform: translateY(-3px);
661  border-color: rgba(167,139,250,0.28);
662  background: rgba(255,255,255,0.06);
663}
664.card:hover::before {
665  opacity: 1;
666}
667
668.icon-box {
669  width: 48px; height: 48px;
670  border-radius: var(--radius-lg);
671  display: flex;
672  align-items: center;
673  justify-content: center;
674  background: rgba(255,255,255,0.06);
675  border: 1px solid rgba(255,255,255,0.10);
676  margin-bottom: var(--spacing-md);
677}
678
679.icon-box .icon {
680  width: 24px;
681  height: 24px;
682}
683
684.card h3 {
685  margin: 0 0 var(--spacing-sm);
686  font-size: var(--font-body-md);
687  letter-spacing: -0.2px;
688}
689.card p {
690  margin: 0;
691  color: var(--text-secondary);
692  line-height: 1.6;
693  font-size: var(--font-body-md);
694}
695
696.quote {
697  font-size: var(--font-body-md);
698  line-height: 1.65;
699  color: var(--text-primary);
700}
701.quoter {
702  margin-top: 10px;
703  color: var(--text-tertiary);
704  font-size: var(--font-caption-md);
705}
706
707
708.tech-stack {
709  display: flex;
710  gap: 10px;
711  flex-wrap: wrap;
712  margin-top: 14px;
713}
714
715.tech-badge {
716  font-size: var(--font-caption-sm);
717  padding: 6px var(--spacing-md);
718  border-radius: 6px;
719  background: rgba(255,255,255,0.03);
720  border: 1px solid rgba(255,255,255,0.08);
721  color: var(--text-secondary);
722}
723
724.tech-badge.rust {
725  background: linear-gradient(135deg, rgba(183,65,14,0.15), rgba(222,165,132,0.10));
726  border-color: rgba(222,165,132,0.3);
727  color: #dea584;
728}
729
730.hello-world-layout {
731  display: flex;
732  flex-direction: column;
733  align-items: center;
734  gap: 40px;
735}
736
737.hello-pill-wrap,
738.hello-cta-wrap {
739  text-align: center;
740}
741
742.hello-editor {
743  width: 100%;
744  max-width: 820px;
745  border-radius: var(--radius-lg);
746  border: 1px solid rgba(255,255,255,0.10);
747  background: rgba(0,0,0,0.3);
748  overflow: hidden;
749  backdrop-filter: blur(8px);
750}
751
752.hello-loading {
753  width: 100%;
754  max-width: 820px;
755  min-height: 305px;
756}
757
758.hello-editor-head {
759  display: flex;
760  align-items: center;
761  justify-content: space-between;
762  padding: 10px 14px;
763  background: rgba(255,255,255,0.03);
764  border-bottom: 1px solid rgba(255,255,255,0.06);
765}
766
767.hello-editor-head .hello-filename {
768  font-size: var(--font-caption-sm);
769  color: var(--text-secondary);
770  font-family: var(--font-mono);
771}
772
773.hello-run-btn {
774  display: inline-flex;
775  align-items: center;
776  gap: 6px;
777  padding: 5px 14px;
778  border-radius: var(--radius-sm);
779  border: 1px solid rgba(52,211,153,0.4);
780  background: rgba(52,211,153,0.10);
781  color: #34d399;
782  font-size: var(--font-caption-sm);
783  font-weight: 600;
784  cursor: pointer;
785  transition: background 0.2s, border-color 0.2s;
786}
787
788.hello-run-btn:hover {
789  background: rgba(52,211,153,0.20);
790  border-color: rgba(52,211,153,0.6);
791}
792
793.hello-run-btn:disabled {
794  opacity: 0.5;
795  cursor: not-allowed;
796}
797
798.hello-editor-body {
799  display: flex;
800  min-height: 260px;
801}
802
803.hello-editor-left {
804  flex: 1;
805  min-width: 0;
806}
807
808.hello-editor-right {
809  flex: 1;
810  min-width: 0;
811  border-left: 1px solid rgba(255,255,255,0.06);
812  display: flex;
813  flex-direction: column;
814}
815
816.hello-output-head {
817  padding: 8px 14px;
818  font-size: var(--font-caption-sm);
819  color: var(--text-secondary);
820  font-family: var(--font-mono);
821  background: rgba(255,255,255,0.02);
822  border-bottom: 1px solid rgba(255,255,255,0.04);
823  text-transform: uppercase;
824  letter-spacing: 0.05em;
825}
826
827.hello-output-body {
828  padding: var(--spacing-md);
829  flex: 1;
830  overflow-y: auto;
831  font-family: var(--font-mono);
832  font-size: var(--font-body-md);
833  line-height: 1.6;
834}
835
836.hello-output-line {
837  margin: 0;
838  white-space: pre-wrap;
839  color: var(--text-primary);
840}
841
842.hello-output-error {
843  margin: 0;
844  white-space: pre-wrap;
845  color: var(--color-error, #f87171);
846}
847
848.hello-output-loading {
849  color: var(--text-secondary);
850  font-style: italic;
851}
852
853.hello-output-empty {
854  color: var(--text-secondary);
855  opacity: 0.5;
856}
857
858@media (max-width: 700px) {
859  .hello-editor-body {
860    flex-direction: column;
861  }
862  .hello-editor-right {
863    border-left: none;
864    border-top: 1px solid rgba(255,255,255,0.06);
865  }
866}
867
868.hello-note {
869  text-align: center;
870  font-size: var(--font-body-md);
871  color: var(--text-secondary);
872  display: inline-block;
873  padding: 8px 20px;
874  border: 1px solid rgba(167,139,250,0.3);
875  border-radius: var(--radius-full);
876  background: rgba(167,139,250,0.06);
877  box-shadow: 0 0 20px rgba(167,139,250,0.12), 0 0 40px rgba(96,165,250,0.08);
878}
879
880.compare-table {
881  display: flex;
882  flex-direction: column;
883  border-radius: var(--radius-lg);
884  border: 1px solid rgba(255,255,255,0.10);
885  overflow: hidden;
886  max-width: 800px;
887  margin: 0 auto;
888}
889
890.compare-row {
891  display: grid;
892  grid-template-columns: 1.2fr repeat(5, 1fr);
893}
894
895.compare-row.header {
896  background: rgba(255,255,255,0.05);
897  font-weight: 600;
898  font-size: var(--font-caption-md);
899}
900
901.compare-row:not(.header) {
902  border-top: 1px solid rgba(255,255,255,0.06);
903}
904
905.compare-cell {
906  padding: var(--spacing-md) 14px;
907  font-size: var(--font-caption-md);
908  color: var(--text-secondary);
909  text-align: center;
910}
911
912.compare-cell.label {
913  text-align: left;
914  color: var(--text-primary);
915  font-weight: 500;
916}
917
918.compare-cell.highlight {
919  background: rgba(167,139,250,0.08);
920  color: var(--color-accent-purple);
921  font-weight: 500;
922}
923
924.compare-row.header .compare-cell.highlight {
925  background: rgba(167,139,250,0.15);
926}
927
928@media (max-width: 700px) {
929  .compare-row {
930    grid-template-columns: 1fr 1fr 1fr;
931  }
932  .compare-cell:nth-child(4),
933  .compare-cell:nth-child(5),
934  .compare-cell:nth-child(6) {
935    display: none;
936  }
937}
938
939.faq-item {
940  padding: var(--spacing-lg) var(--spacing-lg) 14px;
941  border-radius: var(--radius-xl);
942  border: 1px solid rgba(255,255,255,0.10);
943  background: rgba(255,255,255,0.03);
944}
945.faq-q { font-weight: 750; margin-bottom: var(--spacing-sm); }
946.faq-a { color: var(--text-secondary); line-height: 1.6; font-size: var(--font-body-md); }
947
948.footer {
949  padding: 34px 0 44px;
950  border-top: 1px solid rgba(255,255,255,0.06);
951  color: var(--text-tertiary);
952  font-size: var(--font-caption-md);
953}
954
955.footer-row {
956  display: flex;
957  align-items: center;
958  justify-content: space-between;
959  gap: var(--spacing-lg);
960  flex-wrap: wrap;
961}
962
963@media (max-width: 980px) {
964  .hero-grid { grid-template-columns: 1fr; }
965  .demo-body { grid-template-columns: 1fr; }
966  .demo-col + .demo-col { border-left: none; border-top: 1px solid rgba(255,255,255,0.06); }
967  .grid3 { grid-template-columns: 1fr; }
968  .grid2 { grid-template-columns: 1fr; }
969  .h-title { font-size: var(--font-display-lg); }
970}
971
972@keyframes fadeInUp {
973  from { opacity: 0; transform: translateY(24px); }
974  to { opacity: 1; transform: translateY(0); }
975}
976
977@keyframes float {
978  0%, 100% { transform: translate3d(0, 0, 0); }
979  50% { transform: translate3d(0, -20px, 0); }
980}
981
982@keyframes pulse-glow {
983  0%, 100% { opacity: 0.22; }
984  50% { opacity: 0.32; }
985}
986
987@keyframes blink {
988  50% { opacity: 0; }
989}
990
991html { scroll-behavior: smooth; }
992
993.section + .section {
994  border-top: 1px solid rgba(255,255,255,0.04);
995}
996
997.steps {
998  display: flex;
999  align-items: center;
1000  justify-content: center;
1001  gap: var(--spacing-xl);
1002  flex-wrap: wrap;
1003}
1004
1005.step {
1006  flex: 1;
1007  min-width: 200px;
1008  max-width: 280px;
1009  text-align: center;
1010  padding: var(--spacing-xl);
1011  border-radius: var(--radius-xl);
1012  background: rgba(255,255,255,0.04);
1013  border: 1px solid rgba(255,255,255,0.10);
1014  animation: fadeInUp 0.6s ease both;
1015}
1016
1017.step:nth-child(1) { animation-delay: 0s; }
1018.step:nth-child(3) { animation-delay: 0.1s; }
1019.step:nth-child(5) { animation-delay: 0.2s; }
1020
1021.step-num {
1022  width: 48px;
1023  height: 48px;
1024  margin: 0 auto var(--spacing-lg);
1025  border-radius: 50%;
1026  background: linear-gradient(135deg, var(--color-accent-blue), var(--color-accent-purple));
1027  color: #060814;
1028  font-weight: 800;
1029  font-size: var(--font-heading-sm);
1030  display: grid;
1031  place-items: center;
1032}
1033
1034.step h3 {
1035  margin: 0 0 var(--spacing-sm);
1036  font-size: var(--font-body-lg);
1037}
1038
1039.step p {
1040  margin: 0;
1041  color: var(--text-secondary);
1042  font-size: var(--font-body-md);
1043  line-height: 1.5;
1044}
1045
1046.step-arrow {
1047  font-size: 24px;
1048  color: var(--text-tertiary);
1049}
1050
1051.grid3 .card:nth-child(1) .icon-box { background: rgba(0,212,255,0.15); }
1052.grid3 .card:nth-child(2) .icon-box { background: rgba(129,140,248,0.15); }
1053.grid3 .card:nth-child(3) .icon-box { background: rgba(34,197,94,0.15); }
1054.grid3 .card:nth-child(4) .icon-box { background: rgba(251,191,36,0.15); }
1055.grid3 .card:nth-child(5) .icon-box { background: rgba(236,72,153,0.15); }
1056.grid3 .card:nth-child(6) .icon-box { background: rgba(129,140,248,0.15); }
1057
1058/* Mini-Studio */
1059.mini-studio {
1060  border-radius: var(--radius-xl);
1061  border: 1px solid rgba(255,255,255,0.10);
1062  background: linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.03));
1063  backdrop-filter: blur(18px);
1064  box-shadow: 0 30px 80px rgba(0,0,0,0.55);
1065  overflow: hidden;
1066  position: relative;
1067  display: flex;
1068  flex-direction: column;
1069  height: 635px;
1070}
1071.showcase-loading {
1072  min-height: 635px;
1073}
1074.hello-loading {
1075  min-height: 220px;
1076}
1077/* Loading skeleton shown while the wasm boots / a lazy body streams in — reads
1078   as "loading," never as a blank/broken panel. */
1079.mini-studio-skeleton { pointer-events: none; }
1080.skeleton-body {
1081  flex: 1;
1082  padding: 24px;
1083  display: flex;
1084  flex-direction: column;
1085  gap: 16px;
1086}
1087.skeleton-line {
1088  height: 14px;
1089  border-radius: 6px;
1090  background: linear-gradient(90deg, rgba(255,255,255,0.05) 25%, rgba(255,255,255,0.12) 37%, rgba(255,255,255,0.05) 63%);
1091  background-size: 400% 100%;
1092  animation: skeleton-shimmer 1.4s ease infinite;
1093}
1094.skeleton-line.w40 { width: 40%; }
1095.skeleton-line.w50 { width: 50%; }
1096.skeleton-line.w60 { width: 60%; }
1097.skeleton-line.w70 { width: 70%; }
1098.skeleton-line.w80 { width: 80%; }
1099.skeleton-line.w90 { width: 90%; }
1100@keyframes skeleton-shimmer {
1101  0% { background-position: 100% 50%; }
1102  100% { background-position: 0% 50%; }
1103}
1104.mini-studio::before {
1105  content: "";
1106  position: absolute;
1107  inset: -2px;
1108  background: radial-gradient(600px 280px at 10% 10%, rgba(96,165,250,0.22), transparent 55%),
1109              radial-gradient(520px 240px at 90% 20%, rgba(167,139,250,0.22), transparent 55%);
1110  opacity: 0.9;
1111  pointer-events: none;
1112}
1113.mini-studio-head {
1114  position: relative;
1115  display: flex;
1116  align-items: center;
1117  justify-content: center;
1118  padding: 14px var(--spacing-lg);
1119  border-bottom: 1px solid rgba(255,255,255,0.06);
1120  background: rgba(0,0,0,0.10);
1121}
1122.mini-studio-head .win-dots {
1123  position: absolute;
1124  left: var(--spacing-lg);
1125}
1126.mini-mode-toggle {
1127  display: flex;
1128  gap: 4px;
1129  background: rgba(255,255,255,0.04);
1130  border: 1px solid rgba(255,255,255,0.10);
1131  border-radius: var(--radius-full);
1132  padding: 3px;
1133}
1134.mini-toggle-btn {
1135  padding: 6px 12px;
1136  border-radius: var(--radius-full);
1137  border: none;
1138  background: transparent;
1139  color: var(--text-secondary);
1140  font-size: var(--font-caption-sm);
1141  font-weight: 600;
1142  cursor: pointer;
1143  transition: background 0.18s, color 0.18s;
1144  display: flex;
1145  align-items: center;
1146  gap: 6px;
1147  font-family: inherit;
1148}
1149.mini-toggle-btn.active {
1150  background: rgba(96,165,250,0.2);
1151  color: var(--text-primary);
1152}
1153.mini-toggle-btn:hover:not(.active) {
1154  background: rgba(255,255,255,0.06);
1155}
1156.mini-studio-body {
1157  position: relative;
1158  display: grid;
1159  grid-template-columns: 180px 1fr;
1160  flex: 1;
1161  min-height: 0;
1162  overflow: hidden;
1163}
1164.mini-file-tabs {
1165  display: none;
1166  gap: 4px;
1167  padding: 8px 12px;
1168  overflow-x: auto;
1169  border-bottom: 1px solid rgba(255,255,255,0.06);
1170  background: rgba(0,0,0,0.08);
1171  flex-shrink: 0;
1172  -webkit-overflow-scrolling: touch;
1173}
1174.mini-file-tab {
1175  flex-shrink: 0;
1176  padding: 5px 10px;
1177  border-radius: var(--radius-full);
1178  border: 1px solid rgba(255,255,255,0.10);
1179  background: rgba(255,255,255,0.04);
1180  color: var(--text-secondary);
1181  font-size: var(--font-caption-sm);
1182  font-weight: 500;
1183  cursor: pointer;
1184  white-space: nowrap;
1185  font-family: var(--font-mono);
1186  transition: background 0.15s, color 0.15s, border-color 0.15s;
1187}
1188.mini-file-tab:hover {
1189  background: rgba(255,255,255,0.08);
1190}
1191.mini-file-tab.active {
1192  background: rgba(96,165,250,0.2);
1193  border-color: rgba(96,165,250,0.35);
1194  color: var(--text-primary);
1195}
1196.mini-explorer {
1197  border-right: 1px solid rgba(255,255,255,0.06);
1198  padding: 8px 0;
1199  background: rgba(0,0,0,0.08);
1200}
1201.mini-explorer-label {
1202  padding: 7px 14px;
1203  font-size: var(--font-caption-sm);
1204  color: var(--text-tertiary);
1205  text-transform: uppercase;
1206  letter-spacing: 0.5px;
1207  font-weight: 600;
1208}
1209.mini-file-item {
1210  padding: 7px 14px;
1211  font-size: var(--font-caption-sm);
1212  color: var(--text-secondary);
1213  cursor: pointer;
1214  display: flex;
1215  align-items: center;
1216  gap: 8px;
1217  transition: background 0.15s, color 0.15s;
1218  white-space: nowrap;
1219  overflow: hidden;
1220  text-overflow: ellipsis;
1221}
1222.mini-file-item:hover {
1223  background: rgba(255,255,255,0.04);
1224}
1225.mini-file-item.active {
1226  background: rgba(96,165,250,0.15);
1227  color: var(--text-primary);
1228}
1229.mini-file-item.view-more {
1230  color: var(--accent-secondary);
1231  font-style: italic;
1232  opacity: 0.8;
1233  margin-top: 4px;
1234  text-decoration: none;
1235}
1236.mini-file-item.view-more:hover {
1237  opacity: 1;
1238  background: rgba(96,165,250,0.10);
1239}
1240.mini-file-tab.view-more {
1241  color: var(--accent-secondary);
1242  font-style: italic;
1243  border-color: rgba(96,165,250,0.2);
1244  text-decoration: none;
1245}
1246.mini-file-tab.view-more:hover {
1247  background: rgba(96,165,250,0.10);
1248}
1249.mini-file-icon {
1250  opacity: 0.5;
1251}
1252.mini-code-panel {
1253  padding: 16px;
1254  overflow-y: auto;
1255  position: relative;
1256}
1257.mini-code-filename {
1258  display: flex;
1259  align-items: center;
1260  gap: 8px;
1261  margin-bottom: 12px;
1262  font-size: var(--font-caption-sm);
1263  color: var(--text-secondary);
1264}
1265.mini-code-panel .code-editor {
1266  height: 100%;
1267  background: transparent;
1268}
1269.mini-code-panel .code-editor-input {
1270  min-height: 0;
1271}
1272.mini-code-panel .code-editor-textarea,
1273.mini-code-panel .code-editor-highlight {
1274  padding: 0;
1275  padding-bottom: 40px;
1276  font-size: var(--font-caption-md);
1277  line-height: 1.6;
1278}
1279.mini-action-bar {
1280  display: flex;
1281  align-items: center;
1282  justify-content: flex-end;
1283  gap: 8px;
1284  padding: 8px 16px;
1285  border-bottom: 1px solid rgba(255,255,255,0.06);
1286  background: rgba(0,0,0,0.06);
1287  position: relative;
1288  flex-shrink: 0;
1289}
1290.mini-exec-btn {
1291  padding: 6px 14px;
1292  border: none;
1293  border-radius: 6px;
1294  color: white;
1295  font-size: 13px;
1296  font-weight: 500;
1297  cursor: pointer;
1298  transition: all 0.15s ease;
1299  display: flex;
1300  align-items: center;
1301  gap: 6px;
1302  font-family: inherit;
1303}
1304.mini-exec-btn:hover {
1305  transform: translateY(-1px);
1306  box-shadow: 0 4px 12px rgba(102, 126, 234, 0.3);
1307}
1308.mini-exec-btn:active { transform: translateY(0); }
1309.mini-exec-btn.compile {
1310  background: linear-gradient(135deg, #56b6c2 0%, #61afef 100%);
1311}
1312.mini-exec-btn.run {
1313  background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
1314}
1315.mini-terminal {
1316  border-top: 1px solid rgba(255,255,255,0.06);
1317  background: rgba(0,0,0,0.20);
1318  display: flex;
1319  flex-direction: column;
1320  overflow: hidden;
1321  position: relative;
1322}
1323.mini-terminal-head {
1324  display: flex;
1325  align-items: center;
1326  padding: 6px 16px;
1327  font-size: 11px;
1328  text-transform: uppercase;
1329  letter-spacing: 0.5px;
1330  color: var(--text-tertiary);
1331  font-weight: 600;
1332  border-bottom: 1px solid rgba(255,255,255,0.04);
1333  flex-shrink: 0;
1334}
1335.mini-terminal-body {
1336  flex: 1;
1337  min-height: 0;
1338  overflow-y: auto;
1339  padding: 8px 16px 13px;
1340  font-family: var(--font-mono);
1341  font-size: 12px;
1342  line-height: 1.5;
1343}
1344.mini-output-line {
1345  margin: 0;
1346  color: #4ade80;
1347  white-space: pre-wrap;
1348  font: inherit;
1349  line-height: inherit;
1350}
1351.mini-output-error {
1352  margin: 4px 0 0;
1353  color: #e06c75;
1354  white-space: pre-wrap;
1355  font: inherit;
1356  line-height: inherit;
1357  padding: 8px;
1358  background: rgba(224, 108, 117, 0.1);
1359  border-radius: 4px;
1360}
1361.mini-output-empty {
1362  color: var(--text-tertiary);
1363  font-style: italic;
1364}
1365.mini-output-loading {
1366  color: #667eea;
1367  animation: blink 1s step-end infinite;
1368}
1369.mini-term-output {
1370  margin: 0;
1371  color: #4ade80;
1372  white-space: pre-wrap;
1373  font: inherit;
1374  line-height: inherit;
1375}
1376.mini-compiled {
1377  border-top: 1px solid rgba(255,255,255,0.06);
1378  background: rgba(0,0,0,0.25);
1379  display: flex;
1380  flex-direction: column;
1381  overflow: hidden;
1382  position: relative;
1383}
1384.mini-compiled-head {
1385  display: flex;
1386  align-items: center;
1387  padding: 6px 16px;
1388  font-size: 11px;
1389  text-transform: uppercase;
1390  letter-spacing: 0.5px;
1391  color: var(--text-tertiary);
1392  font-weight: 600;
1393  border-bottom: 1px solid rgba(255,255,255,0.04);
1394  flex-shrink: 0;
1395}
1396.mini-compiled-body {
1397  flex: 1;
1398  min-height: 0;
1399  overflow-y: auto;
1400  padding: 8px 16px;
1401  font-family: var(--font-mono);
1402  font-size: 12px;
1403  line-height: 1.5;
1404  color: #e5c07b;
1405  white-space: pre-wrap;
1406  margin: 0;
1407}
1408.mini-terminal-resizer {
1409  height: 16px;
1410  background: transparent;
1411  cursor: row-resize;
1412  position: relative;
1413  flex-shrink: 0;
1414  z-index: 2;
1415}
1416.mini-terminal-resizer::after {
1417  content: "";
1418  position: absolute;
1419  left: 50%;
1420  top: 50%;
1421  transform: translate(-50%, -50%);
1422  width: 40px;
1423  height: 5px;
1424  border-radius: 3px;
1425  background: rgba(255,255,255,0.15);
1426  transition: background 0.15s ease;
1427}
1428.mini-terminal-resizer:hover::after,
1429.mini-terminal-resizer.active::after {
1430  background: rgba(96,165,250,0.6);
1431}
1432.mini-studio-cta {
1433  position: relative;
1434  padding: 12px 16px;
1435  border-top: 1px solid rgba(255,255,255,0.06);
1436  background: rgba(0,0,0,0.12);
1437  text-align: center;
1438  flex-shrink: 0;
1439}
1440.mini-cta-btn {
1441  display: inline-flex;
1442  align-items: center;
1443  gap: 8px;
1444  padding: 10px 24px;
1445  background: linear-gradient(135deg, #3b82f6 0%, #2563eb 100%);
1446  border: none;
1447  border-radius: 8px;
1448  color: white;
1449  font-size: 14px;
1450  font-weight: 600;
1451  cursor: pointer;
1452  transition: all 0.18s ease;
1453  text-decoration: none;
1454  font-family: inherit;
1455}
1456.mini-cta-btn:hover {
1457  transform: translateY(-1px);
1458  box-shadow: 0 6px 20px rgba(59, 130, 246, 0.35);
1459}
1460
1461/* Mode Stories */
1462.mode-stories {
1463  display: grid;
1464  grid-template-columns: repeat(3, 1fr);
1465  gap: 18px;
1466}
1467.mode-story {
1468  border-radius: var(--radius-xl);
1469  border: 1px solid rgba(255,255,255,0.10);
1470  background: rgba(255,255,255,0.04);
1471  backdrop-filter: blur(18px);
1472  padding: 24px;
1473  transition: transform 0.18s ease, border-color 0.18s ease, background 0.18s ease;
1474  overflow: hidden;
1475}
1476.mode-story:hover {
1477  transform: translateY(-3px);
1478  border-color: rgba(167,139,250,0.28);
1479  background: rgba(255,255,255,0.06);
1480}
1481.mode-story-icon {
1482  width: 48px;
1483  height: 48px;
1484  border-radius: var(--radius-lg);
1485  display: flex;
1486  align-items: center;
1487  justify-content: center;
1488  font-size: 22px;
1489  font-weight: 700;
1490  margin-bottom: var(--spacing-md);
1491  border: 1px solid rgba(255,255,255,0.10);
1492}
1493.mode-story:nth-child(1) .mode-story-icon { background: rgba(96,165,250,0.15); color: #60a5fa; }
1494.mode-story:nth-child(2) .mode-story-icon { background: rgba(167,139,250,0.15); color: #a78bfa; }
1495.mode-story:nth-child(3) .mode-story-icon { background: rgba(34,197,94,0.15); color: #22c55e; }
1496.mode-story h3 {
1497  margin: 0 0 var(--spacing-md);
1498  font-size: var(--font-body-lg);
1499}
1500.mode-story-demo {
1501  border-radius: var(--radius-lg);
1502  background: rgba(0,0,0,0.3);
1503  padding: 12px;
1504  margin-bottom: var(--spacing-md);
1505  font-family: var(--font-mono);
1506  font-size: var(--font-caption-md);
1507  line-height: 1.6;
1508}
1509.mode-story-row {
1510  display: flex;
1511  gap: 8px;
1512  align-items: baseline;
1513}
1514.mode-story-label {
1515  color: var(--text-tertiary);
1516  font-size: var(--font-caption-sm);
1517  min-width: 54px;
1518  flex-shrink: 0;
1519}
1520.mode-story-value {
1521  color: var(--text-primary);
1522}
1523.mode-story-value.logic {
1524  color: var(--color-accent-purple);
1525}
1526.mode-story-value.success {
1527  color: var(--color-success);
1528}
1529.mode-story-arrow {
1530  text-align: center;
1531  color: var(--text-tertiary);
1532  padding: 4px 0;
1533  font-size: var(--font-caption-sm);
1534}
1535.mode-story > p {
1536  margin: 0;
1537  color: var(--text-secondary);
1538  font-size: var(--font-body-md);
1539  line-height: 1.6;
1540}
1541
1542/* Security Demo */
1543.security-demo {
1544  margin-top: var(--spacing-xl);
1545  border-radius: var(--radius-xl);
1546  border: 1px solid rgba(167,139,250,0.20);
1547  background: linear-gradient(180deg, rgba(255,255,255,0.06), rgba(255,255,255,0.02));
1548  overflow: hidden;
1549  box-shadow:
1550    0 0 40px rgba(167,139,250,0.08),
1551    0 0 80px rgba(96,165,250,0.06),
1552    0 20px 60px rgba(0,0,0,0.4);
1553  position: relative;
1554}
1555.security-demo::before {
1556  content: "";
1557  position: absolute;
1558  inset: -1px;
1559  border-radius: var(--radius-xl);
1560  background: radial-gradient(400px 200px at 20% 0%, rgba(167,139,250,0.15), transparent 60%),
1561              radial-gradient(400px 200px at 80% 100%, rgba(96,165,250,0.12), transparent 60%);
1562  pointer-events: none;
1563}
1564.security-demo-head {
1565  position: relative;
1566  display: flex;
1567  align-items: center;
1568  justify-content: center;
1569  padding: 16px var(--spacing-lg);
1570  border-bottom: 1px solid rgba(255,255,255,0.08);
1571  background: rgba(0,0,0,0.12);
1572  font-size: var(--font-body-md);
1573  font-weight: 700;
1574  color: var(--text-primary);
1575  letter-spacing: -0.2px;
1576}
1577.security-demo-body {
1578  position: relative;
1579  display: grid;
1580  grid-template-columns: 1fr auto 1fr;
1581  align-items: stretch;
1582}
1583.security-demo-col {
1584  padding: 20px 24px;
1585}
1586.security-demo-col + .security-demo-col {
1587  border-left: 1px solid rgba(255,255,255,0.06);
1588}
1589.security-demo-arrow {
1590  display: flex;
1591  align-items: center;
1592  justify-content: center;
1593  padding: 0 16px;
1594  font-size: 28px;
1595  color: var(--color-accent-purple);
1596  border-left: 1px solid rgba(255,255,255,0.06);
1597  border-right: 1px solid rgba(255,255,255,0.06);
1598  background: rgba(0,0,0,0.06);
1599  text-shadow: 0 0 12px rgba(167,139,250,0.5);
1600}
1601.security-demo-label {
1602  display: inline-block;
1603  font-size: 11px;
1604  text-transform: uppercase;
1605  letter-spacing: 0.5px;
1606  font-weight: 600;
1607  color: #4ade80;
1608  margin-bottom: var(--spacing-sm);
1609  padding: 4px 10px;
1610  border: 1px solid rgba(74,222,128,0.3);
1611  border-radius: var(--radius-full);
1612  background: rgba(74,222,128,0.08);
1613}
1614
1615@media (max-width: 980px) {
1616  .hero-grid { grid-template-columns: 1fr; }
1617  .demo-body { grid-template-columns: 1fr; }
1618  .demo-col + .demo-col { border-left: none; border-top: 1px solid rgba(255,255,255,0.06); }
1619  .grid3 { grid-template-columns: 1fr; }
1620  .grid2 { grid-template-columns: 1fr; }
1621  .h-title { font-size: var(--font-display-lg); }
1622  .step-arrow { display: none; }
1623  .steps { flex-direction: column; }
1624  .mini-studio { height: 78vh !important; }
1625  .showcase-loading { min-height: 78vh; }
1626  .mini-studio-body { grid-template-columns: 1fr; }
1627  .mini-explorer { display: none; }
1628  .mini-file-tabs { display: flex; }
1629  .mini-terminal { max-height: 35vh !important; }
1630  .mini-compiled { max-height: 30vh !important; }
1631  .mode-stories { grid-template-columns: 1fr; }
1632  .security-demo-body { grid-template-columns: 1fr; }
1633  .security-demo-arrow { display: none; }
1634  .security-demo-col + .security-demo-col { border-left: none; border-top: 1px solid rgba(255,255,255,0.06); }
1635}
1636
1637@media (max-width: 768px) {
1638  .mini-studio { height: 78vh !important; }
1639  .mini-studio-head {
1640    justify-content: flex-end;
1641  }
1642  .mini-studio-head .win-dots {
1643    display: none;
1644  }
1645  .mini-exec-btn {
1646    padding: 10px 14px;
1647    min-height: 44px;
1648    font-size: 12px;
1649  }
1650  .mini-cta-btn {
1651    min-height: 44px;
1652    width: 100%;
1653    justify-content: center;
1654  }
1655  .mini-action-bar { padding: 8px 12px; }
1656}
1657
1658@media (max-width: 480px) {
1659  .mini-studio { height: 78vh !important; }
1660  .mini-exec-btn .btn-label { display: none; }
1661}
1662
1663@media (prefers-reduced-motion: reduce) {
1664  * { transition: none !important; animation: none !important; }
1665}
1666"#;
1667
1668#[component]
1669pub fn Landing() -> Element {
1670    let schemas = vec![
1671        organization_schema(),
1672        website_schema(),
1673        faq_schema(&[
1674            ("Is it really free?", "Yes — free for individuals, universities, and teams under 25 people. For commercial licensing, contact us."),
1675            ("Do I need to know logic already?", "No. Start in Learn. The system introduces concepts progressively and uses examples to teach scope, quantifiers, and structure."),
1676            ("Is this an AI that guesses?", "The goal is the opposite: to force explicit structure. When language is ambiguous, the tutor prompts clarifying questions."),
1677            ("Where do I begin?", "If you want speed, open Studio. If you want mastery, Start Learning and follow the lessons."),
1678            ("What is LOGOS written in?", "Rust. The entire transpiler, parser, and runtime are written in Rust for maximum performance and safety."),
1679            ("How fast is it?", "Native speed. LOGOS compiles to Rust, which then compiles via LLVM to optimized machine code. Zero interpreter overhead."),
1680        ]),
1681    ];
1682
1683    rsx! {
1684        PageHead {
1685            title: seo_pages::LANDING.title,
1686            description: seo_pages::LANDING.description,
1687            canonical_path: seo_pages::LANDING.canonical_path,
1688        }
1689        style { "{LANDING_STYLE}" }
1690        JsonLdMultiple { schemas }
1691
1692        div { class: "landing",
1693            div { class: "bg-orb orb1" }
1694            div { class: "bg-orb orb2" }
1695            div { class: "bg-orb orb3" }
1696
1697            MainNav { active: ActivePage::Other }
1698
1699            main { class: "container",
1700                section { class: "hero",
1701                    div { class: "hero-grid",
1702                        div {
1703                            div { class: "badge",
1704                                div { class: "dot" }
1705                                span { "Free for individuals • Commercial licenses available" }
1706                            }
1707
1708                            h1 { class: "h-title", "Debug Your Thoughts." }
1709
1710                            p { class: "h-sub",
1711                                "Write Code, Logic, and Math in plain English. LOGOS compiles your words into programs, proofs, and formal systems — no symbols required."
1712                            }
1713
1714                            div { class: "hero-ctas",
1715                                Link { to: Route::Learn {}, class: "btn btn-primary", "Start Learning" }
1716                                Link { to: Route::Studio { file: None }, class: "btn", "Open Studio" }
1717                                Link { to: Route::Pricing {}, class: "btn btn-ghost", "Contact Us" }
1718                            }
1719
1720                            p { class: "microcopy",
1721                                "Students, engineers, researchers, and attorneys — anyone who thinks for a living."
1722                            }
1723
1724                            div { class: "tech-stack",
1725                                span { class: "tech-badge rust",
1726                                    "Rust-Powered 🦀"
1727                                }
1728                                span { class: "tech-badge", "WASM Ready" }
1729                                span { class: "tech-badge", "Markdown Source" }
1730                                span { class: "tech-badge", "Proof-Checked" }
1731                            }
1732                        }
1733
1734                        SuspenseBoundary {
1735                            fallback: |_| rsx! {
1736                                div { class: "showcase-loading",
1737                                    div { class: "mini-studio mini-studio-skeleton",
1738                                        div { class: "mini-studio-head",
1739                                            div { class: "win-dots",
1740                                                div { class: "wdot wr" }
1741                                                div { class: "wdot wy" }
1742                                                div { class: "wdot wg" }
1743                                            }
1744                                        }
1745                                        div { class: "skeleton-body",
1746                                            div { class: "skeleton-line w70" }
1747                                            div { class: "skeleton-line w90" }
1748                                            div { class: "skeleton-line w50" }
1749                                            div { class: "skeleton-line w80" }
1750                                            div { class: "skeleton-line w40" }
1751                                        }
1752                                    }
1753                                }
1754                            },
1755                            LandingShowcase {}
1756                        }
1757                    }
1758                }
1759
1760                section { class: "section how-it-works section-center",
1761                    h2 { class: "section-title", "How it works" }
1762                    p { class: "section-sub",
1763                        "Three modes. One language: English."
1764                    }
1765
1766                    div { class: "mode-stories",
1767                        div { class: "mode-story",
1768                            div { class: "mode-story-icon", "λ" }
1769                            h3 { "Write a program" }
1770                            div { class: "mode-story-demo",
1771                                div { class: "mode-story-row",
1772                                    span { class: "mode-story-label", "Input" }
1773                                    span { class: "mode-story-value", "Let x be 10. Show x + 5." }
1774                                }
1775                                div { class: "mode-story-arrow", "↓" }
1776                                div { class: "mode-story-row",
1777                                    span { class: "mode-story-label", "Output" }
1778                                    span { class: "mode-story-value success", "15" }
1779                                }
1780                            }
1781                            p { "Type readable definitions. Get compiled programs — Rust under the hood, English on the surface." }
1782                        }
1783
1784                        div { class: "mode-story",
1785                            div { class: "mode-story-icon", "∀" }
1786                            h3 { "Formalize an argument" }
1787                            div { class: "mode-story-demo",
1788                                div { class: "mode-story-row",
1789                                    span { class: "mode-story-label", "Input" }
1790                                    span { class: "mode-story-value", "Every cat sleeps." }
1791                                }
1792                                div { class: "mode-story-arrow", "↓" }
1793                                div { class: "mode-story-row",
1794                                    span { class: "mode-story-label", "Output" }
1795                                    span { class: "mode-story-value logic", "∀x(Cat(x) → Sleep(x))" }
1796                                }
1797                            }
1798                            p { "Turn plain language into First-Order Logic. Every reading surfaced — no guessing." }
1799                        }
1800
1801                        div { class: "mode-story",
1802                            div { class: "mode-story-icon", "π" }
1803                            h3 { "Prove a theorem" }
1804                            div { class: "mode-story-demo",
1805                                div { class: "mode-story-row",
1806                                    span { class: "mode-story-label", "Input" }
1807                                    span { class: "mode-story-value", "Theorem: ∀n, n + 0 = n." }
1808                                }
1809                                div { class: "mode-story-arrow", "↓" }
1810                                div { class: "mode-story-row",
1811                                    span { class: "mode-story-label", "Output" }
1812                                    span { class: "mode-story-value success", "Proof: by induction. ✓" }
1813                                }
1814                            }
1815                            p { "Define types, state theorems, and prove them with automated tactics." }
1816                        }
1817                    }
1818                }
1819
1820                section { class: "section hello-world section-center hello-world-layout",
1821                    h2 { class: "section-title", "Hello World in LOGOS" }
1822
1823                    SuspenseBoundary {
1824                        fallback: |_| rsx! {
1825                            div { class: "hello-loading",
1826                                div { class: "skeleton-body",
1827                                    div { class: "skeleton-line w80" }
1828                                    div { class: "skeleton-line w60" }
1829                                    div { class: "skeleton-line w70" }
1830                                }
1831                            }
1832                        },
1833                        LandingHelloWorld {}
1834                    }
1835                    div { class: "hello-pill-wrap",
1836                        p { class: "hello-note", "Compiles to a native binary via Rust. Zero runtime overhead." }
1837                    }
1838                    div { class: "hello-cta-wrap",
1839                        a { href: crate::ui::router::studio_file_url("examples/code/hello-world.logos"), class: "btn btn-primary",
1840                            "Open in Studio →"
1841                        }
1842                    }
1843                }
1844
1845                section { class: "section",
1846                    h2 { class: "section-title", "What you get" }
1847                    p { class: "section-sub",
1848                        "LOGICAFFEINE translates intuition into structure — so you can test it, teach it, or ship it."
1849                    }
1850
1851                    div { class: "grid3",
1852                        div { class: "card",
1853                            div { class: "icon-box",
1854                                Icon { variant: IconVariant::Lightning, size: IconSize::Large, color: "#00d4ff" }
1855                            }
1856                            h3 { "Instant Transpilation" }
1857                            p { "Type normal English. Get programs, logic, and math output in seconds — readable enough to learn from, strict enough to verify." }
1858                        }
1859                        div { class: "card",
1860                            div { class: "icon-box",
1861                                Icon { variant: IconVariant::Brain, size: IconSize::Large, color: "#818cf8" }
1862                            }
1863                            h3 { "Socratic Tutor" }
1864                            p { "When your statement is ambiguous, the tutor asks questions that force clarity instead of guessing." }
1865                        }
1866                        div { class: "card",
1867                            div { class: "icon-box",
1868                                Icon { variant: IconVariant::Document, size: IconSize::Large, color: "#22c55e" }
1869                            }
1870                            h3 { "Assumption Surfacing" }
1871                            p { "Reveal missing premises, hidden quantifiers, and scope mistakes — the usual sources of bad arguments." }
1872                        }
1873                        div { class: "card",
1874                            div { class: "icon-box",
1875                                Icon { variant: IconVariant::Beaker, size: IconSize::Large, color: "#fbbf24" }
1876                            }
1877                            h3 { "Consistency & Validity Checks" }
1878                            p { "Spot contradictions, invalid inferences, and rule collisions across Code, Logic, and Math modes — before they hit production or policy." }
1879                        }
1880                        div { class: "card",
1881                            div { class: "icon-box",
1882                                Icon { variant: IconVariant::Tools, size: IconSize::Large, color: "#ec4899" }
1883                            }
1884                            h3 { "Studio + Curriculum" }
1885                            p { "Explore freely in Studio, then build mastery in Learn with structured lessons and practice." }
1886                        }
1887                        div { class: "card",
1888                            div { class: "icon-box",
1889                                Icon { variant: IconVariant::Lock, size: IconSize::Large, color: "#8b5cf6" }
1890                            }
1891                            h3 { "Commercial-Ready" }
1892                            p { "Licensing options for teams and enterprises — with a path toward governance and controlled deployments." }
1893                        }
1894                    }
1895                }
1896
1897                section { class: "section section-center",
1898                    h2 { class: "section-title", "Security & Policies" }
1899                    p { class: "section-sub",
1900                        "Capability-based security with policy blocks. Define who can do what in plain English."
1901                    }
1902
1903                    div { class: "grid2",
1904                        div { class: "card",
1905                            div { class: "icon-box",
1906                                Icon { variant: IconVariant::Shield, size: IconSize::Large, color: "#60a5fa" }
1907                            }
1908                            h3 { "Policy Blocks" }
1909                            p { "Define security rules as readable policy sections. Who can access what — stated plainly." }
1910                        }
1911                        div { class: "card",
1912                            div { class: "icon-box",
1913                                Icon { variant: IconVariant::Lock, size: IconSize::Large, color: "#a78bfa" }
1914                            }
1915                            h3 { "Capabilities" }
1916                            p { "Role-based access control expressed in English. No annotation soup." }
1917                        }
1918                        div { class: "card",
1919                            div { class: "icon-box",
1920                                Icon { variant: IconVariant::Beaker, size: IconSize::Large, color: "#22c55e" }
1921                            }
1922                            h3 { "Check Guards" }
1923                            p { "Runtime guard checks that enforce your policies. \"Check that the user is admin.\"" }
1924                        }
1925                        div { class: "card",
1926                            div { class: "icon-box",
1927                                Icon { variant: IconVariant::Brain, size: IconSize::Large, color: "#fbbf24" }
1928                            }
1929                            h3 { "Predicates" }
1930                            p { "Define custom predicates: \"A User is admin if the user's role equals 'admin'.\"" }
1931                        }
1932                    }
1933
1934                    div { class: "security-demo",
1935                        div { class: "security-demo-head",
1936                            span { "Policy → Compiled Output" }
1937                        }
1938                        div { class: "security-demo-body",
1939                            div { class: "security-demo-col",
1940                                div { class: "security-demo-label", "LOGOS Policy" }
1941                                pre { class: "code",
1942"## Definition\nA User has:\n    a role: Text.\n\n## Policy\nA User is admin\n    if the user's role equals \"admin\".\n\n## Main\nLet u be a new User with role \"admin\".\nCheck that u is admin.\nShow \"Access granted\"." }
1943                            }
1944                            div { class: "security-demo-arrow", "→" }
1945                            div { class: "security-demo-col",
1946                                div { class: "security-demo-label", "Compiled Output" }
1947                                pre { class: "code",
1948"struct User {{\n    role: String,\n}}\n\nimpl User {{\n    fn is_admin(&self) -> bool {{\n        self.role == \"admin\"\n    }}\n}}\n\nfn main() {{\n    let u = User {{ role: \"admin\".into() }};\n    assert!(u.is_admin());\n    println!(\"Access granted\");\n}}" }
1949                            }
1950                        }
1951                    }
1952                }
1953
1954                section { class: "section", id: "for",
1955                    h2 { class: "section-title", style: "padding: 50px 0; font-size: var(--font-display-lg);",
1956                        "For people who want their reasoning to survive contact with reality."
1957                    }
1958
1959                    div { class: "grid3",
1960                        div { class: "card",
1961                            div { class: "icon-box",
1962                                Icon { variant: IconVariant::GraduationCap, size: IconSize::Large, color: "#00d4ff" }
1963                            }
1964                            h3 { "Students & Educators" }
1965                            p { "Teach formal reasoning with feedback that's immediate, concrete, and harder to game than multiple choice." }
1966                        }
1967                        div { class: "card",
1968                            div { class: "icon-box",
1969                                Icon { variant: IconVariant::Shield, size: IconSize::Large, color: "#818cf8" }
1970                            }
1971                            h3 { "Law, Policy, Compliance" }
1972                            p { "Translate policy language into verifiable rules. Reduce ambiguity. Make reviews faster and safer." }
1973                        }
1974                        div { class: "card",
1975                            div { class: "icon-box",
1976                                Icon { variant: IconVariant::Tools, size: IconSize::Large, color: "#22c55e" }
1977                            }
1978                            h3 { "Engineering & Research" }
1979                            p { "Specify systems, constraints, and invariants in a form you can test — without forcing everyone into formal syntax." }
1980                        }
1981                    }
1982                }
1983
1984                section { class: "section compare-section section-center",
1985                    h2 { class: "section-title", "How LOGOS Compares" }
1986                    p { class: "section-sub",
1987                        "A new approach to formal reasoning."
1988                    }
1989
1990                    div { class: "compare-table",
1991                        div { class: "compare-row header",
1992                            div { class: "compare-cell", "Feature" }
1993                            div { class: "compare-cell highlight", "LOGOS" }
1994                            div { class: "compare-cell", "Python" }
1995                            div { class: "compare-cell", "Lean 4" }
1996                            div { class: "compare-cell", "Rust" }
1997                            div { class: "compare-cell", "Elixir" }
1998                        }
1999                        div { class: "compare-row",
2000                            div { class: "compare-cell label", "Syntax" }
2001                            div { class: "compare-cell highlight", "English prose" }
2002                            div { class: "compare-cell", "Symbols" }
2003                            div { class: "compare-cell", "Lean DSL" }
2004                            div { class: "compare-cell", "Symbols" }
2005                            div { class: "compare-cell", "Symbols" }
2006                        }
2007                        div { class: "compare-row",
2008                            div { class: "compare-cell label", "File Format" }
2009                            div { class: "compare-cell highlight", "Markdown (.md)" }
2010                            div { class: "compare-cell", ".py" }
2011                            div { class: "compare-cell", ".lean" }
2012                            div { class: "compare-cell", ".rs" }
2013                            div { class: "compare-cell", ".ex" }
2014                        }
2015                        div { class: "compare-row",
2016                            div { class: "compare-cell label", "Performance" }
2017                            div { class: "compare-cell highlight", "Native (via Rust)" }
2018                            div { class: "compare-cell", "Interpreted" }
2019                            div { class: "compare-cell", "Native" }
2020                            div { class: "compare-cell", "Native" }
2021                            div { class: "compare-cell", "BEAM VM" }
2022                        }
2023                        div { class: "compare-row",
2024                            div { class: "compare-cell label", "Proofs" }
2025                            div { class: "compare-cell highlight", "Built-in" }
2026                            div { class: "compare-cell", "None" }
2027                            div { class: "compare-cell", "Required" }
2028                            div { class: "compare-cell", "Optional" }
2029                            div { class: "compare-cell", "None" }
2030                        }
2031                        div { class: "compare-row",
2032                            div { class: "compare-cell label", "Memory" }
2033                            div { class: "compare-cell highlight", "Ownership (English)" }
2034                            div { class: "compare-cell", "GC" }
2035                            div { class: "compare-cell", "GC" }
2036                            div { class: "compare-cell", "Ownership" }
2037                            div { class: "compare-cell", "GC" }
2038                        }
2039                    }
2040                }
2041
2042                section { class: "section", id: "faq",
2043                    h2 { class: "section-title", "FAQ" }
2044                    p { class: "section-sub",
2045                        "Common questions about LOGICAFFEINE."
2046                    }
2047
2048                    div { class: "grid2",
2049                        div { class: "faq-item",
2050                            div { class: "faq-q", "Is it really free?" }
2051                            div { class: "faq-a", "Yes — free for individuals, universities, and teams under 25 people. For commercial licensing, contact us." }
2052                        }
2053                        div { class: "faq-item",
2054                            div { class: "faq-q", "Do I need to know logic already?" }
2055                            div { class: "faq-a", "No. Start in Learn. The system introduces concepts progressively and uses examples to teach scope, quantifiers, and structure." }
2056                        }
2057                        div { class: "faq-item",
2058                            div { class: "faq-q", "Is this an AI that \"guesses\"?" }
2059                            div { class: "faq-a", "The goal is the opposite: to force explicit structure. When language is ambiguous, the tutor prompts clarifying questions." }
2060                        }
2061                        div { class: "faq-item",
2062                            div { class: "faq-q", "Where do I begin?" }
2063                            div { class: "faq-a", "If you want speed, open Studio. If you want mastery, Start Learning and follow the lessons." }
2064                        }
2065                        div { class: "faq-item",
2066                            div { class: "faq-q", "What is LOGOS written in?" }
2067                            div { class: "faq-a", "Rust. The entire transpiler, parser, and runtime are written in Rust for maximum performance and safety." }
2068                        }
2069                        div { class: "faq-item",
2070                            div { class: "faq-q", "How fast is it?" }
2071                            div { class: "faq-a", "Native speed. LOGOS compiles to Rust, which then compiles via LLVM to optimized machine code. Zero interpreter overhead." }
2072                        }
2073                    }
2074                }
2075
2076                section {
2077                    class: "section",
2078                    style: "padding-bottom: 100px;",
2079                    div {
2080                        class: "card",
2081                        style: "padding: 32px; overflow: visible;",
2082                        h2 { class: "section-title", "Make your reasoning impossible to ignore." }
2083                        p {
2084                            class: "section-sub",
2085                            style: "margin-bottom: 20px;",
2086                            "Start with the Curriculum, or explore any mode in the Studio. Code, Logic, Math — your call."
2087                        }
2088                        div { class: "hero-ctas",
2089                            Link { to: Route::Learn {}, class: "btn btn-primary", "Start Learning" }
2090                            Link { to: Route::Pricing {}, class: "btn btn-ghost", "Contact Us" }
2091                        }
2092                    }
2093                }
2094
2095                Footer {}
2096            }
2097        }
2098    }
2099}
2100
2101// `lazy`: with the `split` feature + dx `--wasm-split`, the interactive demo body
2102// (and the LOGOS engine — logicaffeine_compile/logicaffeine_kernel — that only it
2103// references) moves into the lazily-fetched chunk, keeping the eager core engine-free.
2104#[component(lazy)]
2105fn LandingShowcase() -> Element {
2106    let mut demo_mode = use_signal(|| StudioMode::Code);
2107    let mut active_index = use_signal(|| 0usize);
2108    let mut cycling_paused = use_signal(|| false);
2109    let mut timer_started = use_signal(|| false);
2110    let mut terminal_height = use_signal(|| 135.0f64);
2111    let mut resizing_terminal = use_signal(|| false);
2112    let mut compiled_height = use_signal(|| 140.0f64);
2113    let mut show_compiled = use_signal(|| false);
2114    let mut resizing_compiled = use_signal(|| false);
2115    let mut code_content = use_signal(|| String::new());
2116    let mut output_lines = use_signal(|| Vec::<String>::new());
2117    let mut output_error = use_signal(|| Option::<String>::None);
2118    let mut compiled_output = use_signal(|| String::new());
2119    let mut is_running = use_signal(|| false);
2120
2121    use_effect(move || {
2122        let mode = *demo_mode.read();
2123        let idx = *active_index.read();
2124        let examples = examples_for_mode(mode);
2125        let clamped = idx.min(examples.len().saturating_sub(1));
2126        let ex = &examples[clamped];
2127        let content = ex.content.to_string();
2128        code_content.set(content.clone());
2129        output_error.set(None);
2130        compiled_output.set(ex.compiled.to_string());
2131
2132        match mode {
2133            StudioMode::Code => {
2134                output_lines.set(Vec::new());
2135                spawn(async move {
2136                    let result = interpret_for_ui(&content).await;
2137                    output_lines.set(result.lines);
2138                    output_error.set(result.error);
2139                });
2140            }
2141            StudioMode::Logic | StudioMode::Hardware => {
2142                let mut lines: Vec<String> = Vec::new();
2143
2144                if content.contains("## Theorem:") {
2145                    for line in content.lines() {
2146                        let trimmed = line.trim();
2147                        if let Some(sentence) = trimmed.strip_prefix("Given:") {
2148                            let fol = compile_for_ui(sentence.trim());
2149                            if let Some(logic) = fol.logic {
2150                                lines.push(logic);
2151                            }
2152                        } else if let Some(sentence) = trimmed.strip_prefix("Prove:") {
2153                            let fol = compile_for_ui(sentence.trim());
2154                            if let Some(logic) = fol.logic {
2155                                lines.push(format!("Goal: {}", logic));
2156                            }
2157                        }
2158                    }
2159
2160                    let theorem_result = compile_theorem_for_ui(&content);
2161                    if let Some(ref err) = theorem_result.error {
2162                        output_error.set(Some(err.clone()));
2163                    } else {
2164                        lines.push(String::new());
2165                        if theorem_result.derivation.is_some() {
2166                            lines.push(format!("Theorem: {} ✓", theorem_result.name));
2167                        } else {
2168                            lines.push(format!("Theorem: {} — not proved", theorem_result.name));
2169                        }
2170                    }
2171                } else {
2172                    let result = compile_for_ui(&content);
2173                    if let Some(logic) = result.logic {
2174                        for line in logic.lines() {
2175                            lines.push(line.to_string());
2176                        }
2177                    }
2178                    if let Some(ref err) = result.error {
2179                        output_error.set(Some(err.clone()));
2180                    }
2181                }
2182
2183                output_lines.set(lines);
2184            }
2185            StudioMode::Math => {
2186                let (lines, err) = execute_math_code(&content);
2187                output_lines.set(lines);
2188                output_error.set(err);
2189            }
2190        }
2191    });
2192
2193    use_effect(move || {
2194        if *timer_started.read() { return; }
2195        timer_started.set(true);
2196        #[cfg(target_arch = "wasm32")]
2197        spawn(async move {
2198            loop {
2199                gloo_timers::future::TimeoutFuture::new(7_000).await;
2200                if !*cycling_paused.read() {
2201                    let mode = *demo_mode.read();
2202                    let count = examples_for_mode(mode).len();
2203                    let next = (*active_index.read() + 1) % count;
2204                    active_index.set(next);
2205                }
2206            }
2207        });
2208    });
2209
2210    rsx! {
2211        div {
2212            class: "mini-studio",
2213            id: "product",
2214            style: if *resizing_terminal.read() || *resizing_compiled.read() { "user-select: none;" } else { "" },
2215            onmouseenter: move |_| { cycling_paused.set(true); },
2216            onmouseleave: move |_| {
2217                cycling_paused.set(false);
2218                resizing_terminal.set(false);
2219                resizing_compiled.set(false);
2220            },
2221            onmousemove: move |evt| {
2222                let window = web_sys::window().unwrap();
2223                let document = window.document().unwrap();
2224                let cta_height: f64 = 45.0;
2225                if *resizing_terminal.read() {
2226                    if let Some(el) = document.get_element_by_id("product") {
2227                        let rect = el.get_bounding_client_rect();
2228                        let coords = evt.data().client_coordinates();
2229                        let client_y: f64 = coords.y;
2230                        let below = cta_height
2231                            + if *show_compiled.read() { *compiled_height.read() + 6.0 } else { 0.0 };
2232                        let new_height = rect.bottom() - client_y - below;
2233                        terminal_height.set(new_height.clamp(60.0, 300.0));
2234                    }
2235                } else if *resizing_compiled.read() {
2236                    if let Some(el) = document.get_element_by_id("product") {
2237                        let rect = el.get_bounding_client_rect();
2238                        let coords = evt.data().client_coordinates();
2239                        let client_y: f64 = coords.y;
2240                        let new_height = rect.bottom() - client_y - cta_height;
2241                        let max_compiled = rect.height() - *terminal_height.read() - cta_height - 6.0 - 120.0;
2242                        compiled_height.set(new_height.clamp(60.0, max_compiled.max(60.0)));
2243                    }
2244                }
2245            },
2246            onmouseup: move |_| {
2247                resizing_terminal.set(false);
2248                resizing_compiled.set(false);
2249            },
2250            ontouchmove: move |evt| {
2251                let window = web_sys::window().unwrap();
2252                let document = window.document().unwrap();
2253                let cta_height: f64 = 45.0;
2254                if *resizing_terminal.read() || *resizing_compiled.read() {
2255                    evt.prevent_default();
2256                    let touches = evt.data().touches();
2257                    if let Some(touch) = touches.first() {
2258                        if let Some(el) = document.get_element_by_id("product") {
2259                            let rect = el.get_bounding_client_rect();
2260                            let coords = touch.client_coordinates();
2261                            let client_y: f64 = coords.y;
2262                            if *resizing_terminal.read() {
2263                                let below = cta_height
2264                                    + if *show_compiled.read() { *compiled_height.read() + 6.0 } else { 0.0 };
2265                                let new_height = rect.bottom() - client_y - below;
2266                                terminal_height.set(new_height.clamp(60.0, 300.0));
2267                            } else {
2268                                let new_height = rect.bottom() - client_y - cta_height;
2269                                let max_compiled = rect.height() - *terminal_height.read() - cta_height - 6.0 - 120.0;
2270                                compiled_height.set(new_height.clamp(60.0, max_compiled.max(60.0)));
2271                            }
2272                        }
2273                    }
2274                }
2275            },
2276            ontouchend: move |_| {
2277                resizing_terminal.set(false);
2278                resizing_compiled.set(false);
2279            },
2280
2281            div { class: "mini-studio-head",
2282                div { class: "win-dots",
2283                    div { class: "wdot wr" }
2284                    div { class: "wdot wy" }
2285                    div { class: "wdot wg" }
2286                }
2287                div { class: "mini-mode-toggle",
2288                    button {
2289                        class: if *demo_mode.read() == StudioMode::Code { "mini-toggle-btn active" } else { "mini-toggle-btn" },
2290                        onclick: move |_| {
2291                            demo_mode.set(StudioMode::Code);
2292                            active_index.set(0);
2293                        },
2294                        span { "λ" }
2295                        span { class: "mini-toggle-label", "Code" }
2296                    }
2297                    button {
2298                        class: if *demo_mode.read() == StudioMode::Logic { "mini-toggle-btn active" } else { "mini-toggle-btn" },
2299                        onclick: move |_| {
2300                            demo_mode.set(StudioMode::Logic);
2301                            active_index.set(0);
2302                            show_compiled.set(false);
2303                        },
2304                        span { "∀" }
2305                        span { class: "mini-toggle-label", "Logic" }
2306                    }
2307                    button {
2308                        class: if *demo_mode.read() == StudioMode::Math { "mini-toggle-btn active" } else { "mini-toggle-btn" },
2309                        onclick: move |_| {
2310                            demo_mode.set(StudioMode::Math);
2311                            active_index.set(0);
2312                            show_compiled.set(false);
2313                        },
2314                        span { "π" }
2315                        span { class: "mini-toggle-label", "Math" }
2316                    }
2317                }
2318            }
2319
2320            div { class: "mini-action-bar",
2321                if *demo_mode.read() == StudioMode::Code {
2322                    button {
2323                        class: "mini-exec-btn compile",
2324                        onclick: move |_| {
2325                            let code = code_content.read().clone();
2326
2327                            match generate_rust_code(&code) {
2328                                Ok(rust) => compiled_output.set(rust),
2329                                Err(e) => compiled_output.set(format!("// Compile error: {:?}", e)),
2330                            }
2331
2332                            let current = *show_compiled.read();
2333                            if !current {
2334                                show_compiled.set(true);
2335                            }
2336                        },
2337                        "🦀"
2338                        span { class: "btn-label", "Compile to Rust" }
2339                    }
2340                }
2341                button {
2342                    class: "mini-exec-btn run",
2343                    onclick: move |_| {
2344                        let code = code_content.read().clone();
2345                        let mode = *demo_mode.read();
2346                        is_running.set(true);
2347                        output_lines.set(Vec::new());
2348                        output_error.set(None);
2349
2350                        match mode {
2351                            StudioMode::Code => {
2352                                spawn(async move {
2353                                    let result = interpret_for_ui(&code).await;
2354                                    output_lines.set(result.lines);
2355                                    output_error.set(result.error);
2356                                    is_running.set(false);
2357                                });
2358                            }
2359                            StudioMode::Logic | StudioMode::Hardware => {
2360                                let mut lines: Vec<String> = Vec::new();
2361
2362                                if code.contains("## Theorem:") {
2363                                    // FOL transpilation: compile each premise sentence individually
2364                                    for line in code.lines() {
2365                                        let trimmed = line.trim();
2366                                        if let Some(sentence) = trimmed.strip_prefix("Given:") {
2367                                            let sentence = sentence.trim();
2368                                            let fol = compile_for_ui(sentence);
2369                                            if let Some(logic) = fol.logic {
2370                                                lines.push(logic);
2371                                            }
2372                                        } else if let Some(sentence) = trimmed.strip_prefix("Prove:") {
2373                                            let sentence = sentence.trim();
2374                                            let fol = compile_for_ui(sentence);
2375                                            if let Some(logic) = fol.logic {
2376                                                lines.push(format!("Goal: {}", logic));
2377                                            }
2378                                        }
2379                                    }
2380
2381                                    // Proof verification
2382                                    let theorem_result = compile_theorem_for_ui(&code);
2383                                    if let Some(ref err) = theorem_result.error {
2384                                        output_error.set(Some(err.clone()));
2385                                    } else {
2386                                        lines.push(String::new());
2387                                        let proved = theorem_result.derivation.is_some();
2388                                        if proved {
2389                                            lines.push(format!("Theorem: {} ✓", theorem_result.name));
2390                                        } else {
2391                                            lines.push(format!("Theorem: {} — not proved", theorem_result.name));
2392                                        }
2393                                    }
2394                                } else {
2395                                    let result = compile_for_ui(&code);
2396                                    if let Some(logic) = result.logic {
2397                                        for line in logic.lines() {
2398                                            lines.push(line.to_string());
2399                                        }
2400                                    }
2401                                    if let Some(ref err) = result.error {
2402                                        output_error.set(Some(err.clone()));
2403                                    }
2404                                }
2405
2406                                output_lines.set(lines);
2407                                is_running.set(false);
2408                            }
2409                            StudioMode::Math => {
2410                                let (lines, err) = execute_math_code(&code);
2411                                output_lines.set(lines);
2412                                output_error.set(err);
2413                                is_running.set(false);
2414                            }
2415                        }
2416                    },
2417                    "▶"
2418                    span { class: "btn-label",
2419                        if *demo_mode.read() == StudioMode::Code { "Run" } else { "Execute" }
2420                    }
2421                }
2422            }
2423
2424            div { class: "mini-file-tabs",
2425                for i in 0..examples_for_mode(*demo_mode.read()).len() {
2426                    button {
2427                        key: "{i}",
2428                        class: if *active_index.read() == i { "mini-file-tab active" } else { "mini-file-tab" },
2429                        onclick: move |_| {
2430                            active_index.set(i);
2431                            cycling_paused.set(true);
2432                        },
2433                        "{examples_for_mode(*demo_mode.read())[i].filename}"
2434                    }
2435                }
2436                a {
2437                    class: "mini-file-tab view-more",
2438                    href: "/studio",
2439                    "View more..."
2440                }
2441            }
2442
2443            div { class: "mini-studio-body",
2444                div { class: "mini-explorer",
2445                    div { class: "mini-explorer-label", "FILES" }
2446                    for i in 0..examples_for_mode(*demo_mode.read()).len() {
2447                        div {
2448                            key: "{i}",
2449                            class: if *active_index.read() == i { "mini-file-item active" } else { "mini-file-item" },
2450                            onclick: move |_| {
2451                                active_index.set(i);
2452                                cycling_paused.set(true);
2453                            },
2454                            span { class: "mini-file-icon", "●" }
2455                            span { "{examples_for_mode(*demo_mode.read())[i].filename}" }
2456                        }
2457                    }
2458                    a {
2459                        class: "mini-file-item view-more",
2460                        href: "/studio",
2461                        "View more..."
2462                    }
2463                }
2464                div { class: "mini-code-panel",
2465                    {
2466                        let mode = *demo_mode.read();
2467                        let examples = examples_for_mode(mode);
2468                        let idx = (*active_index.read()).min(examples.len().saturating_sub(1));
2469                        let ex = &examples[idx];
2470                        rsx! {
2471                            div { class: "mini-code-filename",
2472                                span { "{ex.filename}" }
2473                                span { "  {ex.icon}" }
2474                            }
2475                            CodeEditor {
2476                                value: code_content.read().clone(),
2477                                on_change: move |v: String| code_content.set(v),
2478                                language: match mode {
2479                                    StudioMode::Code => Language::Logos,
2480                                    StudioMode::Logic | StudioMode::Hardware => Language::Logos,
2481                                    StudioMode::Math => Language::Vernacular,
2482                                },
2483                                placeholder: "Enter code...".to_string(),
2484                            }
2485                        }
2486                    }
2487                }
2488            }
2489
2490            div {
2491                class: if *resizing_terminal.read() { "mini-terminal-resizer active" } else { "mini-terminal-resizer" },
2492                onmousedown: move |e| {
2493                    e.prevent_default();
2494                    resizing_terminal.set(true);
2495                },
2496                ontouchstart: move |e| {
2497                    e.prevent_default();
2498                    resizing_terminal.set(true);
2499                },
2500            }
2501
2502            div { class: "mini-terminal", style: "height: {terminal_height}px;",
2503                div { class: "mini-terminal-head", "OUTPUT" }
2504                div { class: "mini-terminal-body",
2505                    if *is_running.read() {
2506                        div { class: "mini-output-loading", "Running..." }
2507                    }
2508                    {
2509                        let lines = output_lines.read().clone();
2510                        let error = output_error.read().clone();
2511                        rsx! {
2512                            for (i, line) in lines.iter().enumerate() {
2513                                pre { key: "{i}", class: "mini-output-line", "{line}" }
2514                            }
2515                            if let Some(ref err) = error {
2516                                pre { class: "mini-output-error", "{err}" }
2517                            }
2518                            if lines.is_empty() && error.is_none() && !*is_running.read() {
2519                                div { class: "mini-output-empty", "Click Run to see output" }
2520                            }
2521                        }
2522                    }
2523                }
2524            }
2525
2526            if *show_compiled.read() {
2527                div {
2528                    class: if *resizing_compiled.read() { "mini-terminal-resizer active" } else { "mini-terminal-resizer" },
2529                    onmousedown: move |e| {
2530                        e.prevent_default();
2531                        resizing_compiled.set(true);
2532                    },
2533                    ontouchstart: move |e| {
2534                        e.prevent_default();
2535                        resizing_compiled.set(true);
2536                    },
2537                }
2538                div { class: "mini-compiled", style: "height: {compiled_height}px;",
2539                    div { class: "mini-compiled-head", "COMPILED RUST" }
2540                    pre { class: "mini-compiled-body", "{compiled_output}" }
2541                }
2542            }
2543
2544            div { class: "mini-studio-cta",
2545                {
2546                    let mode = *demo_mode.read();
2547                    let examples = examples_for_mode(mode);
2548                    let idx = (*active_index.read()).min(examples.len().saturating_sub(1));
2549                    let studio_url = crate::ui::router::studio_file_url(examples[idx].studio_path);
2550                    rsx! {
2551                        a { href: "{studio_url}", class: "mini-cta-btn",
2552                            "Try it in the Studio →"
2553                        }
2554                    }
2555                }
2556            }
2557        }
2558    }
2559}
2560
2561// `lazy`: keeps the hello-world editor's interpreter dependency out of the eager core.
2562#[component(lazy)]
2563fn LandingHelloWorld() -> Element {
2564    let mut hello_code = use_signal(|| CODE_DEMO_EXAMPLES[0].content.to_string());
2565    let mut hello_output = use_signal(|| CODE_DEMO_EXAMPLES[0].output.lines().map(|l| l.to_string()).collect::<Vec<_>>());
2566    let mut hello_error = use_signal(|| Option::<String>::None);
2567    let mut hello_running = use_signal(|| false);
2568
2569    rsx! {
2570        div { class: "hello-editor",
2571            div { class: "hello-editor-head",
2572                span { class: "hello-filename", "hello-world.logos" }
2573                button {
2574                    class: "hello-run-btn",
2575                    disabled: *hello_running.read(),
2576                    onclick: move |_| {
2577                        let code = hello_code.read().clone();
2578                        hello_running.set(true);
2579                        hello_output.set(Vec::new());
2580                        hello_error.set(None);
2581                        spawn(async move {
2582                            let result = interpret_for_ui(&code).await;
2583                            hello_output.set(result.lines);
2584                            hello_error.set(result.error);
2585                            hello_running.set(false);
2586                        });
2587                    },
2588                    if *hello_running.read() { "Running..." } else { "▶ Run" }
2589                }
2590            }
2591            div { class: "hello-editor-body",
2592                div { class: "hello-editor-left",
2593                    CodeEditor {
2594                        value: hello_code.read().clone(),
2595                        on_change: move |v: String| hello_code.set(v),
2596                        language: Language::Logos,
2597                        placeholder: "Enter code...".to_string(),
2598                    }
2599                }
2600                div { class: "hello-editor-right",
2601                    div { class: "hello-output-head", "Output" }
2602                    div { class: "hello-output-body",
2603                        if *hello_running.read() {
2604                            div { class: "hello-output-loading", "Running..." }
2605                        }
2606                        {
2607                            let lines = hello_output.read().clone();
2608                            let error = hello_error.read().clone();
2609                            rsx! {
2610                                for (i, line) in lines.iter().enumerate() {
2611                                    pre { key: "{i}", class: "hello-output-line", "{line}" }
2612                                }
2613                                if let Some(ref err) = error {
2614                                    pre { class: "hello-output-error", "{err}" }
2615                                }
2616                                if lines.is_empty() && error.is_none() && !*hello_running.read() {
2617                                    div { class: "hello-output-empty", "Click Run to see output" }
2618                                }
2619                            }
2620                        }
2621                    }
2622                }
2623            }
2624        }
2625    }
2626}