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