diff --git a/src/components/ArchDiagramSection/index.js b/src/components/ArchDiagramSection/index.js
new file mode 100644
index 0000000..eeed05a
--- /dev/null
+++ b/src/components/ArchDiagramSection/index.js
@@ -0,0 +1,205 @@
+import React from 'react';
+import styles from './styles.module.css';
+
+function ArrowDown() {
+ return (
+
+
+
+
+ );
+}
+
+function ClusterConnectors() {
+ return (
+
+
+
+
+
+
+
+
+ );
+}
+
+function StorageConnectors() {
+ return (
+
+
+
+
+
+ );
+}
+
+function DatabaseIcon() {
+ return (
+
+
+
+
+
+ );
+}
+
+function StorageIcon() {
+ return (
+
+
+
+
+
+
+ );
+}
+
+const features = [
+ {
+ label: 'High Availability',
+ description: 'Automatic Failover & Self-Healing',
+ icon: (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Backups',
+ description: 'Continuous Backups',
+ icon: (
+
+
+
+
+
+ ),
+ },
+ {
+ label: 'PITR',
+ description: 'Point-in-Time Recovery',
+ icon: (
+
+
+
+
+
+ ),
+ },
+ {
+ label: 'Monitoring',
+ description: 'Built-in Metrics & Alerting',
+ icon: (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Upgrades',
+ description: 'Zero-Downtime Upgrades',
+ icon: (
+
+
+
+
+ ),
+ },
+ {
+ label: 'Scaling',
+ description: 'Cluster Scaling with read replicas',
+ icon: (
+
+
+
+
+
+
+ ),
+ },
+];
+
+/* ── Reusable diagram JSX ────────────────────────────────────────────── */
+function DiagramInner() {
+ return (
+
+
+
+
Users
+
+ Developers
+ |
+ SRE
+ |
+ DBA
+
+
+
+
+
+
+
+
+
Autobase Platform
+
+
+ Provisioning
+ |
+ Maintenance
+ |
+ Scaling
+
+
+
+
+
+
+
PostgreSQL Cluster 1
+
PostgreSQL Cluster 2
+
PostgreSQL Cluster N
+
+
+
+
+
+
+
+
+
Database Storage / Backup Storage
+
Local NVMe, SSD, EBS for data / S3, MinIO, etc. for backups
+
+
+
+
+
+ );
+}
+
+export default function ArchDiagramSection() {
+ return (
+
+
+
+ {/* ── Architecture Diagram ── */}
+
+
+ {/* ── Divider ── */}
+
+
+ {/* ── Features Grid ── */}
+
+ {features.map((f) => (
+
+
{f.icon}
+
{f.label}
+
{f.description}
+
+ ))}
+
+
+
+
+ );
+}
diff --git a/src/components/ArchDiagramSection/styles.module.css b/src/components/ArchDiagramSection/styles.module.css
new file mode 100644
index 0000000..0509c20
--- /dev/null
+++ b/src/components/ArchDiagramSection/styles.module.css
@@ -0,0 +1,300 @@
+/* ─── Section — full viewport width ──────────────────────────────── */
+.section {
+ --diagram-line: #8f8f8f;
+ --diagram-border: #b7b7b7;
+ width: 100vw;
+ min-height: 100vh;
+ background: var(--color-surface);
+ border-bottom: 1px solid var(--color-border);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ position: relative;
+ left: 50%;
+ margin-left: -50vw;
+}
+
+.inner {
+ width: 100%;
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 60px 80px;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+/* ─── Diagram ─────────────────────────────────────────────────────── */
+.diagram {
+ width: 100%;
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+}
+
+/* ─── Row ─────────────────────────────────────────────────────────── */
+.row {
+ width: 100%;
+ display: flex;
+ justify-content: center;
+}
+
+/* ─── Box ─────────────────────────────────────────────────────────── */
+.box {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 28px 0;
+ border: 2px dashed var(--diagram-border);
+ border-radius: 2px;
+ font-size: 20px;
+ font-weight: 400;
+ color: var(--color-text);
+ background: transparent;
+ width: 80%;
+}
+
+.muted {
+ color: var(--color-text-muted);
+ margin-left: 8px;
+}
+
+.usersBox {
+ flex-direction: column;
+ gap: 12px;
+ width: 48%;
+}
+
+.usersTitle {
+ font-size: 22px;
+ color: var(--color-text);
+}
+
+.userRoles {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 12px;
+ flex-wrap: wrap;
+ font-size: 16px;
+ color: var(--color-text-muted);
+}
+
+/* ─── Arrow down ──────────────────────────────────────────────────── */
+.arrowRow {
+ display: flex;
+ justify-content: center;
+ height: 48px;
+ align-items: center;
+ color: var(--diagram-line);
+}
+
+.arrowDown { display: block; }
+
+/* ─── Platform ───────────────────────────────────────────────────── */
+.platform {
+ flex-direction: column;
+ gap: 14px;
+ padding: 32px 0;
+ border-color: var(--color-primary);
+ border-style: dashed;
+ border-width: 2px;
+ width: 80%;
+}
+
+.cpHeader {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 12px;
+}
+
+.cpTitle {
+ font-size: 24px;
+ font-weight: 700;
+ color: var(--color-primary);
+}
+
+.cpPills {
+ display: flex;
+ align-items: center;
+ gap: 12px;
+ flex-wrap: wrap;
+ justify-content: center;
+ font-size: 16px;
+ color: var(--color-text-muted);
+}
+
+.sep { color: var(--color-border); }
+
+.clusterConnectors {
+ width: 80%;
+ height: 72px;
+ color: var(--diagram-line);
+}
+
+.storageConnectors {
+ width: 80%;
+ height: 72px;
+ color: var(--diagram-line);
+}
+
+.mobileConnector {
+ display: none;
+}
+
+/* ─── Clusters ────────────────────────────────────────────────────── */
+.clustersRow {
+ display: flex;
+ align-items: center;
+ gap: 56px;
+ width: 80%;
+}
+
+.clusterBox {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 14px;
+ padding: 32px 0;
+ border: 2px dashed var(--diagram-border);
+ border-radius: 2px;
+ font-size: 16px;
+ color: var(--color-text);
+ text-align: center;
+ line-height: 1.5;
+ flex: 1;
+ background: transparent;
+}
+
+.clusterBoxOptional {
+ opacity: 0.72;
+}
+
+.diagramIcon {
+ color: var(--diagram-line);
+}
+
+/* ─── Storage ─────────────────────────────────────────────────────── */
+.storageRow {
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ text-align: left;
+}
+
+.storageTitle {
+ font-size: 20px;
+ color: var(--color-text);
+}
+
+.storageSub {
+ font-size: 15px;
+ color: var(--color-text-muted);
+ margin-top: 6px;
+}
+
+/* ─── Divider ─────────────────────────────────────────────────────── */
+.divider {
+ width: 80%;
+ border: none;
+ border-top: 1px solid var(--color-border);
+ margin: 48px auto;
+}
+
+/* ─── Features Grid ───────────────────────────────────────────────── */
+.featuresGrid {
+ width: 100%;
+ display: grid;
+ grid-template-columns: repeat(6, 1fr);
+ border: 2px solid var(--color-border);
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+.featureCard {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ padding: 32px 24px;
+ border-right: 2px solid var(--color-border);
+ transition: background 0.2s ease;
+}
+
+.featureCard:last-child { border-right: none; }
+.featureCard:hover { background: var(--color-surface); }
+
+.featureIcon {
+ color: var(--color-text);
+}
+
+.featureIcon svg {
+ display: block;
+ width: 48px;
+ height: 48px;
+}
+
+.featureLabel {
+ font-size: var(--fs-sm);
+ font-weight: var(--fw-bold);
+ color: var(--color-text);
+}
+
+.featureDesc {
+ font-size: 16px;
+ color: var(--color-text-muted);
+ line-height: 1.5;
+}
+
+/* ─── Responsive ──────────────────────────────────────────────────── */
+@media (max-width: 1100px) {
+ .inner { padding: 0 48px; }
+ .box, .controlPlane, .clusterConnectors, .storageConnectors, .clustersRow { width: 90%; }
+ .usersBox { width: 64%; }
+ .featuresGrid { grid-template-columns: repeat(3, 1fr); }
+ .featureCard:nth-child(3) { border-right: none; }
+ .featureCard:nth-child(n+4) { border-top: 2px solid var(--color-border); }
+}
+
+@media (max-width: 768px) {
+ .inner { padding: 40px 24px; }
+ .section { min-height: auto; }
+ .box, .controlPlane, .clusterConnectors, .storageConnectors, .clustersRow { width: 100%; }
+ .usersBox { width: 100%; }
+ .box { font-size: 15px; padding: 20px 12px; }
+ .usersTitle { font-size: 18px; }
+ .userRoles { font-size: 13px; gap: 8px; }
+ .cpTitle { font-size: 18px; }
+ .cpPills { font-size: 13px; gap: 8px; }
+ .clustersRow { gap: 24px; }
+ .clusterBox { padding: 20px 8px; font-size: 13px; gap: 8px; }
+ .storageTitle { font-size: 15px; }
+ .storageSub { font-size: 13px; }
+ .featuresGrid { grid-template-columns: repeat(2, 1fr); }
+ .featureCard:nth-child(n) { border-right: 2px solid var(--color-border); border-top: none; }
+ .featureCard:nth-child(2n) { border-right: none; }
+ .featureCard:last-child { border-right: none; }
+ .featureCard:nth-child(n+3) { border-top: 2px solid var(--color-border); }
+ .featureDesc { font-size: 13px; }
+ .divider { margin: 32px auto; }
+}
+
+@media (max-width: 480px) {
+ .inner { padding: 32px 16px; }
+ .featuresGrid { grid-template-columns: 1fr; }
+ .featureCard { border-right: none; border-bottom: 2px solid var(--color-border); }
+ .featureCard:last-child { border-bottom: none; }
+ .featureCard:nth-child(n) { border-top: none; border-right: none; }
+ .clustersRow { flex-direction: column; gap: 0; }
+ .clusterConnectors,
+ .storageConnectors { display: none; }
+ .mobileConnector {
+ display: flex;
+ justify-content: center;
+ height: 48px;
+ color: var(--diagram-line);
+ }
+ .clusterBox { width: 100%; border-radius: 0; }
+ .clusterBox:first-child { border-radius: 2px 2px 0 0; }
+ .clusterBox:last-child { border-radius: 0 0 2px 2px; }
+}
diff --git a/src/components/CLISection/index.js b/src/components/CLISection/index.js
new file mode 100644
index 0000000..d5d69ae
--- /dev/null
+++ b/src/components/CLISection/index.js
@@ -0,0 +1,155 @@
+import React, { useState, useEffect, useRef } from 'react';
+import styles from './styles.module.css';
+
+/* ── Getting-started workflow (inline terminal) ─────────────────────── */
+const SEQUENCES = [
+ {
+ command: '$ curl -fsSL https://autobase.tech/platform.yml \\\n --output ./docker-compose.platform.yml',
+ result: '✓ Downloaded',
+ detail: ' ./docker-compose.platform.yml',
+ },
+ {
+ command: '$ docker compose \\\n -f docker-compose.platform.yml up -d',
+ result: '✓ Autobase Console started',
+ detail: ' http://your-server-address',
+ },
+];
+
+const CLEAR_CMD = '\n$ \\! clear';
+const CHAR_SPEED = 28;
+const CLS_SPEED = 90;
+const HOLD_MS = 2600;
+const FLASH_MS = 420;
+
+/* ── Inline terminal body (cycles SEQUENCES) ──────────────────────── */
+function InlineBody({ typed, clsTyped, phase, seq }) {
+ const showResult = phase === 'showing' || phase === 'typing_cls' || phase === 'flash';
+ const showCls = phase === 'typing_cls' || phase === 'flash';
+ const isFlashing = phase === 'flash';
+ const displayText = typed.startsWith('$ ') ? typed.slice(2) : typed;
+
+ return (
+
+ $
+ {' '}
+ {displayText}
+ {phase === 'typing' && _ }
+ {showResult && (
+ <>
+ {'\n\n'}
+ {seq.result}
+ {'\n'}
+ {seq.detail}
+ >
+ )}
+ {showCls && (
+ <>
+ {'\n'}
+ {clsTyped}
+ {phase === 'typing_cls' && clsTyped.length < CLEAR_CMD.length && (
+ _
+ )}
+ >
+ )}
+
+ );
+}
+
+export default function CLISection() {
+ /* ── Inline cycling state ── */
+ const [seqIdx, setSeqIdx] = useState(0);
+ const [typed, setTyped] = useState('');
+ const [clsTyped, setClsTyped] = useState('');
+ const [phase, setPhase] = useState('typing');
+ const timer = useRef(null);
+
+ const seq = SEQUENCES[seqIdx];
+
+ /* ── Inline typewriter ── */
+ useEffect(() => {
+ if (phase !== 'typing') return;
+ clearTimeout(timer.current);
+ const cmd = seq.command;
+ if (typed.length < cmd.length) {
+ timer.current = setTimeout(() => setTyped(cmd.slice(0, typed.length + 1)), CHAR_SPEED);
+ } else {
+ timer.current = setTimeout(() => setPhase('showing'), 300);
+ }
+ return () => clearTimeout(timer.current);
+ }, [phase, typed, seq.command]);
+
+ useEffect(() => {
+ if (phase !== 'showing') return;
+ timer.current = setTimeout(() => { setClsTyped(''); setPhase('typing_cls'); }, HOLD_MS);
+ return () => clearTimeout(timer.current);
+ }, [phase]);
+
+ useEffect(() => {
+ if (phase !== 'typing_cls') return;
+ clearTimeout(timer.current);
+ if (clsTyped.length < CLEAR_CMD.length) {
+ timer.current = setTimeout(() => setClsTyped(CLEAR_CMD.slice(0, clsTyped.length + 1)), CLS_SPEED);
+ } else {
+ timer.current = setTimeout(() => setPhase('flash'), 180);
+ }
+ return () => clearTimeout(timer.current);
+ }, [phase, clsTyped]);
+
+ useEffect(() => {
+ if (phase !== 'flash') return;
+ timer.current = setTimeout(() => {
+ setTyped(''); setClsTyped('');
+ setSeqIdx(i => (i + 1) % SEQUENCES.length);
+ setPhase('typing');
+ }, FLASH_MS);
+ return () => clearTimeout(timer.current);
+ }, [phase]);
+
+ const bar = (
+
+
+
+ );
+
+ return (
+
+ );
+}
diff --git a/src/components/CLISection/styles.module.css b/src/components/CLISection/styles.module.css
new file mode 100644
index 0000000..a39ab08
--- /dev/null
+++ b/src/components/CLISection/styles.module.css
@@ -0,0 +1,183 @@
+/* ─── Section ─────────────────────────────────────────────────────── */
+.section {
+ background: var(--color-bg);
+ padding: var(--section-pt) 0 var(--section-pb);
+}
+
+.inner {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 80px;
+}
+
+/* ─── Two-column layout ───────────────────────────────────────────── */
+.layout {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 40px;
+ align-items: center;
+}
+
+/* ─── Terminal (inline) ───────────────────────────────────────────── */
+.terminal {
+ background: #0d0d0d;
+ border-radius: 10px;
+ overflow: hidden;
+ box-shadow: 0 8px 40px rgba(0, 0, 0, 0.15);
+}
+
+.terminalBar {
+ display: flex;
+ align-items: center;
+ gap: 8px;
+ padding: 14px 18px;
+ background: #1a1a1a;
+}
+
+.dot {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ background: #3a3a3a;
+}
+
+/* ─── Terminal code block ─────────────────────────────────────────── */
+.terminalCode {
+ font-family: 'Courier New', Courier, monospace;
+ font-size: 14px;
+ line-height: 1.7;
+ color: #c8c8c8;
+ padding: 24px 28px;
+ margin: 0;
+ white-space: pre;
+ overflow-x: auto;
+ background: transparent;
+ border: none;
+ min-height: 220px;
+}
+
+/* CRT phosphor flash */
+.terminalFlash {
+ animation: crtClear 0.42s ease-in forwards;
+}
+
+@keyframes crtClear {
+ 0% { opacity: 1; filter: brightness(1) blur(0px); }
+ 25% { opacity: 1; filter: brightness(3.5) blur(1px); }
+ 55% { opacity: 0.15; filter: brightness(0.4) blur(2px); }
+ 100% { opacity: 0; filter: brightness(0) blur(0px); }
+}
+
+.prompt {
+ color: var(--color-primary);
+ font-weight: bold;
+}
+
+.caret {
+ display: inline-block;
+ color: #c8c8c8;
+ animation: caretBlink 1s step-end infinite;
+ user-select: none;
+}
+
+@keyframes caretBlink {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0; }
+}
+
+.success {
+ color: #4caf50;
+ font-weight: bold;
+}
+
+.dimmed {
+ color: #666666;
+}
+
+/* ─── CTAs column (original) ──────────────────────────────────────── */
+.ctas {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+
+.ctaPrimary,
+.ctaSecondary {
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ padding: 24px 28px;
+ border-radius: 2px;
+ outline: 1.5px solid transparent;
+ outline-offset: 0px;
+ background: transparent;
+ box-shadow: 6px 6px 0 rgba(0, 0, 0, 0.05);
+ text-decoration: none;
+ transition: border-color 0.18s ease, outline-color 0.18s ease,
+ background 0.18s ease,
+ transform 0.18s ease,
+ box-shadow 0.18s ease;
+}
+
+.ctaPrimary:hover,
+.ctaSecondary:hover {
+ text-decoration: none;
+}
+
+.ctaPrimary {
+ border: 1.5px solid var(--color-primary);
+}
+
+.ctaSecondary {
+ border: 1.5px solid var(--color-border);
+}
+
+.ctaPrimary:hover,
+.ctaSecondary:hover {
+ border-color: var(--color-primary);
+ outline-color: var(--color-primary);
+ background: var(--color-surface);
+ opacity: 1;
+ transform: translate(3px, 3px);
+ box-shadow: 3px 3px 0 rgba(0, 0, 0, 0.1);
+}
+
+.ctaArrow {
+ font-family: monospace;
+ font-size: 20px;
+ font-weight: bold;
+ color: var(--color-primary);
+ flex-shrink: 0;
+}
+
+.ctaTitle {
+ font-family: var(--font-base);
+ font-size: var(--fs-body);
+ font-weight: var(--fw-bold);
+ color: var(--color-text);
+ text-transform: uppercase;
+ letter-spacing: 0.3px;
+}
+
+.ctaSubtitle {
+ font-family: var(--font-base);
+ font-size: var(--fs-sm);
+ font-weight: var(--fw-regular);
+ color: var(--color-text-muted);
+ margin-top: 4px;
+}
+
+/* ─── Responsive ──────────────────────────────────────────────────── */
+@media (max-width: 900px) {
+ .inner { padding: 0 48px; }
+ .layout { grid-template-columns: 1fr; }
+ .ctas { flex-direction: row; flex-wrap: wrap; gap: 12px; }
+ .ctaPrimary, .ctaSecondary { flex: 1; min-width: 200px; padding: 20px 20px; }
+}
+
+@media (max-width: 600px) {
+ .inner { padding: 0 20px; }
+ .terminalCode { font-size: 12px; padding: 16px; min-height: 160px; }
+ .ctas { flex-direction: column; }
+ .ctaPrimary, .ctaSecondary { width: 100%; }
+}
diff --git a/src/components/ClickEffect/index.js b/src/components/ClickEffect/index.js
new file mode 100644
index 0000000..4acbc46
--- /dev/null
+++ b/src/components/ClickEffect/index.js
@@ -0,0 +1,108 @@
+import React, { useEffect, useRef } from 'react';
+
+// Digits pool — mix of decimal + hex for a pg/terminal data feel
+const DIGITS = '0123456789ABCDEF01234567890123456789';
+
+// Weighted color pool — mostly dark, rare orange spark
+const COLORS = [
+ { color: '#111111', weight: 5 },
+ { color: '#555555', weight: 3 },
+ { color: '#999999', weight: 2 },
+ { color: '#ff5722', weight: 1 },
+];
+const TOTAL_WEIGHT = COLORS.reduce((s, c) => s + c.weight, 0);
+
+function pickColor() {
+ let r = Math.random() * TOTAL_WEIGHT;
+ for (const c of COLORS) {
+ r -= c.weight;
+ if (r <= 0) return c.color;
+ }
+ return COLORS[0].color;
+}
+
+function pickDigit() {
+ return DIGITS[Math.floor(Math.random() * DIGITS.length)];
+}
+
+export default function ClickEffect() {
+ const canvasRef = useRef(null);
+
+ useEffect(() => {
+ const canvas = canvasRef.current;
+ if (!canvas) return;
+ const ctx = canvas.getContext('2d');
+ let particles = [];
+ let raf;
+
+ function resize() {
+ canvas.width = window.innerWidth;
+ canvas.height = window.innerHeight;
+ }
+ resize();
+ window.addEventListener('resize', resize);
+
+ function spawn(x, y) {
+ const count = 8 + Math.floor(Math.random() * 7);
+ for (let i = 0; i < count; i++) {
+ const angle = Math.random() * Math.PI * 2;
+ const speed = 1.2 + Math.random() * 4;
+ const fontSize = 10 + Math.floor(Math.random() * 8); // 10–17px
+ particles.push({
+ x, y,
+ vx: Math.cos(angle) * speed,
+ vy: Math.sin(angle) * speed - 2, // bias upward
+ alpha: 0.9 + Math.random() * 0.1,
+ decay: 0.025 + Math.random() * 0.025,
+ color: pickColor(),
+ digit: pickDigit(),
+ fontSize,
+ font: `${fontSize}px "Courier New", monospace`,
+ });
+ }
+ }
+
+ function animate() {
+ ctx.clearRect(0, 0, canvas.width, canvas.height);
+ particles = particles.filter(p => p.alpha > 0);
+ for (const p of particles) {
+ p.x += p.vx;
+ p.y += p.vy;
+ p.vy += 0.18; // gravity
+ p.vx *= 0.97; // drag
+ p.alpha -= p.decay;
+
+ ctx.globalAlpha = Math.max(0, p.alpha);
+ ctx.fillStyle = p.color;
+ ctx.font = p.font;
+ ctx.fillText(p.digit, Math.round(p.x), Math.round(p.y));
+ }
+ ctx.globalAlpha = 1;
+ raf = requestAnimationFrame(animate);
+ }
+ animate();
+
+ function onClick(e) { spawn(e.clientX, e.clientY); }
+ document.addEventListener('click', onClick);
+
+ return () => {
+ cancelAnimationFrame(raf);
+ document.removeEventListener('click', onClick);
+ window.removeEventListener('resize', resize);
+ };
+ }, []);
+
+ return (
+
+ );
+}
diff --git a/src/components/ContactSection/index.js b/src/components/ContactSection/index.js
new file mode 100644
index 0000000..e1052d8
--- /dev/null
+++ b/src/components/ContactSection/index.js
@@ -0,0 +1,37 @@
+import React from 'react';
+import styles from './styles.module.css';
+
+const links = [
+ { label: 'GitHub', href: 'https://github.com/autobase-tech/' },
+ { label: 'X', href: 'https://x.com/autobase_tech' },
+ { label: 'LinkedIn ', href: 'https://www.linkedin.com/company/autobasetech/' },
+ { label: 'YouTube', href: 'https://youtube.com/@autobasetech' },
+ { label: 'Telegram', href: 'https://t.me/pavel_kovcheg' },
+ { label: 'Email', href: 'mailto:info@autobase.tech' },
+ { label: 'Support', href: '/docs/support' },
+];
+
+export default function ContactSection() {
+ return (
+
+
+
Contact
+
+ {links.map((link, index) => (
+
+ {index > 0 && | }
+
+ {link.label}
+
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/ContactSection/styles.module.css b/src/components/ContactSection/styles.module.css
new file mode 100644
index 0000000..468b860
--- /dev/null
+++ b/src/components/ContactSection/styles.module.css
@@ -0,0 +1,66 @@
+/* ─── Section ─────────────────────────────────────────────────────── */
+.section {
+ background:
+ linear-gradient(to right, transparent 10%, var(--color-border) 10%, var(--color-border) 90%, transparent 90%) no-repeat 0 0 / 100% 1px,
+ var(--color-bg);
+ padding: 32px 0 48px;
+ margin-top: 0;
+}
+
+.inner {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 80px;
+ display: flex;
+ align-items: baseline;
+ gap: 28px;
+}
+
+.title {
+ font-family: var(--font-base);
+ font-size: var(--fs-body);
+ font-weight: var(--fw-semibold);
+ color: var(--color-text);
+ margin: 0;
+ flex-shrink: 0;
+}
+
+.links {
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 0 14px;
+ font-family: var(--font-base);
+ font-size: var(--fs-sm);
+ color: var(--color-text-muted);
+}
+
+.link {
+ color: var(--color-text-muted);
+ text-decoration: none;
+ transition: color 0.15s ease;
+}
+
+.link:hover {
+ color: var(--color-text);
+ text-decoration: none;
+}
+
+.separator {
+ color: var(--color-border);
+}
+
+/* ─── Responsive ──────────────────────────────────────────────────── */
+@media (max-width: 900px) {
+ .inner {
+ padding: 0 48px;
+ flex-direction: column;
+ gap: 12px;
+ }
+}
+
+@media (max-width: 600px) {
+ .section { padding: 28px 0 40px; }
+ .inner { padding: 0 20px; }
+ .links { gap: 2px 10px; }
+}
diff --git a/src/components/FeaturesGridSection/index.js b/src/components/FeaturesGridSection/index.js
new file mode 100644
index 0000000..cd18afe
--- /dev/null
+++ b/src/components/FeaturesGridSection/index.js
@@ -0,0 +1,95 @@
+import React from 'react';
+import styles from './styles.module.css';
+
+const features = [
+ {
+ icon: (
+
+
+
+
+ ),
+ label: 'HA',
+ title: 'High Availability',
+ description: 'Automatic High Availability',
+ },
+ {
+ icon: (
+
+
+
+
+
+ ),
+ label: 'Failover',
+ title: 'Failover',
+ description: 'Automatic Failover & Self-Healing',
+ },
+ {
+ icon: (
+
+
+
+
+
+
+ ),
+ label: 'Backups',
+ title: 'Backups',
+ description: 'Continuous Backups',
+ },
+ {
+ icon: (
+
+
+
+
+
+
+
+ ),
+ label: 'PITR',
+ title: 'PITR',
+ description: 'Point-in-Time Recovery',
+ },
+ {
+ icon: (
+
+
+
+
+ ),
+ label: 'Monitoring',
+ title: 'Monitoring',
+ description: 'Built-in Metrics & Alerting',
+ },
+ {
+ icon: (
+
+
+
+
+ ),
+ label: 'Upgrades',
+ title: 'Upgrades',
+ description: 'Zero-Downtime Upgrades',
+ },
+];
+
+export default function FeaturesGridSection() {
+ return (
+
+
+
+ {features.map((f) => (
+
+
{f.icon}
+
{f.label}
+
{f.description}
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/FeaturesGridSection/styles.module.css b/src/components/FeaturesGridSection/styles.module.css
new file mode 100644
index 0000000..a12fb70
--- /dev/null
+++ b/src/components/FeaturesGridSection/styles.module.css
@@ -0,0 +1,93 @@
+/* ─── Section ─────────────────────────────────────────────────────── */
+.section {
+ background:
+ linear-gradient(to right, transparent 10%, var(--color-border) 10%, var(--color-border) 90%, transparent 90%) no-repeat 0 0 / 100% 1px,
+ var(--color-bg);
+ padding: var(--section-pt) 0 var(--section-pb);
+}
+
+.inner {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 200px;
+}
+
+/* ─── Grid ────────────────────────────────────────────────────────── */
+.grid {
+ display: grid;
+ grid-template-columns: repeat(6, 1fr);
+ gap: 0;
+ border: 1px solid var(--color-border);
+ border-radius: 8px;
+ overflow: hidden;
+}
+
+/* ─── Card ────────────────────────────────────────────────────────── */
+.card {
+ display: flex;
+ flex-direction: column;
+ gap: 12px;
+ padding: 32px 24px;
+ border-right: 1px solid var(--color-border);
+ transition: background 0.2s ease;
+}
+
+.card:last-child {
+ border-right: none;
+}
+
+.card:hover {
+ background: var(--color-surface);
+}
+
+/* ─── Icon ────────────────────────────────────────────────────────── */
+.icon {
+ color: var(--color-text);
+ display: flex;
+ align-items: center;
+}
+
+/* ─── Label ───────────────────────────────────────────────────────── */
+.label {
+ font-family: var(--font-base);
+ font-size: var(--fs-sm);
+ font-weight: var(--fw-bold);
+ color: var(--color-text);
+}
+
+/* ─── Description ─────────────────────────────────────────────────── */
+.description {
+ font-family: var(--font-base);
+ font-size: 13px;
+ font-weight: var(--fw-regular);
+ color: var(--color-text-muted);
+ line-height: 1.5;
+}
+
+/* ─── Responsive ──────────────────────────────────────────────────── */
+@media (max-width: 1200px) {
+ .inner { padding: 0 80px; }
+}
+
+@media (max-width: 1100px) {
+ .inner { padding: 0 48px; }
+ .grid { grid-template-columns: repeat(3, 1fr); }
+ .card:nth-child(3) { border-right: none; }
+ .card:nth-child(n+4) { border-top: 1px solid var(--color-border); }
+}
+
+@media (max-width: 768px) {
+ .inner { padding: 0 20px; }
+ .grid { grid-template-columns: repeat(2, 1fr); }
+ .card:nth-child(3) { border-right: 1px solid var(--color-border); }
+ .card:nth-child(2n) { border-right: none; }
+ .card:nth-child(n+3) { border-top: 1px solid var(--color-border); }
+}
+
+@media (max-width: 480px) {
+ .inner { padding: 0 16px; }
+ .grid { grid-template-columns: 1fr; }
+ .card { border-right: none; border-top: none; border-bottom: 1px solid var(--color-border); }
+ .card:last-child { border-bottom: none; }
+ .card:nth-child(n) { border-right: none; border-top: none; }
+}
diff --git a/src/components/HeroSection/index.js b/src/components/HeroSection/index.js
index d08bfb5..63ee467 100644
--- a/src/components/HeroSection/index.js
+++ b/src/components/HeroSection/index.js
@@ -1,126 +1,68 @@
-import React, { useEffect, useRef, useState } from 'react';
-import Link from '@docusaurus/Link';
+import React, { useState, useEffect } from 'react';
+import TrustedByCarousel from '@site/src/components/TrustedByCarousel';
import styles from './styles.module.css';
-const TYPEWRITER_TEXT = 'DBaaS Platform';
-const CHAR_SPEED = 58;
+const LINE1 = 'DATABASE PLATFORM';
+const LINE2 = 'FOR POSTGRESQL';
+const SUBTEXT = 'Self-Hosted DBaaS [Database as a Service]';
+const SPEED = 60; // ms per character
+const H1_TOTAL = LINE1.length + LINE2.length;
+const SUB_DELAY = H1_TOTAL * SPEED + 200; // starts after headline + 0.2s pause
export default function HeroSection() {
- const postgresRef = useRef(null);
- const bodyRef = useRef(null);
- const [typed, setTyped] = useState('');
- const [cursorVisible, setCursorVisible] = useState(false);
+ const [h1Count, setH1Count] = useState(0);
+ const [subCount, setSubCount] = useState(0);
+ const [subStarted, setSubStarted] = useState(false);
+ // headline typing (left → right)
useEffect(() => {
- let mounted = true;
+ if (h1Count >= H1_TOTAL) return;
+ const id = setTimeout(() => setH1Count(n => n + 1), SPEED);
+ return () => clearTimeout(id);
+ }, [h1Count]);
- import('gsap').then(({ gsap }) => {
- if (!mounted) return;
+ // subheading delay trigger
+ useEffect(() => {
+ const id = setTimeout(() => setSubStarted(true), SUB_DELAY);
+ return () => clearTimeout(id);
+ }, []);
- // 1. "PostgreSQL." — scale + opacity entrance
- gsap.fromTo(
- postgresRef.current,
- { opacity: 0, scale: 0.88, y: 10 },
- {
- opacity: 1,
- scale: 1,
- y: 0,
- duration: 0.95,
- ease: 'expo.out',
- onComplete() {
- if (!mounted) return;
- setCursorVisible(true);
- let i = 0;
- const tick = setInterval(() => {
- if (!mounted) { clearInterval(tick); return; }
- i++;
- setTyped(TYPEWRITER_TEXT.slice(0, i));
- if (i >= TYPEWRITER_TEXT.length) {
- clearInterval(tick);
- setTimeout(() => { if (mounted) setCursorVisible(false); }, 800);
- }
- }, CHAR_SPEED);
- },
- }
- );
+ // subheading typing (right → left: rightmost chars appear first)
+ useEffect(() => {
+ if (!subStarted || subCount >= SUBTEXT.length) return;
+ const id = setTimeout(() => setSubCount(n => n + 1), SPEED);
+ return () => clearTimeout(id);
+ }, [subStarted, subCount]);
- // 2. Body + CTAs fade up slightly after
- gsap.fromTo(
- bodyRef.current,
- { opacity: 0, y: 18 },
- { opacity: 1, y: 0, duration: 0.9, ease: 'expo.out', delay: 0.55 }
- );
- });
+ const c1 = Math.min(h1Count, LINE1.length);
+ const c2 = Math.max(0, h1Count - LINE1.length);
- return () => { mounted = false; };
- }, []);
+ // reverse: slice from the right, so last chars appear first
+ const subDisplayed = SUBTEXT.slice(SUBTEXT.length - subCount);
return (
-
-
-
+
-
-
- {/* Text column */}
-
-
-
-
- PostgreSQL
-
-
- {typed}
- {cursorVisible && (
- |
- )}
-
-
+
+
+ {LINE1.slice(0, c1)}
+
+
+ {LINE2.slice(0, c2)}
+
+
-
-
- Get the managed database experience inside your own infrastructure.
- Deploy, operate, scale and manage PostgreSQL with one unified platform and full infrastructure control.
-
-
-
- Get started
-
-
- Chat on Telegram
-
-
-
-
-
-
+
+ {subStarted && (
+ <>
+ {subDisplayed}
+ _
+ >
+ )}
+
- {/* Image column */}
-
-
-
-
-
+
-
-
-
);
}
diff --git a/src/components/HeroSection/styles.module.css b/src/components/HeroSection/styles.module.css
index 2d7d547..bedd7c0 100644
--- a/src/components/HeroSection/styles.module.css
+++ b/src/components/HeroSection/styles.module.css
@@ -1,236 +1,91 @@
-/* ─── Keyframes ───────────────────────────────────────────────────── */
-@keyframes heroFadeIn {
- from { opacity: 0; transform: translateY(24px); }
- to { opacity: 1; transform: translateY(0); }
+/* ─── Section ─────────────────────────────────────────────────────── */
+.hero {
+ background: var(--color-bg);
}
-@keyframes cursorBlink {
- 0%, 49% { opacity: 1; }
- 50%, 100% { opacity: 0; }
-}
-
-/* ─── Section shell ───────────────────────────────────────────────── */
-.heroSection {
- position: relative;
- overflow: hidden;
- border-bottom-left-radius: 48px;
- border-bottom-right-radius: 48px;
- background: linear-gradient(98.84deg, #000000 2.84%, #290a00 42.32%, #1a0600 95.10%);
-}
-
-/* ─── Background texture ──────────────────────────────────────────── */
-.bgTexture {
- position: absolute;
- bottom: -288px;
- left: 0;
- width: 1600px;
- height: 1600px;
- opacity: 0.08;
- pointer-events: none;
- object-fit: cover;
- z-index: 0;
-}
-
-/* ─── Max-width centering wrapper (Bootstrap row lives inside) ────── */
.inner {
- max-width: 1540px;
- margin: 0 auto;
- padding: 0 160px;
position: relative;
- z-index: 1;
-}
-
-/* ─── Left content column ─────────────────────────────────────────── */
-.content {
+ width: 100%;
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 60px 80px 48px;
display: flex;
flex-direction: column;
- gap: 50px;
+ gap: 24px;
}
-/* Body + CTAs wrapper (animated together by GSAP) */
-.bodyWrap {
- display: flex;
- flex-direction: column;
- gap: 50px;
+.inner::after {
+ content: '';
+ position: absolute;
+ right: 80px;
+ bottom: 0;
+ left: 80px;
+ height: 1px;
+ background: var(--color-border);
}
-/* ─── Heading — type.hero.900 ─────────────────────────────────────── */
+/* ─── Heading — Quantico Bold ─────────────────────────────────────── */
.heading {
- font-family: var(--font-base);
- font-size: var(--fs-hero);
- font-weight: var(--fw-black);
+ font-family: 'Quantico', sans-serif;
+ font-size: clamp(36px, 5vw, 64px);
+ font-weight: 700;
line-height: 1.05;
+ color: var(--color-text);
+ letter-spacing: -1px;
margin: 0;
- padding: 0;
-}
-
-.headingWhite {
- color: var(--color-white);
- display: block;
}
-/* Second heading line — block container for gradient text + cursor */
-.headingLine2 {
+.line {
display: block;
min-height: 1.05em;
}
-.headingGradient {
- display: inline;
- background: linear-gradient(to right, var(--color-primary-alt), var(--color-gradient-end));
- -webkit-background-clip: text;
- -webkit-text-fill-color: transparent;
- background-clip: text;
-}
-
-/* Blinking cursor during typewriter */
-.typingCursor {
- display: inline;
- color: var(--color-primary-alt);
- -webkit-text-fill-color: var(--color-primary-alt);
- font-weight: var(--fw-light);
- animation: cursorBlink 0.6s step-end infinite;
- margin-left: 2px;
+/* ─── Terminal cursor ─────────────────────────────────────────────── */
+.cursor {
+ display: inline-block;
+ color: var(--color-text);
+ animation: blink 1s step-end infinite;
user-select: none;
}
-/* ─── Body copy — type.body.200 ───────────────────────────────────── */
-.body {
- font-family: var(--font-base);
- font-size: var(--fs-body);
- font-weight: var(--fw-light);
- line-height: 1.6;
- color: var(--color-white);
- margin: 0;
-}
-
-/* ─── CTA row ─────────────────────────────────────────────────────── */
-.ctaRow {
- display: flex;
- align-items: center;
- gap: 12px;
- flex-wrap: wrap;
+@keyframes blink {
+ 0%, 100% { opacity: 1; }
+ 50% { opacity: 0; }
}
-/* ─── CTA buttons — type.btn.700 ─────────────────────────────────── */
-.ctaPrimary,
-.ctaSecondary {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- height: 54px;
- padding: 0 20px;
- border-radius: 6px;
+/* ─── Subheading ──────────────────────────────────────────────────── */
+.subheading {
font-family: var(--font-base);
- font-size: var(--fs-btn);
- font-weight: var(--fw-bold);
- text-decoration: none;
- cursor: pointer;
- white-space: nowrap;
- transition: opacity 0.2s ease, transform 0.15s ease;
-}
-
-.ctaPrimary {
- min-width: 165px;
- background: var(--color-primary);
- color: var(--color-white);
- border: none;
-}
-
-.ctaPrimary:hover {
- opacity: 0.88;
- transform: translateY(-1px);
- color: var(--color-white);
- text-decoration: none;
-}
-
-.ctaSecondary {
- gap: 6px;
- background: transparent;
- color: var(--color-white);
- border: 1px solid var(--color-primary);
-}
-
-.ctaSecondary:hover {
- opacity: 0.88;
- transform: translateY(-1px);
- color: var(--color-white);
- text-decoration: none;
+ font-size: clamp(20px, 2.5vw, 24px);
+ font-weight: var(--fw-regular);
+ color: var(--color-text-muted);
+ margin: 0;
}
-/* ─── Hero image ──────────────────────────────────────────────────── */
-.heroImage {
- width: 100%;
- max-width: 714px;
- height: auto;
- object-fit: contain;
- pointer-events: none;
- display: block;
- animation: heroFadeIn 0.8s ease-out 0.15s both;
-}
+/* ─── Responsive ──────────────────────────────────────────────────── */
+@media (max-width: 1100px) {
+ .inner { padding: 48px 48px 32px; }
-/* ─── Decorative grid dots ────────────────────────────────────────── */
-.gridDotsLg {
- position: absolute;
- right: 120px;
- bottom: 80px;
- width: 81px;
- height: 81px;
- pointer-events: none;
- z-index: 1;
- opacity: 0.7;
+ .inner::after {
+ right: 48px;
+ left: 48px;
+ }
}
-.gridDotsSm {
- position: absolute;
- right: 490px;
- top: 245px;
- width: 31px;
- height: 31px;
- pointer-events: none;
- z-index: 1;
- opacity: 0.7;
-}
+@media (max-width: 768px) {
+ .inner { padding: 40px 28px 28px; }
-/* ─── Responsive ──────────────────────────────────────────────────── */
-@media (min-width: 1920px) {
- .inner {
- max-width: 1660px;
- padding: 0 128px;
+ .inner::after {
+ right: 28px;
+ left: 28px;
}
-
- .heroImage { max-width: 620px; }
}
-@media (max-width: 1680px) {
- .heroImage { max-width: 480px; }
-}
-
-@media (max-width: 1440px) {
- .inner { padding: 0 96px; }
- .heading { font-size: 56px; }
- .heroImage { max-width: 420px; }
-}
+@media (max-width: 480px) {
+ .inner { padding: 32px 20px 24px; }
-@media (max-width: 900px) {
- .heroSection {
- border-bottom-left-radius: 32px;
- border-bottom-right-radius: 32px;
+ .inner::after {
+ right: 20px;
+ left: 20px;
}
- .inner :global(.row) {
- --bs-gutter-x: 0;
- margin-left: 0;
- margin-right: 0;
- }
- .inner { padding: 120px 48px 80px; }
- .heading { font-size: 52px; }
- .gridDotsLg, .gridDotsSm { display: none; }
-}
-
-@media (max-width: 600px) {
- .inner { padding: 100px 24px 60px; }
- .heading { font-size: 40px; }
- .body { font-size: var(--fs-sm); }
- .ctaRow { flex-direction: column; align-items: stretch; }
- .ctaPrimary, .ctaSecondary { justify-content: center; width: 100%; }
}
diff --git a/src/components/ProductHighlightsSection/index.js b/src/components/ProductHighlightsSection/index.js
new file mode 100644
index 0000000..e051149
--- /dev/null
+++ b/src/components/ProductHighlightsSection/index.js
@@ -0,0 +1,58 @@
+import React from 'react';
+import styles from './styles.module.css';
+
+const highlights = [
+ {
+ icon: (
+
+
+
+
+ ),
+ title: 'Open Source',
+ description: 'MIT License',
+ },
+ {
+ icon: (
+
+
+
+
+
+ ),
+ title: 'Self-Hosted',
+ description: 'Full control. No vendor lock-in.',
+ },
+ {
+ icon: (
+
+
+
+ ),
+ title: 'Production Ready',
+ description: 'Battle-tested. Built for reliability.',
+ },
+];
+
+export default function ProductHighlightsSection() {
+ return (
+
+
+
+ {highlights.map((h, i) => (
+
+
+
{h.icon}
+
+
{h.title}
+
{h.description}
+
+
+ {i < highlights.length - 1 &&
}
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/ProductHighlightsSection/styles.module.css b/src/components/ProductHighlightsSection/styles.module.css
new file mode 100644
index 0000000..4af81d0
--- /dev/null
+++ b/src/components/ProductHighlightsSection/styles.module.css
@@ -0,0 +1,108 @@
+/* ─── Section ─────────────────────────────────────────────────────── */
+.section {
+ background:
+ linear-gradient(to right, transparent 10%, var(--color-border) 10%, var(--color-border) 90%, transparent 90%) no-repeat 0 0 / 100% 1px,
+ linear-gradient(to right, transparent 10%, var(--color-border) 10%, var(--color-border) 90%, transparent 90%) no-repeat 0 100% / 100% 1px,
+ var(--color-bg);
+ padding: var(--section-pt) 0 var(--section-pb);
+}
+
+.inner {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 80px;
+}
+
+/* ─── Row ─────────────────────────────────────────────────────────── */
+.row {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 0;
+}
+
+/* ─── Item ────────────────────────────────────────────────────────── */
+.item {
+ display: flex;
+ align-items: center;
+ gap: 20px;
+ flex: 1;
+ justify-content: center;
+ padding: 0 40px;
+}
+
+/* ─── Icon ────────────────────────────────────────────────────────── */
+.icon {
+ color: var(--color-primary);
+ flex-shrink: 0;
+}
+
+/* ─── Text ────────────────────────────────────────────────────────── */
+.text {
+ display: flex;
+ flex-direction: column;
+ gap: 4px;
+}
+
+.title {
+ font-family: var(--font-base);
+ font-size: var(--fs-body-lg);
+ font-weight: var(--fw-bold);
+ line-height: 1.1;
+ color: var(--color-text);
+}
+
+.description {
+ font-family: var(--font-base);
+ font-size: var(--fs-sm);
+ font-weight: var(--fw-regular);
+ color: var(--color-text-muted);
+}
+
+/* ─── Divider ─────────────────────────────────────────────────────── */
+.divider {
+ width: 1px;
+ height: 60px;
+ background: var(--color-border);
+ flex-shrink: 0;
+}
+
+/* ─── Responsive ──────────────────────────────────────────────────── */
+@media (max-width: 900px) {
+ .inner { padding: 0 48px; }
+ .row {
+ flex-direction: column;
+ align-items: center;
+ gap: 28px;
+ }
+ .divider {
+ width: 88px;
+ height: 1px;
+ }
+ .item {
+ display: grid;
+ grid-template-columns: 64px minmax(0, 1fr);
+ align-items: center;
+ gap: 18px;
+ width: min(100%, 420px);
+ padding: 0;
+ justify-content: initial;
+ }
+ .icon {
+ justify-self: center;
+ }
+}
+
+@media (max-width: 600px) {
+ .inner { padding: 0 20px; }
+ .item {
+ grid-template-columns: 56px minmax(0, 1fr);
+ gap: 14px;
+ width: min(100%, 360px);
+ }
+ .icon svg { width: 40px; height: 40px; }
+}
+
+@media (max-width: 480px) {
+ .inner { padding: 0 16px; }
+}
diff --git a/src/components/SideNavbar/index.js b/src/components/SideNavbar/index.js
new file mode 100644
index 0000000..0ef1634
--- /dev/null
+++ b/src/components/SideNavbar/index.js
@@ -0,0 +1,94 @@
+import React, { useState, useEffect } from 'react';
+import Link from '@docusaurus/Link';
+import styles from './styles.module.css';
+
+function DocsIcon() {
+ return (
+
+
+
+
+ );
+}
+
+function GitHubIcon() {
+ return (
+
+
+
+ );
+}
+
+export default function SideNavbar() {
+ const [visible, setVisible] = useState(false);
+
+ useEffect(() => {
+ // Show side nav after top navbar (72px) has fully left the viewport
+ const THRESHOLD = 80;
+ let ticking = false;
+
+ const onScroll = () => {
+ if (!ticking) {
+ requestAnimationFrame(() => {
+ setVisible(window.scrollY > THRESHOLD);
+ ticking = false;
+ });
+ ticking = true;
+ }
+ };
+
+ window.addEventListener('scroll', onScroll, { passive: true });
+ return () => window.removeEventListener('scroll', onScroll);
+ }, []);
+
+ return (
+
+ {/* Logo */}
+
+
+
+
+
+
+ {/* Docs */}
+
+
+
+
+
+
+ {/* GitHub */}
+
+
+
+
+
+
+ {/* Demo */}
+
+ DEMO
+
+
+ );
+}
diff --git a/src/components/SideNavbar/styles.module.css b/src/components/SideNavbar/styles.module.css
new file mode 100644
index 0000000..b118ccc
--- /dev/null
+++ b/src/components/SideNavbar/styles.module.css
@@ -0,0 +1,120 @@
+/* ─── Sidebar shell ────────────────────────────────────────────────── */
+.sidebar {
+ --font-base: 'Quantico', sans-serif;
+ --color-bg: #ffffff;
+ --color-surface: #f9f9f9;
+ --color-text: #111111;
+ --color-border: #e0e0e0;
+ --color-primary: #ff5722;
+ position: fixed;
+ left: 0;
+ top: 0;
+ height: 100vh;
+ width: 64px;
+ z-index: 190;
+ background: var(--color-bg);
+ border-right: 1px solid var(--color-border);
+
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ padding: 28px 0;
+ gap: 20px;
+
+ /* Hidden by default — slides in from left */
+ transform: translateX(-100%);
+ opacity: 0;
+ transition:
+ transform 0.38s cubic-bezier(0.34, 1.46, 0.64, 1),
+ opacity 0.22s ease;
+
+}
+
+.visible {
+ transform: translateX(0);
+ opacity: 1;
+}
+
+/* ─── Logo ─────────────────────────────────────────────────────────── */
+.logoLink {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 40px;
+ border-radius: 8px;
+ transition: opacity 0.15s ease;
+ text-decoration: none;
+}
+
+.logoLink:hover {
+ opacity: 0.72;
+ text-decoration: none;
+}
+
+.logoImg {
+ display: block;
+}
+
+/* ─── Divider ──────────────────────────────────────────────────────── */
+.divider {
+ width: 28px;
+ height: 1px;
+ background: var(--color-border);
+ flex-shrink: 0;
+}
+
+/* ─── Icon links ───────────────────────────────────────────────────── */
+.iconLink {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 40px;
+ height: 40px;
+ border-radius: 8px;
+ color: hsl(0, 0%, 55%);
+ text-decoration: none;
+ transition: color 0.15s ease, background 0.15s ease;
+}
+
+.iconLink:hover {
+ color: var(--color-text);
+ background: var(--color-surface);
+ text-decoration: none;
+}
+
+/* ─── Demo button ──────────────────────────────────────────────────── */
+.demoBtn {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 44px;
+ height: 32px;
+ border: 1px solid var(--color-border);
+ border-radius: 4px;
+ text-decoration: none;
+ transition: border-color 0.15s ease, color 0.15s ease;
+}
+
+.demoBtn:hover {
+ border-color: var(--color-primary);
+ text-decoration: none;
+}
+
+.demoBtn:hover .demoBtnText {
+ color: var(--color-primary);
+}
+
+.demoBtnText {
+ font-family: var(--font-base);
+ font-size: 10px;
+ font-weight: 600;
+ letter-spacing: 0.8px;
+ color: hsl(0, 0%, 48%);
+ transition: color 0.15s ease;
+}
+
+/* ─── Mobile: never show ───────────────────────────────────────────── */
+@media (max-width: 768px) {
+ .sidebar { display: none; }
+}
diff --git a/src/components/SocialProofSection/index.js b/src/components/SocialProofSection/index.js
new file mode 100644
index 0000000..606542a
--- /dev/null
+++ b/src/components/SocialProofSection/index.js
@@ -0,0 +1,114 @@
+import React from 'react';
+import styles from './styles.module.css';
+
+function CalendarWithClockIcon() {
+ return (
+
+ {/* Calendar body */}
+
+ {/* Top bar */}
+
+
+ {/* Ring tabs */}
+
+
+ {/* Date dots — row 1 */}
+
+
+
+ {/* Date dots — row 2 */}
+
+
+
+ {/* Date dots — row 3 */}
+
+
+
+ {/* Clock overlay — bottom right */}
+
+
+
+
+
+ );
+}
+
+function StopwatchIcon() {
+ return (
+
+ {/* Speed lines */}
+
+
+
+ {/* Top button */}
+
+ {/* Stopwatch circle */}
+
+ {/* Side crown/button */}
+
+
+ {/* "10" text */}
+ 10
+ {/* "MIN" text */}
+ MIN
+
+ );
+}
+
+export default function SocialProofSection() {
+ return (
+
+
+
+
+ {/* Left — text */}
+
+
1 Month of Infrastructure Work
+
10 Minutes in Autobase
+
+
+
+ {/* Right — visual */}
+
+
+
+
+ 1 MONTH
+
+
+ {/* Arrow */}
+
+
+
+
+
+
+
+
+
+ 10 MINUTES
+
+
+
+
+
+
+ );
+}
diff --git a/src/components/SocialProofSection/styles.module.css b/src/components/SocialProofSection/styles.module.css
new file mode 100644
index 0000000..2cd8d02
--- /dev/null
+++ b/src/components/SocialProofSection/styles.module.css
@@ -0,0 +1,120 @@
+/* ─── Section ─────────────────────────────────────────────────────── */
+.section {
+ background: var(--color-bg);
+ padding: 0 0 16px;
+ margin-bottom: 0;
+}
+
+.inner {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 80px;
+}
+
+/* ─── Banner card ─────────────────────────────────────────────────── */
+.banner {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 60px;
+ padding: 40px 52px;
+ border: 1px solid var(--color-border);
+ border-radius: 2px;
+ background: var(--color-bg);
+ box-shadow: 8px 8px 0 rgba(0, 0, 0, 0.05);
+ transition:
+ border-color 0.16s ease,
+ box-shadow 0.16s ease;
+}
+
+.banner:hover {
+ border-color: var(--color-primary);
+ box-shadow: 10px 10px 0 rgba(0, 0, 0, 0.1);
+}
+
+/* ─── Text block ──────────────────────────────────────────────────── */
+.text {
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+}
+
+.before {
+ font-family: var(--font-base);
+ font-size: clamp(22px, 2.5vw, 30px);
+ font-weight: var(--fw-bold);
+ color: var(--color-text);
+ margin: 0;
+ line-height: 1.2;
+}
+
+.after {
+ font-family: var(--font-base);
+ font-size: clamp(22px, 2.5vw, 30px);
+ font-weight: var(--fw-black);
+ color: var(--color-primary);
+ margin: 0;
+ line-height: 1.2;
+}
+
+.underbar {
+ display: block;
+ width: 40px;
+ height: 3px;
+ background: var(--color-primary);
+ border-radius: 2px;
+ margin-top: 10px;
+}
+
+/* ─── Visual block ────────────────────────────────────────────────── */
+.visual {
+ display: flex;
+ align-items: center;
+ gap: 28px;
+ flex-shrink: 0;
+}
+
+.timeBlock {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 10px;
+}
+
+.timeLabel {
+ font-family: var(--font-base);
+ font-size: 12px;
+ font-weight: var(--fw-bold);
+ color: var(--color-text);
+ letter-spacing: 1.2px;
+}
+
+.accentLabel {
+ color: var(--color-primary);
+}
+
+.arrow {
+ flex-shrink: 0;
+}
+
+.divider {
+ width: 1px;
+ height: 80px;
+ background: var(--color-border);
+ flex-shrink: 0;
+}
+
+/* ─── Responsive ──────────────────────────────────────────────────── */
+@media (max-width: 900px) {
+ .inner { padding: 0 48px; }
+ .banner { flex-direction: column; gap: 32px; text-align: center; padding: 36px 40px; }
+ .underbar { margin: 10px auto 0; }
+}
+
+@media (max-width: 600px) {
+ .inner { padding: 0 20px; }
+ .banner { flex-direction: column; gap: 24px; padding: 28px 24px; }
+ .visual { gap: 16px; }
+ .divider { display: none; }
+ .before, .after { font-size: clamp(18px, 5vw, 24px); }
+}
diff --git a/src/components/TrustedByCarousel/index.js b/src/components/TrustedByCarousel/index.js
new file mode 100644
index 0000000..a54f67a
--- /dev/null
+++ b/src/components/TrustedByCarousel/index.js
@@ -0,0 +1,59 @@
+import React from 'react';
+import styles from './styles.module.css';
+
+const sponsors = [
+ { name: 'Axiom', img: '/img/sponsors/axiom.png', href: 'https://axiom.trade' },
+ { name: 'Awarebuildings', img: '/img/sponsors/awarebuildings.png', href: 'https://www.awarebuildings.com' },
+ { name: 'Antistock', img: '/img/sponsors/antistock.png', href: 'https://antistock.io' },
+ { name: 'Codefloe', img: '/img/sponsors/codefloe.png', href: 'https://codefloe.com' },
+ { name: 'Edclub', img: '/img/sponsors/edclub.png', href: 'https://www.edclub.com' },
+ { name: 'Fera', img: '/img/sponsors/fera.png', href: 'https://fera.ai' },
+ { name: 'GS Labs', img: '/img/sponsors/gs-labs.png', href: 'https://gs-labs.ru' },
+ { name: 'New Byte', img: '/img/sponsors/newbyte.png', href: 'https://newbyte.net.br' },
+ { name: 'Optiwise', img: '/img/sponsors/optiwise.png', href: 'https://optiwise.nl' },
+ { name: 'Postgres.AI', img: '/img/sponsors/postgresai.png', href: 'https://postgres.ai' },
+ { name: 'Staffery', img: '/img/sponsors/staffery.png', href: 'https://www.staffery.com' },
+ { name: 'Toncarton', img: '/img/sponsors/toncarton.png', href: 'https://www.toncarton.com' },
+ { name: 'We-Manage', img: '/img/sponsors/we-manage.png', href: 'https://we-manage.de' },
+];
+
+function LogoSet({ hidden = false }) {
+ return (
+
+ {sponsors.map((sponsor) => (
+
+
+
+ ))}
+
+ );
+}
+
+export default function TrustedByCarousel() {
+ return (
+
+
+ //
+ Trusted by teams running Autobase in production
+
+
+
+ );
+}
diff --git a/src/components/TrustedByCarousel/styles.module.css b/src/components/TrustedByCarousel/styles.module.css
new file mode 100644
index 0000000..f2c82f5
--- /dev/null
+++ b/src/components/TrustedByCarousel/styles.module.css
@@ -0,0 +1,135 @@
+.trustedBy {
+ width: 100%;
+ max-width: 920px;
+ margin-top: 2rem;
+ display: flex;
+ flex-direction: column;
+ justify-content: flex-start;
+ align-items: flex-start;
+ overflow: hidden;
+}
+
+.label {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ gap: 8px;
+ margin-bottom: 10px;
+ font-family: var(--font-base);
+ font-size: clamp(12px, 1vw, 14px);
+ color: var(--color-text-muted);
+ text-transform: uppercase;
+}
+
+.prompt {
+ color: var(--color-primary);
+}
+
+.strip {
+ position: relative;
+ width: 100%;
+ max-width: 100%;
+ overflow: hidden;
+}
+
+.strip::before,
+.strip::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ z-index: 1;
+ width: 64px;
+ pointer-events: none;
+}
+
+.strip::before {
+ left: 0;
+ background: linear-gradient(to right, var(--color-bg), transparent);
+}
+
+.strip::after {
+ right: 0;
+ background: linear-gradient(to left, var(--color-bg), transparent);
+}
+
+.track {
+ display: flex;
+ width: max-content;
+ animation: marquee 48s linear infinite;
+}
+
+.strip:hover .track {
+ animation-play-state: paused;
+}
+
+.logoSet {
+ display: flex;
+ align-items: center;
+ flex-shrink: 0;
+}
+
+.logoLink {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 160px;
+ height: 58px;
+ padding: 12px 26px;
+ flex-shrink: 0;
+}
+
+.logoImg {
+ display: block;
+ max-width: 100%;
+ max-height: 34px;
+ width: auto;
+ height: auto;
+ object-fit: contain;
+ filter: grayscale(100%) contrast(115%);
+ opacity: 0.68;
+ transition: filter 0.15s ease, opacity 0.15s ease;
+}
+
+.logoLink:hover .logoImg {
+ filter: grayscale(40%) contrast(110%);
+ opacity: 0.9;
+}
+
+@keyframes marquee {
+ from { transform: translateX(0); }
+ to { transform: translateX(-50%); }
+}
+
+@media (max-width: 768px) {
+ .trustedBy {
+ margin-top: 4px;
+ }
+
+ .logoLink {
+ width: 132px;
+ height: 52px;
+ padding: 12px 22px;
+ }
+
+ .logoImg {
+ max-height: 30px;
+ }
+}
+
+@media (max-width: 480px) {
+ .strip::before,
+ .strip::after {
+ width: 32px;
+ }
+
+ .logoLink {
+ width: 118px;
+ }
+}
+
+@media (prefers-reduced-motion: reduce) {
+ .track {
+ animation: none;
+ }
+}
diff --git a/src/components/ValuePropsSection/index.js b/src/components/ValuePropsSection/index.js
new file mode 100644
index 0000000..f4877d0
--- /dev/null
+++ b/src/components/ValuePropsSection/index.js
@@ -0,0 +1,85 @@
+import React, { useRef, useEffect } from 'react';
+import styles from './styles.module.css';
+
+const props = [
+ {
+ icon: (
+
+
+ {'> _'}
+
+ ),
+ title: 'Your Infrastructure',
+ description: 'Deploy anywhere. Stay in control.',
+ },
+ {
+ icon: (
+
+
+
+
+
+ ),
+ title: 'Your Data',
+ description: 'Your data never leaves your infrastructure.',
+ },
+ {
+ icon: (
+
+
+
+
+ ),
+ title: 'Your Security',
+ description: 'Your network. Your rules.',
+ },
+];
+
+export default function ValuePropsSection() {
+ const gridRef = useRef(null);
+
+ useEffect(() => {
+ let ctx;
+ import('gsap').then(({ gsap }) =>
+ import('gsap/ScrollTrigger').then(({ ScrollTrigger }) => {
+ gsap.registerPlugin(ScrollTrigger);
+ ctx = gsap.context(() => {
+ gsap.fromTo(
+ gridRef.current?.querySelectorAll(`.${styles.card}`),
+ { opacity: 0, scale: 0.6, y: -10 },
+ {
+ opacity: 1,
+ scale: 1,
+ y: 0,
+ duration: 0.55,
+ ease: 'back.out(1.4)',
+ stagger: 0.12,
+ scrollTrigger: {
+ trigger: gridRef.current,
+ start: 'top 85%',
+ once: true,
+ },
+ }
+ );
+ });
+ })
+ );
+ return () => ctx?.revert();
+ }, []);
+
+ return (
+
+
+
+ {props.map((p) => (
+
+
{p.icon}
+
{p.title}
+
{p.description}
+
+ ))}
+
+
+
+ );
+}
diff --git a/src/components/ValuePropsSection/styles.module.css b/src/components/ValuePropsSection/styles.module.css
new file mode 100644
index 0000000..cb32821
--- /dev/null
+++ b/src/components/ValuePropsSection/styles.module.css
@@ -0,0 +1,92 @@
+/* ─── Section ─────────────────────────────────────────────────────── */
+.section {
+ background: var(--color-bg);
+ padding: var(--section-pt) 0 var(--section-pb);
+}
+
+.inner {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 0 80px;
+}
+
+/* ─── Grid ────────────────────────────────────────────────────────── */
+.grid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 24px;
+}
+
+/* ─── Card ────────────────────────────────────────────────────────── */
+.card {
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ padding: 32px;
+ border: 1px solid var(--color-border);
+ border-radius: 2px;
+ background: var(--color-bg);
+ box-shadow: 8px 8px 0 rgba(0, 0, 0, 0.05);
+ transition:
+ border-color 0.16s ease,
+ box-shadow 0.16s ease,
+ color 0.16s ease;
+ opacity: 0;
+ will-change: transform, opacity;
+}
+
+.card:hover {
+ border-color: var(--color-primary);
+ box-shadow: 10px 10px 0 rgba(0, 0, 0, 0.1);
+}
+
+/* ─── Icon ────────────────────────────────────────────────────────── */
+.icon {
+ color: var(--color-text);
+ transition: color 0.16s ease;
+}
+
+.card:hover .icon {
+ color: var(--color-primary);
+}
+
+/* ─── Title ───────────────────────────────────────────────────────── */
+.title {
+ font-family: var(--font-base);
+ font-size: var(--fs-body-lg);
+ font-weight: var(--fw-bold);
+ line-height: 1.1;
+ color: var(--color-text);
+ margin: 0;
+ transition: color 0.16s ease;
+}
+
+.card:hover .title {
+ color: var(--color-primary);
+}
+
+/* ─── Description ─────────────────────────────────────────────────── */
+.description {
+ font-family: var(--font-base);
+ font-size: var(--fs-sm);
+ font-weight: var(--fw-regular);
+ color: var(--color-text-muted);
+ line-height: 1.6;
+ margin: 0;
+}
+
+/* ─── Responsive ──────────────────────────────────────────────────── */
+@media (max-width: 900px) {
+ .inner { padding: 0 48px; }
+ .grid { grid-template-columns: 1fr 1fr; gap: 16px; }
+}
+
+@media (max-width: 600px) {
+ .inner { padding: 0 20px; }
+ .grid { grid-template-columns: 1fr; gap: 12px; }
+ .card { padding: 24px 20px; gap: 12px; }
+}
+
+@media (max-width: 480px) {
+ .inner { padding: 0 16px; }
+}
diff --git a/src/css/custom.css b/src/css/custom.css
index b269b16..00607fe 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -1,4 +1,5 @@
@import url('https://fonts.googleapis.com/css2?family=Zalando+Sans+SemiExpanded:ital,wght@0,200..900;1,200..900&display=swap');
+@import url('https://fonts.googleapis.com/css2?family=Quantico:ital,wght@0,400;0,700;1,400;1,700&display=swap');
@import 'bootstrap/dist/css/bootstrap-grid.min.css';
/**
@@ -100,8 +101,8 @@ html.docs-wrapper[data-theme='light'] .theme-doc-toc-desktop {
}
.landingPage {
- --ifm-background-color: #ffffff !important;
- --ifm-background-surface-color: #ffffff !important;
+ --ifm-background-color: #F9FAFB !important;
+ --ifm-background-surface-color: #F9FAFB !important;
--ifm-font-color-base: #000000;
--ifm-heading-color: #000000;
--ifm-color-primary: #0366d6;
@@ -112,15 +113,77 @@ html.docs-wrapper[data-theme='light'] .theme-doc-toc-desktop {
--ifm-color-primary-lighter: #69b0e3;
--ifm-color-primary-lightest: #a8d1ef;
--docusaurus-highlighted-code-line-bg: rgba(0, 0, 0, 0.1);
- background-color: #ffffff;
- color: #000000;
+
+ --font-base: 'Quantico', sans-serif;
+ --fw-light: 200;
+ --fw-regular: 400;
+ --fw-medium: 500;
+ --fw-semibold: 600;
+ --fw-bold: 700;
+ --fw-black: 900;
+
+ --fs-hero: clamp(48px, 6vw, 86px);
+ --fs-h2: clamp(32px, 4vw, 58px);
+ --fs-h3: clamp(22px, 2.8vw, 38px);
+ --fs-navbar: clamp(18px, 2.2vw, 33px);
+ --fs-body-lg: clamp(18px, 2vw, 29px);
+ --fs-body: clamp(16px, 1.7vw, 24px);
+ --fs-btn: clamp(14px, 1.4vw, 22px);
+ --fs-sm: clamp(13px, 1.2vw, 19px);
+
+ --color-primary: #ff5722;
+ --color-primary-alt: #fc6902;
+ --color-gradient-end: #be987d;
+ --color-white: #ffffff;
+ --color-black: #000000;
+ --color-muted: #c7c7c7;
+ --color-bg: #F9FAFB;
+ --color-bg-alt: #f5f5f5;
+ --color-surface: #f9f9f9;
+ --color-text: #111111;
+ --color-text-muted: #555555;
+ --color-border: #e0e0e0;
+
+ --section-pt: 64px;
+ --section-pb: 64px;
+
+ background-color: var(--color-bg);
+ color: #111111;
+ font-family: var(--font-base);
+}
+
+.landingPage h1,
+.landingPage h2,
+.landingPage h3,
+.landingPage h4,
+.landingPage h5,
+.landingPage h6 {
+ font-family: var(--font-base);
+ font-weight: 700;
+}
+
+.landingPage p {
+ font-family: var(--font-base);
+ font-weight: var(--fw-light);
}
.landingPage main {
- background-color: #ffffff;
+ background-color: var(--color-bg);
+}
+
+@media (max-width: 900px) {
+ .landingPage {
+ --section-pt: 48px;
+ --section-pb: 48px;
+ }
}
@media (max-width: 768px) {
+ .landingPage {
+ --section-pt: 36px;
+ --section-pb: 36px;
+ }
+
html:has(.landingPage),
body:has(.landingPage) {
overflow-x: hidden;
diff --git a/src/pages/index.js b/src/pages/index.js
index 95a3244..354ee73 100644
--- a/src/pages/index.js
+++ b/src/pages/index.js
@@ -1,46 +1,38 @@
import React, { useEffect } from 'react';
import Layout from '@theme/Layout';
import HeroSection from '@site/src/components/HeroSection';
-import AboutSection from '@site/src/components/AboutSection';
-import ProblemSection from '@site/src/components/ProblemSection';
-import WhatIsAutobaseSection from '@site/src/components/WhatIsAutobaseSection';
-import ExplainSection from '@site/src/components/ExplainSection';
-import HowItWorksSection from '@site/src/components/HowItWorksSection';
-import FeaturedSection from '@site/src/components/FeaturedSection';
-import CloudProviders from '@site/src/components/CloudProviders';
-import VideoSection from '@site/src/components/VideoSection';
-import WhatYouGetSection from '@site/src/components/WhatYouGetSection';
-import PricingSection from '@site/src/components/PricingSection';
-import ComparisonSection from '@site/src/components/ComparisonSection';
-import Sponsors from '@site/src/components/Sponsors';
+import ArchDiagramSection from '@site/src/components/ArchDiagramSection';
+import ValuePropsSection from '@site/src/components/ValuePropsSection';
+import ProductHighlightsSection from '@site/src/components/ProductHighlightsSection';
+import CLISection from '@site/src/components/CLISection';
+import ContactSection from '@site/src/components/ContactSection';
+import SocialProofSection from '@site/src/components/SocialProofSection';
-function HomepageContent() {
+export default function Home() {
// GSAP scroll reveal — blur + fade from below, fires once per section
useEffect(() => {
- if (typeof window !== 'undefined' && window.matchMedia('(max-width: 768px)').matches) {
- return undefined;
- }
-
let ctx;
Promise.all([import('gsap'), import('gsap/ScrollTrigger')]).then(
([{ gsap }, { ScrollTrigger }]) => {
gsap.registerPlugin(ScrollTrigger);
ctx = gsap.context(() => {
document.querySelectorAll('main section').forEach((section) => {
- gsap.from(section, {
- y: 48,
- opacity: 0,
- duration: 1.0,
- ease: 'expo.out',
- immediateRender: true,
- scrollTrigger: {
- trigger: section,
- start: 'top 88%',
- once: true,
- invalidateOnRefresh: true,
- toggleActions: 'play none none none',
- },
- });
+ gsap.fromTo(
+ section,
+ { y: 32, opacity: 0, filter: 'blur(6px)' },
+ {
+ y: 0,
+ opacity: 1,
+ filter: 'blur(0px)',
+ duration: 0.85,
+ ease: 'expo.out',
+ scrollTrigger: {
+ trigger: section,
+ start: 'top 90%',
+ once: true,
+ },
+ }
+ );
});
});
}
@@ -48,34 +40,20 @@ function HomepageContent() {
return () => ctx?.revert();
}, []);
- return (
- <>
-
-
- {/* */}
- {/* */}
-
-
-
-
-
-
-
-
- {/* */}
-
-
- >
- );
-}
-
-export default function Home() {
return (
-
+
+
+
+
+
+
+
+
+
);
}
diff --git a/src/pages/index.module.css b/src/pages/index.module.css
index e635b07..71c44aa 100644
--- a/src/pages/index.module.css
+++ b/src/pages/index.module.css
@@ -67,7 +67,7 @@
}
/* Adaptive style for mobile devices */
-@media (max-width: 1440px) {
+@media (max-width: 1200px) {
.heroBanner_description,
.heroLead,
.heroBenefits {
diff --git a/src/theme/Footer/index.js b/src/theme/Footer/index.js
index 489b131..b7dff0d 100644
--- a/src/theme/Footer/index.js
+++ b/src/theme/Footer/index.js
@@ -1,26 +1,9 @@
import React from 'react';
import useBaseUrl from '@docusaurus/useBaseUrl';
import { useLocation } from '@docusaurus/router';
-import Link from '@docusaurus/Link';
import OriginalFooter from '@theme-original/Footer';
-import clsx from 'clsx';
import styles from './styles.module.css';
-const navGroups = [
- {
- title: 'Docs',
- links: [{ label: 'Introduction', href: '/docs/' }],
- },
- {
- title: 'Support',
- links: [{ label: 'Support Packages', href: '/docs/support' }],
- },
- {
- title: 'Source code',
- links: [{ label: 'GitHub', href: 'https://github.com/autobase-tech/autobase', external: true }],
- },
-];
-
function normalizePath(pathname) {
if (!pathname || pathname === '/') {
return '/';
@@ -39,125 +22,26 @@ export default function Footer(props) {
}
return (
-
+
);
}
diff --git a/src/theme/Footer/styles.module.css b/src/theme/Footer/styles.module.css
index 31eb8c6..deb0bc0 100644
--- a/src/theme/Footer/styles.module.css
+++ b/src/theme/Footer/styles.module.css
@@ -1,251 +1,76 @@
-/* ─── Footer wrapper ─────────────────────────────────────────────── */
-.footerSurface {
- background-color: #ffffff;
-}
-
+/* ─── Footer ──────────────────────────────────────────────────────── */
.footer {
- display: flex;
- flex-direction: column;
- position: relative;
- overflow: hidden;
- border-top-left-radius: 48px;
- border-top-right-radius: 48px;
- background-color: #f7f5f3;
- min-height: 100vh;
+ --font-base: 'Quantico', sans-serif;
+ --fw-regular: 400;
+ --fs-sm: clamp(13px, 1.2vw, 19px);
+ --color-bg: #F9FAFB;
+ --color-text: #111111;
+ --color-text-muted: #555555;
+ --color-border: #e0e0e0;
+ background: var(--color-bg);
}
-/* ─── Inner — constrained width, full height ──────────────────────── */
-.inner {
- flex: 1;
- display: flex;
- flex-direction: column;
- max-width: 1540px;
+.divider {
width: 100%;
- margin: 0 auto;
- padding: 0 160px;
- position: relative;
- z-index: 1;
-}
-
-/* ─── Decorative vector — right-anchored, bleeds off edge ─────────── */
-.vectorLine {
- position: absolute;
- right: -100px;
- top: 36px;
- width: 820px;
- height: 717px;
- pointer-events: none;
- z-index: 0;
-}
-
-/* ─── Hero area — fills remaining height, centers content ────────── */
-.heroArea {
- flex: 1;
- display: flex;
- align-items: center;
- padding: 80px 0;
-}
-
-.heroContent {
- display: flex;
- flex-direction: column;
- gap: 25px;
- max-width: 535px;
-}
-
-/* type.hero.900 */
-.heroHeading {
- font-family: var(--font-base);
- font-size: var(--fs-hero);
- font-weight: var(--fw-black);
- color: var(--color-black);
- line-height: 1.05;
+ height: 1px;
+ background: var(--color-border);
margin: 0;
}
-/* type.body-lg.500 */
-.heroSubtext {
- font-family: var(--font-base);
- font-size: var(--fs-body-lg);
- font-weight: var(--fw-medium);
- color: var(--color-black);
- margin: 0;
-}
-
-.orange { color: var(--color-primary); }
-
-/* ─── CTAs ───────────────────────────────────────────────────────── */
-.ctaRow {
- display: flex;
- align-items: center;
- gap: 12px;
- flex-wrap: wrap;
-}
-
-.ctaPrimary {
- display: inline-flex;
- align-items: center;
- justify-content: center;
- height: 54px;
- padding: 0 28px;
- background: var(--color-primary);
- color: var(--color-white);
- border-radius: 6px;
- font-family: var(--font-base);
- font-size: var(--fs-btn);
- font-weight: var(--fw-bold);
- text-decoration: none;
- transition: opacity 0.15s ease;
-}
-
-.ctaPrimary:hover {
- color: var(--color-white);
- opacity: 0.9;
- text-decoration: none;
-}
-
-.ctaSecondary {
- display: inline-flex;
- align-items: center;
- gap: 6px;
- height: 54px;
- padding: 0 20px;
- border: 1.5px solid var(--color-primary);
- color: var(--color-black);
- border-radius: 6px;
- font-family: var(--font-base);
- font-size: var(--fs-btn);
- font-weight: var(--fw-bold);
- text-decoration: none;
- transition: opacity 0.15s ease;
-}
-
-.ctaSecondary:hover {
- color: var(--color-black);
- opacity: 0.85;
- text-decoration: none;
-}
-
-/* ─── Footer bottom ──────────────────────────────────────────────── */
-.footerBottom {
- padding: 60px 0 44px;
- border-top: 1px solid rgba(0, 0, 0, 0.08);
-}
-
-.navRow {
- margin-bottom: 40px;
-}
-
-/* ─── Nav groups ─────────────────────────────────────────────────── */
-.navGroup {
- display: flex;
- flex-direction: column;
- gap: 10px;
- margin-right: 80px;
- margin-bottom: 24px;
-}
-
-/* type.body-lg.600 */
-.navTitle {
- font-family: var(--font-base);
- font-size: var(--fs-body-lg);
- font-weight: var(--fw-semibold);
- color: var(--color-black);
-}
-
-/* type.caption.400 */
-.navLink {
- font-family: var(--font-base);
- font-size: var(--fs-sm);
- font-weight: var(--fw-regular);
- color: rgba(0, 0, 0, 0.6);
- text-decoration: none;
- transition: color 0.15s ease;
-}
-
-.navLink:hover { color: var(--color-black); text-decoration: none; }
-
-/* ─── Social links ───────────────────────────────────────────────── */
-.socialGroup {
- display: flex;
- flex-direction: column;
- gap: 10px;
- margin-bottom: 24px;
-}
-
-.socialItem {
- display: flex;
- align-items: center;
- gap: 10px;
- font-family: var(--font-base);
- font-size: var(--fs-sm);
- font-weight: var(--fw-regular);
- color: rgba(0, 0, 0, 0.6);
- text-decoration: none;
- transition: color 0.15s ease;
-}
-
-.socialItem:hover { color: var(--color-black); text-decoration: none; }
-
-/* ─── Copyright row ──────────────────────────────────────────────── */
-.copyrightRow {
+.inner {
+ max-width: 1200px;
+ margin: 0 auto;
+ padding: 48px 80px 56px;
display: flex;
flex-direction: column;
- gap: 10px;
+ gap: 20px;
}
+/* ─── Logo ────────────────────────────────────────────────────────── */
.logoMark {
display: flex;
align-items: center;
gap: 10px;
+ margin-bottom: 4px;
}
-/* type.navbar.400 */
.logoText {
font-family: var(--font-base);
- font-size: var(--fs-navbar);
+ font-size: 20px;
font-weight: var(--fw-regular);
- color: var(--color-black);
+ color: var(--color-text);
+ line-height: 1;
}
-/* type.caption.400 */
+/* ─── Copyright ───────────────────────────────────────────────────── */
.copyright {
font-family: var(--font-base);
font-size: var(--fs-sm);
font-weight: var(--fw-regular);
- color: rgba(0, 0, 0, 0.6);
+ color: var(--color-text);
margin: 0;
+ line-height: 1.6;
}
-.billingInfo {
+/* ─── Legal text ──────────────────────────────────────────────────── */
+.legal {
font-family: var(--font-base);
- font-size: 14px;
+ font-size: clamp(12px, 1vw, 16px);
font-weight: var(--fw-regular);
- color: rgba(0, 0, 0, 0.6);
- line-height: 1.45;
+ color: var(--color-text-muted);
margin: 0;
+ line-height: 1.7;
}
-/* ─── Responsive ─────────────────────────────────────────────────── */
-@media (min-width: 1920px) {
- .inner {
- max-width: 1700px;
- padding: 0 112px;
- }
-}
-
-@media (max-width: 1440px) {
- .inner { padding: 0 96px; }
+/* ─── Responsive ──────────────────────────────────────────────────── */
+@media (max-width: 900px) {
+ .inner { padding: 40px 48px 48px; }
}
-@media (max-width: 900px) {
- .inner { padding: 0 48px; }
- .heroHeading { font-size: var(--fs-h2); }
+@media (max-width: 600px) {
+ .inner { padding: 32px 20px 40px; }
}
-@media (max-width: 768px) {
- .inner { padding: 0 24px; }
- .heroHeading { font-size: var(--fs-h3); }
- .vectorLine { display: none; }
- .navGroup { margin-right: 0; }
+@media (max-width: 480px) {
+ .inner { padding: 28px 16px 36px; }
}
diff --git a/src/theme/Navbar/index.js b/src/theme/Navbar/index.js
index 1145411..b4f5bfd 100644
--- a/src/theme/Navbar/index.js
+++ b/src/theme/Navbar/index.js
@@ -1,13 +1,17 @@
import React from 'react';
import useBaseUrl from '@docusaurus/useBaseUrl';
import { useLocation } from '@docusaurus/router';
-import { useThemeConfig } from '@docusaurus/theme-common';
-import { useHideableNavbar } from '@docusaurus/theme-common/internal';
import Link from '@docusaurus/Link';
import OriginalNavbar from '@theme-original/Navbar';
import clsx from 'clsx';
import styles from './styles.module.css';
+const navLinks = [
+ { label: '/docs', to: '/docs' },
+ { label: '/github', href: 'https://github.com/autobase-tech/autobase' },
+ { label: '/demo', href: 'https://demo.autobase.tech' },
+];
+
function normalizePath(pathname) {
if (!pathname || pathname === '/') {
return '/';
@@ -18,14 +22,8 @@ function normalizePath(pathname) {
export default function Navbar(props) {
const { pathname } = useLocation();
- const {
- navbar: { hideOnScroll },
- } = useThemeConfig();
const homePath = useBaseUrl('/');
const isHomepage = normalizePath(pathname) === normalizePath(homePath);
- const { navbarRef, isNavbarVisible } = useHideableNavbar(
- isHomepage && hideOnScroll
- );
if (!isHomepage) {
return (
@@ -36,15 +34,7 @@ export default function Navbar(props) {
}
return (
-
+
{/* Logo */}
@@ -53,54 +43,33 @@ export default function Navbar(props) {
src="/img/navbar/logo-icon.svg"
alt=""
className={styles.logoIcon}
- width={48}
- height={42}
+ width={40}
+ height={35}
/>
-
autobase
+
Autobase
- {/* Right actions */}
-
+ {/* Center nav links */}
+
+ {navLinks.map((link) =>
+ link.to ? (
+
+ {link.label}
+
+ ) : (
+
+ {link.label}
+
+ )
+ )}
+
- {/* Mobile: only "Get started" */}
-
-
- Get started
-
-
diff --git a/src/theme/Navbar/styles.module.css b/src/theme/Navbar/styles.module.css
index eaafb54..5215a86 100644
--- a/src/theme/Navbar/styles.module.css
+++ b/src/theme/Navbar/styles.module.css
@@ -8,29 +8,28 @@
}
.navbar {
- background: rgba(0, 0, 0, 0.96) !important;
- border-bottom: 1px solid rgba(255, 255, 255, 0.06);
+ --font-base: 'Quantico', sans-serif;
+ --fw-regular: 400;
+ --color-bg: #F9FAFB;
+ --color-surface: #f9f9f9;
+ --color-text: #111111;
+ --color-border: #e0e0e0;
+ --color-white: #ffffff;
+ --color-primary: #ff5722;
+ background: var(--color-bg);
padding: 0 !important;
- height: auto !important;
-}
-
-.navbarHideable {
- transition: transform var(--ifm-transition-fast) ease;
-}
-
-.navbarHidden {
- transform: translate3d(0, calc(-100% - 2px), 0);
+ height: auto;
}
-/* ─── Inner container ─────────────────────────────────────────────── */
+/* ─── Inner container — matches hero padding ──────────────────────── */
.inner {
display: flex;
align-items: center;
justify-content: space-between;
- max-width: 1540px;
+ max-width: 1200px;
margin: 0 auto;
- padding: 0 160px;
- height: 72px;
+ padding: 0 80px;
+ height: 88px;
width: 100%;
}
@@ -40,48 +39,87 @@
align-items: center;
gap: 10px;
text-decoration: none;
+ flex-shrink: 0;
}
.logo:hover {
text-decoration: none;
- opacity: 0.85;
+ opacity: 0.75;
}
.logoIcon {
display: block;
- flex-shrink: 0;
- width: 42px;
+ width: 48px;
height: auto;
}
-/* ─── Logo text — type.navbar.400 ────────────────────────────────── */
.logoText {
font-family: var(--font-base);
- font-size: 24px;
+ font-size: 26px;
font-weight: var(--fw-regular);
- color: var(--color-white);
+ color: var(--color-text);
white-space: nowrap;
line-height: 1;
}
+/* ─── Right nav links ─────────────────────────────────────────────── */
+.navLinks {
+ display: flex;
+ align-items: center;
+ gap: 32px;
+ margin-left: auto;
+}
+
+.navLink {
+ font-family: var(--font-base);
+ font-size: 17px;
+ font-weight: 400;
+ color: hsl(0, 0%, 52%);
+ text-decoration: none;
+ position: relative;
+ white-space: nowrap;
+ transition: color 0.2s ease;
+}
+
+.navLink::after {
+ content: '';
+ position: absolute;
+ left: 0;
+ bottom: -2px;
+ width: 0;
+ height: 1px;
+ background: var(--color-text);
+ transition: width 0.25s ease;
+}
+
+.navLink:hover {
+ color: var(--color-text);
+ text-decoration: none;
+}
+
+.navLink:hover::after {
+ width: 100%;
+}
+
/* ─── Right actions ───────────────────────────────────────────────── */
.actions {
display: flex;
align-items: center;
- gap: 20px;
+ gap: 16px;
+ flex-shrink: 0;
}
-/* ─── CTA buttons — type.btn.700 ─────────────────────────────────── */
+/* ─── CTA buttons (unchanged) ─────────────────────────────────────── */
.cta {
display: inline-flex;
align-items: center;
justify-content: center;
- height: 48px;
- width: 165px;
+ height: 44px;
+ padding: 0 20px;
border-radius: 6px;
font-family: var(--font-base);
- font-size: var(--fs-btn);
- font-weight: var(--fw-bold);
+ font-size: var(--fs-sm);
+ font-weight: var(--fw-regular);
white-space: nowrap;
text-decoration: none;
cursor: pointer;
@@ -100,88 +138,15 @@
border: none;
}
-.ctaPrimary:hover {
- color: var(--color-white);
-}
+.ctaPrimary:hover { color: var(--color-white); }
.ctaSecondary {
background: transparent;
- color: var(--color-white);
- border: 1px solid var(--color-primary);
-}
-
-.ctaSecondary:hover {
- color: var(--color-white);
+ color: var(--color-text);
+ border: 1px solid var(--color-border);
}
-.demoCta {
- position: relative;
-}
-
-.demoTooltip,
-.demoTooltip::after {
- position: absolute;
- left: 50%;
- opacity: 0;
- visibility: hidden;
- pointer-events: none;
- transition: opacity 0.12s ease, transform 0.12s ease, visibility 0.12s ease;
- z-index: 20;
-}
-
-.demoTooltip {
- top: calc(100% + 12px);
- transform: translateX(-50%) translateY(6px);
- display: inline-flex;
- align-items: center;
- gap: 0.28em;
- padding: 10px 14px;
- border: 1px solid rgba(255, 87, 34, 0.75);
- border-radius: 10px;
- background: rgba(10, 10, 10, 0.96);
- box-shadow: 0 12px 28px rgba(0, 0, 0, 0.28);
- color: var(--color-white);
- font-family: var(--font-base);
- font-size: 14px;
- font-weight: var(--fw-medium);
- line-height: 1.25;
- letter-spacing: 0.01em;
- white-space: nowrap;
-}
-
-.demoTooltip::after {
- content: '';
- top: calc(100% + 7px);
- width: 10px;
- height: 10px;
- background: rgba(10, 10, 10, 0.96);
- border-top: 1px solid rgba(255, 87, 34, 0.75);
- border-left: 1px solid rgba(255, 87, 34, 0.75);
- transform: translateX(-50%) translateY(6px) rotate(45deg);
-}
-
-.demoToken {
- color: var(--color-primary);
- font-weight: var(--fw-bold);
-}
-
-.demoCta:hover .demoTooltip,
-.demoCta:hover .demoTooltip::after,
-.demoCta:focus-visible .demoTooltip,
-.demoCta:focus-visible .demoTooltip::after {
- opacity: 1;
- visibility: visible;
-}
-
-.demoCta:hover .demoTooltip,
-.demoCta:focus-visible .demoTooltip {
- transform: translateX(-50%) translateY(0);
-}
-
-.demoCta:hover .demoTooltip::after,
-.demoCta:focus-visible .demoTooltip::after {
- transform: translateX(-50%) translateY(0) rotate(45deg);
-}
+.ctaSecondary:hover { color: var(--color-text); border-color: #aaaaaa; }
/* ─── Icon links ──────────────────────────────────────────────────── */
.iconLink {
@@ -191,73 +156,33 @@
width: 28px;
height: 28px;
flex-shrink: 0;
- opacity: 0.9;
- transition: opacity 0.2s ease, transform 0.15s ease;
-}
-
-.iconLink:hover {
- opacity: 1;
- transform: translateY(-1px);
-}
-
-/* ─── Mobile actions ──────────────────────────────────────────────── */
-.mobileActions {
- display: none;
-}
-
-/* ─── Responsive: ≤ 1440px ────────────────────────────────────────── */
-@media (min-width: 1920px) {
- .inner {
- max-width: 1660px;
- padding: 0 128px;
- }
+ opacity: 0.55;
+ transition: opacity 0.2s ease;
}
-@media (max-width: 1919px) {
- .inner {
- height: 64px;
- }
-
- .logoIcon {
- width: 36px;
- }
-
- .logoText {
- font-size: 22px;
- }
+.iconLink:hover { opacity: 1; }
- .actions {
- gap: 16px;
- }
+.iconLink img { filter: brightness(0); }
- .cta {
- height: 42px;
- width: 148px;
- font-size: 16px;
- }
+/* ─── Mobile ──────────────────────────────────────────────────────── */
+.mobileActions { display: none; }
- .iconLink {
- width: 26px;
- height: 26px;
- }
-}
-
-@media (max-width: 1440px) {
- .inner { padding: 0 96px; }
+/* ─── Responsive ──────────────────────────────────────────────────── */
+@media (max-width: 1100px) {
+ .inner { padding: 0 48px; }
+ .navLinks { gap: 20px; }
}
-/* ─── Responsive: ≤ 900px ─────────────────────────────────────────── */
@media (max-width: 900px) {
- .inner { padding: 0 48px; }
- .cta { width: auto; padding: 0 16px; font-size: var(--fs-sm); }
+ .navLinks { display: none; }
+ .inner { padding: 0 32px; }
}
-/* ─── Responsive: ≤ 768px ────────────────────────────────────────── */
@media (max-width: 768px) {
- .inner { padding: 0 24px; height: 58px; }
+ .inner { padding: 0 24px; height: 72px; }
+ .logoIcon { width: 42px; }
+ .logoText { font-size: 23px; }
.actions { display: none; }
.mobileActions { display: flex; align-items: center; }
- .logoIcon { width: 36px; }
- .logoText { font-size: 20px; }
- .mobileActions .cta { height: 38px; width: auto; padding: 0 16px; font-size: 15px; }
+ .mobileActions .cta { height: 40px; }
}
diff --git a/src/theme/Root.js b/src/theme/Root.js
new file mode 100644
index 0000000..b870c76
--- /dev/null
+++ b/src/theme/Root.js
@@ -0,0 +1,5 @@
+import React from 'react';
+
+export default function Root({ children }) {
+ return <>{children}>;
+}