@utopia-studio-design/design-system-cli 0.6.1 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +28 -10
- package/bin/utopia-ds-mcp.mjs +6 -2
- package/bin/utopia-ds.mjs +94 -21
- package/data/docs/arabic-friendly.md +19 -2
- package/data/docs/billing-setup.md +80 -0
- package/data/docs/cer-003-032-033-round-8-repair.md +41 -0
- package/data/docs/cer-007-checkout.md +51 -0
- package/data/docs/cer-008-011-qa-repair.md +64 -0
- package/data/docs/cer-016-023-round-6-repair.md +92 -0
- package/data/docs/cer-024-031-round-7-repair.md +51 -0
- package/data/docs/cer-033-035-036-round-12-repair.md +37 -0
- package/data/docs/cer-035-037-round-10-repair.md +34 -0
- package/data/docs/charts.md +34 -3
- package/data/docs/chat-service-methodology.md +181 -0
- package/data/docs/code-block.md +20 -0
- package/data/docs/creative-production.md +149 -0
- package/data/docs/designer-agent-backend-contract.md +552 -0
- package/data/docs/email-resend.md +29 -0
- package/data/docs/foundations.md +46 -8
- package/data/docs/guide.md +9 -9
- package/data/docs/handover-billing-aiden.md +132 -0
- package/data/docs/logo-maker-methodology.md +109 -0
- package/data/docs/presentation-asset-repository.md +53 -0
- package/data/docs/product-architecture.md +42 -0
- package/data/docs/quick-start-ai.md +4 -4
- package/data/docs/shadcn-conversion.md +1 -1
- package/data/docs/sidebar-placement.md +56 -0
- package/data/docs/theme-authoring.md +6 -3
- package/data/manifests/catalog.json +42 -46
- package/data/manifests/components.json +317 -66
- package/data/manifests/logo-skills.json +174 -0
- package/data/manifests/motion-profiles.json +2 -2
- package/data/manifests/patterns.json +201 -7
- package/data/manifests/presentation-assets.schema.json +44 -0
- package/data/manifests/templates.json +87 -1
- package/data/manifests/theme-dextrum.json +7 -7
- package/data/manifests/theme-prism-mono.json +19 -0
- package/data/manifests/theme-utopia-cloudblur.json +135 -0
- package/data/manifests/theme-utopia-default.json +31 -31
- package/data/manifests/theme-vyapti.json +17 -1
- package/data/manifests/theme-y2k-pop.json +18 -0
- package/data/manifests/themes.json +285 -57
- package/data/templates/analytics-dashboard/main.tsx +14 -1
- package/data/templates/calendar-application/main.tsx +14 -1
- package/data/templates/chat-workspace/README.md +12 -0
- package/data/templates/chat-workspace/index.html +11 -0
- package/data/templates/chat-workspace/main.tsx +97 -0
- package/data/templates/chat-workspace/styles.css +19 -0
- package/data/templates/chat-workspace/template.manifest.json +13 -0
- package/data/templates/composition-registry-lab/main.tsx +12 -1
- package/data/templates/dashboard-composer/main.tsx +14 -1
- package/data/templates/database-workspace/main.tsx +14 -1
- package/data/templates/interaction-lab/main.tsx +12 -1
- package/data/templates/quantum-verification-story/README.md +12 -0
- package/data/templates/quantum-verification-story/components.json +21 -0
- package/data/templates/quantum-verification-story/eslint.config.mjs +13 -0
- package/data/templates/quantum-verification-story/next-env.d.ts +7 -0
- package/data/templates/quantum-verification-story/next.config.mjs +11 -0
- package/data/templates/quantum-verification-story/package-lock.json +7535 -0
- package/data/templates/quantum-verification-story/package.json +46 -0
- package/data/templates/quantum-verification-story/postcss.config.js +6 -0
- package/data/templates/quantum-verification-story/src/app/assessment/page.tsx +138 -0
- package/data/templates/quantum-verification-story/src/app/ceramic-theme.css +48 -0
- package/data/templates/quantum-verification-story/src/app/deployment/page.tsx +178 -0
- package/data/templates/quantum-verification-story/src/app/fonts/IBMPlexSansArabic-Bold.ttf +0 -0
- package/data/templates/quantum-verification-story/src/app/fonts/IBMPlexSansArabic-Medium.ttf +0 -0
- package/data/templates/quantum-verification-story/src/app/fonts/IBMPlexSansArabic-Regular.ttf +0 -0
- package/data/templates/quantum-verification-story/src/app/fonts/ReadexPro-Variable.ttf +0 -0
- package/data/templates/quantum-verification-story/src/app/fonts/TWKLausanne-350.ttf +0 -0
- package/data/templates/quantum-verification-story/src/app/fonts/TWKLausanne-500.ttf +0 -0
- package/data/templates/quantum-verification-story/src/app/fonts/TWKLausanne-700.ttf +0 -0
- package/data/templates/quantum-verification-story/src/app/globals.css +175 -0
- package/data/templates/quantum-verification-story/src/app/layout.tsx +45 -0
- package/data/templates/quantum-verification-story/src/app/not-found.tsx +39 -0
- package/data/templates/quantum-verification-story/src/app/page.tsx +24 -0
- package/data/templates/quantum-verification-story/src/app/products/page.tsx +132 -0
- package/data/templates/quantum-verification-story/src/app/utopia-default.css +312 -0
- package/data/templates/quantum-verification-story/src/components/RotatingText.css +36 -0
- package/data/templates/quantum-verification-story/src/components/RotatingText.tsx +189 -0
- package/data/templates/quantum-verification-story/src/components/brand-mark.tsx +14 -0
- package/data/templates/quantum-verification-story/src/components/console-preview-section.tsx +57 -0
- package/data/templates/quantum-verification-story/src/components/console-preview.tsx +72 -0
- package/data/templates/quantum-verification-story/src/components/fade-up.tsx +54 -0
- package/data/templates/quantum-verification-story/src/components/floating-network.tsx +125 -0
- package/data/templates/quantum-verification-story/src/components/footer.tsx +83 -0
- package/data/templates/quantum-verification-story/src/components/harvest-timeline.tsx +70 -0
- package/data/templates/quantum-verification-story/src/components/lattice-diagram.tsx +73 -0
- package/data/templates/quantum-verification-story/src/components/lattice-field.tsx +129 -0
- package/data/templates/quantum-verification-story/src/components/nav.tsx +104 -0
- package/data/templates/quantum-verification-story/src/components/presentation-layout.tsx +91 -0
- package/data/templates/quantum-verification-story/src/components/readiness-estimator.tsx +135 -0
- package/data/templates/quantum-verification-story/src/components/scramble-text.tsx +60 -0
- package/data/templates/quantum-verification-story/src/components/section-backdrop.tsx +38 -0
- package/data/templates/quantum-verification-story/src/components/sections/clients.tsx +140 -0
- package/data/templates/quantum-verification-story/src/components/sections/contact.tsx +125 -0
- package/data/templates/quantum-verification-story/src/components/sections/hero.tsx +92 -0
- package/data/templates/quantum-verification-story/src/components/sections/moat.tsx +73 -0
- package/data/templates/quantum-verification-story/src/components/sections/offer.tsx +113 -0
- package/data/templates/quantum-verification-story/src/components/sections/pilot.tsx +63 -0
- package/data/templates/quantum-verification-story/src/components/sections/problem.tsx +53 -0
- package/data/templates/quantum-verification-story/src/components/text-particle.tsx +204 -0
- package/data/templates/quantum-verification-story/src/components/ticker.tsx +27 -0
- package/data/templates/quantum-verification-story/src/components/ui/badge.tsx +29 -0
- package/data/templates/quantum-verification-story/src/components/ui/button.tsx +55 -0
- package/data/templates/quantum-verification-story/src/components/ui/card.tsx +46 -0
- package/data/templates/quantum-verification-story/src/components/ui/cursor-driven-particle-typography.tsx +288 -0
- package/data/templates/quantum-verification-story/src/components/ui/input.tsx +20 -0
- package/data/templates/quantum-verification-story/src/components/ui/label.tsx +21 -0
- package/data/templates/quantum-verification-story/src/components/ui/separator.tsx +25 -0
- package/data/templates/quantum-verification-story/src/components/ui/textarea.tsx +19 -0
- package/data/templates/quantum-verification-story/src/lib/utils.ts +6 -0
- package/data/templates/quantum-verification-story/tailwind.config.js +95 -0
- package/data/templates/quantum-verification-story/template.manifest.json +23 -0
- package/data/templates/quantum-verification-story/tsconfig.json +42 -0
- package/data/templates/saas-solution-homepage/main.tsx +91 -14
- package/data/templates/saas-solution-homepage/privacy/index.html +1 -0
- package/data/templates/saas-solution-homepage/styles.css +47 -2
- package/data/templates/saas-solution-homepage/team/index.html +1 -0
- package/data/templates/saas-solution-homepage/template.manifest.json +41 -0
- package/data/templates/saas-solution-homepage/terms/index.html +1 -0
- package/lib/api.mjs +52 -3
- package/lib/template-runtime.mjs +1 -0
- package/package.json +2 -2
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "quantum-verification-story",
|
|
3
|
+
"version": "2.0.0",
|
|
4
|
+
"private": true,
|
|
5
|
+
"scripts": {
|
|
6
|
+
"dev": "next dev",
|
|
7
|
+
"start": "next start",
|
|
8
|
+
"build": "next build",
|
|
9
|
+
"lint": "eslint ."
|
|
10
|
+
},
|
|
11
|
+
"dependencies": {
|
|
12
|
+
"@radix-ui/react-accordion": "^1.2.13",
|
|
13
|
+
"@radix-ui/react-dialog": "^1.1.16",
|
|
14
|
+
"@radix-ui/react-label": "^2.1.9",
|
|
15
|
+
"@radix-ui/react-navigation-menu": "^1.2.15",
|
|
16
|
+
"@radix-ui/react-select": "^2.3.0",
|
|
17
|
+
"@radix-ui/react-separator": "^1.1.9",
|
|
18
|
+
"@radix-ui/react-slot": "^1.2.5",
|
|
19
|
+
"@radix-ui/react-tabs": "^1.1.14",
|
|
20
|
+
"autoprefixer": "^10.5.0",
|
|
21
|
+
"framer-motion": "^12.40.0",
|
|
22
|
+
"motion": "^12.40.0",
|
|
23
|
+
"next": "16.3.2",
|
|
24
|
+
"react": "^18",
|
|
25
|
+
"react-dom": "^18"
|
|
26
|
+
},
|
|
27
|
+
"devDependencies": {
|
|
28
|
+
"@types/node": "^20",
|
|
29
|
+
"@types/react": "^18",
|
|
30
|
+
"@types/react-dom": "^18",
|
|
31
|
+
"class-variance-authority": "^0.7.1",
|
|
32
|
+
"clsx": "^2.1.1",
|
|
33
|
+
"eslint": "^9",
|
|
34
|
+
"eslint-config-next": "16.3.2",
|
|
35
|
+
"lucide-react": "^1.18.0",
|
|
36
|
+
"postcss": "^8",
|
|
37
|
+
"tailwind-merge": "^3.6.0",
|
|
38
|
+
"tailwindcss": "^3.4.19",
|
|
39
|
+
"tailwindcss-animate": "^1.0.7",
|
|
40
|
+
"typescript": "^5"
|
|
41
|
+
},
|
|
42
|
+
"allowScripts": {
|
|
43
|
+
"unrs-resolver@1.12.2": true,
|
|
44
|
+
"fsevents@2.3.3": true
|
|
45
|
+
}
|
|
46
|
+
}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import type { Metadata } from "next"
|
|
2
|
+
import Link from "next/link"
|
|
3
|
+
import { Boxes, ListChecks, FileText, ShieldCheck } from "lucide-react"
|
|
4
|
+
import { Button } from "@/components/ui/button"
|
|
5
|
+
import { ScrambleText } from "@/components/scramble-text"
|
|
6
|
+
import { ReadinessEstimator } from "@/components/readiness-estimator"
|
|
7
|
+
import { ConsolePreviewSection } from "@/components/console-preview-section"
|
|
8
|
+
|
|
9
|
+
export const metadata: Metadata = {
|
|
10
|
+
title: "PQC Readiness Assessment — Your Company",
|
|
11
|
+
description:
|
|
12
|
+
"A fixed-scope, 30-day audit of your cryptographic posture. Estimate your harvest-now-decrypt-later exposure with the Mosca model, then get a board-ready migration roadmap.",
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
const audits = [
|
|
16
|
+
{ icon: Boxes, title: "Cryptographic inventory", body: "Every key, certificate, cipher suite, and library — across applications, networks, and third-party dependencies." },
|
|
17
|
+
{ icon: ListChecks, title: "Risk scoring", body: "Each asset scored against NIST migration tiers and your data's confidentiality shelf-life." },
|
|
18
|
+
{ icon: FileText, title: "Migration roadmap", body: "A sequenced, costed plan — what to migrate first, what it takes, and what it protects." },
|
|
19
|
+
{ icon: ShieldCheck,title: "Board-ready evidence", body: "An executive briefing and report mapped to RBI, CERT-In, and US federal mandates." },
|
|
20
|
+
]
|
|
21
|
+
|
|
22
|
+
const phases = [
|
|
23
|
+
{ n: "Days 1–10", t: "Discover", b: "Agentless scan plus interviews to inventory your full cryptographic footprint." },
|
|
24
|
+
{ n: "Days 11–20", t: "Analyze", b: "Score every asset, model your exposure window, and prioritize against your threat model." },
|
|
25
|
+
{ n: "Days 21–30", t: "Deliver", b: "Board-ready roadmap, executive briefing, and a migration kickoff plan if you proceed." },
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
export default function AssessmentPage() {
|
|
29
|
+
return (
|
|
30
|
+
<>
|
|
31
|
+
{/* Hero */}
|
|
32
|
+
<section className="section-y border-b border-[var(--color-border)] bg-white">
|
|
33
|
+
<div className="container-main">
|
|
34
|
+
<ScrambleText text="NIST Estimator" className="eyebrow mb-4 block" />
|
|
35
|
+
<h1 className="font-bold leading-[1.08] tracking-tight text-[var(--color-text-primary)] mb-6"
|
|
36
|
+
style={{ fontSize: "clamp(36px, 4vw, 60px)" }}>
|
|
37
|
+
PQC Readiness<br />
|
|
38
|
+
<span className="text-[var(--primary-500)]">Assessment</span>
|
|
39
|
+
</h1>
|
|
40
|
+
<p className="text-[17px] leading-[1.7] text-[var(--color-text-secondary)] max-w-2xl">
|
|
41
|
+
A rigorous audit of your cryptographic posture. We map every vulnerable protocol, quantify your
|
|
42
|
+
technical debt, and deliver a board-ready roadmap — in 30 days, fixed scope and fixed price.
|
|
43
|
+
</p>
|
|
44
|
+
</div>
|
|
45
|
+
</section>
|
|
46
|
+
|
|
47
|
+
{/* Live console */}
|
|
48
|
+
<ConsolePreviewSection
|
|
49
|
+
dark
|
|
50
|
+
eyebrow="What you'll get"
|
|
51
|
+
heading="Your findings, in one console."
|
|
52
|
+
body="Assessment results land in the live QSP console — every exposed asset scored, mapped, and ready to export."
|
|
53
|
+
/>
|
|
54
|
+
|
|
55
|
+
{/* Estimator */}
|
|
56
|
+
<section className="section-y border-b border-[var(--color-border)] bg-[var(--gray-50)]">
|
|
57
|
+
<div className="container-main">
|
|
58
|
+
<div className="max-w-xl mb-8">
|
|
59
|
+
<ScrambleText text="Estimate your exposure" className="eyebrow mb-3 block" />
|
|
60
|
+
<h2 className="font-bold leading-[1.12] tracking-tight text-[var(--color-text-primary)]"
|
|
61
|
+
style={{ fontSize: "var(--type-h1)" }}>
|
|
62
|
+
Are you already in the window?
|
|
63
|
+
</h2>
|
|
64
|
+
</div>
|
|
65
|
+
<ReadinessEstimator />
|
|
66
|
+
</div>
|
|
67
|
+
</section>
|
|
68
|
+
|
|
69
|
+
{/* What we audit */}
|
|
70
|
+
<section className="section-y border-b border-[var(--color-border)] bg-white">
|
|
71
|
+
<div className="container-main">
|
|
72
|
+
<div className="max-w-xl mb-12">
|
|
73
|
+
<ScrambleText text="What's included" className="eyebrow mb-3 block" />
|
|
74
|
+
<h2 className="font-bold leading-[1.12] tracking-tight text-[var(--color-text-primary)]"
|
|
75
|
+
style={{ fontSize: "var(--type-h1)" }}>
|
|
76
|
+
Four deliverables, one engagement.
|
|
77
|
+
</h2>
|
|
78
|
+
</div>
|
|
79
|
+
<div className="grid sm:grid-cols-2 gap-5">
|
|
80
|
+
{audits.map((a) => {
|
|
81
|
+
const Icon = a.icon
|
|
82
|
+
return (
|
|
83
|
+
<div key={a.title} className="rounded-2xl border border-[var(--color-border)] bg-white p-8 hover:shadow-md transition-all">
|
|
84
|
+
<div className="flex items-center justify-center w-11 h-11 rounded-xl bg-[var(--deep-900)] mb-5">
|
|
85
|
+
<Icon size={19} className="text-[var(--primary-400)]" strokeWidth={2} />
|
|
86
|
+
</div>
|
|
87
|
+
<h3 className="text-[18px] font-bold tracking-tight text-[var(--color-text-primary)] mb-2">{a.title}</h3>
|
|
88
|
+
<p className="text-[14px] leading-[1.7] text-[var(--color-text-secondary)]">{a.body}</p>
|
|
89
|
+
</div>
|
|
90
|
+
)
|
|
91
|
+
})}
|
|
92
|
+
</div>
|
|
93
|
+
</div>
|
|
94
|
+
</section>
|
|
95
|
+
|
|
96
|
+
{/* 30-day process */}
|
|
97
|
+
<section className="section-y border-b border-[var(--color-border)] bg-[var(--gray-50)]">
|
|
98
|
+
<div className="container-main">
|
|
99
|
+
<div className="max-w-xl mb-12">
|
|
100
|
+
<ScrambleText text="The 30-day process" className="eyebrow mb-3 block" />
|
|
101
|
+
<h2 className="font-bold leading-[1.12] tracking-tight text-[var(--color-text-primary)]"
|
|
102
|
+
style={{ fontSize: "var(--type-h1)" }}>
|
|
103
|
+
From blind spot to board pack.
|
|
104
|
+
</h2>
|
|
105
|
+
</div>
|
|
106
|
+
<div className="grid md:grid-cols-3 gap-5">
|
|
107
|
+
{phases.map((p, i) => (
|
|
108
|
+
<div key={p.t} className="rounded-2xl border border-[var(--color-border)] bg-white p-8 relative">
|
|
109
|
+
<div className="text-[44px] font-bold leading-none text-[var(--primary-200)] mb-4">0{i + 1}</div>
|
|
110
|
+
<div className="font-mono text-[10px] tracking-[0.12em] uppercase text-[var(--primary-500)] font-semibold mb-1">{p.n}</div>
|
|
111
|
+
<h3 className="text-[18px] font-bold tracking-tight text-[var(--color-text-primary)] mb-2">{p.t}</h3>
|
|
112
|
+
<p className="text-[14px] leading-[1.7] text-[var(--color-text-secondary)]">{p.b}</p>
|
|
113
|
+
</div>
|
|
114
|
+
))}
|
|
115
|
+
</div>
|
|
116
|
+
</div>
|
|
117
|
+
</section>
|
|
118
|
+
|
|
119
|
+
{/* CTA */}
|
|
120
|
+
<section className="section-y bg-white">
|
|
121
|
+
<div className="container-main">
|
|
122
|
+
<div className="rounded-2xl bg-[var(--deep-900)] px-8 py-12 sm:px-12 sm:py-14 text-center">
|
|
123
|
+
<h2 className="text-white font-bold leading-[1.15] tracking-tight mb-4"
|
|
124
|
+
style={{ fontSize: "clamp(24px, 3vw, 36px)" }}>
|
|
125
|
+
Get your readiness score.
|
|
126
|
+
</h2>
|
|
127
|
+
<p className="text-white/60 text-[16px] leading-[1.7] mx-auto mb-8" style={{ maxWidth: "46ch" }}>
|
|
128
|
+
Run a scan and see your exposure in days — no install, no obligation.
|
|
129
|
+
</p>
|
|
130
|
+
<Button asChild className="rounded-full bg-[var(--primary-500)] text-[var(--gray-950)] hover:bg-[var(--primary-400)] font-semibold h-11 px-7 text-[15px]">
|
|
131
|
+
<Link href="/#contact">Run a Free Scan</Link>
|
|
132
|
+
</Button>
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</section>
|
|
136
|
+
</>
|
|
137
|
+
)
|
|
138
|
+
}
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
@import '@utopia-studio-design/design-system/themes/utopia-default.css';
|
|
2
|
+
@import '@utopia-studio-design/design-system/themes/dextrum.css';
|
|
3
|
+
@import '@utopia-studio-design/design-system/themes/barrier-intelligence.css';
|
|
4
|
+
@import '@utopia-studio-design/design-system/themes/renacore.css';
|
|
5
|
+
@import '@utopia-studio-design/design-system/themes/vyapti.css';
|
|
6
|
+
@import '@utopia-studio-design/design-system/themes/utopia-cloudblur.css';
|
|
7
|
+
|
|
8
|
+
:root {
|
|
9
|
+
--primary-50: color-mix(in srgb, var(--primary) 8%, var(--background));
|
|
10
|
+
--primary-100: color-mix(in srgb, var(--primary) 14%, var(--background));
|
|
11
|
+
--primary-200: color-mix(in srgb, var(--primary) 24%, var(--background));
|
|
12
|
+
--primary-300: color-mix(in srgb, var(--primary) 42%, var(--background));
|
|
13
|
+
--primary-400: color-mix(in srgb, var(--primary) 72%, var(--background));
|
|
14
|
+
--primary-500: var(--primary);
|
|
15
|
+
--primary-600: color-mix(in srgb, var(--primary) 82%, var(--foreground));
|
|
16
|
+
--primary-700: color-mix(in srgb, var(--primary) 68%, var(--foreground));
|
|
17
|
+
--deep-50: color-mix(in srgb, var(--primary) 5%, var(--background));
|
|
18
|
+
--deep-700: color-mix(in srgb, var(--primary) 30%, var(--foreground));
|
|
19
|
+
--deep-800: color-mix(in srgb, var(--primary) 20%, var(--foreground));
|
|
20
|
+
--deep-900: color-mix(in srgb, var(--primary) 12%, var(--foreground));
|
|
21
|
+
--deep-950: color-mix(in srgb, var(--primary) 6%, var(--foreground));
|
|
22
|
+
--gray-0: var(--background);
|
|
23
|
+
--gray-50: var(--surface);
|
|
24
|
+
--gray-100: var(--muted);
|
|
25
|
+
--gray-200: var(--border);
|
|
26
|
+
--gray-400: var(--muted-foreground);
|
|
27
|
+
--gray-600: var(--muted-foreground);
|
|
28
|
+
--gray-900: var(--foreground);
|
|
29
|
+
--gray-950: color-mix(in srgb, var(--foreground) 94%, black);
|
|
30
|
+
--color-bg: var(--background);
|
|
31
|
+
--color-bg-subtle: var(--surface);
|
|
32
|
+
--color-bg-muted: var(--muted);
|
|
33
|
+
--color-surface: var(--background);
|
|
34
|
+
--color-surface-raised: var(--surface);
|
|
35
|
+
--color-border: var(--border);
|
|
36
|
+
--color-border-strong: color-mix(in srgb, var(--border) 62%, var(--foreground));
|
|
37
|
+
--color-text-primary: var(--foreground);
|
|
38
|
+
--color-text-secondary: var(--muted-foreground);
|
|
39
|
+
--color-text-muted: color-mix(in srgb, var(--muted-foreground) 72%, var(--background));
|
|
40
|
+
--color-text-inverse: var(--primary-foreground);
|
|
41
|
+
--color-brand: var(--primary);
|
|
42
|
+
--color-brand-hover: color-mix(in srgb, var(--primary) 82%, var(--foreground));
|
|
43
|
+
--color-brand-subtle: color-mix(in srgb, var(--primary) 8%, var(--background));
|
|
44
|
+
--color-brand-text: color-mix(in srgb, var(--primary) 64%, var(--foreground));
|
|
45
|
+
--color-deep: var(--deep-900);
|
|
46
|
+
--color-deep-hover: var(--deep-800);
|
|
47
|
+
--color-deep-subtle: var(--deep-50);
|
|
48
|
+
}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
import type { Metadata } from "next"
|
|
2
|
+
import Link from "next/link"
|
|
3
|
+
import { Search, RefreshCw, BadgeCheck, Boxes, KeyRound, ShieldCheck, Layers } from "lucide-react"
|
|
4
|
+
import { Button } from "@/components/ui/button"
|
|
5
|
+
import { ScrambleText } from "@/components/scramble-text"
|
|
6
|
+
import { ConsolePreviewSection } from "@/components/console-preview-section"
|
|
7
|
+
|
|
8
|
+
export const metadata: Metadata = {
|
|
9
|
+
title: "Continuous Verification — Your Company",
|
|
10
|
+
description:
|
|
11
|
+
"Quantum readiness isn't a one-time scan. The platform continuously re-scans and re-verifies your cryptographic posture, so it's provable any day — not just audit day.",
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
const modes = [
|
|
15
|
+
{ icon: Search, name: "One-Time Scan", best: "Best for a first look", body: "A full point-in-time inventory and readiness score across your entire stack." },
|
|
16
|
+
{ icon: RefreshCw, name: "Continuous Monitoring", best: "Best for staying ready", body: "Automated re-scans flag new quantum-vulnerable assets the moment they ship." },
|
|
17
|
+
{ icon: BadgeCheck, name: "Audit Certification", best: "Best for proof on demand", body: "Board- and regulator-ready evidence of your posture, exportable whenever you need it." },
|
|
18
|
+
]
|
|
19
|
+
|
|
20
|
+
const detects = [
|
|
21
|
+
{ icon: Boxes, t: "Quantum-vulnerable algorithms", b: "RSA, ECC, and Diffie-Hellman exposure across every service and dependency." },
|
|
22
|
+
{ icon: KeyRound, t: "Key & certificate risk", b: "Expiring, weak, or non-agile keys and certificates — inventoried at scale." },
|
|
23
|
+
{ icon: ShieldCheck, t: "Protocol & config gaps", b: "TLS, SSH, and API layers still negotiating quantum-broken cipher suites." },
|
|
24
|
+
{ icon: Layers, t: "Standards drift", b: "Assets falling behind NIST FIPS-203/204 as the standards keep evolving." },
|
|
25
|
+
]
|
|
26
|
+
|
|
27
|
+
const steps = [
|
|
28
|
+
{ t: "Connect", b: "Point The platform at your stack — agentless and read-only." },
|
|
29
|
+
{ t: "Scan", b: "Every key, certificate, cipher, and dependency inventoried." },
|
|
30
|
+
{ t: "Score", b: "Each asset rated against NIST tiers and your data's shelf-life." },
|
|
31
|
+
{ t: "Re-verify", b: "Automated re-scans keep your posture provably current." },
|
|
32
|
+
]
|
|
33
|
+
|
|
34
|
+
const stats = [
|
|
35
|
+
{ n: "Agentless", l: "no install on\nyour servers" },
|
|
36
|
+
{ n: "24/7", l: "continuous\nre-verification" },
|
|
37
|
+
{ n: "NIST", l: "FIPS-203/204\naligned" },
|
|
38
|
+
{ n: "3", l: "frameworks mapped\nRBI · CERT-In · US" },
|
|
39
|
+
]
|
|
40
|
+
|
|
41
|
+
export default function VerificationPage() {
|
|
42
|
+
return (
|
|
43
|
+
<>
|
|
44
|
+
{/* Hero */}
|
|
45
|
+
<section className="section-y border-b border-[var(--color-border)] bg-white">
|
|
46
|
+
<div className="container-main">
|
|
47
|
+
<ScrambleText text="Continuous Verification" className="eyebrow mb-4 block" />
|
|
48
|
+
<h1 className="font-bold leading-[1.08] tracking-tight text-[var(--color-text-primary)] mb-6"
|
|
49
|
+
style={{ fontSize: "clamp(36px, 4vw, 60px)" }}>
|
|
50
|
+
Verified once isn't<br />
|
|
51
|
+
<span className="text-[var(--primary-500)]">verified.</span>
|
|
52
|
+
</h1>
|
|
53
|
+
<p className="text-[17px] leading-[1.7] text-[var(--color-text-secondary)] max-w-2xl">
|
|
54
|
+
Cryptography drifts — new keys, new services, new standards. The platform re-scans and re-verifies
|
|
55
|
+
continuously, so your readiness is provable on any given day, not just audit day.
|
|
56
|
+
</p>
|
|
57
|
+
</div>
|
|
58
|
+
</section>
|
|
59
|
+
|
|
60
|
+
{/* Live console */}
|
|
61
|
+
<ConsolePreviewSection
|
|
62
|
+
dark
|
|
63
|
+
eyebrow="Continuous monitoring"
|
|
64
|
+
heading="Provable on any given day."
|
|
65
|
+
body="The console re-verifies your posture around the clock — drift, downgrades, and false-stability surfaced the moment they appear."
|
|
66
|
+
/>
|
|
67
|
+
|
|
68
|
+
{/* Stats */}
|
|
69
|
+
<section className="section-y border-b border-[var(--color-border)] bg-[var(--gray-50)]">
|
|
70
|
+
<div className="container-main">
|
|
71
|
+
<div className="grid grid-cols-2 md:grid-cols-4 divide-x divide-[var(--color-border)]">
|
|
72
|
+
{stats.map(({ n, l }) => (
|
|
73
|
+
<div key={n} className="px-6 py-10 text-center">
|
|
74
|
+
<div className="text-[2.2rem] font-bold leading-none text-[var(--deep-900)] mb-2 tracking-tight">{n}</div>
|
|
75
|
+
<div className="text-[11px] font-mono uppercase tracking-[0.07em] text-[var(--color-text-muted)] leading-relaxed whitespace-pre-line">{l}</div>
|
|
76
|
+
</div>
|
|
77
|
+
))}
|
|
78
|
+
</div>
|
|
79
|
+
</div>
|
|
80
|
+
</section>
|
|
81
|
+
|
|
82
|
+
{/* Modes */}
|
|
83
|
+
<section className="section-y border-b border-[var(--color-border)] bg-white">
|
|
84
|
+
<div className="container-main">
|
|
85
|
+
<div className="max-w-xl mb-12">
|
|
86
|
+
<ScrambleText text="How you run it" className="eyebrow mb-3 block" />
|
|
87
|
+
<h2 className="font-bold leading-[1.12] tracking-tight text-[var(--color-text-primary)]"
|
|
88
|
+
style={{ fontSize: "var(--type-h1)" }}>
|
|
89
|
+
Scan once, or stay verified.
|
|
90
|
+
</h2>
|
|
91
|
+
</div>
|
|
92
|
+
<div className="grid md:grid-cols-3 gap-5">
|
|
93
|
+
{modes.map((m) => {
|
|
94
|
+
const Icon = m.icon
|
|
95
|
+
return (
|
|
96
|
+
<div key={m.name} className="rounded-2xl border border-[var(--color-border)] bg-white p-8 hover:shadow-md hover:border-[var(--color-border-strong)] transition-all flex flex-col">
|
|
97
|
+
<div className="flex items-center justify-center w-12 h-12 rounded-xl bg-[var(--deep-900)] mb-5">
|
|
98
|
+
<Icon size={20} className="text-[var(--primary-400)]" strokeWidth={2} />
|
|
99
|
+
</div>
|
|
100
|
+
<h3 className="text-[19px] font-bold tracking-tight text-[var(--color-text-primary)] mb-1.5">{m.name}</h3>
|
|
101
|
+
<div className="font-mono text-[10px] tracking-[0.1em] uppercase text-[var(--primary-500)] font-semibold mb-4">{m.best}</div>
|
|
102
|
+
<p className="text-[14px] leading-[1.7] text-[var(--color-text-secondary)]">{m.body}</p>
|
|
103
|
+
</div>
|
|
104
|
+
)
|
|
105
|
+
})}
|
|
106
|
+
</div>
|
|
107
|
+
</div>
|
|
108
|
+
</section>
|
|
109
|
+
|
|
110
|
+
{/* What we detect */}
|
|
111
|
+
<section className="section-y border-b border-[var(--color-border)] bg-[var(--gray-50)]">
|
|
112
|
+
<div className="container-main">
|
|
113
|
+
<div className="max-w-xl mb-12">
|
|
114
|
+
<ScrambleText text="What we detect" className="eyebrow mb-3 block" />
|
|
115
|
+
<h2 className="font-bold leading-[1.12] tracking-tight text-[var(--color-text-primary)]"
|
|
116
|
+
style={{ fontSize: "var(--type-h1)" }}>
|
|
117
|
+
Every place quantum risk hides.
|
|
118
|
+
</h2>
|
|
119
|
+
</div>
|
|
120
|
+
<div className="grid sm:grid-cols-2 gap-5">
|
|
121
|
+
{detects.map((c) => {
|
|
122
|
+
const Icon = c.icon
|
|
123
|
+
return (
|
|
124
|
+
<div key={c.t} className="rounded-2xl border border-[var(--color-border)] bg-white p-8 hover:shadow-md transition-all">
|
|
125
|
+
<div className="flex items-center justify-center w-11 h-11 rounded-xl bg-[var(--primary-500)]/12 border border-[var(--primary-500)]/25 mb-5">
|
|
126
|
+
<Icon size={19} className="text-[var(--primary-600)]" strokeWidth={2} />
|
|
127
|
+
</div>
|
|
128
|
+
<h3 className="text-[18px] font-bold tracking-tight text-[var(--color-text-primary)] mb-2">{c.t}</h3>
|
|
129
|
+
<p className="text-[14px] leading-[1.7] text-[var(--color-text-secondary)]">{c.b}</p>
|
|
130
|
+
</div>
|
|
131
|
+
)
|
|
132
|
+
})}
|
|
133
|
+
</div>
|
|
134
|
+
</div>
|
|
135
|
+
</section>
|
|
136
|
+
|
|
137
|
+
{/* Process */}
|
|
138
|
+
<section className="section-y border-b border-[var(--color-border)] bg-white">
|
|
139
|
+
<div className="container-main">
|
|
140
|
+
<div className="max-w-xl mb-12">
|
|
141
|
+
<ScrambleText text="How it works" className="eyebrow mb-3 block" />
|
|
142
|
+
<h2 className="font-bold leading-[1.12] tracking-tight text-[var(--color-text-primary)]"
|
|
143
|
+
style={{ fontSize: "var(--type-h1)" }}>
|
|
144
|
+
Connect, scan, score, re-verify.
|
|
145
|
+
</h2>
|
|
146
|
+
</div>
|
|
147
|
+
<div className="grid md:grid-cols-4 gap-5">
|
|
148
|
+
{steps.map((s, i) => (
|
|
149
|
+
<div key={s.t} className="rounded-2xl border border-[var(--color-border)] bg-white p-7">
|
|
150
|
+
<div className="text-[40px] font-bold leading-none text-[var(--primary-200)] mb-4">0{i + 1}</div>
|
|
151
|
+
<h3 className="text-[17px] font-bold tracking-tight text-[var(--color-text-primary)] mb-2">{s.t}</h3>
|
|
152
|
+
<p className="text-[13px] leading-[1.7] text-[var(--color-text-secondary)]">{s.b}</p>
|
|
153
|
+
</div>
|
|
154
|
+
))}
|
|
155
|
+
</div>
|
|
156
|
+
</div>
|
|
157
|
+
</section>
|
|
158
|
+
|
|
159
|
+
{/* CTA */}
|
|
160
|
+
<section className="section-y bg-white">
|
|
161
|
+
<div className="container-main">
|
|
162
|
+
<div className="rounded-2xl bg-[var(--deep-900)] px-8 py-12 sm:px-12 sm:py-14 text-center">
|
|
163
|
+
<h2 className="text-white font-bold leading-[1.15] tracking-tight mb-4"
|
|
164
|
+
style={{ fontSize: "clamp(24px, 3vw, 36px)" }}>
|
|
165
|
+
See where you stand today.
|
|
166
|
+
</h2>
|
|
167
|
+
<p className="text-white/60 text-[16px] leading-[1.7] mx-auto mb-8" style={{ maxWidth: "46ch" }}>
|
|
168
|
+
Connect your stack and get a first exposure report — no install, no commitment.
|
|
169
|
+
</p>
|
|
170
|
+
<Button asChild className="rounded-full bg-[var(--primary-500)] text-[var(--gray-950)] hover:bg-[var(--primary-400)] font-semibold h-11 px-7 text-[15px]">
|
|
171
|
+
<Link href="/#contact">Run a Free Scan</Link>
|
|
172
|
+
</Button>
|
|
173
|
+
</div>
|
|
174
|
+
</div>
|
|
175
|
+
</section>
|
|
176
|
+
</>
|
|
177
|
+
)
|
|
178
|
+
}
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
Binary file
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
@tailwind base;
|
|
2
|
+
@tailwind components;
|
|
3
|
+
@tailwind utilities;
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
/* Template-level layout and type scale. Brand roles come from Ceramic. */
|
|
7
|
+
:root {
|
|
8
|
+
/* Color roles are supplied by the Ceramic theme bridge. */
|
|
9
|
+
|
|
10
|
+
/* ── Type scale (generous) ── */
|
|
11
|
+
--type-display-xl: clamp(2.5rem, 3.5rem + 2.5vw, 5.5rem);
|
|
12
|
+
--type-display: clamp(1.875rem, 1.5rem + 2.4vw, 3rem);
|
|
13
|
+
--type-h1: clamp(1.5rem, 1.2rem + 1.6vw, 2.25rem);
|
|
14
|
+
--type-h2: clamp(1.25rem, 1rem + 1.2vw, 1.875rem);
|
|
15
|
+
--type-h3: clamp(1.125rem, 1rem + 0.6vw, 1.375rem);
|
|
16
|
+
--type-h4: 1rem;
|
|
17
|
+
--type-body: 0.9375rem;
|
|
18
|
+
--type-caption: 0.8125rem;
|
|
19
|
+
|
|
20
|
+
/* ── Radius ── */
|
|
21
|
+
--radius-sm: 0.375rem;
|
|
22
|
+
--radius: 0.5rem;
|
|
23
|
+
--radius-lg: 0.75rem;
|
|
24
|
+
--radius-xl: 1rem;
|
|
25
|
+
--radius-full: 9999px;
|
|
26
|
+
|
|
27
|
+
/* ── Shadow ── */
|
|
28
|
+
--shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
|
|
29
|
+
--shadow: 0 1px 3px 0 rgb(0 0 0 / 0.1), 0 1px 2px -1px rgb(0 0 0 / 0.1);
|
|
30
|
+
--shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
|
|
31
|
+
--shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
|
|
32
|
+
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
@layer base {
|
|
36
|
+
*, *::before, *::after {
|
|
37
|
+
box-sizing: border-box;
|
|
38
|
+
margin: 0;
|
|
39
|
+
padding: 0;
|
|
40
|
+
border-color: var(--color-border);
|
|
41
|
+
}
|
|
42
|
+
html { scroll-behavior: smooth; }
|
|
43
|
+
body {
|
|
44
|
+
background: var(--color-bg);
|
|
45
|
+
color: var(--color-text-primary);
|
|
46
|
+
font-family: var(--font-sans);
|
|
47
|
+
font-size: var(--type-body);
|
|
48
|
+
line-height: 1.6;
|
|
49
|
+
-webkit-font-smoothing: antialiased;
|
|
50
|
+
overflow-x: hidden;
|
|
51
|
+
}
|
|
52
|
+
h1, h2, h3, h4, h5, h6 {
|
|
53
|
+
font-weight: 700;
|
|
54
|
+
line-height: 1.15;
|
|
55
|
+
letter-spacing: -0.02em;
|
|
56
|
+
color: var(--color-text-primary);
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
@layer utilities {
|
|
61
|
+
.container-main {
|
|
62
|
+
max-width: 1200px;
|
|
63
|
+
margin-left: auto;
|
|
64
|
+
margin-right: auto;
|
|
65
|
+
padding-left: 1.5rem;
|
|
66
|
+
padding-right: 1.5rem;
|
|
67
|
+
}
|
|
68
|
+
@media (min-width: 768px) {
|
|
69
|
+
.container-main { padding-left: 2rem; padding-right: 2rem; }
|
|
70
|
+
}
|
|
71
|
+
@media (min-width: 1024px) {
|
|
72
|
+
.container-main { padding-left: 3rem; padding-right: 3rem; }
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
.section-y { padding-top: 5rem; padding-bottom: 5rem; }
|
|
76
|
+
.section-y-lg { padding-top: 7rem; padding-bottom: 7rem; }
|
|
77
|
+
|
|
78
|
+
/* eyebrow label */
|
|
79
|
+
.eyebrow {
|
|
80
|
+
font-size: 0.6875rem;
|
|
81
|
+
font-weight: 600;
|
|
82
|
+
letter-spacing: 0.12em;
|
|
83
|
+
text-transform: uppercase;
|
|
84
|
+
color: var(--color-brand);
|
|
85
|
+
font-family: var(--font-mono);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
/* brand surface helpers */
|
|
89
|
+
.bg-deep { background-color: var(--deep-900); }
|
|
90
|
+
.bg-deep-mid { background-color: var(--deep-800); }
|
|
91
|
+
.bg-brand { background-color: var(--primary-500); }
|
|
92
|
+
.text-brand { color: var(--primary-500); }
|
|
93
|
+
.text-brand-light { color: var(--primary-300); }
|
|
94
|
+
.text-deep { color: var(--deep-900); }
|
|
95
|
+
.border-brand { border-color: var(--primary-500); }
|
|
96
|
+
.font-mono-brand { font-family: var(--font-mono); }
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
/* ── Accessibility: visible keyboard focus ── */
|
|
100
|
+
a:focus-visible,
|
|
101
|
+
button:focus-visible,
|
|
102
|
+
input:focus-visible,
|
|
103
|
+
select:focus-visible,
|
|
104
|
+
textarea:focus-visible,
|
|
105
|
+
[tabindex]:focus-visible {
|
|
106
|
+
outline: 2px solid var(--primary-500);
|
|
107
|
+
outline-offset: 2px;
|
|
108
|
+
border-radius: 3px;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
/* Skip-to-content link — visible only when focused */
|
|
112
|
+
.skip-link {
|
|
113
|
+
position: fixed;
|
|
114
|
+
top: 0.5rem;
|
|
115
|
+
left: 0.5rem;
|
|
116
|
+
z-index: 100;
|
|
117
|
+
padding: 0.6rem 1rem;
|
|
118
|
+
border-radius: 9999px;
|
|
119
|
+
background: var(--primary-500);
|
|
120
|
+
color: var(--gray-950);
|
|
121
|
+
font-size: 0.8125rem;
|
|
122
|
+
font-weight: 600;
|
|
123
|
+
transform: translateY(-150%);
|
|
124
|
+
transition: transform 0.18s ease;
|
|
125
|
+
}
|
|
126
|
+
.skip-link:focus {
|
|
127
|
+
transform: translateY(0);
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
/* ── Animated glow border (light travels along the edge) ── */
|
|
131
|
+
@property --glow-angle {
|
|
132
|
+
syntax: '<angle>';
|
|
133
|
+
initial-value: 0deg;
|
|
134
|
+
inherits: false;
|
|
135
|
+
}
|
|
136
|
+
@keyframes glow-spin { to { --glow-angle: 360deg; } }
|
|
137
|
+
@keyframes glow-breathe {
|
|
138
|
+
0%, 100% { box-shadow: 0 0 22px -4px color-mix(in srgb, var(--primary-500) 30%, transparent); }
|
|
139
|
+
50% { box-shadow: 0 0 34px -2px color-mix(in srgb, var(--primary-500) 55%, transparent); }
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
.glow-border {
|
|
143
|
+
position: relative;
|
|
144
|
+
isolation: isolate;
|
|
145
|
+
animation: glow-breathe 3.6s ease-in-out infinite;
|
|
146
|
+
}
|
|
147
|
+
/* rotating gradient ring drawn only on the border via mask */
|
|
148
|
+
.glow-border::before {
|
|
149
|
+
content: "";
|
|
150
|
+
position: absolute;
|
|
151
|
+
inset: 0;
|
|
152
|
+
border-radius: inherit;
|
|
153
|
+
padding: 1.5px;
|
|
154
|
+
background: conic-gradient(
|
|
155
|
+
from var(--glow-angle),
|
|
156
|
+
transparent 0deg,
|
|
157
|
+
color-mix(in srgb, var(--primary-500) 15%, transparent) 40deg,
|
|
158
|
+
var(--primary-300) 90deg,
|
|
159
|
+
var(--primary-400) 120deg,
|
|
160
|
+
color-mix(in srgb, var(--primary-500) 15%, transparent) 170deg,
|
|
161
|
+
transparent 210deg,
|
|
162
|
+
transparent 360deg
|
|
163
|
+
);
|
|
164
|
+
-webkit-mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
|
165
|
+
mask: linear-gradient(#000 0 0) content-box, linear-gradient(#000 0 0);
|
|
166
|
+
-webkit-mask-composite: xor;
|
|
167
|
+
mask-composite: exclude;
|
|
168
|
+
animation: glow-spin 4s linear infinite;
|
|
169
|
+
pointer-events: none;
|
|
170
|
+
z-index: 1;
|
|
171
|
+
}
|
|
172
|
+
@media (prefers-reduced-motion: reduce) {
|
|
173
|
+
.glow-border { animation: none; box-shadow: 0 0 22px -6px color-mix(in srgb, var(--primary-500) 40%, transparent); }
|
|
174
|
+
.glow-border::before { animation: none; }
|
|
175
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import type { Metadata } from "next"
|
|
2
|
+
import "./globals.css"
|
|
3
|
+
import "./ceramic-theme.css"
|
|
4
|
+
import { Nav } from "@/components/nav"
|
|
5
|
+
import { Footer } from "@/components/footer"
|
|
6
|
+
|
|
7
|
+
export const metadata: Metadata = {
|
|
8
|
+
metadataBase: new URL(process.env.NEXT_PUBLIC_SITE_URL || "http://localhost:3000"),
|
|
9
|
+
title: "Your Company — Verify Your Quantum Readiness",
|
|
10
|
+
description:
|
|
11
|
+
"Is your encryption quantum-safe? The platform scans your stack, diagnoses every quantum-vulnerable algorithm, and verifies your post-quantum readiness — board-ready and provable.",
|
|
12
|
+
openGraph: {
|
|
13
|
+
title: "Your Company — Verify Your Quantum Readiness",
|
|
14
|
+
description:
|
|
15
|
+
"Scan, diagnose, and verify whether your encryption survives the quantum era — the PQC verification platform.",
|
|
16
|
+
type: "website",
|
|
17
|
+
},
|
|
18
|
+
twitter: {
|
|
19
|
+
card: "summary",
|
|
20
|
+
title: "Your Company — Verify Your Quantum Readiness",
|
|
21
|
+
description: "Scan, diagnose, and verify whether your encryption survives the quantum era.",
|
|
22
|
+
},
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
const themeBootstrap = `(() => {
|
|
26
|
+
const supportedThemes = new Set(['utopia-default', 'dextrum', 'barrier-intelligence', 'renacore', 'vyapti', 'utopia-cloudblur']);
|
|
27
|
+
const requestedTheme = new URLSearchParams(window.location.search).get('theme');
|
|
28
|
+
if (!requestedTheme || !supportedThemes.has(requestedTheme)) return;
|
|
29
|
+
document.documentElement.dataset.theme = requestedTheme;
|
|
30
|
+
document.documentElement.dataset.brand = requestedTheme;
|
|
31
|
+
})();`
|
|
32
|
+
|
|
33
|
+
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
34
|
+
return (
|
|
35
|
+
<html lang="en" data-theme="utopia-default" data-brand="utopia-default" data-color-mode="light" suppressHydrationWarning>
|
|
36
|
+
<head><script dangerouslySetInnerHTML={{ __html: themeBootstrap }} /></head>
|
|
37
|
+
<body>
|
|
38
|
+
<a href="#main-content" className="skip-link">Skip to content</a>
|
|
39
|
+
<Nav />
|
|
40
|
+
<main id="main-content">{children}</main>
|
|
41
|
+
<Footer />
|
|
42
|
+
</body>
|
|
43
|
+
</html>
|
|
44
|
+
)
|
|
45
|
+
}
|