Vanshik Waghela commited on
Commit
70299ab
·
1 Parent(s): 28c1fa2

feat: Redesign landing page with widescreen hero and interactive autopilot simulator

Browse files
apps/web/src/app/[locale]/layout.tsx CHANGED
@@ -54,7 +54,7 @@ export default async function LocaleLayout({
54
  >
55
  <div
56
  style={{
57
- maxWidth: 980,
58
  margin: "0 auto",
59
  padding: "0 20px",
60
  height: 56,
 
54
  >
55
  <div
56
  style={{
57
+ maxWidth: 1200,
58
  margin: "0 auto",
59
  padding: "0 20px",
60
  height: 56,
apps/web/src/app/[locale]/page.tsx CHANGED
@@ -14,6 +14,25 @@ import {
14
  DialogDescription,
15
  } from "@/components/ui/dialog";
16
  import { stateToStage } from "@/components/mission";
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
17
 
18
  // ────────────────────────────────────────────────────────────────
19
  // Domain config
@@ -21,6 +40,17 @@ import { stateToStage } from "@/components/mission";
21
 
22
  const DOMAINS: IssueDomain[] = ["consumer", "payment", "cyber_fraud"];
23
 
 
 
 
 
 
 
 
 
 
 
 
24
  // Stage chip colours
25
  const STAGE_CHIP_STYLES: Record<string, { bg: string; fg: string; border: string }> = {
26
  describe: { bg: "var(--surface-elevated)", fg: "var(--foreground-muted)", border: "var(--border)" },
@@ -45,9 +75,9 @@ function StageChip({ state }: { state: MissionState }) {
45
  return (
46
  <span
47
  style={{
48
- padding: "2px 9px",
49
  borderRadius: 999,
50
- fontSize: 11,
51
  fontWeight: 700,
52
  textTransform: "uppercase",
53
  letterSpacing: "0.05em",
@@ -274,7 +304,7 @@ function CreateMissionDialog({ open, onOpenChange, onCreated }: CreateDialogProp
274
  }
275
 
276
  // ────────────────────────────────────────────────────────────────
277
- // Mission card
278
  // ────────────────────────────────────────────────────────────────
279
 
280
  function MissionCard({ mission, locale }: { mission: Mission; locale: string }) {
@@ -285,27 +315,11 @@ function MissionCard({ mission, locale }: { mission: Mission; locale: string })
285
  return (
286
  <Link
287
  href={`/${locale}/missions/${mission.id}`}
288
- style={{ textDecoration: "none", display: "block" }}
 
289
  >
290
  <div
291
- style={{
292
- padding: "16px 18px",
293
- background: "var(--card)",
294
- border: "1px solid var(--border)",
295
- borderRadius: 12,
296
- cursor: "pointer",
297
- transition: "border-color 0.15s, box-shadow 0.15s",
298
- position: "relative",
299
- overflow: "hidden",
300
- }}
301
- onMouseEnter={(e) => {
302
- (e.currentTarget as HTMLDivElement).style.borderColor = "hsl(228 50% 70%)";
303
- (e.currentTarget as HTMLDivElement).style.boxShadow = "0 2px 12px hsl(228 58% 36% / 0.1)";
304
- }}
305
- onMouseLeave={(e) => {
306
- (e.currentTarget as HTMLDivElement).style.borderColor = "var(--border)";
307
- (e.currentTarget as HTMLDivElement).style.boxShadow = "none";
308
- }}
309
  >
310
  {/* Subtle indigo accent stripe */}
311
  <div
@@ -314,55 +328,33 @@ function MissionCard({ mission, locale }: { mission: Mission; locale: string })
314
  left: 0,
315
  top: 0,
316
  bottom: 0,
317
- width: 3,
318
  background: "var(--primary)",
319
- opacity: 0.3,
320
  borderRadius: "12px 0 0 12px",
321
  }}
322
  />
323
 
324
- <div style={{ paddingLeft: 8 }}>
325
- <div
326
- style={{
327
- display: "flex",
328
- alignItems: "flex-start",
329
- justifyContent: "space-between",
330
- gap: 12,
331
- marginBottom: 8,
332
- }}
333
- >
334
  <div
335
- style={{
336
- fontWeight: 700,
337
- fontSize: 15,
338
- color: "var(--foreground)",
339
- lineHeight: 1.3,
340
- flex: 1,
341
- }}
342
  >
343
  {mission.title}
344
  </div>
345
  <StageChip state={mission.state} />
346
  </div>
347
 
348
- <div style={{ display: "flex", gap: 8, alignItems: "center", flexWrap: "wrap" }}>
 
 
349
  <span
350
- style={{
351
- padding: "2px 9px",
352
- borderRadius: 999,
353
- fontSize: 11,
354
- fontWeight: 700,
355
- textTransform: "uppercase",
356
- letterSpacing: "0.04em",
357
- background: "var(--primary-light)",
358
- color: "var(--primary)",
359
- border: "1px solid hsl(228 50% 80%)",
360
- }}
361
  >
362
  {domainLabel}
363
  </span>
364
- <span style={{ fontSize: 12, color: "var(--foreground-muted)" }}>
365
- {new Date(mission.updatedAt).toLocaleDateString("en-IN", { day: "numeric", month: "short" })}
366
  </span>
367
  </div>
368
  </div>
@@ -377,52 +369,26 @@ function MissionCard({ mission, locale }: { mission: Mission; locale: string })
377
 
378
  function EmptyMissionState({ onStart }: { onStart: () => void }) {
379
  const t = useTranslations("mission.board");
 
380
  return (
381
  <div
382
- style={{
383
- padding: "40px 20px",
384
- textAlign: "center",
385
- color: "var(--foreground-muted)",
386
- border: "2px dashed var(--border)",
387
- borderRadius: 16,
388
- background: "var(--card)",
389
- }}
390
  >
391
  <div
392
- style={{
393
- width: 56,
394
- height: 56,
395
- borderRadius: "50%",
396
- background: "var(--primary-light)",
397
- margin: "0 auto 16px",
398
- display: "flex",
399
- alignItems: "center",
400
- justifyContent: "center",
401
- fontSize: 24,
402
- }}
403
  >
404
 
405
  </div>
406
- <div style={{ fontFamily: "var(--font-serif)", fontSize: 18, fontWeight: 700, color: "var(--foreground)", marginBottom: 6 }}>
407
- No missions yet
408
  </div>
409
- <div style={{ fontSize: 14, lineHeight: 1.6, marginBottom: 18 }}>
410
  {t("empty")}
411
- </div>
412
  <button
413
  onClick={onStart}
414
- style={{
415
- background: "var(--primary)",
416
- color: "#fff",
417
- border: "none",
418
- borderRadius: 10,
419
- padding: "10px 20px",
420
- fontSize: 14,
421
- fontWeight: 700,
422
- cursor: "pointer",
423
- minHeight: 44,
424
- marginTop: 0,
425
- }}
426
  >
427
  {t("createBtn")}
428
  </button>
@@ -436,6 +402,7 @@ function EmptyMissionState({ onStart }: { onStart: () => void }) {
436
 
437
  export default function MissionBoard() {
438
  const locale = useLocale();
 
439
  const router = useRouter();
440
  const tLanding = useTranslations("landing");
441
  const tBoard = useTranslations("mission.board");
@@ -451,6 +418,9 @@ export default function MissionBoard() {
451
  const [domainFilter, setDomainFilter] = useState<IssueDomain | "all">("all");
452
  const [search, setSearch] = useState("");
453
 
 
 
 
454
  async function refresh() {
455
  setLoadingMissions(true);
456
  try {
@@ -479,292 +449,356 @@ export default function MissionBoard() {
479
  });
480
 
481
  return (
482
- <div className="container">
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
483
 
484
- {/* ── Hero ──────────────────────────────────────────── */}
485
- <div
486
- style={{
487
- marginBottom: 36,
488
- padding: "32px 0 28px",
489
- borderBottom: "1px solid var(--border)",
490
- position: "relative",
491
- }}
492
- >
493
- {/* Decorative background */}
494
- <div
495
- aria-hidden
496
- style={{
497
- position: "absolute",
498
- top: 0,
499
- right: 0,
500
- width: 280,
501
- height: 280,
502
- background: "radial-gradient(circle at 70% 30%, hsl(228 58% 36% / 0.05) 0%, transparent 70%)",
503
- pointerEvents: "none",
504
- }}
505
- />
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
506
 
507
- <div style={{ maxWidth: 580, position: "relative" }}>
508
- <div
509
- style={{
510
- display: "inline-flex",
511
- alignItems: "center",
512
- gap: 6,
513
- padding: "3px 10px",
514
- background: "var(--primary-light)",
515
- border: "1px solid hsl(228 50% 80%)",
516
- borderRadius: 999,
517
- fontSize: 11,
518
- fontWeight: 700,
519
- color: "var(--primary)",
520
- letterSpacing: "0.06em",
521
- textTransform: "uppercase",
522
- marginBottom: 14,
523
- }}
524
- >
525
- {tCommon("appName")} · Phase 1
526
- </div>
527
 
528
- <h1
529
- style={{
530
- fontFamily: "var(--font-serif)",
531
- fontSize: "clamp(26px, 4vw, 36px)",
532
- fontWeight: 700,
533
- color: "var(--foreground)",
534
- lineHeight: 1.2,
535
- margin: "0 0 12px",
536
- }}
537
- >
538
- {tLanding("headline")}
539
- </h1>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
540
 
541
- <p
542
- style={{
543
- fontSize: 16,
544
- color: "var(--foreground-muted)",
545
- lineHeight: 1.7,
546
- margin: "0 0 24px",
547
- }}
548
- >
549
- {tLanding("subheadline")}
550
- </p>
551
 
552
- <div style={{ display: "flex", gap: 10, flexWrap: "wrap" }}>
553
- <button
554
- onClick={() => setDialogOpen(true)}
555
- style={{
556
- background: "var(--primary)",
557
- color: "#fff",
558
- border: "none",
559
- borderRadius: 10,
560
- padding: "12px 22px",
561
- fontSize: 15,
562
- fontWeight: 700,
563
- cursor: "pointer",
564
- minHeight: 48,
565
- marginTop: 0,
566
- letterSpacing: "-0.01em",
567
- }}
568
- >
569
- {tLanding("ctaStart")}
570
- </button>
571
- <Link
572
- href={`/${locale}/ledger`}
573
- style={{
574
- display: "inline-flex",
575
- alignItems: "center",
576
- padding: "12px 22px",
577
- background: "var(--surface-elevated)",
578
- color: "var(--foreground)",
579
- border: "1px solid var(--border)",
580
- borderRadius: 10,
581
- fontSize: 15,
582
- fontWeight: 600,
583
- textDecoration: "none",
584
- minHeight: 48,
585
- }}
586
- >
587
- {tLanding("ctaLedger")}
588
- </Link>
589
  </div>
590
  </div>
591
- </div>
592
-
593
- {/* ── Mission list ──────────────────────────────────── */}
594
- <div style={{ marginBottom: 16 }}>
595
- <div
596
- style={{
597
- display: "flex",
598
- alignItems: "center",
599
- justifyContent: "space-between",
600
- gap: 12,
601
- flexWrap: "wrap",
602
- marginBottom: 14,
603
- }}
604
- >
605
- <h2
606
- style={{
607
- fontFamily: "var(--font-serif)",
608
- fontSize: 18,
609
- fontWeight: 700,
610
- color: "var(--foreground)",
611
- margin: 0,
612
- }}
613
- >
614
- {tBoard("heading")}
615
- {!loadingMissions && (
616
- <span
617
- style={{
618
- marginLeft: 8,
619
- fontSize: 14,
620
- fontWeight: 600,
621
- fontFamily: "var(--font-sans)",
622
- color: "var(--foreground-muted)",
623
- }}
624
- >
625
- ({missions.length})
626
- </span>
627
- )}
628
- </h2>
629
 
630
- <button
631
- onClick={() => setDialogOpen(true)}
632
- style={{
633
- background: "var(--primary)",
634
- color: "#fff",
635
- border: "none",
636
- borderRadius: 8,
637
- padding: "8px 16px",
638
- fontSize: 13,
639
- fontWeight: 700,
640
- cursor: "pointer",
641
- minHeight: 36,
642
- marginTop: 0,
643
- }}
644
- >
645
- + {tNav("newMission")}
646
- </button>
 
647
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
648
 
649
- {/* Filters */}
650
- <div style={{ display: "flex", gap: 8, flexWrap: "wrap", marginBottom: 16 }}>
651
- <input
652
- value={search}
653
- onChange={(e) => setSearch(e.target.value)}
654
- placeholder="Search missions…"
655
- style={{
656
- flex: "1 1 200px",
657
- padding: "8px 12px",
658
- fontSize: 13,
659
- borderRadius: 8,
660
- border: "1px solid var(--border)",
661
- background: "var(--background)",
662
- color: "var(--foreground)",
663
- }}
664
- />
665
- <div style={{ display: "flex", gap: 6 }}>
666
- {(["all", ...DOMAINS] as ("all" | IssueDomain)[]).map((d) => {
667
- const label = d === "all" ? "All" : d.replace(/_/g, " ");
668
- const isActive = domainFilter === d;
669
  return (
670
- <button
671
- key={d}
672
- onClick={() => setDomainFilter(d)}
673
- style={{
674
- padding: "7px 12px",
675
- borderRadius: 8,
676
- fontSize: 12,
677
- fontWeight: isActive ? 700 : 500,
678
- cursor: "pointer",
679
- border: isActive ? "2px solid var(--primary)" : "1px solid var(--border)",
680
- background: isActive ? "var(--primary-light)" : "var(--background)",
681
- color: isActive ? "var(--primary)" : "var(--foreground-muted)",
682
- minHeight: "auto",
683
- marginTop: 0,
684
- textTransform: "capitalize",
685
- transition: "all 0.15s",
686
- whiteSpace: "nowrap",
687
- }}
688
  >
689
- {label}
690
- </button>
 
 
 
 
 
 
 
 
 
 
 
691
  );
692
  })}
693
  </div>
694
  </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
695
 
696
- {/* Error state */}
697
- {error && (
698
- <div
699
- style={{
700
- padding: "10px 14px",
701
- background: "var(--danger-light)",
702
- border: "1px solid hsl(3 72% 44% / 0.3)",
703
- borderRadius: 10,
704
- fontSize: 13,
705
- color: "var(--danger-fg)",
706
- marginBottom: 14,
707
- }}
708
- >
709
- {error}
710
  </div>
711
- )}
712
 
713
- {/* Loading */}
714
- {loadingMissions && (
715
- <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
716
- {[1, 2, 3].map((i) => (
717
- <div
718
- key={i}
719
- style={{
720
- height: 76,
721
- background: "var(--card)",
722
- border: "1px solid var(--border)",
723
- borderRadius: 12,
724
- overflow: "hidden",
725
- position: "relative",
726
- }}
727
- >
728
- <div
729
- style={{
730
- position: "absolute",
731
- inset: 0,
732
- background: "linear-gradient(90deg, transparent, hsl(228 20% 94%), transparent)",
733
- animation: "shimmer 1.5s infinite",
734
- backgroundSize: "200% 100%",
735
- }}
736
- />
737
- </div>
738
- ))}
 
 
 
 
 
739
  </div>
740
- )}
741
 
742
- {/* List */}
743
- {!loadingMissions && filtered.length === 0 && missions.length > 0 && (
744
- <div
745
- style={{
746
- padding: "20px 0",
747
- textAlign: "center",
748
- color: "var(--foreground-muted)",
749
- fontSize: 14,
750
- }}
751
- >
752
- No missions match your filter.
753
- </div>
754
- )}
755
 
756
- {!loadingMissions && missions.length === 0 && (
757
- <EmptyMissionState onStart={() => setDialogOpen(true)} />
758
- )}
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
759
 
760
- {!loadingMissions && filtered.length > 0 && (
761
- <div style={{ display: "flex", flexDirection: "column", gap: 10 }}>
762
- {filtered.map((m) => (
763
- <MissionCard key={m.id} mission={m} locale={locale} />
764
- ))}
765
- </div>
766
- )}
767
- </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
768
 
769
  {/* ── Create dialog ─────────────────────────────────── */}
770
  <CreateMissionDialog
@@ -773,13 +807,15 @@ export default function MissionBoard() {
773
  onCreated={handleCreated}
774
  />
775
 
776
- {/* Shimmer animation */}
777
  <style>{`
778
  @keyframes shimmer {
779
  0% { background-position: -200% 0; }
780
  100% { background-position: 200% 0; }
781
  }
782
  `}</style>
 
783
  </div>
784
  );
785
  }
 
 
14
  DialogDescription,
15
  } from "@/components/ui/dialog";
16
  import { stateToStage } from "@/components/mission";
17
+ import { AutopilotSimulator, TemplateId } from "@/components/app/AutopilotSimulator";
18
+ import {
19
+ ShoppingBag,
20
+ CreditCard,
21
+ ShieldAlert,
22
+ Briefcase,
23
+ Home as HomeIcon,
24
+ Building2,
25
+ Smartphone,
26
+ HeartPulse,
27
+ ArrowRight,
28
+ TrendingUp,
29
+ Clock,
30
+ CheckCircle,
31
+ HelpCircle,
32
+ Search,
33
+ Sparkles,
34
+ Zap
35
+ } from "lucide-react";
36
 
37
  // ────────────────────────────────────────────────────────────────
38
  // Domain config
 
40
 
41
  const DOMAINS: IssueDomain[] = ["consumer", "payment", "cyber_fraud"];
42
 
43
+ const DOMAIN_INFO: Record<string, { icon: React.ComponentType<{ className?: string }>; color: string; bg: string }> = {
44
+ consumer: { icon: ShoppingBag, color: "var(--primary)", bg: "var(--primary-light)" },
45
+ payment: { icon: CreditCard, color: "var(--info-fg)", bg: "var(--info-light)" },
46
+ cyber_fraud: { icon: ShieldAlert, color: "var(--danger-fg)", bg: "var(--danger-light)" },
47
+ employment: { icon: Briefcase, color: "var(--caution-fg)", bg: "var(--caution-light)" },
48
+ housing: { icon: HomeIcon, color: "var(--primary)", bg: "var(--primary-light)" },
49
+ govt_service: { icon: Building2, color: "var(--info-fg)", bg: "var(--info-light)" },
50
+ telecom: { icon: Smartphone, color: "var(--primary)", bg: "var(--primary-light)" },
51
+ healthcare: { icon: HeartPulse, color: "var(--danger-fg)", bg: "var(--danger-light)" },
52
+ };
53
+
54
  // Stage chip colours
55
  const STAGE_CHIP_STYLES: Record<string, { bg: string; fg: string; border: string }> = {
56
  describe: { bg: "var(--surface-elevated)", fg: "var(--foreground-muted)", border: "var(--border)" },
 
75
  return (
76
  <span
77
  style={{
78
+ padding: "3px 10px",
79
  borderRadius: 999,
80
+ fontSize: 10,
81
  fontWeight: 700,
82
  textTransform: "uppercase",
83
  letterSpacing: "0.05em",
 
304
  }
305
 
306
  // ────────────────────────────────────────────────────────────────
307
+ // Mission card (Grid version)
308
  // ────────────────────────────────────────────────────────────────
309
 
310
  function MissionCard({ mission, locale }: { mission: Mission; locale: string }) {
 
315
  return (
316
  <Link
317
  href={`/${locale}/missions/${mission.id}`}
318
+ className="block group"
319
+ style={{ textDecoration: "none" }}
320
  >
321
  <div
322
+ className="relative overflow-hidden rounded-xl border border-border bg-card p-5 cursor-pointer shadow-sm transition-all duration-200 hover:-translate-y-0.5 group-hover:border-primary/50 group-hover:shadow-md"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
323
  >
324
  {/* Subtle indigo accent stripe */}
325
  <div
 
328
  left: 0,
329
  top: 0,
330
  bottom: 0,
331
+ width: 4,
332
  background: "var(--primary)",
333
+ opacity: 0.4,
334
  borderRadius: "12px 0 0 12px",
335
  }}
336
  />
337
 
338
+ <div className="pl-2">
339
+ <div className="flex items-start justify-between gap-4 mb-3.5">
 
 
 
 
 
 
 
 
340
  <div
341
+ className="font-serif font-bold text-[16px] text-foreground leading-snug group-hover:text-primary transition-colors duration-200"
 
 
 
 
 
 
342
  >
343
  {mission.title}
344
  </div>
345
  <StageChip state={mission.state} />
346
  </div>
347
 
348
+
349
+
350
+ <div className="flex items-center justify-between mt-auto pt-2 border-t border-border/40">
351
  <span
352
+ className="px-2.5 py-0.5 rounded-full text-[10px] font-bold uppercase tracking-wider bg-primary-light text-primary border border-primary/20"
 
 
 
 
 
 
 
 
 
 
353
  >
354
  {domainLabel}
355
  </span>
356
+ <span className="text-[11px] text-foreground-faint font-semibold font-sans">
357
+ {new Date(mission.updatedAt).toLocaleDateString("en-IN", { day: "numeric", month: "short", year: "numeric" })}
358
  </span>
359
  </div>
360
  </div>
 
369
 
370
  function EmptyMissionState({ onStart }: { onStart: () => void }) {
371
  const t = useTranslations("mission.board");
372
+ const locale = useLocale();
373
  return (
374
  <div
375
+ className="p-10 text-center rounded-xl border-2 border-dashed border-border bg-card shadow-sm"
 
 
 
 
 
 
 
376
  >
377
  <div
378
+ className="w-14 h-14 rounded-full bg-primary-light border border-primary/20 text-primary mx-auto mb-4 flex items-center justify-center text-2xl shadow-inner animate-bounce"
379
+ style={{ animationDuration: '3s' }}
 
 
 
 
 
 
 
 
 
380
  >
381
 
382
  </div>
383
+ <div className="font-serif text-lg font-bold text-foreground mb-2">
384
+ {locale === "hi" ? "कोई सक्रिय मामला नहीं" : "No active cases"}
385
  </div>
386
+ <p className="text-[14px] text-foreground-muted max-w-sm mx-auto mb-5 leading-relaxed">
387
  {t("empty")}
388
+ </p>
389
  <button
390
  onClick={onStart}
391
+ className="bg-primary text-white border-none rounded-lg px-6 py-2.5 font-bold cursor-pointer hover:bg-primary-hover shadow transition-all duration-200"
 
 
 
 
 
 
 
 
 
 
 
392
  >
393
  {t("createBtn")}
394
  </button>
 
402
 
403
  export default function MissionBoard() {
404
  const locale = useLocale();
405
+ const activeLocale = (locale === "hi" ? "hi" : "en") as "en" | "hi";
406
  const router = useRouter();
407
  const tLanding = useTranslations("landing");
408
  const tBoard = useTranslations("mission.board");
 
418
  const [domainFilter, setDomainFilter] = useState<IssueDomain | "all">("all");
419
  const [search, setSearch] = useState("");
420
 
421
+ // Autopilot Simulator template state
422
+ const [activeTemplate, setActiveTemplate] = useState<TemplateId>("upi");
423
+
424
  async function refresh() {
425
  setLoadingMissions(true);
426
  try {
 
449
  });
450
 
451
  return (
452
+ <div className="w-full min-h-screen bg-background pb-16">
453
+
454
+ {/* ── 1. Hero Section (Full bleed with wide layout grid) ─────���──────────────── */}
455
+ <section className="w-full bg-radial-glow border-b border-border/60 py-12 lg:py-16 relative overflow-hidden grid-bg">
456
+ {/* Glow sphere graphics */}
457
+ <div className="absolute top-0 right-0 w-96 h-96 bg-primary/5 rounded-full blur-3xl pointer-events-none" />
458
+ <div className="absolute bottom-0 left-0 w-80 h-80 bg-amber-500/5 rounded-full blur-3xl pointer-events-none" />
459
+
460
+ <div className="container-wide">
461
+ <div className="grid grid-cols-1 lg:grid-cols-12 gap-10 lg:gap-14 items-center">
462
+
463
+ {/* Left Column: Headline and actions */}
464
+ <div className="lg:col-span-7 flex flex-col items-start text-left">
465
+
466
+ {/* Badge */}
467
+ <div
468
+ className="inline-flex items-center gap-2 px-3 py-1 bg-primary-light border border-primary/20 rounded-full text-[11px] font-bold text-primary uppercase tracking-wider mb-6 animate-pulse-border"
469
+ >
470
+ <Sparkles className="w-3.5 h-3.5 text-amber-500" />
471
+ <span>{tCommon("appName")} · {locale === "hi" ? "फेज 1 ऑटोपायलट" : "Phase 1 Autopilot"}</span>
472
+ </div>
473
 
474
+ {/* Majestic Headline */}
475
+ <h1
476
+ className="font-serif text-4xl md:text-5xl lg:text-[52px] font-bold text-foreground leading-[1.1] tracking-tight mb-4"
477
+ >
478
+ {locale === "hi" ? (
479
+ <>
480
+ अपने अधिकारों के लिए लड़ें — <span className="text-primary underline decoration-amber-500/50 decoration-wavy decoration-2 underline-offset-4">स्वचालित रूप से</span>
481
+ </>
482
+ ) : (
483
+ <>
484
+ Fight for your rights — <span className="text-primary underline decoration-amber-500/50 decoration-wavy decoration-2 underline-offset-4">automatically</span>
485
+ </>
486
+ )}
487
+ </h1>
488
+
489
+ {/* Subheadline */}
490
+ <p
491
+ className="text-base md:text-lg text-foreground-muted leading-relaxed mb-8 max-w-2xl font-medium"
492
+ >
493
+ {tLanding("subheadline")}
494
+ </p>
495
+
496
+ {/* Live Simulator quick template switchers */}
497
+ <div className="w-full mb-8">
498
+ <div className="text-[10px] font-bold text-foreground-muted uppercase tracking-widest mb-3 flex items-center gap-1">
499
+ <Zap className="w-3.5 h-3.5 text-amber-500 fill-amber-500" />
500
+ <span>{locale === "hi" ? "सिम्युलेटर समस्या चुनें" : "Choose issue to test in simulator"}</span>
501
+ </div>
502
+ <div className="flex flex-wrap gap-2">
503
+ <button
504
+ onClick={() => setActiveTemplate("upi")}
505
+ className={`px-3.5 py-1.5 rounded-lg border text-[11px] font-bold transition-all duration-200 cursor-pointer min-h-0 mt-0 ${
506
+ activeTemplate === "upi"
507
+ ? "bg-primary text-white border-primary shadow-sm scale-105"
508
+ : "bg-background text-foreground-muted border-border/80 hover:bg-surface-elevated"
509
+ }`}
510
+ >
511
+ 💸 {locale === "hi" ? "UPI पेमेंट फंसना" : "UPI Payment Failure"}
512
+ </button>
513
+ <button
514
+ onClick={() => setActiveTemplate("ecommerce")}
515
+ className={`px-3.5 py-1.5 rounded-lg border text-[11px] font-bold transition-all duration-200 cursor-pointer min-h-0 mt-0 ${
516
+ activeTemplate === "ecommerce"
517
+ ? "bg-primary text-white border-primary shadow-sm scale-105"
518
+ : "bg-background text-foreground-muted border-border/80 hover:bg-surface-elevated"
519
+ }`}
520
+ >
521
+ 📦 {locale === "hi" ? "ई-कॉमर्स रिफंड" : "E-Commerce Refund"}
522
+ </button>
523
+ <button
524
+ onClick={() => setActiveTemplate("cyber")}
525
+ className={`px-3.5 py-1.5 rounded-lg border text-[11px] font-bold transition-all duration-200 cursor-pointer min-h-0 mt-0 ${
526
+ activeTemplate === "cyber"
527
+ ? "bg-primary text-white border-primary shadow-sm scale-105"
528
+ : "bg-background text-foreground-muted border-border/80 hover:bg-surface-elevated"
529
+ }`}
530
+ >
531
+ 🚨 {locale === "hi" ? "साइबर फ्रॉड (तत्काल)" : "Cyber Fraud (Urgent)"}
532
+ </button>
533
+ </div>
534
+ </div>
535
 
536
+ {/* CTAs */}
537
+ <div className="flex flex-wrap gap-3.5 mb-8">
538
+ <button
539
+ onClick={() => setDialogOpen(true)}
540
+ className="bg-primary text-white border-none rounded-xl px-7 py-3.5 font-bold cursor-pointer transition-all duration-200 hover:bg-primary-hover shadow-lg hover:-translate-y-0.5 text-[15px] animate-pulse-border"
541
+ style={{
542
+ boxShadow: "0 10px 20px -5px rgba(29, 53, 87, 0.25)"
543
+ }}
544
+ >
545
+ {tLanding("ctaStart")}
546
+ </button>
547
+ <Link
548
+ href={`/${locale}/ledger`}
549
+ className="inline-flex items-center justify-center bg-card text-foreground border border-border rounded-xl px-7 py-3.5 font-bold text-[15px] text-decoration-none transition-all duration-200 hover:bg-surface-elevated hover:-translate-y-0.5"
550
+ >
551
+ {tLanding("ctaLedger")}
552
+ </Link>
553
+ </div>
 
 
554
 
555
+ {/* Widescreen Statistics Capsule */}
556
+ <div className="flex flex-wrap items-center gap-6 py-4 px-5 bg-card/60 dark:bg-card/40 border border-border/60 rounded-xl w-full max-w-2xl backdrop-blur-sm">
557
+ <div className="flex items-center gap-3">
558
+ <div className="p-2 rounded-lg bg-emerald-500/10 text-emerald-600 border border-emerald-500/20">
559
+ <TrendingUp className="w-5 h-5" />
560
+ </div>
561
+ <div>
562
+ <div className="text-xl font-bold text-foreground">₹24.8L+</div>
563
+ <div className="text-[10px] font-bold text-foreground-muted uppercase tracking-wider font-sans">
564
+ {locale === "hi" ? "कुल वसूल राशि" : "Funds Recovered"}
565
+ </div>
566
+ </div>
567
+ </div>
568
+
569
+ <div className="h-8 w-px bg-border/60 hidden sm:block" />
570
+
571
+ <div className="flex items-center gap-3">
572
+ <div className="p-2 rounded-lg bg-indigo-500/10 text-indigo-600 border border-indigo-500/20">
573
+ <CheckCircle className="w-5 h-5" />
574
+ </div>
575
+ <div>
576
+ <div className="text-xl font-bold text-foreground">91.4%</div>
577
+ <div className="text-[10px] font-bold text-foreground-muted uppercase tracking-wider font-sans">
578
+ {locale === "hi" ? "सफलता दर" : "Resolution Rate"}
579
+ </div>
580
+ </div>
581
+ </div>
582
+
583
+ <div className="h-8 w-px bg-border/60 hidden sm:block" />
584
+
585
+ <div className="flex items-center gap-3">
586
+ <div className="p-2 rounded-lg bg-amber-500/10 text-amber-600 border border-amber-500/20">
587
+ <Clock className="w-5 h-5" />
588
+ </div>
589
+ <div>
590
+ <div className="text-xl font-bold text-foreground">~14 Days</div>
591
+ <div className="text-[10px] font-bold text-foreground-muted uppercase tracking-wider font-sans">
592
+ {locale === "hi" ? "औसत समय" : "Avg. Resolution"}
593
+ </div>
594
+ </div>
595
+ </div>
596
+ </div>
597
 
598
+ </div>
599
+
600
+ {/* Right Column: Autopilot simulator card */}
601
+ <div className="lg:col-span-5 flex justify-center w-full">
602
+ <div className="w-full max-w-[440px] lg:max-w-full">
603
+ <AutopilotSimulator activeTemplate={activeTemplate} locale={locale} />
604
+ </div>
605
+ </div>
 
 
606
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
607
  </div>
608
  </div>
609
+ </section>
610
+
611
+ {/* ── 2. How it works Section ─────────────────────────────────────────── */}
612
+ <section className="py-14 w-full bg-surface/30 dark:bg-surface-sunken/15 border-b border-border/40">
613
+ <div className="container-wide">
614
+ <div className="text-center max-w-xl mx-auto mb-10">
615
+ <h2 className="font-serif text-2xl md:text-3xl font-bold text-foreground mb-3">
616
+ {locale === "hi" ? "सच्चा स्वायत्त निवारण प्रवाह" : "True Autonomous Legal Autopilot"}
617
+ </h2>
618
+ <p className="text-[14px] text-foreground-muted leading-relaxed">
619
+ {locale === "hi"
620
+ ? "आप केवल समस्या बताएं, कानूनी और शिकायत भेजने की बाकी सारी कानूनी प्रक्रिया कोर्टमित्र खुद संभालता है।"
621
+ : "You describe the grievance. CourtMitra automatically translates, cites statutes, sends notices, and tracks replies."}
622
+ </p>
623
+ </div>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
624
 
625
+ <div className="grid grid-cols-1 md:grid-cols-5 gap-6">
626
+ {[
627
+ { num: "01", t: { en: "Describe Once", hi: "विवरण दर्ज करें" }, d: { en: "Type your grievance in plain language or Hindi.", hi: "अपनी शिकायत साधारण हिंदी ��ा अंग्रेज़ी में लिखें।" } },
628
+ { num: "02", t: { en: "Extract Facts", hi: "तथ्य खोजें" }, d: { en: "AI parses invoices and proof to form verified facts.", hi: "AI बिलों और साक्ष्यों को पढ़कर तथ्य निकालता है।" } },
629
+ { num: "03", t: { en: "Ground in Law", hi: "कानूनी आधार" }, d: { en: "Finds statutory citations in real time from Indian law.", hi: "भारतीय कानून से प्रासंगिक धाराएं और साइटेशन जोड़ता है।" } },
630
+ { num: "04", t: { en: "Send Complaints", hi: "शिकायत प्रेषण" }, d: { en: "Drafts and auto-dispatches formal legal complaints.", hi: "शिकायत का आधिकारिक मसौदा तैयार करके भेजता है।" } },
631
+ { num: "05", t: { en: "Get Resolved", hi: "सफल निवारण" }, d: { en: "Follows up and logs outcomes to the public ledger.", hi: "लगातार फ़ॉलो-अप करता है और रिफंड दिलाता है।" } }
632
+ ].map((step, idx) => (
633
+ <div key={idx} className="bg-card border border-border/60 rounded-xl p-5 relative shadow-sm hover:border-primary/30 transition-all duration-200">
634
+ <div className="text-2xl font-serif font-black text-primary/20 mb-2">{step.num}</div>
635
+ <h3 className="font-serif text-[15px] font-bold text-foreground mb-1.5">{step.t[activeLocale]}</h3>
636
+ <p className="text-[12px] text-foreground-muted leading-relaxed">{step.d[activeLocale]}</p>
637
+ {idx < 4 && (
638
+ <ArrowRight className="w-5 h-5 text-border hidden md:block absolute -right-6 top-1/2 -translate-y-1/2 z-10" />
639
+ )}
640
+ </div>
641
+ ))}
642
+ </div>
643
  </div>
644
+ </section>
645
+
646
+ {/* ── 3. Supported Areas Grid ─────────────────────────────────────────── */}
647
+ <section className="py-14 w-full border-b border-border/40">
648
+ <div className="container-wide">
649
+ <div className="text-center max-w-xl mx-auto mb-10">
650
+ <h2 className="font-serif text-2xl md:text-3xl font-bold text-foreground mb-3">
651
+ {locale === "hi" ? "निवारण के लिए उपलब्ध श्रेणियां" : "Supported Issue Categories"}
652
+ </h2>
653
+ <p className="text-[14px] text-foreground-muted leading-relaxed">
654
+ {locale === "hi"
655
+ ? "इन सभी क्षेत्रों में होने वाली असुविधाओं के लिए आप कोर्टमित्र का उपयोग कर शिकायत दर्ज कर सकते हैं।"
656
+ : "Resolve issues across standard consumer and legal channels using matched AI legal groundings."}
657
+ </p>
658
+ </div>
659
 
660
+ <div className="grid grid-cols-1 sm:grid-cols-2 lg:grid-cols-4 gap-4">
661
+ {Object.keys(DOMAIN_INFO).map((key) => {
662
+ const info = DOMAIN_INFO[key] || { icon: HelpCircle, color: "var(--foreground-muted)", bg: "var(--surface-elevated)" };
663
+ const Icon = info.icon;
664
+ const title = tLanding(`domains.${key}`);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
665
  return (
666
+ <div
667
+ key={key}
668
+ className="flex items-center gap-3.5 bg-card border border-border/60 rounded-xl p-4.5 transition-all duration-200 hover:bg-surface-elevated/40 hover:border-primary/30 shadow-sm"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
669
  >
670
+ <div
671
+ className="p-3 rounded-lg flex items-center justify-center shrink-0"
672
+ style={{ backgroundColor: info.bg, color: info.color }}
673
+ >
674
+ <Icon className="w-5 h-5" />
675
+ </div>
676
+ <div>
677
+ <h3 className="font-serif text-[14px] font-bold text-foreground leading-tight mb-0.5">{title}</h3>
678
+ <span className="text-[10px] font-bold text-foreground-faint uppercase font-sans tracking-wide">
679
+ {locale === "hi" ? "ऑटो-सक्षम" : "Auto-enabled"}
680
+ </span>
681
+ </div>
682
+ </div>
683
  );
684
  })}
685
  </div>
686
  </div>
687
+ </section>
688
+
689
+ {/* ── 4. Dashboard Divider & Mission Board (Expanded layout) ───────────────── */}
690
+ <section id="dashboard" className="py-14 w-full bg-surface-sunken/10 dark:bg-surface-sunken/5">
691
+ <div className="container-wide">
692
+
693
+ <div className="flex flex-col md:flex-row items-start md:items-center justify-between gap-4 mb-8">
694
+ <div>
695
+ <h2 className="font-serif text-2xl font-bold text-foreground">
696
+ {tBoard("heading")}
697
+ {!loadingMissions && (
698
+ <span className="ml-2 px-2 py-0.5 bg-accent text-primary text-[13px] font-bold rounded-md border border-primary/10">
699
+ {missions.length} Case{missions.length === 1 ? "" : "s"}
700
+ </span>
701
+ )}
702
+ </h2>
703
+ <p className="text-[13px] text-foreground-muted mt-1 leading-relaxed">
704
+ {locale === "hi" ? "आपके सक्रिय मामले और उनकी कानूनी स्थितियां।" : "Your ongoing legal autopilot processes and status tracker."}
705
+ </p>
706
+ </div>
707
 
708
+ <button
709
+ onClick={() => setDialogOpen(true)}
710
+ className="bg-primary text-white border-none rounded-lg px-4 py-2 font-bold text-[13px] cursor-pointer hover:bg-primary-hover shadow-sm transition-all duration-200 shrink-0 mt-0 flex items-center gap-1.5"
711
+ >
712
+ <Zap className="w-3.5 h-3.5" />
713
+ <span>+ {tNav("newMission")}</span>
714
+ </button>
 
 
 
 
 
 
 
715
  </div>
 
716
 
717
+ {/* Filters Panel */}
718
+ <div className="flex flex-col md:flex-row gap-4 mb-6">
719
+ <div className="relative flex-1">
720
+ <Search className="w-4 h-4 text-foreground-faint absolute left-3 top-1/2 -translate-y-1/2" />
721
+ <input
722
+ value={search}
723
+ onChange={(e) => setSearch(e.target.value)}
724
+ placeholder={tBoard("searchPlaceholder")}
725
+ className="pl-9 pr-4 py-2.5 w-full text-[13px] rounded-lg border border-border/80 bg-background text-foreground transition-all duration-150 focus:border-primary focus:ring-1 focus:ring-primary/20"
726
+ />
727
+ </div>
728
+
729
+ <div className="flex gap-2 overflow-x-auto pb-1 md:pb-0 scrollbar-none">
730
+ {(["all", ...DOMAINS] as ("all" | IssueDomain)[]).map((d) => {
731
+ const label = d === "all" ? tBoard("filterAll") : tLanding(`domains.${d}`);
732
+ const isActive = domainFilter === d;
733
+ return (
734
+ <button
735
+ key={d}
736
+ onClick={() => setDomainFilter(d)}
737
+ className={`px-4 py-2 rounded-lg text-[12px] font-bold cursor-pointer transition-all duration-150 border whitespace-nowrap min-h-0 mt-0 ${
738
+ isActive
739
+ ? "bg-primary/10 text-primary border-primary"
740
+ : "bg-card text-foreground-muted border-border/80 hover:bg-surface-elevated"
741
+ }`}
742
+ >
743
+ {label}
744
+ </button>
745
+ );
746
+ })}
747
+ </div>
748
  </div>
 
749
 
750
+ {/* Error Alert */}
751
+ {error && (
752
+ <div className="p-3.5 mb-6 rounded-lg bg-danger-light border border-destructive/20 text-danger-fg text-[13px] font-medium font-sans">
753
+ {error}
754
+ </div>
755
+ )}
 
 
 
 
 
 
 
756
 
757
+ {/* Loading States */}
758
+ {loadingMissions && (
759
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
760
+ {[1, 2, 3, 4].map((i) => (
761
+ <div
762
+ key={i}
763
+ className="h-32 bg-card border border-border/60 rounded-xl overflow-hidden relative shadow-sm"
764
+ >
765
+ <div
766
+ style={{
767
+ position: "absolute",
768
+ inset: 0,
769
+ background: "linear-gradient(90deg, transparent, var(--surface-elevated), transparent)",
770
+ animation: "shimmer 1.5s infinite",
771
+ backgroundSize: "200% 100%",
772
+ }}
773
+ />
774
+ </div>
775
+ ))}
776
+ </div>
777
+ )}
778
 
779
+ {/* Empty Filter Matches */}
780
+ {!loadingMissions && filtered.length === 0 && missions.length > 0 && (
781
+ <div className="p-12 text-center rounded-xl bg-card border border-border/60 text-foreground-muted text-[13px]">
782
+ {tBoard("noFilterMatch")}
783
+ </div>
784
+ )}
785
+
786
+ {/* Complete Empty State */}
787
+ {!loadingMissions && missions.length === 0 && (
788
+ <EmptyMissionState onStart={() => setDialogOpen(true)} />
789
+ )}
790
+
791
+ {/* Responsive Cases Grid */}
792
+ {!loadingMissions && filtered.length > 0 && (
793
+ <div className="grid grid-cols-1 md:grid-cols-2 gap-4">
794
+ {filtered.map((m) => (
795
+ <MissionCard key={m.id} mission={m} locale={locale} />
796
+ ))}
797
+ </div>
798
+ )}
799
+
800
+ </div>
801
+ </section>
802
 
803
  {/* ── Create dialog ─────────────────────────────────── */}
804
  <CreateMissionDialog
 
807
  onCreated={handleCreated}
808
  />
809
 
810
+ {/* Shimmer keyframe */}
811
  <style>{`
812
  @keyframes shimmer {
813
  0% { background-position: -200% 0; }
814
  100% { background-position: 200% 0; }
815
  }
816
  `}</style>
817
+
818
  </div>
819
  );
820
  }
821
+
apps/web/src/app/globals.css CHANGED
@@ -1,3 +1,4 @@
 
1
  @import "tailwindcss";
2
  @import "tw-animate-css";
3
  @import "shadcn/tailwind.css";
@@ -9,7 +10,6 @@
9
  ============================================================ */
10
 
11
  /* Google Fonts — Noto Serif (display) + Noto Sans (body, Devanagari) */
12
- @import url("https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Noto+Serif:ital,wght@0,400;0,600;0,700;1,400&display=swap");
13
 
14
  @custom-variant dark (&:is(.dark *));
15
 
@@ -546,3 +546,105 @@ button.btn-small {
546
  position: relative;
547
  overflow: hidden;
548
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ @import url("https://fonts.googleapis.com/css2?family=Noto+Sans:ital,wght@0,300;0,400;0,500;0,600;0,700;1,400&family=Noto+Serif:ital,wght@0,400;0,600;0,700;1,400&display=swap");
2
  @import "tailwindcss";
3
  @import "tw-animate-css";
4
  @import "shadcn/tailwind.css";
 
10
  ============================================================ */
11
 
12
  /* Google Fonts — Noto Serif (display) + Noto Sans (body, Devanagari) */
 
13
 
14
  @custom-variant dark (&:is(.dark *));
15
 
 
546
  position: relative;
547
  overflow: hidden;
548
  }
549
+
550
+ /* ── Redesign Additions: Wide Container & Animations ── */
551
+ .container-wide {
552
+ max-width: 1200px;
553
+ margin: 0 auto;
554
+ padding: 0 20px;
555
+ }
556
+
557
+ @keyframes float {
558
+ 0%, 100% {
559
+ transform: translateY(0px);
560
+ }
561
+ 50% {
562
+ transform: translateY(-8px);
563
+ }
564
+ }
565
+
566
+ @keyframes laserScan {
567
+ 0% {
568
+ top: 0%;
569
+ }
570
+ 50% {
571
+ top: 100%;
572
+ }
573
+ 100% {
574
+ top: 0%;
575
+ }
576
+ }
577
+
578
+ @keyframes blink {
579
+ 50% {
580
+ border-color: transparent;
581
+ }
582
+ }
583
+
584
+ @keyframes pulseBorder {
585
+ 0%, 100% {
586
+ border-color: var(--primary);
587
+ box-shadow: 0 0 0 0px hsl(228 58% 36% / 0.2);
588
+ }
589
+ 50% {
590
+ border-color: var(--primary-ring);
591
+ box-shadow: 0 0 0 4px hsl(228 58% 60% / 0.15);
592
+ }
593
+ }
594
+
595
+ @keyframes pulseGold {
596
+ 0%, 100% {
597
+ border-color: var(--caution);
598
+ box-shadow: 0 0 0 0px hsl(38 92% 44% / 0.2);
599
+ }
600
+ 50% {
601
+ border-color: hsl(38 92% 54%);
602
+ box-shadow: 0 0 0 6px hsl(38 92% 44% / 0.15);
603
+ }
604
+ }
605
+
606
+ .animate-float {
607
+ animation: float 6s ease-in-out infinite;
608
+ }
609
+
610
+ .animate-scan {
611
+ position: absolute;
612
+ left: 0;
613
+ width: 100%;
614
+ height: 2px;
615
+ background: linear-gradient(90deg, transparent, var(--primary), transparent);
616
+ animation: laserScan 3s linear infinite;
617
+ }
618
+
619
+ .animate-pulse-border {
620
+ animation: pulseBorder 3s infinite;
621
+ }
622
+
623
+ .animate-pulse-gold {
624
+ animation: pulseGold 3.5s infinite;
625
+ }
626
+
627
+ .typing-cursor {
628
+ border-right: 2px solid var(--foreground);
629
+ animation: blink 0.75s step-end infinite;
630
+ }
631
+
632
+ .bg-radial-glow {
633
+ background-image:
634
+ radial-gradient(circle at 80% 20%, hsl(228 58% 36% / 0.08) 0%, transparent 60%),
635
+ radial-gradient(circle at 20% 80%, hsl(38 92% 44% / 0.04) 0%, transparent 50%);
636
+ }
637
+
638
+ .bg-radial-glow-dark {
639
+ background-image:
640
+ radial-gradient(circle at 80% 20%, hsl(228 60% 64% / 0.06) 0%, transparent 60%),
641
+ radial-gradient(circle at 20% 80%, hsl(38 92% 58% / 0.03) 0%, transparent 50%);
642
+ }
643
+
644
+ .grid-bg {
645
+ background-size: 30px 30px;
646
+ background-image:
647
+ linear-gradient(to right, color-mix(in srgb, var(--border) 25%, transparent) 1px, transparent 1px),
648
+ linear-gradient(to bottom, color-mix(in srgb, var(--border) 25%, transparent) 1px, transparent 1px);
649
+ }
650
+
apps/web/src/components/app/AutopilotSimulator.tsx ADDED
@@ -0,0 +1,474 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "use client";
2
+
3
+ import { useState, useEffect, useRef } from "react";
4
+ import {
5
+ CheckCircle,
6
+ Check,
7
+ Scale,
8
+ Send,
9
+ TrendingUp,
10
+ Clock,
11
+ Sparkles,
12
+ ChevronRight,
13
+ Database,
14
+ Search
15
+ } from "lucide-react";
16
+
17
+ export type TemplateId = "upi" | "ecommerce" | "cyber";
18
+
19
+ interface SimulatorProps {
20
+ activeTemplate: TemplateId;
21
+ locale: string;
22
+ }
23
+
24
+ // ────────────────────────────────────────────────────────────────
25
+ // Data cases for Simulator (English + Hindi)
26
+ // ────────────────────────────────────────────────────────────────
27
+
28
+ const CASES_DATA = {
29
+ en: {
30
+ upi: {
31
+ input: "Tried to send ₹5,000 to my father via GPay. The money was debited from my HDFC bank account, but it says transaction failed. Bank is not responding.",
32
+ opposing: "HDFC Bank & GPay",
33
+ amount: "₹5,000",
34
+ relief: "Refund + TAT Compensation",
35
+ routeTitle: "NPCI / RBI Ombudsman Route",
36
+ routeBasis: "RBI Circular DPSS.CO.PD No. 629 (TAT TAT Compensation)",
37
+ routeSteps: ["File NPCI Dispute", "Escalate to RBI CMS Ombudsman"],
38
+ actionDest: "HDFC Grievance Desk",
39
+ actionSubj: "Failed UPI Transaction Tat Breach",
40
+ actionBody: "Notice regarding failed transaction of ₹5,000 debited from Account No. ******123. Under RBI guidelines, compensation of ₹100 per day is payable for TAT delay exceeding T+1 days...",
41
+ outcomeRecovery: "₹5,600",
42
+ outcomeDetail: "HDFC credited the refund of ₹5,000. Additionally, ₹600 compensation was paid for the 6-day delay. Status: Resolved."
43
+ },
44
+ ecommerce: {
45
+ input: "I ordered a phone from Amazon for ₹32,000. The screen was shattered when opened. Amazon refuses return, saying electronics return policy is expired.",
46
+ opposing: "Amazon India Retail",
47
+ amount: "₹32,000",
48
+ relief: "Replacement or Full Refund",
49
+ routeTitle: "National Consumer Commission",
50
+ routeBasis: "Consumer Protection Act, 2019 — Section 35 (Defective Goods)",
51
+ routeSteps: ["NCH Conciliation Docket", "Legal Notice under E-Commerce Rules"],
52
+ actionDest: "Amazon India Grievance Officer",
53
+ actionSubj: "Legal Notice — Defective mobile phone delivery",
54
+ actionBody: "Notice is hereby given for the delivery of defective OnePlus phone (Order #403-12891) valued at ₹32,000. Refusal to replace damaged goods constitutes deficiency in service under Section 2(47)...",
55
+ outcomeRecovery: "₹32,000",
56
+ outcomeDetail: "Amazon initiated a full refund of ₹32,000 after NCH issued a conciliation notice. Status: Resolved."
57
+ },
58
+ cyber: {
59
+ input: "Received a fake electricity bill SMS. I clicked the link and entered my banking details. Within 5 minutes, ₹85,000 was debited from my credit card.",
60
+ opposing: "Fraudulent Recipient Account",
61
+ amount: "₹85,000",
62
+ relief: "Account Freeze & Fund Recovery",
63
+ routeTitle: "National Cyber Crime Cell",
64
+ routeBasis: "IT Act, 2000 — Section 66D & RBI Zero Liability guidelines",
65
+ routeSteps: ["Report Cyber Crime Portal", "Aadhaar/UPI trace & Bank Cyber Cell"],
66
+ actionDest: "National Cyber Crime Portal & Bank Fraud Desk",
67
+ actionSubj: "Urgent Cyber Fraud Report — Phishing transaction of ₹85,000",
68
+ actionBody: "Unauthorized debit of ₹85,000 from credit card ******567. Recipient bank account is ICICI Bank Account ******492. Requesting immediate lien under RBI Customer Protection regulations...",
69
+ outcomeRecovery: "₹85,000",
70
+ outcomeDetail: "National Cyber Cell successfully froze the recipient account before funds were withdrawn. Full credit returned. Status: Resolved."
71
+ }
72
+ },
73
+ hi: {
74
+ upi: {
75
+ input: "पिताजी को GPay से ₹5,000 भेजने की कोशिश की। HDFC बैंक खाते से पैसे कट गए पर ट्रांजैक्शन फेल दिखा रहा है। बैंक कोई जवाब नहीं दे रहा है।",
76
+ opposing: "HDFC बैंक और GPay",
77
+ amount: "₹5,000",
78
+ relief: "रिफंड + समयसीमा (TAT) मुआवजा",
79
+ routeTitle: "NPCI / RBI लोकपाल मार्ग",
80
+ routeBasis: "RBI परिपत्र DPSS.CO.PD No. 629 (TAT मुआवजा)",
81
+ routeSteps: ["NPCI विवाद दर्ज करें", "RBI CMS लोकपाल को भेजें"],
82
+ actionDest: "HDFC शिकायत डेस्क",
83
+ actionSubj: "UPI विफलता TAT उल्लंघन शिकायत",
84
+ actionBody: "खाता संख्या ******123 से कटे ₹5,000 के फेल ट्रांजैक्शन के संबंध में। RBI न���यमों के अनुसार, T+1 दिन से अधिक की देरी के लिए ₹100 प्रतिदिन का मुआवजा देय है...",
85
+ outcomeRecovery: "₹5,600",
86
+ outcomeDetail: "HDFC ने ₹5,000 का रिफंड वापस किया। साथ ही 6 दिनों की देरी के लिए ₹600 का मुआवजा दिया। स्थिति: हल हो गया।"
87
+ },
88
+ ecommerce: {
89
+ input: "अमेज़न से ₹32,000 का फोन मंगवाया। खोलने पर स्क्रीन टूटी मिली। अमेज़न वापस लेने से मना कर रहा है, कह रहा है इलेक्ट्रॉनिक रिटर्न पॉलिसी खत्म हो गई है।",
90
+ opposing: "अमेज़न इंडिया रिटेल",
91
+ amount: "₹32,000",
92
+ relief: "बदलाव या पूरा रिफंड",
93
+ routeTitle: "राष्ट्रीय उपभोक्ता आयोग",
94
+ routeBasis: "उपभोक्ता संरक्षण अधिनियम, 2019 — धारा 35 (दोषपूर्ण वस्तुएं)",
95
+ routeSteps: ["NCH मध्यस्थता डॉकेट", "ई-कॉमर्स नियमों के तहत कानूनी नोटिस"],
96
+ actionDest: "अमेज़न इंडिया शिकायत अधिकारी",
97
+ actionSubj: "कानूनी नोटिस — दोषपूर्ण मोबाइल फोन डिलीवरी",
98
+ actionBody: "₹32,000 मूल्य के टूटे फोन (ऑर्डर #403-12891) की डिलीवरी के संबंध में। दोषपूर्ण सामान को बदलने से इनकार करना उपभोक्ता संरक्षण अधिनियम 2019 के तहत सेवा में कमी है...",
99
+ outcomeRecovery: "₹32,000",
100
+ outcomeDetail: "NCH द्वारा मध्यस्थता नोटिस जारी करने के बाद अमेज़न ने ₹32,000 का पूरा रिफंड जारी कर दिया। स्थिति: हल हो गया।"
101
+ },
102
+ cyber: {
103
+ input: "बिजली बिल का फर्जी SMS मिला। लिंक पर क्लिक कर बैंक विवरण डाला। 5 मिनट में मेरे क्रेडिट कार्ड से ₹85,000 कट गए।",
104
+ opposing: "धोखाधड़ी वाला प्राप्तकर्ता खाता",
105
+ amount: "₹85,000",
106
+ relief: "खाता फ़्रीज़ और राशि की वसूली",
107
+ routeTitle: "राष्ट्रीय साइबर अपराध सेल",
108
+ routeBasis: "IT अधिनियम, 2000 — धारा 66D और RBI शून्य दायित्व नियम",
109
+ routeSteps: ["साइबर अपराध पोर्टल रिपोर्ट", "आधार/UPI ट्रेस और बैंक साइबर सेल"],
110
+ actionDest: "राष्ट्रीय साइबर अपराध सेल और बैंक फ्रॉड डेस्क",
111
+ actionSubj: "आपातकालीन साइबर धोखाधड़ी रिपोर्ट — ₹85,000 का फिशिंग ट्रांजैक्शन",
112
+ actionBody: "क्रेडिट कार्ड ******567 से ₹85,000 का अनधिकृत डेबिट। प्राप्तकर्ता खाता ICICI बैंक खाता ******492 है। RBI नियमों के तहत तुरंत खाता फ्रीज किया जाए...",
113
+ outcomeRecovery: "₹85,000",
114
+ outcomeDetail: "साइबर सेल ने पैसे निकाले जाने से पहले ही प्राप्तकर्ता का खाता फ्रीज कर दिया। पूरा रिफंड वापस मिला। स्थिति: हल हो गया।"
115
+ }
116
+ }
117
+ };
118
+
119
+ const STAGES = [
120
+ { id: 1, label: { en: "1. Intake", hi: "1. शिकायत दर्ज" } },
121
+ { id: 2, label: { en: "2. Facts", hi: "2. तथ्य विश्लेषण" } },
122
+ { id: 3, label: { en: "3. Law Route", hi: "3. कानूनी मार्ग" } },
123
+ { id: 4, label: { en: "4. Send Action", hi: "4. शिकायत प्रेषण" } },
124
+ { id: 5, label: { en: "5. Resolution", hi: "5. समाधान" } }
125
+ ];
126
+
127
+ export function AutopilotSimulator({ activeTemplate, locale }: SimulatorProps) {
128
+ const activeLocale = (locale === "hi" ? "hi" : "en") as "en" | "hi";
129
+ const caseData = CASES_DATA[activeLocale][activeTemplate] || CASES_DATA.en.upi;
130
+
131
+ const [currentStage, setCurrentStage] = useState(1);
132
+ const [typedText, setTypedText] = useState("");
133
+ const [typingIndex, setTypingIndex] = useState(0);
134
+ const [isTyping, setIsTyping] = useState(false);
135
+ const [scanComplete, setScanComplete] = useState(false);
136
+
137
+ // Timer for cycling through stages
138
+ const cycleTimeoutRef = useRef<NodeJS.Timeout | null>(null);
139
+
140
+ // Restart simulator when activeTemplate changes
141
+ useEffect(() => {
142
+ if (cycleTimeoutRef.current) {
143
+ clearTimeout(cycleTimeoutRef.current);
144
+ }
145
+ setCurrentStage(1);
146
+ setTypedText("");
147
+ setTypingIndex(0);
148
+ setIsTyping(true);
149
+ setScanComplete(false);
150
+ }, [activeTemplate]);
151
+
152
+ // Handle stage transitions
153
+ useEffect(() => {
154
+ if (cycleTimeoutRef.current) {
155
+ clearTimeout(cycleTimeoutRef.current);
156
+ }
157
+
158
+ if (currentStage === 1) {
159
+ // Typing phase
160
+ if (typingIndex < caseData.input.length) {
161
+ const timer = setTimeout(() => {
162
+ setTypedText((prev) => prev + caseData.input[typingIndex]);
163
+ setTypingIndex((prev) => prev + 1);
164
+ }, 15);
165
+ return () => clearTimeout(timer);
166
+ } else {
167
+ setIsTyping(false);
168
+ // Pause, then go to Stage 2
169
+ cycleTimeoutRef.current = setTimeout(() => {
170
+ setCurrentStage(2);
171
+ setScanComplete(false);
172
+ }, 1500);
173
+ }
174
+ } else if (currentStage === 2) {
175
+ // Scanning phase
176
+ const timer = setTimeout(() => {
177
+ setScanComplete(true);
178
+ }, 2000);
179
+
180
+ cycleTimeoutRef.current = setTimeout(() => {
181
+ setCurrentStage(3);
182
+ }, 4000);
183
+ return () => clearTimeout(timer);
184
+ } else if (currentStage === 3) {
185
+ // Legal Citation phase
186
+ cycleTimeoutRef.current = setTimeout(() => {
187
+ setCurrentStage(4);
188
+ }, 4000);
189
+ } else if (currentStage === 4) {
190
+ // Outgoing Action phase
191
+ cycleTimeoutRef.current = setTimeout(() => {
192
+ setCurrentStage(5);
193
+ }, 4500);
194
+ } else if (currentStage === 5) {
195
+ // Outcomes phase
196
+ cycleTimeoutRef.current = setTimeout(() => {
197
+ setCurrentStage(1);
198
+ setTypedText("");
199
+ setTypingIndex(0);
200
+ setIsTyping(true);
201
+ setScanComplete(false);
202
+ }, 6000);
203
+ }
204
+
205
+ return () => {
206
+ if (cycleTimeoutRef.current) {
207
+ clearTimeout(cycleTimeoutRef.current);
208
+ }
209
+ };
210
+ }, [currentStage, typingIndex, caseData.input]);
211
+
212
+ const handleStageClick = (stageId: number) => {
213
+ if (cycleTimeoutRef.current) {
214
+ clearTimeout(cycleTimeoutRef.current);
215
+ }
216
+
217
+ setCurrentStage(stageId);
218
+ if (stageId === 1) {
219
+ setTypedText(caseData.input);
220
+ setTypingIndex(caseData.input.length);
221
+ setIsTyping(false);
222
+ } else if (stageId === 2) {
223
+ setScanComplete(true);
224
+ }
225
+ };
226
+
227
+ return (
228
+ <div
229
+ className="relative rounded-2xl border border-border/80 bg-card/90 dark:bg-card/75 backdrop-blur-md p-6 shadow-xl w-full h-[400px] flex flex-col justify-between overflow-hidden animate-float transition-all duration-300 hover:border-primary/50"
230
+ style={{
231
+ boxShadow: "0 20px 40px -15px rgba(29, 53, 87, 0.12)"
232
+ }}
233
+ >
234
+ {/* Decorative Gradient Background inside card */}
235
+ <div className="absolute inset-0 bg-radial-glow opacity-30 pointer-events-none" />
236
+
237
+ {/* Card Header */}
238
+ <div className="relative z-10 flex items-center justify-between border-b border-border/60 pb-3">
239
+ <div className="flex items-center gap-2">
240
+ <div className="h-2.5 w-2.5 rounded-full bg-emerald-500 animate-pulse" />
241
+ <span className="text-[11px] font-bold text-foreground-muted uppercase tracking-wider font-sans">
242
+ {activeLocale === "hi" ? "स्वचालित सिम्युलेटर" : "Autopilot Simulator"}
243
+ </span>
244
+ </div>
245
+ <div className="flex items-center gap-1.5 px-2 py-0.5 bg-accent/80 rounded-md border border-border/50">
246
+ <Database className="w-3.5 h-3.5 text-primary" />
247
+ <span className="text-[10px] font-semibold text-primary/80 font-sans">
248
+ {activeLocale === "hi" ? "आधिकारिक डेटा" : "Govt APIs Linked"}
249
+ </span>
250
+ </div>
251
+ </div>
252
+
253
+ {/* Progress indicators */}
254
+ <div className="relative z-10 grid grid-cols-5 gap-1 my-3.5">
255
+ {STAGES.map((s) => {
256
+ const isActive = currentStage === s.id;
257
+ const isCompleted = currentStage > s.id;
258
+ return (
259
+ <button
260
+ key={s.id}
261
+ onClick={() => handleStageClick(s.id)}
262
+ className={`text-center py-1.5 px-1 rounded-lg border text-[9px] font-bold tracking-tight font-sans cursor-pointer transition-all duration-200 uppercase ${
263
+ isActive
264
+ ? "bg-primary text-white border-primary shadow-sm scale-105"
265
+ : isCompleted
266
+ ? "bg-emerald-500/10 text-emerald-600 border-emerald-500/30"
267
+ : "bg-surface-elevated text-foreground-muted border-border/80 hover:bg-surface-sunken"
268
+ }`}
269
+ >
270
+ <div className="flex items-center justify-center gap-0.5">
271
+ {isCompleted && <Check className="w-2.5 h-2.5" />}
272
+ {s.label[activeLocale]}
273
+ </div>
274
+ </button>
275
+ );
276
+ })}
277
+ </div>
278
+
279
+ {/* Simulator Content Body */}
280
+ <div className="relative z-10 flex-1 flex flex-col justify-center rounded-xl bg-background/90 dark:bg-background/80 border border-border/40 p-4 overflow-hidden min-h-0">
281
+
282
+ {/* STAGE 1: INTAKE */}
283
+ {currentStage === 1 && (
284
+ <div className="flex flex-col h-full justify-between">
285
+ <div className="flex items-center gap-1.5 text-primary mb-2">
286
+ <Sparkles className="w-4 h-4 text-amber-500 animate-spin" style={{ animationDuration: '3s' }} />
287
+ <span className="text-[12px] font-bold uppercase tracking-wider font-sans">
288
+ {activeLocale === "hi" ? "चरण 1: शिकायत विवरण लिखना" : "Stage 1: Grievance Intake"}
289
+ </span>
290
+ </div>
291
+ <div className="flex-1 text-[13px] leading-relaxed text-foreground font-medium p-2 bg-surface-elevated/40 rounded-lg border border-border/20 overflow-y-auto italic max-h-[170px] select-none">
292
+ "{typedText}"
293
+ {isTyping && <span className="typing-cursor ml-0.5"></span>}
294
+ </div>
295
+ <div className="text-[10px] text-foreground-muted mt-2 text-right font-sans font-medium">
296
+ {isTyping
297
+ ? (activeLocale === "hi" ? "उपयोगकर्ता समस्या दर्ज कर रहा है..." : "User writing problem...")
298
+ : (activeLocale === "hi" ? "विवरण पूर्ण! विश्लेषण के लिए तैयार।" : "Intake complete! Ready to analyze.")
299
+ }
300
+ </div>
301
+ </div>
302
+ )}
303
+
304
+ {/* STAGE 2: FACTS */}
305
+ {currentStage === 2 && (
306
+ <div className="flex flex-col h-full justify-between relative">
307
+ {!scanComplete && <div className="animate-scan" />}
308
+ <div className="flex items-center justify-between mb-2">
309
+ <div className="flex items-center gap-1.5 text-primary">
310
+ <Search className="w-4 h-4 text-primary animate-pulse" />
311
+ <span className="text-[12px] font-bold uppercase tracking-wider font-sans">
312
+ {activeLocale === "hi" ? "चरण 2: AI तथ्य निष्कर्षण" : "Stage 2: Entity & Fact Extraction"}
313
+ </span>
314
+ </div>
315
+ {!scanComplete && (
316
+ <span className="text-[10px] font-bold text-amber-500 bg-amber-500/10 px-2 py-0.5 rounded-full font-sans animate-pulse">
317
+ {activeLocale === "hi" ? "स्कैनिंग..." : "Scanning Proof..."}
318
+ </span>
319
+ )}
320
+ </div>
321
+ <div className="flex-1 flex flex-col gap-2 mt-1">
322
+ <div className="grid grid-cols-3 gap-2">
323
+ <div className={`p-2 rounded-lg border text-center transition-all duration-300 ${scanComplete ? 'bg-primary-light border-primary/20 scale-100' : 'bg-surface-elevated/40 border-border/20 opacity-40 scale-95'}`}>
324
+ <div className="text-[9px] font-bold text-foreground-muted font-sans uppercase">
325
+ {activeLocale === "hi" ? "विरोधी पक्ष" : "Opponent"}
326
+ </div>
327
+ <div className="text-[11px] font-bold text-primary truncate mt-0.5">{caseData.opposing}</div>
328
+ </div>
329
+ <div className={`p-2 rounded-lg border text-center transition-all duration-300 ${scanComplete ? 'bg-primary-light border-primary/20 scale-100' : 'bg-surface-elevated/40 border-border/20 opacity-40 scale-95'}`}>
330
+ <div className="text-[9px] font-bold text-foreground-muted font-sans uppercase">
331
+ {activeLocale === "hi" ? "विवादित राशि" : "Value"}
332
+ </div>
333
+ <div className="text-[11px] font-bold text-emerald-600 truncate mt-0.5">{caseData.amount}</div>
334
+ </div>
335
+ <div className={`p-2 rounded-lg border text-center transition-all duration-300 ${scanComplete ? 'bg-primary-light border-primary/20 scale-100' : 'bg-surface-elevated/40 border-border/20 opacity-40 scale-95'}`}>
336
+ <div className="text-[9px] font-bold text-foreground-muted font-sans uppercase">
337
+ {activeLocale === "hi" ? "अपेक्षित राहत" : "Requested Relief"}
338
+ </div>
339
+ <div className="text-[10px] font-bold text-amber-600 truncate mt-0.5" title={caseData.relief}>{caseData.relief}</div>
340
+ </div>
341
+ </div>
342
+ <div className={`p-2 rounded-lg border bg-surface-elevated/20 transition-all duration-500 flex-1 flex flex-col justify-center ${scanComplete ? 'opacity-100' : 'opacity-0'}`}>
343
+ <div className="text-[10px] font-bold text-foreground-muted font-sans mb-1 uppercase">
344
+ {activeLocale === "hi" ? "सत्यापित तथ्य ढांचा" : "Verified Claims Framework"}
345
+ </div>
346
+ <p className="text-[11px] leading-relaxed text-foreground font-medium">
347
+ {activeLocale === "hi"
348
+ ? `तथ्य: शिकायतकर्ता ने ${caseData.opposing} से ${caseData.amount} मूल्य के लेन-देन में नुकसान दर्ज किया।`
349
+ : `Claimant reports financial loss of ${caseData.amount} from ${caseData.opposing}. Proof verified.`
350
+ }
351
+ </p>
352
+ </div>
353
+ </div>
354
+ </div>
355
+ )}
356
+
357
+ {/* STAGE 3: LAW ROUTE */}
358
+ {currentStage === 3 && (
359
+ <div className="flex flex-col h-full justify-between">
360
+ <div className="flex items-center gap-1.5 text-primary mb-2">
361
+ <Scale className="w-4 h-4 text-indigo-600" />
362
+ <span className="text-[12px] font-bold uppercase tracking-wider font-sans">
363
+ {activeLocale === "hi" ? "चरण 3: कानूनी खोज और मार्ग" : "Stage 3: Grounded Legal Citations"}
364
+ </span>
365
+ </div>
366
+ <div className="flex-1 flex flex-col gap-2.5">
367
+ <div className="p-2.5 rounded-lg border border-primary/30 bg-primary-light flex items-center justify-between">
368
+ <div>
369
+ <div className="text-[10px] font-bold text-primary font-sans uppercase tracking-wider">
370
+ {activeLocale === "hi" ? "चुना गया फोरम" : "Matched Jurisdiction"}
371
+ </div>
372
+ <div className="text-[12px] font-bold text-foreground mt-0.5">{caseData.routeTitle}</div>
373
+ </div>
374
+ <div className="text-right">
375
+ <span className="px-2 py-0.5 bg-emerald-500/10 text-emerald-600 text-[10px] font-bold rounded-full font-sans">
376
+ 95% Match
377
+ </span>
378
+ </div>
379
+ </div>
380
+ <div className="p-2.5 rounded-lg border border-border/80 bg-surface-elevated/20 flex-1">
381
+ <div className="text-[10px] font-bold text-foreground-muted font-sans uppercase mb-1">
382
+ {activeLocale === "hi" ? "कानूनी आधार (संविधि साइट)" : "Statute / Authority Citation"}
383
+ </div>
384
+ <div className="text-[11px] font-bold text-indigo-700 dark:text-indigo-400 font-serif leading-tight">
385
+ {caseData.routeBasis}
386
+ </div>
387
+ <div className="mt-2 flex flex-col gap-1">
388
+ {caseData.routeSteps.map((step, idx) => (
389
+ <div key={idx} className="flex items-center gap-1.5 text-[10px] font-semibold text-foreground-muted font-sans">
390
+ <ChevronRight className="w-3.5 h-3.5 text-amber-500" />
391
+ <span>{step}</span>
392
+ </div>
393
+ ))}
394
+ </div>
395
+ </div>
396
+ </div>
397
+ </div>
398
+ )}
399
+
400
+ {/* STAGE 4: ACTION */}
401
+ {currentStage === 4 && (
402
+ <div className="flex flex-col h-full justify-between">
403
+ <div className="flex items-center justify-between mb-2">
404
+ <div className="flex items-center gap-1.5 text-primary">
405
+ <Send className="w-4 h-4 text-emerald-500 animate-bounce" />
406
+ <span className="text-[12px] font-bold uppercase tracking-wider font-sans">
407
+ {activeLocale === "hi" ? "चरण 4: नोटिस तैयार व प्रेषण" : "Stage 4: Automated Dispatch"}
408
+ </span>
409
+ </div>
410
+ <span className="text-[10px] font-bold text-emerald-600 bg-emerald-500/10 px-2 py-0.5 rounded-full font-sans animate-pulse">
411
+ {activeLocale === "hi" ? "भेजा जा रहा है..." : "Sending..."}
412
+ </span>
413
+ </div>
414
+ <div className="flex-1 rounded-lg border border-border/60 bg-surface-elevated/10 p-2.5 flex flex-col justify-between font-mono text-[9px] leading-relaxed max-h-[160px] overflow-hidden select-none">
415
+ <div>
416
+ <span className="text-foreground-muted font-sans font-bold">To: </span>
417
+ <span className="font-bold text-foreground">{caseData.actionDest}</span>
418
+ </div>
419
+ <div>
420
+ <span className="text-foreground-muted font-sans font-bold">Sub: </span>
421
+ <span className="font-bold text-foreground">{caseData.actionSubj}</span>
422
+ </div>
423
+ <div className="border-t border-border/40 mt-1 pt-1 text-foreground-muted overflow-hidden max-h-[85px] leading-normal font-sans italic">
424
+ "{caseData.actionBody}"
425
+ </div>
426
+ </div>
427
+ </div>
428
+ )}
429
+
430
+ {/* STAGE 5: OUTCOME */}
431
+ {currentStage === 5 && (
432
+ <div className="flex flex-col h-full justify-between items-center text-center p-1">
433
+ <div className="flex items-center justify-center h-11 w-11 rounded-full bg-emerald-100 dark:bg-emerald-900/30 text-emerald-600 mb-2 border border-emerald-300/30 shadow-inner scale-110">
434
+ <CheckCircle className="w-6 h-6 animate-bounce" />
435
+ </div>
436
+ <div>
437
+ <h4 className="text-[14px] font-bold text-foreground font-serif">
438
+ {activeLocale === "hi" ? "शिकायत का सफल निवारण!" : "Grievance Successfully Resolved!"}
439
+ </h4>
440
+ <div className="flex justify-center items-center gap-2 mt-2">
441
+ <div className="flex items-center gap-1 px-2.5 py-1 bg-emerald-500/15 text-emerald-600 font-bold rounded-lg border border-emerald-500/20 text-[12px] font-sans">
442
+ <TrendingUp className="w-3.5 h-3.5" />
443
+ <span>{activeLocale === "hi" ? `वसूली: ${caseData.outcomeRecovery}` : `Recovered: ${caseData.outcomeRecovery}`}</span>
444
+ </div>
445
+ <div className="flex items-center gap-1 px-2 py-1 bg-primary/10 text-primary font-bold rounded-lg border border-primary/20 text-[11px] font-sans">
446
+ <Clock className="w-3 h-3" />
447
+ <span>{activeLocale === "hi" ? "समय: ~8 दिन" : "Time: ~8 Days"}</span>
448
+ </div>
449
+ </div>
450
+ </div>
451
+ <p className="text-[11px] leading-relaxed text-foreground-muted font-medium bg-emerald-500/5 p-2 rounded-lg border border-emerald-500/10 mt-2 font-sans">
452
+ {caseData.outcomeDetail}
453
+ </p>
454
+ </div>
455
+ )}
456
+
457
+ </div>
458
+
459
+ {/* Simulator Footer */}
460
+ <div className="relative z-10 flex items-center justify-between border-t border-border/50 pt-2 text-[10px] text-foreground-muted font-sans font-semibold">
461
+ <span>{activeLocale === "hi" ? "चक्र: स्वचालित" : "Cycle Mode: Autopilot"}</span>
462
+ <button
463
+ onClick={() => {
464
+ if (cycleTimeoutRef.current) clearTimeout(cycleTimeoutRef.current);
465
+ setCurrentStage((prev) => (prev % 5) + 1);
466
+ }}
467
+ className="mt-0 text-[10px] text-primary hover:text-primary-hover font-bold flex items-center gap-0.5 hover:underline bg-transparent p-0 min-h-0 cursor-pointer"
468
+ >
469
+ {activeLocale === "hi" ? "अगला चरण →" : "Next Step →"}
470
+ </button>
471
+ </div>
472
+ </div>
473
+ );
474
+ }