diff --git a/blog/2022-1-28-ivorysql-arrived/index.md b/blog/2022-1-28-ivorysql-arrived/index.md
index a0bc46a..8500dec 100644
--- a/blog/2022-1-28-ivorysql-arrived/index.md
+++ b/blog/2022-1-28-ivorysql-arrived/index.md
@@ -4,7 +4,7 @@ title: IvorySQL Has Arrived
authors: [official]
authorTwitter: IvorySql
category: IvorySQL
-image: img/blog/IvorySQL-has-arrived.png
+image: img/blog/covers/ivorysql-arrived.svg
tags: [IvorySQL, Welcome, Database, Oracle Compatible, PostgreSQL, Join Us]
---
diff --git a/blog/2022-3-25-postgres-world-webinar/index.md b/blog/2022-3-25-postgres-world-webinar/index.md
index 579cb2c..24ef218 100644
--- a/blog/2022-3-25-postgres-world-webinar/index.md
+++ b/blog/2022-3-25-postgres-world-webinar/index.md
@@ -4,7 +4,7 @@ title: PostgresWorld Webinar | A Deep Dive Into IvorySQL
authors: [official]
authorTwitter: IvorySql
category: PostgreSQL
-image: img/blog/PostgresWorld-Webinar.png
+image: img/blog/covers/pg-webinar.svg
tags: [IvorySQL, PostgresWorld, Database, Oracle Compatible, PostgreSQL, Join Us]
---
diff --git a/blog/2022-4-18-sv2022/index.md b/blog/2022-4-18-sv2022/index.md
index 89085b2..40a4fc2 100644
--- a/blog/2022-4-18-sv2022/index.md
+++ b/blog/2022-4-18-sv2022/index.md
@@ -4,7 +4,7 @@ title: IvorySQL at PostgresConf SV 2022
authors: [official]
authorTwitter: IvorySql
category: PostgreSQL
-image: img/blog/PostgresConf-SV-2022.png
+image: img/blog/covers/pgconf-sv-2022.svg
tags: [IvorySQL,PostgresConf SV , Database, Oracle Compatible, PostgreSQL, Join Us]
---
diff --git a/blog/2022-5-17-linux/index.md b/blog/2022-5-17-linux/index.md
index a3a7fca..8d68722 100644
--- a/blog/2022-5-17-linux/index.md
+++ b/blog/2022-5-17-linux/index.md
@@ -4,7 +4,7 @@ title: Compiling and Installing IvorySQL on Linux
authors: [official]
authorTwitter: IvorySql
category: IvorySQL
-image: img/blog/Compiling-and-Installing-IvorySQL-on-Linux.png
+image: img/blog/covers/linux-install.svg
tags: [IvorySQL, Welcome,Linux, PostgreSQL, Join Us]
---
diff --git a/blog/2022-5-27-packages/index.md b/blog/2022-5-27-packages/index.md
index bd1705a..6810cba 100644
--- a/blog/2022-5-27-packages/index.md
+++ b/blog/2022-5-27-packages/index.md
@@ -3,7 +3,7 @@ slug: ivorysql-packages
title: Introduction to IvorySQL Packages
authors: [Asif]
category: IvorySQL
-image: img/blog/IvorySQL-packages.png
+image: img/blog/covers/ivorysql-packages.svg
tags: [IvorySQL, Oracle, Packages, PostgreSQL, Join Us]
---
diff --git a/blog/2022-5-6-yum/index.md b/blog/2022-5-6-yum/index.md
index 48275fd..8083e06 100644
--- a/blog/2022-5-6-yum/index.md
+++ b/blog/2022-5-6-yum/index.md
@@ -4,7 +4,7 @@ title: Install software through the YUM source
authors: [official]
authorTwitter: IvorySql
category: IvorySQL
-image: img/blog/Install-software-through-the-YUM-source.png
+image: img/blog/covers/yum-install.svg
tags: [IvorySQL, Welcome, YUM, PostgreSQL, Join Us]
---
diff --git a/blog/2022-6-2-PGCon2022/index.md b/blog/2022-6-2-PGCon2022/index.md
index 24e0bef..208291b 100644
--- a/blog/2022-6-2-PGCon2022/index.md
+++ b/blog/2022-6-2-PGCon2022/index.md
@@ -4,7 +4,7 @@ title: PGCon2022 meeting review | Technical explanation of IvorySQL project
authors: [official]
authorTwitter: IvorySql
category: PostgreSQL
-image: img/blog/PGCon2022-meeting-review.png
+image: img/blog/covers/pgcon-2022.svg
tags: [IvorySQL,PGCon2022, PostgreSQL, Join Us]
---
diff --git a/blog/2024-11-27-ivorysql-high-availability/index.md b/blog/2024-11-27-ivorysql-high-availability/index.md
index a65b5fd..f024aa7 100644
--- a/blog/2024-11-27-ivorysql-high-availability/index.md
+++ b/blog/2024-11-27-ivorysql-high-availability/index.md
@@ -4,7 +4,7 @@ title: IvorySQL High Availability—Zero Loss Logical Replication Slots
authors: [official]
authorTwitter: IvorySql
category: IvorySQL
-image: img/blog/IvorySQL-High-Availability.png
+image: img/blog/covers/ha-replication.svg
tags: [IvorySQL, Database, Oracle Compatible, PostgreSQL, High Availability]
---
diff --git a/blog/2024-12-05-ivorysql-external-storage-manager/index.md b/blog/2024-12-05-ivorysql-external-storage-manager/index.md
index cba35e1..e742c23 100644
--- a/blog/2024-12-05-ivorysql-external-storage-manager/index.md
+++ b/blog/2024-12-05-ivorysql-external-storage-manager/index.md
@@ -4,7 +4,7 @@ title: External Storage Manager in IvorySQL Database
authors: [official]
authorTwitter: IvorySql
category: IvorySQL
-image: img/blog/External-Storage-Manager.png
+image: img/blog/covers/external-storage.svg
tags: [IvorySQL, Database, Oracle Compatible, PostgreSQL]
---
In general, a database storage system is divided into two parts: memory and external storage. Except for in-memory databases, data is eventually persisted, which means that it needs to be written from the memory buffer to the external storage. This article will discuss the external storage manager in IvorySQL.
diff --git a/blog/2025-01-02-ivorysql-upgrade-3.x-to-4.0/index.md b/blog/2025-01-02-ivorysql-upgrade-3.x-to-4.0/index.md
index fce0df8..be8f87e 100644
--- a/blog/2025-01-02-ivorysql-upgrade-3.x-to-4.0/index.md
+++ b/blog/2025-01-02-ivorysql-upgrade-3.x-to-4.0/index.md
@@ -4,7 +4,7 @@ title: IvorySQL Upgrade Guide-A Smooth Transition from 3.x to 4.0
authors: [official]
authorTwitter: IvorySql
category: IvorySQL
-image: img/blog/ivorysql-upgrade.png
+image: img/blog/covers/upgrade-guide.svg
tags: [IvorySQL, Database, Oracle Compatible, PostgreSQL]
---
Recently, IvorySQL 4.0 was released, offering full support for PostgreSQL 17 and enhanced compatibility with Oracle.
diff --git a/blog/2025-01-09-ivorysql-4.0-package/index.md b/blog/2025-01-09-ivorysql-4.0-package/index.md
index 0354743..a3ba230 100644
--- a/blog/2025-01-09-ivorysql-4.0-package/index.md
+++ b/blog/2025-01-09-ivorysql-4.0-package/index.md
@@ -4,7 +4,7 @@ title: IvorySQL 4.0-Design Insights into Oracle Package Compatibility Feature
authors: [official]
authorTwitter: IvorySql
category: IvorySQL
-image: img/blog/Oracle-Package-Compatibility.png
+image: img/blog/covers/oracle-package.svg
tags: [IvorySQL, Database, Oracle Compatible, PostgreSQL, Oracle Package, Package]
---
diff --git a/blog/2025-03-05-ivorysql-v4-logical-replication-slot/index.md b/blog/2025-03-05-ivorysql-v4-logical-replication-slot/index.md
index 4bca5ed..699980f 100644
--- a/blog/2025-03-05-ivorysql-v4-logical-replication-slot/index.md
+++ b/blog/2025-03-05-ivorysql-v4-logical-replication-slot/index.md
@@ -4,7 +4,7 @@ title: Analysis of the Logical Replication Slot Synchronization Feature in Ivory
authors: [official]
authorTwitter: IvorySql
category: IvorySQL
-image: img/blog/IvorySQL-Logical-Replication-Slot.png
+image: img/blog/covers/logical-replication-slot.svg
tags: [IvorySQL, Database, Oracle Compatible, PostgreSQL, Logical Replication Slot]
---
diff --git a/blog/2025-03-20-ivorySQL-incremental-backup-and-merge-features/index.md b/blog/2025-03-20-ivorySQL-incremental-backup-and-merge-features/index.md
index 4132408..2b51d29 100644
--- a/blog/2025-03-20-ivorySQL-incremental-backup-and-merge-features/index.md
+++ b/blog/2025-03-20-ivorySQL-incremental-backup-and-merge-features/index.md
@@ -4,7 +4,7 @@ title: IvorySQL Incremental Backup and Merge Features
authors: [official]
authorTwitter: IvorySql
category: IvorySQL
-image: img/blog/IvorySQL-Incremental-Backup.png
+image: img/blog/covers/incremental-backup.svg
tags: [IvorySQL, Database, Oracle Compatible, PostgreSQL, Incremental Backup]
---
diff --git a/blog/2025-05-27-ivorysql-wasm/index.md b/blog/2025-05-27-ivorysql-wasm/index.md
index e0eba42..509a827 100644
--- a/blog/2025-05-27-ivorysql-wasm/index.md
+++ b/blog/2025-05-27-ivorysql-wasm/index.md
@@ -4,7 +4,7 @@ title: IvorySQL-WASM, An Exploration Journey of Installation-Free Databases
authors: [official]
authorTwitter: IvorySql
category: IvorySQL
-image: img/blog/ivorysql-wasm.png
+image: img/blog/covers/wasm.svg
tags: [IvorySQL, Database, Oracle Compatible, PostgreSQL, WasmEdge]
---
diff --git a/blog/2025-09-26-Analysis-of-PG-18-Key-New-Features/index.md b/blog/2025-09-26-Analysis-of-PG-18-Key-New-Features/index.md
index 6277977..91dd14f 100644
--- a/blog/2025-09-26-Analysis-of-PG-18-Key-New-Features/index.md
+++ b/blog/2025-09-26-Analysis-of-PG-18-Key-New-Features/index.md
@@ -4,7 +4,7 @@ title: In-Depth Analysis of PostgreSQL 18 Key New Features
authors: [official]
authorTwitter: IvorySql
category: PostgreSQL
-image: img/blog/20250926-cover.png
+image: img/blog/covers/pg18-features.svg
tags: [IvorySQL, Database, UUIDv7, PostgreSQL, I/O, OAuth]
---
diff --git a/blog/2025-1-13-ivorysql-4.0-invisible-column/index.md b/blog/2025-1-13-ivorysql-4.0-invisible-column/index.md
index a5bd88d..44e7ad8 100644
--- a/blog/2025-1-13-ivorysql-4.0-invisible-column/index.md
+++ b/blog/2025-1-13-ivorysql-4.0-invisible-column/index.md
@@ -4,7 +4,7 @@ title: Analysis of the Invisible Column Feature in IvorySQL 4.0
authors: [official]
authorTwitter: IvorySql
category: IvorySQL
-image: img/blog/IvorySQL-Invisible-Column.png
+image: img/blog/covers/invisible-column.svg
tags: [IvorySQL, Database, Oracle Compatible, PostgreSQL, Invisible Column]
---
diff --git a/blog/2026-02-10-ivorysql-5.0-oracle-to-postgresql-migration/index.md b/blog/2026-02-10-ivorysql-5.0-oracle-to-postgresql-migration/index.md
index ae5f5ed..b9c0b17 100644
--- a/blog/2026-02-10-ivorysql-5.0-oracle-to-postgresql-migration/index.md
+++ b/blog/2026-02-10-ivorysql-5.0-oracle-to-postgresql-migration/index.md
@@ -3,7 +3,7 @@ slug: ivorysql-5.0-oracle-to-postgresql-migration
title: IvorySQL 5.0+ - a game changer for Oracle to PostgreSQL transitions
authors: [Yasir Hussain Shah]
category: IvorySQL
-image: img/blog/2026-2-10-cover.png
+image: img/blog/covers/oracle-migration.svg
tags: [IvorySQL, Database, Oracle Compatible, PostgreSQL, migration]
---
diff --git a/src/css/custom.css b/src/css/custom.css
index 2efb002..52c85e2 100644
--- a/src/css/custom.css
+++ b/src/css/custom.css
@@ -3,167 +3,772 @@
flex: 0 0 100% !important;
}
-.category-nav-container {
+/* ── (legacy) keep old classes so nothing else breaks ── */
+.category-nav-container { display: flex; gap: 30px; margin: 10px 0 40px 0; border-bottom: 1px solid #ebedf0; padding-bottom: 15px; }
+.category-nav-link { font-weight: bold; font-size: 1.1rem; color: #444; text-decoration: none; }
+.active-link { color: var(--ifm-color-primary) !important; border-bottom: 2px solid var(--ifm-color-primary); }
+.tag-pill-static { display: inline-flex; align-items: center; background: #f4f4f5; color: #606266; padding: 2px 12px; border-radius: 4px; font-size: 0.8rem; border: 1px solid #e9e9eb; white-space: nowrap; }
+
+/* ─────────────────────────────────────────────────────────
+ Blog Page Header
+───────────────────────────────────────────────────────── */
+.blog-page-header {
display: flex;
- gap: 30px;
- margin: 10px 0 40px 0;
- border-bottom: 1px solid #ebedf0;
- padding-bottom: 15px;
+ align-items: flex-start;
+ justify-content: space-between;
+ gap: 16px;
+ margin-bottom: 32px;
+ padding-bottom: 28px;
+ border-bottom: 1px solid #e5e9f2;
+ flex-wrap: wrap;
}
-.category-nav-link {
- font-weight: bold;
- font-size: 1.1rem;
- color: #444;
- text-decoration: none;
+.blog-page-header-inner {}
+
+.blog-page-title {
+ font-size: 2rem;
+ font-weight: 800;
+ color: #0d1b3e;
+ margin: 0 0 6px 0;
+ line-height: 1.2;
+}
+
+.blog-page-subtitle {
+ font-size: 0.95rem;
+ color: #64748b;
+ margin: 0;
+ line-height: 1.5;
+}
+
+.blog-page-count-badge {
+ display: inline-flex;
+ align-items: center;
+ background: linear-gradient(135deg, #eff4ff 0%, #dbeafe 100%);
+ border: 1px solid rgba(47, 116, 255, 0.2);
+ color: #2f74ff;
+ font-size: 0.82rem;
+ font-weight: 700;
+ padding: 4px 14px;
+ border-radius: 20px;
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+/* ─────────────────────────────────────────────────────────
+ Category Filter Bar
+───────────────────────────────────────────────────────── */
+.blog-filter-bar {
+ display: flex;
+ gap: 4px;
+ margin-bottom: 16px;
+ padding: 4px;
+ background: #f1f5f9;
+ border-radius: 10px;
+ width: fit-content;
+}
+
+.blog-cat-btn {
+ display: inline-flex;
+ align-items: center;
+ padding: 7px 20px;
+ border-radius: 7px;
+ font-size: 0.88rem;
+ font-weight: 600;
+ color: #64748b;
+ text-decoration: none !important;
+ transition: all 0.18s;
+ white-space: nowrap;
+ border: none;
+ background: transparent;
+}
+
+.blog-cat-btn:hover {
+ color: #2f74ff;
+ background: rgba(255, 255, 255, 0.8);
+}
+
+.blog-cat-btn.active {
+ background: #fff;
+ color: #2f74ff;
+ box-shadow: 0 1px 6px rgba(47, 116, 255, 0.15), 0 0 0 1px rgba(47, 116, 255, 0.12);
+}
+
+/* ─────────────────────────────────────────────────────────
+ Two-column blog layout
+───────────────────────────────────────────────────────── */
+.blog-body-layout {
+ display: flex;
+ align-items: flex-start;
+ gap: 28px;
+}
+
+.blog-main-col {
+ flex: 1;
+ min-width: 0;
+}
+
+/* ─────────────────────────────────────────────────────────
+ Tag Sidebar (right)
+───────────────────────────────────────────────────────── */
+.blog-tag-sidebar {
+ flex: 0 0 220px;
+ width: 220px;
+ position: sticky;
+ top: 80px;
+ background: #fff;
+ border: 1px solid #e5e9f2;
+ border-radius: 12px;
+ padding: 18px 0 14px;
+ box-shadow: 0 2px 10px rgba(15, 35, 100, 0.05);
+}
+
+.blog-tag-sidebar-header {
+ display: flex;
+ align-items: center;
+ gap: 7px;
+ font-size: 0.78rem;
+ font-weight: 700;
+ color: #94a3b8;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ padding: 0 18px 12px;
+ border-bottom: 1px solid #f1f5f9;
+ margin-bottom: 6px;
+}
+
+.blog-tag-sidebar-list {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+ max-height: 420px;
+ overflow-y: auto;
+}
+
+.blog-tag-sidebar-list::-webkit-scrollbar {
+ width: 4px;
+}
+.blog-tag-sidebar-list::-webkit-scrollbar-track {
+ background: transparent;
+}
+.blog-tag-sidebar-list::-webkit-scrollbar-thumb {
+ background: #e2e8f0;
+ border-radius: 2px;
+}
+
+.blog-tag-sidebar-item {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ width: 100%;
+ padding: 7px 18px;
+ border: none;
+ background: transparent;
+ cursor: pointer;
+ text-align: left;
+ transition: background 0.15s, color 0.15s;
+ border-left: 3px solid transparent;
+}
+
+.blog-tag-sidebar-item:hover {
+ background: #f8faff;
+ border-left-color: rgba(47, 116, 255, 0.3);
+}
+
+.blog-tag-sidebar-item.active {
+ background: #eff4ff;
+ border-left-color: #2f74ff;
+}
+
+.blog-tag-sidebar-item.active .blog-tag-sidebar-label {
+ color: #2f74ff;
+ font-weight: 600;
}
-.active-link {
- color: var(--ifm-color-primary) !important;
- border-bottom: 2px solid var(--ifm-color-primary);
+.blog-tag-sidebar-item.active .blog-tag-sidebar-count {
+ background: rgba(47, 116, 255, 0.15);
+ color: #2f74ff;
}
-.custom-horizontal-card {
+.blog-tag-sidebar-label {
+ font-size: 0.84rem;
+ color: #475569;
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+}
+
+.blog-tag-sidebar-count {
+ flex-shrink: 0;
+ min-width: 20px;
+ height: 20px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ padding: 0 5px;
+ border-radius: 10px;
+ background: #f1f5f9;
+ color: #94a3b8;
+ font-size: 0.7rem;
+ font-weight: 700;
+ margin-left: 8px;
+}
+
+.blog-tag-sidebar-clear {
+ display: block;
+ width: calc(100% - 36px);
+ margin: 10px 18px 0;
+ padding: 7px 12px;
+ border-radius: 6px;
+ border: 1px solid #fecaca;
+ background: #fff5f5;
+ color: #dc2626;
+ font-size: 0.78rem;
+ font-weight: 600;
+ cursor: pointer;
+ text-align: center;
+ transition: all 0.18s;
+}
+
+.blog-tag-sidebar-clear:hover {
+ background: #fee2e2;
+}
+
+.blog-tag-sidebar-empty {
+ padding: 12px 18px;
+ font-size: 0.82rem;
+ color: #cbd5e1;
+ margin: 0;
+}
+
+/* ─────────────────────────────────────────────────────────
+ Results Bar
+───────────────────────────────────────────────────────── */
+.blog-results-bar {
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ margin-bottom: 20px;
+ min-height: 28px;
+}
+
+.blog-results-text {
+ font-size: 0.85rem;
+ color: #94a3b8;
+ display: flex;
+ align-items: center;
+ gap: 6px;
+}
+
+.blog-results-tag-label {
+ color: #2f74ff;
+ font-weight: 600;
+}
+
+.blog-results-clear {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 18px;
+ height: 18px;
+ border-radius: 50%;
+ border: none;
+ background: #e2e8f0;
+ color: #64748b;
+ font-size: 0.65rem;
+ cursor: pointer;
+ transition: all 0.18s;
+ padding: 0;
+ line-height: 1;
+}
+
+.blog-results-clear:hover {
+ background: #fecaca;
+ color: #dc2626;
+}
+
+.blog-results-page {
+ font-size: 0.82rem;
+ color: #94a3b8;
+}
+
+/* ─────────────────────────────────────────────────────────
+ Blog Card (list view)
+───────────────────────────────────────────────────────── */
+.blog-card {
display: flex !important;
flex-direction: row !important;
background: #fff;
- border: 1px solid #e5e7eb;
- border-radius: 12px;
- margin-bottom: 30px !important;
- height: 220px;
+ border: 1px solid #e5e9f2;
+ border-radius: 14px;
+ margin-bottom: 20px !important;
+ min-height: 200px;
overflow: hidden;
- box-shadow: 0 4px 12px rgba(0,0,0,0.05);
+ box-shadow: 0 2px 10px rgba(15, 35, 100, 0.06);
+ transition: box-shadow 0.22s, transform 0.22s, border-color 0.22s;
}
-.card-left-img {
- flex: 0 0 350px !important;
- background: #f0f2f5;
- border-right: 1px solid #eee;
+.blog-card:hover {
+ box-shadow: 0 8px 28px rgba(47, 116, 255, 0.13);
+ transform: translateY(-2px);
+ border-color: rgba(47, 116, 255, 0.25);
}
-.card-left-img img {
+/* Cover image */
+.blog-card-img-wrap {
+ flex: 0 0 300px;
+ display: block;
+ overflow: hidden;
+ background: #f1f5f9;
+}
+
+.blog-card-img {
width: 100%;
height: 100%;
- object-fit: cover;
+ object-fit: contain;
+ display: block;
+ transition: transform 0.4s;
+}
+
+.blog-card:hover .blog-card-img {
+ transform: scale(1.02);
+}
+
+.blog-card-img-placeholder {
+ width: 100%;
+ height: 100%;
+ min-height: 200px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ background: linear-gradient(135deg, #0d1b3e 0%, #1e3a8a 50%, #102268 100%);
}
-.card-right-content {
+/* Card body */
+.blog-card-body {
flex: 1;
- padding: 24px 30px !important;
+ padding: 22px 26px;
display: flex;
flex-direction: column;
- justify-content: space-between;
+ gap: 8px;
+ min-width: 0;
}
-.post-item-title {
- margin: 0 0 10px 0;
- font-size: 1.5rem;
+/* Category badge */
+.blog-card-cat {
+ display: inline-flex;
+ align-items: center;
+ font-size: 0.72rem;
+ font-weight: 700;
+ letter-spacing: 0.05em;
+ text-transform: uppercase;
+ padding: 2px 10px;
+ border-radius: 20px;
+ width: fit-content;
}
-.post-item-title a {
- color: var(--ifm-color-primary);
- text-decoration: none;
+.blog-card-cat--ivorysql {
+ background: rgba(47, 116, 255, 0.1);
+ color: #2f74ff;
+ border: 1px solid rgba(47, 116, 255, 0.2);
}
-.post-item-date {
- color: #666;
- font-size: 0.9rem;
- margin-bottom: auto;
+.blog-card-cat--postgresql {
+ background: rgba(8, 145, 178, 0.1);
+ color: #0891b2;
+ border: 1px solid rgba(8, 145, 178, 0.2);
}
-.post-item-tags {
+/* Title */
+.blog-card-title {
+ margin: 0 !important;
+ font-size: 1.1rem !important;
+ font-weight: 700 !important;
+ line-height: 1.4 !important;
+}
+
+.blog-card-title a {
+ color: #1e293b !important;
+ text-decoration: none !important;
+ transition: color 0.18s !important;
+}
+
+.blog-card-title a:hover {
+ color: #2f74ff !important;
+}
+
+/* Date */
+.blog-card-date {
display: flex;
- width: 100%;
+ align-items: center;
+ gap: 5px;
+ font-size: 0.82rem;
+ color: #94a3b8;
+}
+
+/* Tags */
+.blog-card-tags {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ margin-top: 2px;
}
-.tags-list {
+/* Authors */
+.blog-card-authors {
display: flex;
flex-wrap: wrap;
- gap: 8px 12px;
+ gap: 10px;
+ margin-top: auto;
+ padding-top: 10px;
+ border-top: 1px solid #f1f5f9;
}
-.tag-pill-static {
+.blog-author-chip {
display: inline-flex;
align-items: center;
- background: #f4f4f5;
- color: #606266;
- padding: 2px 12px;
- border-radius: 4px;
- font-size: 0.8rem;
- border: 1px solid #e9e9eb;
+ gap: 7px;
+ text-decoration: none !important;
+ color: #475569 !important;
+ font-size: 0.82rem;
+ font-weight: 500;
+ transition: color 0.18s;
+}
+
+.blog-author-chip:hover {
+ color: #2f74ff !important;
+}
+
+.blog-author-avatar {
+ width: 26px;
+ height: 26px;
+ border-radius: 50%;
+ object-fit: cover;
+ border: 2px solid #e2e8f0;
+ flex-shrink: 0;
+}
+
+.blog-author-initials {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ font-size: 0.65rem;
+ font-weight: 700;
+ color: #fff;
+ letter-spacing: 0.02em;
+}
+
+.blog-author-name {
+ line-height: 1;
+}
+
+/* ─────────────────────────────────────────────────────────
+ Clickable Tag Pill (cards + post footer)
+───────────────────────────────────────────────────────── */
+.blog-tag-pill {
+ display: inline-flex;
+ align-items: center;
+ padding: 3px 10px;
+ border-radius: 5px;
+ background: #f1f5f9;
+ color: #475569 !important;
+ font-size: 0.76rem;
+ font-weight: 500;
+ border: 1px solid #e2e8f0;
+ text-decoration: none !important;
white-space: nowrap;
+ transition: all 0.18s;
+ line-height: 1.4;
}
+.blog-tag-pill:hover {
+ background: #eff4ff;
+ color: #2f74ff !important;
+ border-color: rgba(47, 116, 255, 0.3);
+}
+
+.blog-tag-more {
+ display: inline-flex;
+ align-items: center;
+ padding: 3px 8px;
+ border-radius: 5px;
+ background: #f8faff;
+ color: #94a3b8;
+ font-size: 0.76rem;
+ border: 1px solid #e2e8f0;
+}
+
+/* ─────────────────────────────────────────────────────────
+ Blog Post Footer (detail page)
+───────────────────────────────────────────────────────── */
+.blog-post-footer {
+ margin-top: 48px;
+ padding-top: 24px;
+ border-top: 1px solid #e5e9f2;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+}
+
+.blog-post-footer-tags {
+ display: flex;
+ align-items: flex-start;
+ gap: 12px;
+ flex-wrap: wrap;
+}
+
+.blog-post-footer-tags-label {
+ font-size: 0.82rem;
+ font-weight: 600;
+ color: #94a3b8;
+ padding-top: 2px;
+ white-space: nowrap;
+}
+
+.blog-post-footer-tags-list {
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+}
+
+.blog-post-footer-edit {
+ font-size: 0.85rem;
+}
+
+/* ─────────────────────────────────────────────────────────
+ Pagination
+───────────────────────────────────────────────────────── */
.blog-pagination-wrapper {
display: flex;
justify-content: center;
- margin: 50px 0;
+ margin: 40px 0 20px;
width: 100%;
}
-.custom-pagination {
+.blog-pagination {
display: flex;
align-items: center;
- gap: 15px;
+ gap: 8px;
}
-.pagination-number-list {
+.blog-page-list {
display: flex;
list-style: none;
padding: 0;
margin: 0;
- gap: 8px;
+ gap: 4px;
}
-.pagination-nav-item, .pagination-number-item {
+.blog-page-nav {
display: inline-flex;
align-items: center;
- justify-content: center;
+ gap: 5px;
padding: 8px 16px;
- border: 1px solid #e5e7eb;
- border-radius: 6px;
- color: #444;
- text-decoration: none !important;
- font-size: 0.9rem;
+ border-radius: 8px;
+ border: 1px solid #e5e9f2;
+ background: #fff;
+ color: #475569;
+ font-size: 0.85rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.18s;
+}
+
+.blog-page-nav:hover:not(.disabled) {
+ border-color: #2f74ff;
+ color: #2f74ff;
+ background: #eff4ff;
+}
+
+.blog-page-nav.disabled,
+.blog-page-nav:disabled {
+ opacity: 0.38;
+ cursor: not-allowed;
+}
+
+.blog-page-num {
+ min-width: 36px;
+ height: 36px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border-radius: 7px;
+ border: 1px solid #e5e9f2;
background: #fff;
+ color: #475569;
+ font-size: 0.88rem;
+ font-weight: 500;
+ cursor: pointer;
+ transition: all 0.18s;
+ padding: 0;
+}
+
+.blog-page-num:hover:not(.active) {
+ border-color: #2f74ff;
+ color: #2f74ff;
+ background: #eff4ff;
}
-.pagination-number-item.active {
- background: var(--ifm-color-primary);
+.blog-page-num.active {
+ background: #2f74ff;
color: #fff;
- border-color: var(--ifm-color-primary);
+ border-color: #2f74ff;
+ box-shadow: 0 2px 8px rgba(47, 116, 255, 0.35);
}
-.pagination-nav-item.disabled {
- color: #ccc;
- border-color: #f3f4f6;
- background: #fafafa;
+/* ─────────────────────────────────────────────────────────
+ Empty state
+───────────────────────────────────────────────────────── */
+.blog-empty-state {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ justify-content: center;
+ padding: 60px 20px;
+ color: #94a3b8;
+ text-align: center;
+ gap: 12px;
+}
+
+.blog-empty-state p {
+ font-size: 0.95rem;
+ margin: 0;
+}
+
+/* ─────────────────────────────────────────────────────────
+ Responsive
+───────────────────────────────────────────────────────── */
+@media (max-width: 900px) {
+ .blog-body-layout {
+ flex-direction: column;
+ }
+
+ .blog-tag-sidebar {
+ flex: none;
+ width: 100%;
+ position: static;
+ order: -1; /* show above posts on mobile */
+ }
+
+ .blog-tag-sidebar-list {
+ max-height: none;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+ padding: 6px 18px 2px;
+ }
+
+ .blog-tag-sidebar-item {
+ width: auto;
+ padding: 4px 12px;
+ border-radius: 20px;
+ border: 1px solid #e2e8f0;
+ border-left: 1px solid #e2e8f0;
+ }
+
+ .blog-tag-sidebar-item:hover,
+ .blog-tag-sidebar-item.active {
+ border-color: #2f74ff;
+ border-left-color: #2f74ff;
+ }
+
+ .blog-tag-sidebar-clear {
+ width: calc(100% - 36px);
+ }
}
@media (max-width: 768px) {
- .custom-horizontal-card {
+ .blog-page-header {
+ flex-direction: column;
+ gap: 12px;
+ }
+
+ .blog-page-title {
+ font-size: 1.6rem;
+ }
+
+ .blog-filter-bar {
+ width: 100%;
+ }
+
+ .blog-cat-btn {
+ flex: 1;
+ justify-content: center;
+ padding: 7px 12px;
+ }
+
+ .blog-card {
flex-direction: column !important;
- height: auto !important;
+ min-height: auto;
}
- .card-left-img {
+ .blog-card-img-wrap {
flex: 0 0 auto !important;
- width: 100% !important;
- border-right: none !important;
- border-bottom: 1px solid #eee;
- height: 200px;
+ height: 180px;
}
- .card-right-content {
- padding: 16px !important;
+ .blog-card-img-placeholder {
+ min-height: 180px;
}
- .post-item-title {
- font-size: 1.2rem !important;
- margin-bottom: 8px !important;
+ .blog-card-body {
+ padding: 16px 18px;
}
- .post-item-tags {
- margin-top: 12px;
+ .blog-card-title {
+ font-size: 1rem !important;
}
-}
\ No newline at end of file
+
+ .blog-pagination {
+ gap: 6px;
+ }
+
+ .blog-page-nav {
+ padding: 7px 12px;
+ font-size: 0.8rem;
+ }
+}
+
+/* ─────────────────────────────────────────────────────────
+ IvorySQL Footer Override
+───────────────────────────────────────────────────────── */
+.footer--dark {
+ background: linear-gradient(180deg, #0d1b3e 0%, #091530 100%);
+ border-top: 1px solid rgba(47, 116, 255, 0.18);
+}
+
+.footer--dark .footer__title {
+ color: rgba(200, 220, 255, 0.9);
+ font-weight: 600;
+ font-size: 0.85rem;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+}
+
+.footer--dark .footer__link-item {
+ color: rgba(160, 185, 220, 0.65);
+ font-size: 0.9rem;
+ line-height: 2;
+ transition: color 0.18s;
+}
+
+.footer--dark .footer__link-item:hover {
+ color: #ffffff;
+ text-decoration: none;
+}
+
+.footer--dark .footer__copyright {
+ color: rgba(130, 155, 195, 0.45);
+ font-size: 0.8rem;
+ border-top: 1px solid rgba(47, 116, 255, 0.12);
+ padding-top: 24px;
+ margin-top: 40px;
+}
+
+.footer--dark .footer__logo-link {
+ opacity: 0.85;
+ transition: opacity 0.18s;
+}
+
+.footer--dark .footer__logo-link:hover {
+ opacity: 1;
+}
diff --git a/src/pages/index.js b/src/pages/index.js
index 5fe7fe8..984b120 100644
--- a/src/pages/index.js
+++ b/src/pages/index.js
@@ -1,118 +1,552 @@
+import clsx from 'clsx';
import Link from '@docusaurus/Link';
-import Translate from '@docusaurus/Translate';
import useDocusaurusContext from '@docusaurus/useDocusaurusContext';
import Layout from '@theme/Layout';
-import clsx from 'clsx';
-import React, { useEffect } from 'react';
-import Slider from "react-slick";
-import RecruitPhone from "../../static/img/index-recruit-phone.jpg";
-import Recruit from "../../static/img/index-recruit.jpg";
-import indexbug from '../../static/img/indexbug.png';
-import indexbugphone from '../../static/img/indexbugphone.png';
-import Elephant from '../../svg/img-elephant-balloon.svg';
-import HOW from '../../static/img/ivorysql-how.jpg';
-import HomepageFeatures from '../components/HomepageFeatures';
+import React, { useEffect, useState } from 'react';
import styles from './index.module.css';
-import SliderIndex from './slider';
-import SliderBug from './slider-bug';
-import SliderBugPhone from './slider-bug-phone';
-import SliderPhoneIndex from './slider-phone';
-import { customFields } from '../../docusaurus.config';
-function HomepageHeader() {
- const {siteConfig} = useDocusaurusContext();
- const settings = {
- autoplay: true,
- autoplaySpeed: 5000,
- dots: true,
- infinite: true,
- slidesToShow: 1,
- slidesToScroll: 1,
- arrows: false,
- };
- const { i18n } = useDocusaurusContext();
- const isEnglish = i18n.currentLocale === 'en';
+
+const Icon01 = require('../../svg/icon-01.svg').default;
+const Icon02 = require('../../svg/icon-02.svg').default;
+const Icon03 = require('../../svg/icon-03.svg').default;
+const Icon04 = require('../../svg/icon-04.svg').default;
+const Icon05 = require('../../svg/icon-05.svg').default;
+const Icon06 = require('../../svg/icon-06.svg').default;
+const HeroElephant = require('../../svg/img-elephant-balloon.svg').default;
+
+const CoreAdvantageIcon = Icon01;
+const ScenarioIcon = Icon03;
+const EcosystemIcon = Icon02;
+const CertificateIcon = Icon05;
+const InstallDeployIcon = Icon04;
+
+const CORE_CARD_ICONS = [Icon01, Icon03, Icon04, Icon02, Icon05, Icon06, Icon01, Icon03];
+const SCENARIO_CARD_ICONS = [Icon04, Icon02, Icon06, Icon01, Icon05];
+const INSTALL_CARD_ICONS = [Icon04, Icon01, Icon06];
+
+const RELEASES_URL = 'https://github.com/IvorySQL/IvorySQL/releases';
+const ONLINE_TRIAL_URL = 'https://trial.ivorysql.org/';
+
+/* Trusted-by customer list — logo path optional; nameZh shown in zh locale */
+const TRUSTED_CUSTOMERS = [
+ { name: 'Highgo', nameZh: '瀚高软件', logo: '/img/partners/highgo.png', logoZh: 'https://2025.pgconf.dev/static/logo/highgo.png', logoHeight: 36 },
+ { name: 'Data Bene', logo: '/img/partners/databene.png' },
+ { name: 'Ongres', logo: '/img/partners/ongres.png', logoHeight: 18 },
+ { name: 'State Grid Corporation', nameZh: '国家电网', logo: '/img/partners/state-grid.png', logoHeight: 28 },
+ { name: 'Zhongtai Securities', nameZh: '中泰证券', logo: '/img/partners/zhongtai-securities.png' },
+ { name: 'Goldwind', nameZh: '金风科技', logo: '/img/partners/goldwind.png' },
+];
+const LATEST_RELEASE_API_URL = 'https://api.github.com/repos/IvorySQL/IvorySQL/releases/latest';
+const LATEST_VERSION_CACHE_KEY = 'ivorysql_latest_release_label';
+const LATEST_VERSION_CACHE_TTL = 6 * 60 * 60 * 1000;
+
+// Tool metadata: description + homepage URL for hover tooltips (bilingual)
+const TOOL_META = {
+ // Data Access Middleware
+ 'pgpool-II': { desc: 'Middleware proxy for PostgreSQL: connection pooling, load balancing, and automatic failover.', descZh: 'PostgreSQL 中间件代理,提供连接池、负载均衡和自动故障转移能力。', url: 'https://www.pgpool.net/' },
+ 'pgBouncer': { desc: 'Ultra-lightweight connection pooler for PostgreSQL, minimizing connection overhead.', descZh: '超轻量级 PostgreSQL 连接池,大幅降低连接建立开销。', url: 'https://www.pgbouncer.org/' },
+ 'odyssey': { desc: 'Advanced multi-threaded PostgreSQL connection pooler by Yandex, designed for high concurrency.', descZh: 'Yandex 开发的高性能多线程 PostgreSQL 连接池,专为高并发场景设计。', url: 'https://github.com/yandex/odyssey' },
+ 'HAProxy': { desc: 'High-performance TCP/HTTP load balancer widely used for PostgreSQL read/write splitting.', descZh: '高性能 TCP/HTTP 负载均衡器,常用于 PostgreSQL 读写分离架构。', url: 'https://www.haproxy.org/' },
+ 'ShardingSphere': { desc: 'Apache distributed database ecosystem providing sharding, scaling, and encryption for PostgreSQL.', descZh: 'Apache 分布式数据库生态,为 PostgreSQL 提供分库分表、弹性伸缩和数据加密能力。', url: 'https://shardingsphere.apache.org/' },
+ 'Citus': { desc: 'Distributed PostgreSQL extension that horizontally scales your database across multiple nodes.', descZh: 'PostgreSQL 分布式扩展,通过水平分片将数据库扩展到多个节点。', url: 'https://www.citusdata.com/' },
+ 'vip-manager': { desc: 'Manages virtual IP addresses for PostgreSQL HA clusters, ensuring seamless failover.', descZh: '为 PostgreSQL 高可用集群管理虚拟 IP,确保故障切换时业务无感知。', url: 'https://github.com/Cybertec-PostgreSQL/vip-manager' },
+ // ORM
+ 'MyBatis': { desc: 'Java SQL mapping framework that eliminates boilerplate JDBC code with flexible SQL control.', descZh: 'Java SQL 映射框架,以灵活的 SQL 控制方式消除繁琐的 JDBC 样板代码。', url: 'https://mybatis.org/' },
+ 'Hibernate': { desc: 'Powerful Java ORM framework with full PostgreSQL and JPQL support.', descZh: '强大的 Java ORM 框架,全面支持 PostgreSQL 和 JPQL 查询语言。', url: 'https://hibernate.org/' },
+ // Standard SQL & Drivers
+ 'libpq': { desc: 'Official C client library for PostgreSQL, the foundation for most language drivers.', descZh: 'PostgreSQL 官方 C 客户端库,是大多数语言驱动的底层基础。', url: 'https://www.postgresql.org/docs/current/libpq.html' },
+ 'JDBC': { desc: 'Official Java Database Connectivity driver for PostgreSQL (pgjdbc).', descZh: 'PostgreSQL 官方 Java 数据库连接驱动(pgjdbc)。', url: 'https://jdbc.postgresql.org/' },
+ 'ODBC': { desc: 'psqlODBC — official PostgreSQL ODBC driver for Windows and Linux applications.', descZh: 'psqlODBC — 适用于 Windows 和 Linux 应用程序的官方 PostgreSQL ODBC 驱动。', url: 'https://odbc.postgresql.org/' },
+ 'psycopg2': { desc: 'Most popular PostgreSQL adapter for Python, featuring full async support.', descZh: '最流行的 Python PostgreSQL 适配器,支持完整的异步操作。', url: 'https://www.psycopg.org/' },
+ 'ADO.NET': { desc: 'Npgsql — high-performance .NET data provider for PostgreSQL with EF Core support.', descZh: 'Npgsql — 高性能 .NET PostgreSQL 数据提供器,支持 Entity Framework Core。', url: 'https://www.npgsql.org/' },
+ 'lib/pq': { desc: 'Pure Go PostgreSQL driver (legacy), compatible with database/sql standard interface.', descZh: '纯 Go 实现的 PostgreSQL 驱动(经典版),兼容 database/sql 标准接口。', url: 'https://github.com/lib/pq' },
+ 'pgx': { desc: 'High-performance PostgreSQL driver for Go with low-level protocol access.', descZh: '高性能 Go 语言 PostgreSQL 驱动,支持底层协议直接访问。', url: 'https://github.com/jackc/pgx' },
+ 'Ruby': { desc: 'pg gem — the official Ruby interface to PostgreSQL.', descZh: 'pg gem — Ruby 访问 PostgreSQL 的官方接口库。', url: 'https://github.com/ged/ruby-pg' },
+ 'Rust': { desc: 'rust-postgres — native PostgreSQL driver for Rust, with tokio async support.', descZh: 'rust-postgres — 原生 Rust PostgreSQL 驱动,支持 tokio 异步运行时。', url: 'https://github.com/sfackler/rust-postgres' },
+ // Client Tools
+ 'DBeaver': { desc: 'Universal multi-database GUI management tool with ERD, SQL editor, and data export.', descZh: '通用多数据库 GUI 管理工具,内置 ER 图、SQL 编辑器和数据导出功能。', url: 'https://dbeaver.io/' },
+ 'pgAdmin': { desc: 'Official open-source PostgreSQL administration and management web application.', descZh: 'PostgreSQL 官方开源管理工具,提供完整的数据库管理与监控功能。', url: 'https://www.pgadmin.org/' },
+ 'Navicat': { desc: 'Professional GUI tool for PostgreSQL with visual query builder and data modeling.', descZh: '专业的 PostgreSQL GUI 工具,提供可视化查询构建器和数据建模功能。', url: 'https://www.navicat.com/' },
+ 'Navicat Premium': { desc: 'Multi-connection GUI tool supporting PostgreSQL, MySQL, Oracle, and more simultaneously.', descZh: '多连接 GUI 工具,可同时管理 PostgreSQL、MySQL、Oracle 等多种数据库。', url: 'https://www.navicat.com/en/products/navicat-premium' },
+ // Backup & HA
+ 'pg_rman': { desc: 'Online backup and recovery manager for PostgreSQL with PITR support.', descZh: 'PostgreSQL 在线备份与恢复管理器,支持时间点恢复(PITR)。', url: 'https://github.com/ossc-db/pg_rman' },
+ 'WAL-G': { desc: 'Fast cloud-native backup tool using cloud storage (S3, GCS, Azure) with delta compression.', descZh: '云原生备份工具,支持 S3/GCS/Azure 存储,具备增量压缩能力。', url: 'https://github.com/wal-g/wal-g' },
+ 'pg_probackup': { desc: 'Backup and recovery solution for PostgreSQL with parallel processing and incremental backups.', descZh: 'PostgreSQL 备份与恢复方案,支持并行处理和增量备份。', url: 'https://github.com/postgrespro/pg_probackup' },
+ 'pgBackRest': { desc: 'Reliable, feature-rich backup solution with parallel restore and cloud storage support.', descZh: '功能丰富的可靠备份方案,支持并行恢复和云存储对接。', url: 'https://pgbackrest.org/' },
+ // Cluster Management
+ 'Patroni': { desc: 'HA template for PostgreSQL using DCS (etcd/Consul/ZooKeeper) for automatic failover.', descZh: '基于 DCS(etcd/Consul/ZooKeeper)的 PostgreSQL 高可用模板,实现自动故障转移。', url: 'https://patroni.readthedocs.io/' },
+ 'repmgr': { desc: 'Replication manager for PostgreSQL: manages streaming replication and switchover.', descZh: 'PostgreSQL 复制管理器,负责流复制管理和主从切换。', url: 'https://repmgr.org/' },
+ 'Pacemaker Corosync': { desc: 'Open-source cluster resource manager providing HA for PostgreSQL and other services.', descZh: '开源集群资源管理器,为 PostgreSQL 等服务提供高可用保障。', url: 'https://clusterlabs.org/' },
+ // Monitoring
+ 'Prometheus': { desc: 'Open-source monitoring and alerting toolkit; pairs with pg_exporter for PostgreSQL metrics.', descZh: '开源监控与告警工具包,配合 pg_exporter 采集 PostgreSQL 指标。', url: 'https://prometheus.io/' },
+ 'Alertmanager': { desc: 'Handles alerts from Prometheus, routing notifications to email, Slack, PagerDuty, etc.', descZh: '处理 Prometheus 告警,将通知路由至邮件、Slack、PagerDuty 等渠道。', url: 'https://prometheus.io/docs/alerting/latest/alertmanager/' },
+ 'pgMonitor': { desc: 'Pre-configured PostgreSQL monitoring stack by Crunchy Data using Prometheus and Grafana.', descZh: 'Crunchy Data 提供的预配置 PostgreSQL 监控方案,基于 Prometheus 和 Grafana。', url: 'https://github.com/CrunchyData/pgmonitor' },
+ 'Grafana': { desc: 'Observability and data visualization platform for dashboards and alerting.', descZh: '可观测性与数据可视化平台,用于构建监控大屏和告警规则。', url: 'https://grafana.com/' },
+ 'PoWA': { desc: 'PostgreSQL Workload Analyzer — query performance insights with historical data.', descZh: 'PostgreSQL 工作负载分析器,基于历史数据提供查询性能洞察。', url: 'https://powa.readthedocs.io/' },
+ // Heterogeneous Access
+ 'Debezium': { desc: 'CDC platform for capturing row-level database change events in real time.', descZh: '变更数据捕获(CDC)平台,实时捕获数据库行级变更事件。', url: 'https://debezium.io/' },
+ 'pglogical': { desc: 'Logical replication extension for PostgreSQL supporting selective table replication.', descZh: 'PostgreSQL 逻辑复制扩展,支持按需选择性地复制指定表。', url: 'https://github.com/2ndQuadrant/pglogical' },
+ 'mysql_fdw': { desc: 'PostgreSQL Foreign Data Wrapper for accessing MySQL tables directly from PostgreSQL.', descZh: 'PostgreSQL 外部数据包装器,可直接在 PostgreSQL 中查询 MySQL 表。', url: 'https://github.com/EnterpriseDB/mysql_fdw' },
+ 'oracle_fdw': { desc: 'PostgreSQL Foreign Data Wrapper for querying Oracle databases transparently.', descZh: 'PostgreSQL 外部数据包装器,透明访问 Oracle 数据库中的数据。', url: 'https://github.com/laurenz/oracle_fdw' },
+ // Multi-Model
+ 'TimescaleDB': { desc: 'Time-series database built on PostgreSQL with automatic partitioning and compression.', descZh: '基于 PostgreSQL 的时序数据库,具备自动分区和数据压缩能力。', url: 'https://www.timescale.com/' },
+ 'DocumentDB': { desc: 'Open-source document database compatible with MongoDB wire protocol, built on PostgreSQL.', descZh: '开源文档数据库,兼容 MongoDB 协议,以 PostgreSQL 为存储引擎。', url: 'https://github.com/microsoft/documentdb' },
+ 'PostgreSQL AGE': { desc: 'Apache AGE — graph database extension for PostgreSQL supporting openCypher queries.', descZh: 'Apache AGE — PostgreSQL 图数据库扩展,支持 openCypher 图查询语言。', url: 'https://age.apache.org/' },
+ 'FerretDB': { desc: 'MongoDB-compatible backend using PostgreSQL for storage, enabling Mongo drivers to work.', descZh: '以 PostgreSQL 为存储层的 MongoDB 兼容后端,让 Mongo 驱动开箱即用。', url: 'https://www.ferretdb.com/' },
+ // Geospatial
+ 'PostGIS': { desc: 'Adds spatial and geographic object support to PostgreSQL, the gold standard for GIS.', descZh: '为 PostgreSQL 添加空间与地理对象支持,是 GIS 领域的事实标准。', url: 'https://postgis.net/' },
+ 'pgRouting': { desc: 'Geospatial routing extension extending PostGIS for path-finding and network analysis.', descZh: '扩展 PostGIS 的地理路由插件,支持最短路径与网络分析。', url: 'https://pgrouting.org/' },
+ // ML & AI
+ 'pgvector': { desc: 'Open-source vector similarity search for PostgreSQL, ideal for AI embeddings and RAG.', descZh: '开源 PostgreSQL 向量相似度搜索扩展,专为 AI 嵌入和 RAG 场景设计。', url: 'https://github.com/pgvector/pgvector' },
+ 'MADlib': { desc: 'Apache MADlib — in-database machine learning library for scalable analytics.', descZh: 'Apache MADlib — 数据库内机器学习库,支持大规模分析计算。', url: 'https://madlib.apache.org/' },
+ // DDL & Loading
+ 'pg_bulkload': { desc: 'High-speed data loading tool for PostgreSQL, bypassing WAL for maximum throughput.', descZh: '高速 PostgreSQL 数据加载工具,绕过 WAL 日志以获得最大吞吐量。', url: 'https://github.com/ossc-db/pg_bulkload' },
+ 'ddlx': { desc: 'PostgreSQL extension to extract clean, executable DDL scripts from database objects.', descZh: 'PostgreSQL 扩展,从数据库对象中提取干净、可执行的 DDL 脚本。', url: 'https://github.com/lacanoid/pgddl' },
+ // Online Demo
+ 'postgres-wasm': { desc: 'PostgreSQL compiled to WebAssembly — run a full database in your browser, zero install.', descZh: 'PostgreSQL 的 WebAssembly 编译版本,无需安装即可在浏览器中运行完整数据库。', url: 'https://github.com/snaplet/postgres-wasm' },
+ // Job Scheduling
+ 'pg_cron': { desc: 'Cron-based job scheduler for PostgreSQL, running SQL commands on a schedule inside the DB.', descZh: '基于 Cron 的 PostgreSQL 作业调度器,可在数据库内部按计划执行 SQL 命令。', url: 'https://github.com/citusdata/pg_cron' },
+ 'pgAgent': { desc: 'Job scheduling agent for PostgreSQL integrated with pgAdmin for scheduled tasks.', descZh: 'PostgreSQL 作业调度代理,与 pgAdmin 深度集成,方便管理定时任务。', url: 'https://www.pgadmin.org/docs/pgadmin4/latest/pgagent.html' },
+ // Ecosystem Partnerships
+ 'StackGres': { desc: 'Production-grade PostgreSQL on Kubernetes with automated ops, monitoring, and backups.', descZh: '生产级 Kubernetes 上的 PostgreSQL 方案,自动化运维、监控和备份一体化。', url: 'https://stackgres.io/' },
+ 'Databene': { desc: 'Database testing and synthetic data generation framework for regression and performance tests.', descZh: '数据库测试与合成数据生成框架,用于回归测试和性能基准测试。', url: 'https://databene.org/' },
+ // Migration
+ 'Ora2Pg': { desc: 'Free open-source tool for migrating Oracle database schemas and data to PostgreSQL.', descZh: '免费开源的 Oracle 到 PostgreSQL 迁移工具,支持 Schema 和数据全量迁移。', url: 'https://ora2pg.darold.net/' },
+ // Cloud
+ 'Docker Compose': { desc: 'Define and run multi-container applications; official IvorySQL Docker images available.', descZh: '多容器应用编排工具,IvorySQL 官方提供 Docker 镜像支持。', url: 'https://docs.docker.com/compose/' },
+ 'Podman': { desc: 'Daemonless, rootless container engine fully compatible with Docker images and compose files.', descZh: '无守护进程、无 root 权限的容器引擎,完全兼容 Docker 镜像和 Compose 文件。', url: 'https://podman.io/' },
+ 'Docker Swarm': { desc: 'Native Docker clustering for deploying IvorySQL in a replicated, highly available setup.', descZh: 'Docker 原生集群方案,用于以高可用、多副本方式部署 IvorySQL。', url: 'https://docs.docker.com/engine/swarm/' },
+};
+
+const ECOSYSTEM_TOOL_STATUS = {
+ progress: new Set(['citus', 'pg_ai_query', 'stackgres', 'databene', 'madlib']),
+ planned: new Set(['shardingsphere', 'pacemaker corosync', 'postgresql age', 'yukon', 'powa']),
+ proprietary: new Set(['ivymigration', 'ivyevaluation', 'ivorysql serverless']),
+};
+
+function normalizeToolName(toolName) {
+ return toolName.replace(/\u200c/g, '').toLowerCase().trim();
+}
+
+function getEcosystemToolTone(toolName) {
+ const normalizedName = normalizeToolName(toolName);
+ if (ECOSYSTEM_TOOL_STATUS.proprietary.has(normalizedName)) {
+ return 'proprietary';
+ }
+ if (ECOSYSTEM_TOOL_STATUS.progress.has(normalizedName)) {
+ return 'progress';
+ }
+ if (ECOSYSTEM_TOOL_STATUS.planned.has(normalizedName)) {
+ return 'planned';
+ }
+ return 'supported';
+}
+
+function formatLatestReleaseLabel(release, fallbackLabel) {
+ const source = `${release?.name || ''} ${release?.tag_name || ''}`;
+ const versionMatch = source.match(/(\d+(?:\.\d+){1,2})/);
+ if (versionMatch) {
+ return `IvorySQL ${versionMatch[1]}`;
+ }
+ const cleaned = (release?.name || release?.tag_name || '').trim();
+ return cleaned || fallbackLabel;
+}
+
+function readLatestVersionFromCache() {
+ if (typeof window === 'undefined') {
+ return null;
+ }
+
+ try {
+ const rawCache = window.localStorage.getItem(LATEST_VERSION_CACHE_KEY);
+ if (!rawCache) {
+ return null;
+ }
+ const parsedCache = JSON.parse(rawCache);
+ if (!parsedCache?.label || !parsedCache?.time) {
+ return null;
+ }
+ if (Date.now() - parsedCache.time > LATEST_VERSION_CACHE_TTL) {
+ return null;
+ }
+ return parsedCache.label;
+ } catch {
+ return null;
+ }
+}
+
+function writeLatestVersionToCache(label) {
+ if (typeof window === 'undefined') {
+ return;
+ }
+
+ try {
+ window.localStorage.setItem(
+ LATEST_VERSION_CACHE_KEY,
+ JSON.stringify({
+ label,
+ time: Date.now(),
+ }),
+ );
+ } catch {
+ // Ignore storage failures in private mode / restricted environments.
+ }
+}
+
+const CONTENT = {
+ zh: {
+ slogan: '一款开源的兼容 Oracle 的 PostgreSQL',
+ intro:
+ 'IvorySQL 是一款先进、功能齐全的开源 Oracle 兼容 PostgreSQL,致力于保持高兼容性,并可作为最新 PostgreSQL 的完全替代品。通过 compatible_mode 开关可在 Oracle 与 PostgreSQL 兼容模式间切换,PL/iSQL 支持 Oracle PL/SQL 语法及 Oracle 风格包(Packages)。',
+ heroBadges: ['Oracle 兼容', 'Apache 2.0 开源', '基于 PostgreSQL 内核'],
+ latestVersionPrefix: '最新版本',
+ latestVersionLabel: 'IvorySQL 5.1',
+ actions: [
+ { label: '免费下载', to: '/releases-page', ariaLabel: '免费下载 IvorySQL' },
+ { label: '在线体验', href: ONLINE_TRIAL_URL, ariaLabel: '在线体验 IvorySQL' },
+ { label: '最新活动', to: '/webinars-page', ariaLabel: '查看 IvorySQL 最新活动' },
+ ],
+ heroTrustLabel: '受到众多企业信赖',
+ statsItems: [
+ { value: 'PostgreSQL 18', label: '内核版本' },
+ { value: 'Apache 2.0', label: '开源协议' },
+ { value: '55+', label: '生态工具' },
+ { value: 'Oracle 兼容', label: '无缝迁移' },
+ ],
+ oracleShowcase: {
+ title: '让 Oracle 代码直接运行',
+ subtitle: '深度 Oracle 兼容',
+ points: [
+ 'PL/iSQL 支持 Oracle PL/SQL 过程语言语法',
+ 'ivorysql_ora 插件提供 Oracle 内置函数',
+ 'compatible_mode 开关随时切换兼容模式',
+ '支持 Oracle 风格的 Package 包体结构',
+ ],
+ cta: '查看迁移指南',
+ ctaTo: 'https://docs.ivorysql.org/en/ivorysql-doc/v5.3/4.5',
+ },
+ coreTitle: 'IvorySQL 核心优势',
+ coreDesc: '从内核兼容到生态扩展,提供面向企业生产环境的数据库能力。',
+ coreItems: [
+ {
+ title: '核心开源',
+ description: '采用 Apache 2.0 协议开源,无厂商限制,代码透明且支持定制化开发。',
+ },
+ {
+ title: '深度 Oracle 兼容',
+ description: '通过 PL/iSQL 过程语言和 ivorysql_ora 插件实现 PL/SQL 语法兼容,支持 Oracle 数据库迁移。',
+ },
+ {
+ title: '国产化全平台兼容',
+ description: '全面兼容国内外主流软硬件,兼容国产芯片架构和操作系统,提供全平台介质包确保便捷部署。',
+ },
+ {
+ title: '云原生支持',
+ description: '容器化方案覆盖 Docker Compose/Swarm、K8S Operator 及云服务平台。',
+ },
+ {
+ title: '企业级支持',
+ description: '由瀚高股份提供技术支持,并在多个企业生产环境落地。',
+ },
+ {
+ title: '生态融合',
+ description: '继承 PostgreSQL 完整 SQL 能力、可靠性和丰富生态组件。',
+ },
+ {
+ title: '场景覆盖广',
+ description: '覆盖企业数据库、LBS、数据仓库、建站开发、数据库迁移等核心场景。',
+ },
+ {
+ title: '易用性强',
+ description: '降低系统管理成本,提供开发者友好接口和第三方工具集成能力。',
+ },
+ ],
+ scenariosTitle: 'IvorySQL 应用场景',
+ scenariosDesc: '覆盖从交易系统到分析平台的典型数据库工作负载。',
+ scenarioItems: [
+ {
+ title: '企业数据库',
+ description: '适用于 ERP、交易系统、财务系统等对高可用和复杂业务逻辑有要求的场景。',
+ },
+ {
+ title: 'LBS 应用',
+ description: '支持地理空间查询(如 O2O、游戏地图),通过 PostGIS 实现位置服务。',
+ },
+ {
+ title: '数据仓库 / 大数据',
+ description: '利用丰富数据类型和计算能力搭建分析平台。',
+ },
+ {
+ title: '建站 / App 开发',
+ description: '依托高性能能力提升网站与应用效率。',
+ },
+ {
+ title: '数据库迁移',
+ description: '支持将 Oracle 数据库迁移到 IvorySQL。',
+ },
+ ],
+ installTitle: 'IvorySQL 安装部署',
+ installDesc:
+ '结合官网文档与版本发布信息,提供从快速上手到生产部署的清晰路径,可按环境选择包安装、源码构建或容器化部署。',
+ installItems: [
+ {
+ title: '快速安装(推荐)',
+ description: '通过官方安装文档完成依赖准备、实例初始化和服务启动,适合首次体验与标准化部署。',
+ action: { label: '查看安装文档', to: '/docs-installation' },
+ },
+ {
+ title: '版本与介质包安装',
+ description: '在 Releases 页面查看当前稳定版本与历史版本,并根据系统环境选择对应安装介质包。',
+ action: { label: '查看 Releases', to: '/releases-page' },
+ },
+ {
+ title: '容器化部署',
+ description: '基于官方 Docker 仓库进行镜像部署,便于在开发测试、CI/CD 与云原生环境中快速落地。',
+ action: { label: '查看 Docker 仓库', href: 'https://github.com/IvorySQL/docker_library' },
+ },
+ ],
+ ecosystemTitle: 'IvorySQL 及周边工具生态',
+ ecosystemDesc:
+ '社区提供丰富的生态工具:客户端工具、高可用工具、云原生工具、监控运维工具、备份恢复工具、地理信息工具等。',
+ ecosystemGroups: [
+ { title: '数据访问中间件', items: ['pgpool-II', 'pgBouncer', 'odyssey', 'HAProxy', 'ShardingSphere', 'Citus', 'vip-manager'], wide: true },
+ { title: 'ORM', items: ['Go', 'NodeJS', 'MyBatis', 'Hibernate'] },
+ { title: '标准 SQL 及驱动', items: ['libpq', 'JDBC', 'ODBC', 'NodeJS', 'psycopg2', 'Go', 'Python', 'Rust', 'Ruby', 'ADO.NET', 'lib/pq', 'pgx'], wide: true },
+ { title: '客户端工具', items: ['DBeaver', 'pgAdmin', 'Navicat', 'Navicat Premium'] },
+ { title: '内核扩展', items: ['Oracle 兼容', 'PG 兼容及跟进'] },
+ { title: '高可靠', items: ['pg_rman', 'WAL-G', 'pg_probackup', 'pgBackRest'] },
+ { title: '集群工具', items: ['Patroni', 'repmgr', 'Pacemaker Corosync'] },
+ { title: '监控运维', items: ['Prometheus', 'Alertmanager', 'pgMonitor', 'Grafana', 'PoWA'] },
+ { title: '异构数据库访问工具', items: ['Debezium', 'pglogical', 'mysql_fdw', 'oracle_fdw'] },
+ { title: '多模数据库', items: ['TimescaleDB', 'DocumentDB', 'PostgreSQL AGE', 'FerretDB'] },
+ { title: '地理信息', items: ['PostGIS', 'pgRouting'] },
+ { title: '机器学习及 AI', items: ['pgvector', 'MADlib', 'pg_ai_query'] },
+ { title: 'DDL 及数据加载工具', items: ['pg_bulkload', 'ddlx'] },
+ { title: '在线体验平台', items: ['postgres-wasm', 'IVYOnlineTrial'] },
+ { title: '定时任务工具', items: ['pg_cron', 'pgAgent', 'pg_jobs'] },
+ { title: '生态合作', items: ['Yukon', 'StackGres', 'Databene', 'WhaleOps'] },
+ { title: '迁移/评估工具', items: ['Ora2Pg', 'ivyMigration', 'ivyEvaluation'] },
+ {
+ title: '云生态',
+ items: ['Docker Compose', 'Podman', 'Docker Swarm', 'IvorySQL Cloud', 'IvorySQL Operator', 'IvorySQL Serverless'],
+ },
+ ],
+ ecosystemCategories: [
+ { title: '连接与分发层', desc: '连接池、负载均衡与水平分片', accent: 'blue', tools: ['pgpool-II', 'pgBouncer', 'odyssey', 'HAProxy', 'ShardingSphere', 'Citus', 'vip-manager'] },
+ { title: '高可用与备份', desc: '集群管理、自动故障转移与时间点恢复', accent: 'teal', tools: ['Patroni', 'repmgr', 'Pacemaker Corosync', 'StackGres', 'pg_rman', 'WAL-G', 'pg_probackup', 'pgBackRest', 'Docker Compose', 'Podman', 'Docker Swarm'] },
+ { title: '开发者工具与驱动', desc: '图形客户端、ORM 框架与多语言驱动', accent: 'indigo', tools: ['DBeaver', 'pgAdmin', 'Navicat', 'Navicat Premium', 'MyBatis', 'Hibernate', 'libpq', 'JDBC', 'ODBC', 'psycopg2', 'pgx', 'ADO.NET', 'lib/pq', 'Ruby', 'Rust', 'Go', 'NodeJS', 'Python'] },
+ { title: '监控与运维', desc: '指标采集、可视化大屏与查询性能分析', accent: 'amber', tools: ['Prometheus', 'Alertmanager', 'pgMonitor', 'Grafana', 'PoWA', 'pg_cron', 'pgAgent', 'pg_jobs'] },
+ { title: '数据集成与迁移', desc: 'CDC 变更捕获、异构数据访问与 Oracle 迁移', accent: 'purple', tools: ['Debezium', 'pglogical', 'mysql_fdw', 'oracle_fdw', 'Ora2Pg', 'ivyMigration', 'ivyEvaluation', 'pg_bulkload', 'ddlx', 'Yukon', 'Databene', 'WhaleOps'] },
+ { title: 'AI、地理与多模型', desc: '向量检索、时序、地理空间与图数据库扩展', accent: 'rose', tools: ['pgvector', 'MADlib', 'pg_ai_query', 'PostGIS', 'pgRouting', 'TimescaleDB', 'DocumentDB', 'PostgreSQL AGE', 'FerretDB'] },
+ ],
+ ecosystemFooters: [
+ '操作系统(windows / CentOS / Redhat / ubuntu / openEuler / 银河麒麟 / 统信 UOS 等)',
+ 'x86、鲲鹏、龙芯、兆芯、申威、海光、飞腾、MIPS、RISC-V',
+ ],
+ ecosystemLegend: [
+ { label: '已支持', tone: 'supported' },
+ { label: '正在支持', tone: 'progress' },
+ { label: '未来支持', tone: 'planned' },
+ { label: '闭源产品', tone: 'proprietary' },
+ ],
+ compatibilityTitle: 'IvorySQL 兼容认证',
+ compatibilityDesc: '更多兼容认证与生态合作信息,请查看合作伙伴页面。',
+ },
+ en: {
+ slogan: 'The Open-Source PostgreSQL for Seamless Oracle Compatibility.',
+ intro:
+ 'Bridge the gap between Oracle and PostgreSQL with IvorySQL. Experience a robust, open-source database that combines the power of PostgreSQL with native Oracle syntax support, PL/SQL compatibility, and enterprise-grade performance. Migrate faster, lower costs, and scale with confidence.',
+ heroBadges: ['Oracle Compatibility', 'Apache 2.0 Open-Source', 'Built on PostgreSQL'],
+ latestVersionPrefix: 'Latest Version',
+ latestVersionLabel: 'IvorySQL 5.1',
+ actions: [
+ { label: 'Free Download', to: '/releases-page', ariaLabel: 'Free Download IvorySQL' },
+ { label: 'Online Trial', href: ONLINE_TRIAL_URL, ariaLabel: 'Try IvorySQL Online' },
+ { label: 'Latest Webinars', to: '/webinars-page', ariaLabel: 'View Latest IvorySQL Webinars' },
+ ],
+ heroTrustLabel: 'Trusted by enterprises worldwide',
+ statsItems: [
+ { value: 'PostgreSQL 18', label: 'Kernel Base' },
+ { value: 'Apache 2.0', label: 'Open Source' },
+ { value: '55+', label: 'Ecosystem Tools' },
+ { value: 'Oracle SQL', label: 'Natively Compatible' },
+ ],
+ oracleShowcase: {
+ title: 'Run Oracle Code. No Rewrite.',
+ subtitle: 'Oracle Compatibility',
+ points: [
+ 'PL/iSQL supports Oracle PL/SQL procedural syntax natively',
+ 'ivorysql_ora plugin provides Oracle built-in functions',
+ 'compatible_mode switch toggles compatibility on the fly',
+ 'Oracle-style Package structures supported out of the box',
+ ],
+ cta: 'View Migration Guide',
+ ctaTo: 'https://docs.ivorysql.org/en/ivorysql-doc/v5.3/4.5',
+ },
+ coreTitle: 'Core Advantages',
+ coreDesc: 'From kernel compatibility to ecosystem integration, built for production workloads.',
+ coreItems: [
+ {
+ title: 'Open Source Core',
+ description: 'Apache 2.0 licensed with no vendor lock-in, transparent code, and easy customization.',
+ },
+ {
+ title: 'Deep Oracle Compatibility',
+ description: 'PL/iSQL and the ivorysql_ora extension provide strong PL/SQL compatibility for Oracle migrations.',
+ },
+ {
+ title: 'Full-Platform Compatibility',
+ description: 'Compatible with mainstream hardware and operating systems, including domestic chip architectures.',
+ },
+ {
+ title: 'Cloud-Native Support',
+ description: 'Container-ready support across Docker Compose/Swarm, K8S Operator, and cloud platforms.',
+ },
+ {
+ title: 'Enterprise Support',
+ description: 'Backed by HighGo and validated in production-grade enterprise deployments.',
+ },
+ {
+ title: 'Ecosystem Integration',
+ description: 'Inherits PostgreSQL SQL completeness, reliability, and ecosystem extensibility.',
+ },
+ {
+ title: 'Broad Scenario Coverage',
+ description: 'Covers enterprise workloads, LBS, data warehousing, web/app development, and migrations.',
+ },
+ {
+ title: 'Easy to Use',
+ description: 'Reduces management overhead with developer-friendly interfaces and third-party integration.',
+ },
+ ],
+ scenariosTitle: 'Application Scenarios',
+ scenariosDesc: 'Supports mainstream database workloads from OLTP systems to analytical platforms.',
+ scenarioItems: [
+ {
+ title: 'Enterprise Databases',
+ description: 'Fits ERP, transaction systems, and finance systems requiring high availability and complex logic.',
+ },
+ {
+ title: 'LBS Applications',
+ description: 'Supports geospatial workloads such as O2O and game maps through PostGIS.',
+ },
+ {
+ title: 'Data Warehouse / Big Data',
+ description: 'Build analytical platforms with rich data types and robust processing capabilities.',
+ },
+ {
+ title: 'Websites / App Development',
+ description: 'Improves website and application efficiency with high-performance database capabilities.',
+ },
+ {
+ title: 'Database Migration',
+ description: 'Enables direct migration paths from Oracle databases to IvorySQL.',
+ },
+ ],
+ installTitle: 'IvorySQL Installation & Deployment',
+ installDesc:
+ 'Based on official docs and release resources, choose package installation, source build, or container deployment to match your environment.',
+ installItems: [
+ {
+ title: 'Quick Installation (Recommended)',
+ description:
+ 'Follow the official installation guide to prepare dependencies, initialize clusters, and start services quickly.',
+ action: { label: 'Installation Guide', to: '/docs-installation' },
+ },
+ {
+ title: 'Packages & Releases',
+ description:
+ 'Use the Releases page to check stable/historical versions and pick proper installation packages for your platform.',
+ action: { label: 'View Releases', to: '/releases-page' },
+ },
+ {
+ title: 'Container Deployment',
+ description:
+ 'Use the official Docker repository for fast setup in development, CI/CD pipelines, and cloud-native environments.',
+ action: { label: 'Docker Repository', href: 'https://github.com/IvorySQL/docker_library' },
+ },
+ ],
+ ecosystemTitle: 'IvorySQL Ecosystem & Tools',
+ ecosystemDesc:
+ 'The community provides a rich ecosystem of tools, including client tools, high availability tools, cloud-native tools, monitoring and operations tools, backup and recovery tools, and geospatial tools.',
+ ecosystemGroups: [
+ {
+ title: 'Data Access Middleware',
+ items: ['pgpool-II', 'pgBouncer', 'odyssey', 'HAProxy', 'ShardingSphere', 'Citus', 'vip-manager'],
+ wide: true,
+ },
+ { title: 'ORM', items: ['Go', 'NodeJS', 'MyBatis', 'Hibernate'] },
+ {
+ title: 'Standard SQL & Drivers',
+ items: ['libpq', 'JDBC', 'ODBC', 'NodeJS', 'psycopg2', 'Go', 'Python', 'Rust', 'Ruby', 'ADO.NET', 'lib/pq', 'pgx'],
+ wide: true,
+ },
+ { title: 'Client Tools', items: ['DBeaver', 'pgAdmin', 'Navicat', 'Navicat Premium'] },
+ { title: 'Core Extensions', items: ['Oracle Compatibility', 'PG Compatibility & Upstream Tracking'] },
+ { title: 'High Availability', items: ['pg_rman', 'WAL-G', 'pg_probackup', 'pgBackRest'] },
+ { title: 'Cluster Management Tools', items: ['Patroni', 'repmgr', 'Pacemaker Corosync'] },
+ { title: 'Monitoring & Operations', items: ['Prometheus', 'Alertmanager', 'pgMonitor', 'Grafana', 'PoWA'] },
+ { title: 'Heterogeneous Access Tools', items: ['Debezium', 'pglogical', 'mysql_fdw', 'oracle_fdw'] },
+ { title: 'Multi-Model Database', items: ['TimescaleDB', 'DocumentDB', 'PostgreSQL AGE', 'FerretDB'] },
+ { title: 'Geospatial', items: ['PostGIS', 'pgRouting'] },
+ { title: 'Machine Learning & AI', items: ['pgvector', 'MADlib', 'pg_ai_query'] },
+ { title: 'DDL & Data Loading Tools', items: ['pg_bulkload', 'ddlx'] },
+ { title: 'Online Demo Platform', items: ['postgres-wasm', 'IVYOnlineTrial'] },
+ { title: 'Job Scheduling Tools', items: ['pg_cron', 'pgAgent', 'pg_jobs'] },
+ { title: 'Ecosystem Partnerships', items: ['Yukon', 'StackGres', 'Databene', 'WhaleOps'] },
+ { title: 'Migration & Assessment Tools', items: ['Ora2Pg', 'ivyMigration', 'ivyEvaluation'] },
+ {
+ title: 'Cloud Ecosystem',
+ items: ['Docker Compose', 'Podman', 'Docker Swarm', 'IvorySQL Cloud', 'IvorySQL Operator', 'IvorySQL Serverless'],
+ },
+ ],
+ ecosystemCategories: [
+ { title: 'Connectivity & Pooling', desc: 'Connection pooling, load balancing & horizontal sharding', accent: 'blue', tools: ['pgpool-II', 'pgBouncer', 'odyssey', 'HAProxy', 'ShardingSphere', 'Citus', 'vip-manager'] },
+ { title: 'High Availability & Backup', desc: 'Cluster management, automatic failover & point-in-time recovery', accent: 'teal', tools: ['Patroni', 'repmgr', 'Pacemaker Corosync', 'StackGres', 'pg_rman', 'WAL-G', 'pg_probackup', 'pgBackRest', 'Docker Compose', 'Podman', 'Docker Swarm'] },
+ { title: 'Developer Tools & Drivers', desc: 'GUI clients, ORM frameworks & multi-language database drivers', accent: 'indigo', tools: ['DBeaver', 'pgAdmin', 'Navicat', 'Navicat Premium', 'MyBatis', 'Hibernate', 'libpq', 'JDBC', 'ODBC', 'psycopg2', 'pgx', 'ADO.NET', 'lib/pq', 'Ruby', 'Rust', 'Go', 'NodeJS', 'Python'] },
+ { title: 'Monitoring & Operations', desc: 'Metrics collection, dashboards & query performance analysis', accent: 'amber', tools: ['Prometheus', 'Alertmanager', 'pgMonitor', 'Grafana', 'PoWA', 'pg_cron', 'pgAgent', 'pg_jobs'] },
+ { title: 'Data Integration & Migration', desc: 'CDC, heterogeneous access & Oracle-to-PostgreSQL migration', accent: 'purple', tools: ['Debezium', 'pglogical', 'mysql_fdw', 'oracle_fdw', 'Ora2Pg', 'ivyMigration', 'ivyEvaluation', 'pg_bulkload', 'ddlx', 'Yukon', 'Databene', 'WhaleOps'] },
+ { title: 'AI, Geo & Multi-Model', desc: 'Vector search, time-series, geospatial & graph extensions', accent: 'rose', tools: ['pgvector', 'MADlib', 'pg_ai_query', 'PostGIS', 'pgRouting', 'TimescaleDB', 'DocumentDB', 'PostgreSQL AGE', 'FerretDB'] },
+ ],
+ ecosystemFooters: [
+ 'Operating System (windows / CentOS / Redhat / ubuntu / openEuler / kylin OS / UnionTech OS)',
+ 'x86 / Kunpeng / LoongArch / Zhaoxin / Sunway / Hygon / Phytium / MIPS / RISC-V',
+ ],
+ ecosystemLegend: [
+ { label: 'Supported', tone: 'supported' },
+ { label: 'Support In Progress', tone: 'progress' },
+ { label: 'Support Planned', tone: 'planned' },
+ { label: 'Proprietary Software', tone: 'proprietary' },
+ ],
+ compatibilityTitle: 'IvorySQL Compatibility Certificates',
+ compatibilityDesc: 'See more compatibility certificates and ecosystem partnerships on the partners page.',
+ },
+};
+
+function ActionLink({ action, className }) {
+ if (action.href) {
+ return (
+
+ {action.label}
+
+ );
+ }
return (
-
-
- {/* HOW 大会宣传,根据中英版显示不同图片及链接*/}
-
- {/* 页面一 */}
-
-
-
-
- {/* */}
-
-
-
-
IvorySQL
-
Open Source Oracle Compatible PostgreSQL
-
-
- Online Trial
-
-
- Learn More
-
-
-
-
-
- {/* */}
-
-
-
-
-
- {/* 页面二 */}
-
-
-

-
-
-
-

-
-
-
-
-
+
+ {action.label}
+
);
}
function ChatWidget() {
- const {siteConfig:{customFields}} = useDocusaurusContext();
-
+ const {
+ siteConfig: { customFields },
+ } = useDocusaurusContext();
+
useEffect(() => {
- // 创建外部 script 标签加载 SDK
const script = document.createElement('script');
- script.src = "https://lf-cdn.coze.cn/obj/unpkg/flow-platform/chat-app-sdk/1.1.0-beta.3/libs/cn/index.js";
+ script.src = 'https://lf-cdn.coze.cn/obj/unpkg/flow-platform/chat-app-sdk/1.1.0-beta.3/libs/cn/index.js';
script.async = true;
- // 当脚本加载完成后调用初始化代码
script.onload = () => {
if (window.CozeWebSDK && window.CozeWebSDK.WebChatClient) {
new window.CozeWebSDK.WebChatClient({
@@ -122,43 +556,477 @@ function ChatWidget() {
componentProps: {
title: 'IvorySQL Chatroom',
icon: 'https://raw.githubusercontent.com/IvorySQL/Ivory-www/main/static/img/ivory-black.png',
-
},
auth: {
- type: "token",
+ type: 'token',
token: customFields.patToken,
- onRefreshToken: function () {
+ onRefreshToken() {
return customFields.patToken;
- }
- }
+ },
+ },
});
} else {
- console.error('CozeWebSDK 未加载成功!');
+ console.error('Failed to load CozeWebSDK.');
}
};
- // 将 script 标签添加到 body 中
document.body.appendChild(script);
-
- // 可选:组件卸载时清除 script 标签
return () => {
document.body.removeChild(script);
};
- }, []);
+ }, [customFields.botId, customFields.patToken]);
+
+ return null;
+}
- return null; // 该组件不需要渲染任何内容
+function SectionTitle({ title, Icon }) {
+ return (
+
+
+ {Icon ? (
+
+
+
+ ) : null}
+
{title}
+
+
+ );
}
export default function Home() {
- const {siteConfig} = useDocusaurusContext();
+ const { siteConfig, i18n } = useDocusaurusContext();
+ const isZh = i18n.currentLocale.toLowerCase().startsWith('zh');
+ const content = isZh ? CONTENT.zh : CONTENT.en;
+ const [latestVersionLabel, setLatestVersionLabel] = useState(content.latestVersionLabel);
+ const certImages = [
+ '/img/partners/cert1.jpg',
+ '/img/partners/cert2.jpg',
+ '/img/partners/cert3.jpg',
+ '/img/partners/cert4.jpg',
+ '/img/partners/cert5.png',
+ ];
+ const certCarouselImages = [...certImages, ...certImages];
+
+ // Scroll-triggered reveal via IntersectionObserver
+ useEffect(() => {
+ const elements = document.querySelectorAll('[data-reveal]');
+ if (!elements.length) return;
+
+ const observer = new IntersectionObserver(
+ (entries) => {
+ entries.forEach((entry) => {
+ if (entry.isIntersecting) {
+ entry.target.dataset.revealed = 'true';
+ observer.unobserve(entry.target);
+ }
+ });
+ },
+ { threshold: 0.12, rootMargin: '0px 0px -80px 0px' },
+ );
+
+ elements.forEach((el) => observer.observe(el));
+ return () => observer.disconnect();
+ }, []);
+
+ useEffect(() => {
+ let cancelled = false;
+
+ setLatestVersionLabel(content.latestVersionLabel);
+
+ const cacheLabel = readLatestVersionFromCache();
+ if (cacheLabel) {
+ setLatestVersionLabel(cacheLabel);
+ return () => {
+ cancelled = true;
+ };
+ }
+
+ const updateLatestVersion = async () => {
+ try {
+ const response = await fetch(LATEST_RELEASE_API_URL, {
+ headers: {
+ Accept: 'application/vnd.github+json',
+ },
+ });
+
+ if (!response.ok) {
+ return;
+ }
+
+ const release = await response.json();
+ const label = formatLatestReleaseLabel(release, content.latestVersionLabel);
+
+ if (!cancelled && label) {
+ setLatestVersionLabel(label);
+ writeLatestVersionToCache(label);
+ }
+ } catch {
+ // Keep default label when request fails.
+ }
+ };
+
+ updateLatestVersion();
+
+ return () => {
+ cancelled = true;
+ };
+ }, [content.latestVersionLabel]);
+
return (
-
+
-
-
-
+
+
+
+
+
+ {content.heroBadges.map((badge) => (
+ {badge}
+ ))}
+
+
IvorySQL
+
{content.slogan}
+
+ {content.actions.map((action) => (
+
+ ))}
+
+
+
+
+
+
+
+
+ {/* Trusted-by customer bar */}
+
+
{content.heroTrustLabel}
+
+ {TRUSTED_CUSTOMERS.map((c) => {
+ const displayName = isZh && c.nameZh ? c.nameZh : c.name;
+ return (
+ -
+ {c.logo
+ ?
+ : {displayName}
+ }
+
+ );
+ })}
+
+
+
+
+
+
+
+ {content.statsItems.map((stat) => (
+
+ {stat.value}
+ {stat.label}
+
+ ))}
+
+
+
+
+
+
+
+
+
{content.oracleShowcase.subtitle}
+
{content.oracleShowcase.title}
+
+ {content.oracleShowcase.points.map((pt) => (
+ -
+ ✓
+ {pt}
+
+ ))}
+
+
+ {content.oracleShowcase.cta}
+
+
+
+
+
+
+
+ {isZh ? 'Oracle 语法 → IvorySQL' : 'Oracle syntax → IvorySQL'}
+
+
+
{isZh ? '-- Oracle Package 结构' : '-- Oracle Package syntax'}
+
CREATE OR REPLACE PACKAGE hr_pkg AS
+
FUNCTION get_salary(emp_id NUMBER)
+
RETURN NUMBER;
+
END;
+
/
+
+
{isZh ? '-- Oracle 内置函数' : '-- Oracle built-in functions'}
+
SELECT NVL(salary, 0),
+
TO_DATE('2024-01-01', 'YYYY-MM-DD'),
+
DECODE(dept_id, 10, 'HR', 'Other')
+
FROM employees;
+
+
✓ {isZh ? '与 Oracle 100% 语法兼容' : '100% Oracle syntax compatible'}
+
+
+
+
+
+
+
+
+
+
{content.coreDesc}
+
+ {content.coreItems.map((item, index) => {
+ const CardIcon = CORE_CARD_ICONS[index % CORE_CARD_ICONS.length];
+ return (
+
+
+
+
+
+
{item.title}
+
{item.description}
+
+
+ );
+ })}
+
+
+
+
+
+
+
+
{content.scenariosDesc}
+
+ {content.scenarioItems.map((item, index) => {
+ const CardIcon = SCENARIO_CARD_ICONS[index % SCENARIO_CARD_ICONS.length];
+ return (
+
+
+
+
+
+
{item.title}
+
+ {item.description}
+
+ );
+ })}
+
+
+
+
+
+
+
+
{content.installDesc}
+
+ {content.installItems.map((item, index) => {
+ const CardIcon = INSTALL_CARD_ICONS[index % INSTALL_CARD_ICONS.length];
+ return (
+
+
+
+
+
+
{item.title}
+
+ {item.description}
+
+
+ );
+ })}
+
+
+
+
+
+
+
+
{content.ecosystemDesc}
+
+ {/* 6 category spotlight cards */}
+
+ {content.ecosystemCategories.map((cat, idx) => {
+ const CatIcon = [Icon01, Icon02, Icon03, Icon04, Icon05, Icon06][idx % 6];
+ return (
+
+
+
+
+
{cat.title}
+
{cat.desc}
+
+
+
+ {cat.tools.map((item) => {
+ const tone = getEcosystemToolTone(item);
+ const meta = TOOL_META[item];
+ const tooltipDesc = meta && (isZh ? (meta.descZh || meta.desc) : meta.desc);
+ return (
+
+ {item}
+ {meta && (
+
+ {tooltipDesc}
+ {meta.url && (
+
+ {isZh ? '访问官网 →' : 'Visit homepage →'}
+
+ )}
+
+ )}
+
+ );
+ })}
+
+
+ );
+ })}
+
+
+ {/* Platform coverage bar */}
+
+ {content.ecosystemFooters.map((line) => (
+
{line}
+ ))}
+
+
+ {/* Legend */}
+
+ {content.ecosystemLegend.map((legend) => (
+
+
+ {legend.label}
+
+ ))}
+
+
+ {/* View all tools link */}
+
+
+
+
+
+
+
+
{content.compatibilityDesc}
+
+
+ {certCarouselImages.map((image, index) => (
+
+
+

+
+
+ ))}
+
+
+
+
+
+
+ {/* Tech decorative elements */}
+
+ {/* Right: concentric orbital rings with node dots */}
+
+ {/* Left: circuit board fragment */}
+
+
+
+
+
{isZh ? '准备好开始迁移了吗?' : 'Ready to Start Your Migration?'}
+
{isZh ? '免费开源,生产可用,立即体验 IvorySQL。' : 'Free, open-source, production-ready. Try IvorySQL today.'}
+
+
+
+
);
diff --git a/src/pages/index.module.css b/src/pages/index.module.css
index afdb33b..6e3becf 100644
--- a/src/pages/index.module.css
+++ b/src/pages/index.module.css
@@ -1,189 +1,2576 @@
-/**
- * CSS files with the .module.css suffix will be treated as CSS modules
- * and scoped locally.
- */
-@import url(https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick.min.css);
-@import url(https://cdnjs.cloudflare.com/ajax/libs/slick-carousel/1.6.0/slick-theme.min.css);
-.heroBanner {
- padding: 5rem 0;
+/* ─── Keyframes ─────────────────────────────────────────────── */
+@keyframes fadeInUp {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+/* latestPulse: animate opacity on ::before ring instead of box-shadow (compositor-only) */
+@keyframes latestPulse {
+ 0%, 100% { opacity: 0; }
+ 50% { opacity: 1; }
+}
+
+@keyframes cardIn {
+ from {
+ opacity: 0;
+ translate: 0 14px;
+ }
+ to {
+ opacity: 1;
+ translate: 0 0;
+ }
+}
+
+@keyframes certScroll {
+ 0% { transform: translateX(0); }
+ 100% { transform: translateX(calc(var(--cert-slide-width) * -5)); }
+}
+
+/* Mascot float — spring-physics easing, starts after entrance completes */
+@keyframes elephantFloat {
+ 0%, 100% { translate: 0 0; }
+ 50% { translate: 0 -10px; }
+}
+
+/* ─── Scroll Reveal ──────────────────────────────────────────── */
+/* :global() ensures attribute selectors are NOT scoped by CSS Modules */
+:global([data-reveal]) {
+ transition:
+ opacity 0.85s cubic-bezier(0.16, 1, 0.3, 1),
+ transform 0.85s cubic-bezier(0.16, 1, 0.3, 1);
+}
+
+/* slide up — starts 60px lower, slightly tilted */
+:global([data-reveal="up"]):not(:global([data-revealed])) {
+ opacity: 0;
+ transform: translateY(60px) scale(0.96);
+}
+
+/* scale emerge — shrinks + sinks before popping in */
+:global([data-reveal="scale"]):not(:global([data-revealed])) {
+ opacity: 0;
+ transform: scale(0.88) translateY(40px);
+}
+
+/* pure fade */
+:global([data-reveal="fade"]):not(:global([data-revealed])) {
+ opacity: 0;
+}
+
+/* Stagger — wider gaps so wave effect is visible */
+:global([data-delay="1"]):not(:global([data-revealed])) { transition-delay: 0.10s; }
+:global([data-delay="2"]):not(:global([data-revealed])) { transition-delay: 0.20s; }
+:global([data-delay="3"]):not(:global([data-revealed])) { transition-delay: 0.30s; }
+:global([data-delay="4"]):not(:global([data-revealed])) { transition-delay: 0.40s; }
+:global([data-delay="5"]):not(:global([data-revealed])) { transition-delay: 0.50s; }
+:global([data-delay="6"]):not(:global([data-revealed])) { transition-delay: 0.60s; }
+:global([data-delay="7"]):not(:global([data-revealed])) { transition-delay: 0.70s; }
+:global([data-delay="8"]):not(:global([data-revealed])) { transition-delay: 0.80s; }
+
+@media (prefers-reduced-motion: reduce) {
+ :global([data-reveal]):not(:global([data-revealed])) {
+ opacity: 1 !important;
+ transform: none !important;
+ transition: none !important;
+ }
+}
+
+/* ─── Page Shell ─────────────────────────────────────────────── */
+.homePage {
+ background: linear-gradient(180deg, #f4f8ff 0%, #ffffff 24%, #f6f9ff 100%);
+ overflow-x: hidden; /* prevent horizontal bleed from rounded corners */
+}
+
+/* ─── Hero Section ───────────────────────────────────────────── */
+.heroSection {
+ position: relative;
+ overflow: hidden;
+ padding: 48px 0 112px;
+ /* Base deep ocean gradient only — stars live in ::after GPU layer */
+ background: linear-gradient(168deg, #060c28 0%, #0b1a50 35%, #102268 60%, #0d3070 100%);
+ color: #f8faff;
+}
+
+/* Shooting star streak — top-right */
+.heroSection::before {
+ content: '';
+ position: absolute;
+ top: 8%;
+ right: 12%;
+ width: 180px;
+ height: 1px;
+ background: linear-gradient(90deg, transparent 0%, rgba(200,230,255,0.65) 60%, rgba(255,255,255,0.9) 100%);
+ transform: rotate(-28deg);
+ transform-origin: right center;
+ border-radius: 1px;
+ filter: blur(0.4px);
+ pointer-events: none;
+}
+
+/* Stars + Nebula — GPU-composited, painted once */
+.heroSection::after {
+ content: '';
+ position: absolute;
+ inset: 0;
+ pointer-events: none;
+ transform: translateZ(0);
+ will-change: transform;
+ background:
+ /* ── Stars: 1px tiny dots ── */
+ radial-gradient(1px 1px at 8% 12%, rgba(255,255,255,0.85) 0%, transparent 100%),
+ radial-gradient(1px 1px at 22% 6%, rgba(255,255,255,0.70) 0%, transparent 100%),
+ radial-gradient(1px 1px at 37% 19%, rgba(255,255,255,0.80) 0%, transparent 100%),
+ radial-gradient(1px 1px at 53% 8%, rgba(255,255,255,0.65) 0%, transparent 100%),
+ radial-gradient(1px 1px at 68% 15%, rgba(255,255,255,0.90) 0%, transparent 100%),
+ radial-gradient(1px 1px at 81% 5%, rgba(255,255,255,0.70) 0%, transparent 100%),
+ radial-gradient(1px 1px at 92% 22%, rgba(255,255,255,0.75) 0%, transparent 100%),
+ radial-gradient(1px 1px at 14% 32%, rgba(255,255,255,0.60) 0%, transparent 100%),
+ radial-gradient(1px 1px at 46% 35%, rgba(255,255,255,0.70) 0%, transparent 100%),
+ radial-gradient(1px 1px at 61% 28%, rgba(255,255,255,0.55) 0%, transparent 100%),
+ radial-gradient(1px 1px at 75% 38%, rgba(255,255,255,0.65) 0%, transparent 100%),
+ radial-gradient(1px 1px at 18% 55%, rgba(255,255,255,0.55) 0%, transparent 100%),
+ radial-gradient(1px 1px at 57% 52%, rgba(255,255,255,0.50) 0%, transparent 100%),
+ radial-gradient(1px 1px at 41% 13%, rgba(255,255,255,0.55) 0%, transparent 100%),
+ radial-gradient(1px 1px at 83% 27%, rgba(255,255,255,0.60) 0%, transparent 100%),
+ radial-gradient(1px 1px at 97% 14%, rgba(255,255,255,0.50) 0%, transparent 100%),
+ /* ── Stars: 2px glowing blue-white ── */
+ radial-gradient(2px 2px at 16% 9%, rgba(200,230,255,0.95) 0%, transparent 100%),
+ radial-gradient(2px 2px at 44% 3%, rgba(200,230,255,0.85) 0%, transparent 100%),
+ radial-gradient(2px 2px at 78% 11%, rgba(200,230,255,0.90) 0%, transparent 100%),
+ radial-gradient(2px 2px at 91% 38%, rgba(200,230,255,0.75) 0%, transparent 100%),
+ radial-gradient(2px 2px at 6% 61%, rgba(200,230,255,0.65) 0%, transparent 100%),
+ radial-gradient(2px 2px at 55% 66%, rgba(200,230,255,0.60) 0%, transparent 100%),
+ radial-gradient(2px 2px at 29% 41%, rgba(255,255,255,0.80) 0%, transparent 100%),
+ radial-gradient(2px 2px at 64% 21%, rgba(255,255,255,0.70) 0%, transparent 100%),
+ /* ── Nebula A: Blue-cyan pillar (top-right) — 3-layer depth ── */
+ radial-gradient(ellipse 28% 18% at 78% 12%, rgba(180,230,255,0.55) 0%, rgba(100,180,255,0.25) 45%, transparent 75%),
+ radial-gradient(ellipse 45% 32% at 74% 17%, rgba( 60,140,255,0.32) 0%, rgba( 30, 90,220,0.15) 55%, transparent 80%),
+ radial-gradient(ellipse 65% 48% at 80% 8%, rgba( 40,100,220,0.14) 0%, transparent 70%),
+ /* ── Nebula B: Purple-violet cloud (left-center) — 3-layer depth ── */
+ radial-gradient(ellipse 22% 28% at 10% 38%, rgba(210,130,255,0.50) 0%, rgba(160, 70,240,0.28) 40%, transparent 72%),
+ radial-gradient(ellipse 38% 42% at 8% 42%, rgba(120, 40,210,0.28) 0%, rgba( 80, 20,180,0.12) 55%, transparent 78%),
+ radial-gradient(ellipse 55% 55% at 5% 48%, rgba( 90, 30,180,0.12) 0%, transparent 70%),
+ /* ── Nebula C: Pink-magenta wisp (center) ── */
+ radial-gradient(ellipse 32% 18% at 52% 42%, rgba(240, 90,200,0.30) 0%, rgba(180, 50,160,0.15) 50%, transparent 75%),
+ radial-gradient(ellipse 50% 28% at 55% 38%, rgba(180, 40,150,0.14) 0%, transparent 70%),
+ /* ── Nebula D: Teal-green aurora (bottom sweep) ── */
+ radial-gradient(ellipse 70% 22% at 35% 88%, rgba( 20,200,180,0.32) 0%, rgba( 10,160,140,0.16) 50%, transparent 75%),
+ radial-gradient(ellipse 90% 30% at 40% 92%, rgba( 10,140,120,0.15) 0%, transparent 68%),
+ /* ── Galaxy dust band — diagonal streak across middle ── */
+ radial-gradient(ellipse 80% 12% at 50% 52%, rgba(120,160,255,0.09) 0%, transparent 100%),
+ /* ── Sea horizon glow ── */
+ linear-gradient(180deg, transparent 52%, rgba(20,70,160,0.38) 78%, rgba(10,35,110,0.60) 100%);
+}
+
+.heroContainer {
+ position: relative;
+ z-index: 1;
+ max-width: 1240px;
+ display: grid;
+ grid-template-columns: minmax(0, 1.05fr) minmax(340px, 540px);
+ gap: 40px;
+ align-items: center;
+}
+
+.heroContent {
+ max-width: 760px;
+ padding: 4px 10px 0 0;
+ display: flex;
+ flex-direction: column;
+ gap: 32px;
+ text-align: left;
+ animation: fadeInUp 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
+}
+
+.heroVisual {
+ position: relative;
+ display: flex;
+ justify-content: center;
+ align-items: center;
+ min-height: 446px;
+ pointer-events: none;
+ animation: fadeInUp 0.9s 0.15s cubic-bezier(0.22, 1, 0.36, 1) both;
+}
+
+.heroVisual :global(svg) {
+ position: relative;
+ z-index: 1;
+ display: block;
+ width: clamp(420px, 34vw, 620px);
+ height: auto;
+ /* will-change promotes to its own compositor layer:
+ filter is rasterized once into the layer texture,
+ the infinite translate animation then only moves the layer — no repaint */
+ will-change: transform;
+ filter:
+ drop-shadow(0 2px 0 rgba(255, 255, 255, 0.08))
+ drop-shadow(0 18px 34px rgba(3, 18, 63, 0.42));
+ transform: translateX(10px);
+ /* Float starts after entrance animation (0.9s + 0.15s delay ≈ 1.1s) */
+ animation: elephantFloat 4.5s 1.2s cubic-bezier(0.37, 0, 0.63, 1) infinite backwards;
+}
+
+.heroVisual::before {
+ content: '';
+ position: absolute;
+ width: min(100%, 520px);
+ aspect-ratio: 1 / 1;
+ border-radius: 50%;
+ background: radial-gradient(circle, rgba(255, 255, 255, 0.24) 0%, rgba(255, 255, 255, 0.06) 42%, rgba(255, 255, 255, 0) 72%);
+}
+
+.heroVisual::after {
+ content: none;
+}
+
+/* ── Hero Trust Bar ────────────────────────────────────────────── */
+.heroTrustBar {
+ position: relative;
+ z-index: 2;
+ width: 100%;
+ padding: 20px 0 48px; /* extra bottom so statsStrip overlap doesn't cut off content */
+ margin-top: 12px;
+ border-top: 1px solid rgba(255, 255, 255, 0.1);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ flex-wrap: wrap;
+ gap: 16px 28px;
+}
+
+.heroTrustLabel {
+ font-size: 0.78rem;
+ font-weight: 500;
+ letter-spacing: 0.06em;
+ text-transform: uppercase;
+ color: rgba(200, 220, 255, 0.45);
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+.heroTrustList {
+ list-style: none;
+ margin: 0;
+ padding: 0;
+ display: flex;
+ align-items: center;
+ flex-wrap: wrap;
+ gap: 6px 24px;
+}
+
+.heroTrustItem {
+ display: flex;
+ align-items: center;
+}
+
+/* Logo images — transparent bg: turn white via brightness+invert */
+.heroTrustLogo {
+ height: 28px;
+ width: auto;
+ object-fit: contain;
+ filter: brightness(0) invert(1);
+ opacity: 0.45;
+ transition: opacity 0.2s;
+}
+
+.heroTrustItem:hover .heroTrustLogo {
+ opacity: 0.75;
+}
+
+/* Logo images — white bg: brightness+invert to white, same as regular logos */
+.heroTrustLogoBg {
+ height: 28px;
+ width: auto;
+ object-fit: contain;
+ filter: brightness(0) invert(1);
+ opacity: 0.45;
+ transition: opacity 0.2s;
+}
+
+.heroTrustItem:hover .heroTrustLogoBg {
+ opacity: 0.85;
+}
+
+/* Text fallback badge for companies without logos */
+.heroTrustText {
+ font-size: 0.82rem;
+ font-weight: 600;
+ color: rgba(200, 220, 255, 0.45);
+ letter-spacing: 0.02em;
+ white-space: nowrap;
+ transition: color 0.2s;
+}
+
+.heroTrustItem:hover .heroTrustText {
+ color: rgba(200, 220, 255, 0.75);
+}
+
+/* Dot separator between items */
+.heroTrustList > li + li::before {
+ content: '·';
+ margin-right: 24px;
+ color: rgba(255, 255, 255, 0.18);
+ font-size: 1.1rem;
+ line-height: 1;
+ pointer-events: none;
+}
+
+.heroTitle {
+ margin: 0;
+ background: linear-gradient(135deg, #ffffff 0%, #d4e8ff 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ font-size: clamp(2.5rem, 4.5vw, 3.65rem);
+ line-height: 1.1;
+ font-weight: 800;
+ letter-spacing: -0.02em;
+ filter: drop-shadow(0 8px 24px rgba(3, 18, 63, 0.32));
+}
+
+.slogan {
+ margin: 0;
+ max-width: 60ch;
+ font-size: clamp(1.22rem, 2.2vw, 1.78rem);
+ font-weight: 700;
+ color: #fbaf42;
+ line-height: 1.5;
+ text-shadow: 0 3px 12px rgba(12, 25, 78, 0.28);
+}
+
+.heroBadges {
+ margin: 0;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+ gap: 10px;
+}
+
+.heroBadge {
+ border-radius: 999px;
+ border: 1px solid rgba(180, 208, 255, 0.5);
+ background: rgba(12, 32, 100, 0.55);
+ padding: 6px 13px;
+ font-size: 0.82rem;
+ color: #e7f0ff;
+ transition: background 0.2s ease, border-color 0.2s ease;
+}
+
+.heroBadge:hover {
+ background: rgba(255, 255, 255, 0.18);
+ border-color: rgba(180, 208, 255, 0.75);
+}
+
+.heroIntro {
+ margin: 0;
+ max-width: 72ch;
+ color: #dfebff;
+ font-size: 1rem;
+ line-height: 1.75;
+ background: rgba(7, 22, 68, 0.68);
+ border: 1px solid rgba(170, 200, 255, 0.24);
+ border-left: 3px solid rgba(251, 175, 66, 0.9);
+ border-radius: 16px;
+ padding: 20px 22px;
+ box-shadow:
+ 0 0 0 1px rgba(255, 255, 255, 0.04) inset,
+ 0 12px 28px rgba(3, 18, 63, 0.2);
+}
+
+.latestVersion {
+ margin: 0;
+ position: relative;
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+ padding: 10px 16px;
+ border-radius: 999px;
+ border: 1px solid rgba(123, 171, 255, 0.58);
+ background: linear-gradient(90deg, rgba(74, 143, 255, 0.3) 0%, rgba(255, 255, 255, 0.08) 100%);
+ box-shadow: 0 10px 22px rgba(6, 22, 70, 0.22);
+}
+
+/* Glow ring — opacity animation is compositor-only (no paint) */
+.latestVersion::before {
+ content: '';
+ position: absolute;
+ inset: -5px;
+ border-radius: 999px;
+ box-shadow: 0 0 0 5px rgba(251, 175, 66, 0.22);
+ opacity: 0;
+ pointer-events: none;
+ animation: latestPulse 3.6s ease-in-out 3;
+}
+
+.latestVersion span {
+ color: #deebff;
+ font-size: 0.9rem;
+ font-weight: 500;
+}
+
+.latestVersion a {
+ color: #fffdf8;
+ font-weight: 600;
+ text-decoration: none;
+}
+
+.latestVersion a:hover {
+ text-decoration: underline;
+}
+
+.heroActions {
+ margin: 0;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: flex-start;
+ gap: 12px;
+}
+
+.heroActionsEn {
+ width: 100%;
+ max-width: 900px;
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+}
+
+.actionButton {
+ min-width: 194px;
+ min-height: 48px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ border: 1px solid rgba(198, 220, 255, 0.68);
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.20) 0%, rgba(255, 255, 255, 0.10) 100%);
+ box-shadow:
+ 0 0 0 1px rgba(255, 255, 255, 0.08) inset,
+ 0 10px 22px rgba(6, 22, 70, 0.22);
+ color: #ffffff;
+ font-weight: 600;
+ letter-spacing: 0.02em;
+ cursor: pointer;
+ transition: background 0.2s ease, transform 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease;
+}
+
+.actionButton:focus-visible {
+ outline: 2px solid rgba(255, 255, 255, 0.85);
+ outline-offset: 3px;
+}
+
+.actionButtonEn {
+ min-width: 0;
+ width: 100%;
+ padding-left: 1rem;
+ padding-right: 1rem;
+}
+
+.actionButton:first-child {
+ border-color: rgba(251, 175, 66, 0.96);
+ background: linear-gradient(135deg, #fbb44f 0%, #f79e1f 100%);
+ color: #ffffff;
+ box-shadow:
+ 0 0 0 3px rgba(251, 175, 66, 0.22),
+ 0 14px 30px rgba(245, 151, 23, 0.42),
+ 0 4px 12px rgba(0, 0, 0, 0.18);
+}
+
+.actionButton:hover {
+ color: #ffffff;
+ border-color: rgba(251, 175, 66, 0.94);
+ background: linear-gradient(135deg, rgba(251, 175, 66, 0.95) 0%, rgba(247, 158, 31, 0.95) 100%);
+ transform: translateY(-3px) scale(1.03);
+ box-shadow:
+ 0 0 0 3px rgba(251, 175, 66, 0.28),
+ 0 18px 36px rgba(245, 151, 23, 0.36);
+}
+
+.actionButton:first-child:hover {
+ color: #ffffff;
+ border-color: rgba(252, 188, 92, 0.98);
+ background: linear-gradient(135deg, #fcbf61 0%, #faa12f 100%);
+ transform: translateY(-3px) scale(1.04);
+ box-shadow:
+ 0 0 0 4px rgba(251, 175, 66, 0.32),
+ 0 20px 40px rgba(245, 151, 23, 0.46),
+ 0 4px 12px rgba(0, 0, 0, 0.15);
+}
+
+/* ── SQL Terminal in Hero ── */
+.sqlTerminal {
+ width: 100%;
+ max-width: 480px;
+ border-radius: 14px;
+ overflow: hidden;
+ box-shadow:
+ 0 0 0 1px rgba(100, 160, 255, 0.2),
+ 0 24px 64px rgba(6, 22, 70, 0.5),
+ 0 8px 24px rgba(6, 22, 70, 0.3);
+ font-family: 'Menlo', 'Monaco', 'Consolas', monospace;
+ font-size: 0.82rem;
+ line-height: 1.7;
+}
+
+.sqlTerminalBar {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 10px 14px;
+ background: #1e2433;
+ border-bottom: 1px solid rgba(255,255,255,0.06);
+}
+
+.sqlDot {
+ width: 12px;
+ height: 12px;
+ border-radius: 50%;
+ display: inline-block;
+}
+
+.sqlTerminalTitle {
+ margin-left: 8px;
+ font-size: 0.72rem;
+ color: rgba(180, 200, 255, 0.45);
+ font-family: -apple-system, sans-serif;
+}
+
+.sqlTerminalBody {
+ background: #111827;
+ padding: 18px 20px;
+}
+
+.sqlLine {
+ display: block;
+ white-space: pre;
+}
+
+.sqlComment { color: #6b7a99; font-style: italic; }
+.sqlKw { color: #c792ea; }
+.sqlFn { color: #82aaff; }
+.sqlParam { color: #f07178; }
+.sqlType { color: #ffcb6b; }
+.sqlStr { color: #c3e88d; }
+.sqlNum { color: #f78c6c; }
+.sqlPunct { color: #89ddff; }
+.sqlIndent { display: inline-block; }
+.sqlSpacer { height: 10px; display: block; }
+.sqlGreen { color: #c3e88d; }
+.sqlMuted { color: rgba(150, 180, 230, 0.6); font-style: italic; }
+.sqlPrompt { display: flex; align-items: center; gap: 4px; margin-top: 4px; }
+
+/* ═══════════════════════════════════════════════════════════════
+ SECTIONS — shared shell
+ ═══════════════════════════════════════════════════════════════ */
+.section {
+ position: relative;
+ overflow: hidden;
+ padding: 80px 0 72px;
+}
+
+.section :global(.container) {
+ position: relative;
+ z-index: 1;
+ max-width: 1240px;
+}
+
+/* ─── Section Stacking — rounded-top card transitions ───────────
+ Each section slides over the previous one, removing hard dividers.
+ z-index increases so later sections always render on top.
+ ────────────────────────────────────────────────────────────── */
+.statsStrip,
+.sectionOracleShowcase,
+.sectionToneCore,
+.sectionToneScenario,
+.sectionToneDeployment,
+.sectionToneEcosystem,
+.sectionToneCertificate,
+.ctaBanner {
+ border-radius: 48px 48px 0 0;
+ margin-top: -48px;
+ position: relative;
+}
+
+.statsStrip { z-index: 2; }
+.sectionOracleShowcase { z-index: 3; }
+.sectionToneCore { z-index: 4; }
+.sectionToneScenario { z-index: 5; }
+.sectionToneDeployment { z-index: 6; }
+.sectionToneEcosystem { z-index: 7; }
+.sectionToneCertificate{ z-index: 8; }
+.ctaBanner { z-index: 9; }
+
+/* ─── Section Head ───────────────────────────────────────────── */
+.sectionHead {
+ margin-bottom: 28px;
+ display: flex;
+ justify-content: center;
+}
+
+.sectionTitleRow {
+ display: inline-flex;
+ align-items: center;
+ gap: 10px;
+ padding: 9px 20px;
+ border-radius: 999px;
+ border: 1px solid #d8e6ff;
+ background: linear-gradient(180deg, #ffffff 0%, #f5f9ff 100%);
+ box-shadow:
+ 0 0 0 4px rgba(47, 116, 255, 0.06),
+ 0 6px 18px rgba(21, 63, 131, 0.08);
+}
+
+.sectionIcon {
+ width: 32px;
+ height: 32px;
+ border-radius: 999px;
+ background: linear-gradient(135deg, #eef4ff 0%, #e3efff 100%);
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.sectionIcon :global(svg) {
+ width: 16px;
+ height: 16px;
+}
+
+.sectionTitleRow h2 {
+ margin: 0;
+ background: linear-gradient(135deg, #fbaf42 0%, #f07e0c 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ font-size: clamp(1.55rem, 3vw, 2rem);
+}
+
+.sectionDescription {
+ margin: 0 auto 32px;
+ max-width: 820px;
+ text-align: center;
+ color: #4a5a83;
+ line-height: 1.625;
+}
+
+.wideDescription {
+ max-width: 1080px;
+ text-wrap: pretty;
+ text-wrap: balance;
+}
+
+/* ═══════════════════════════════════════════════════════════════
+ § 1 · CORE ADVANTAGES — Blueprint style
+ Background: clean white + dot grid
+ Cards: left accent border (blue), icon ring, asymmetric feel
+ ═══════════════════════════════════════════════════════════════ */
+.sectionToneCore {
+ background:
+ radial-gradient(circle, rgba(47, 116, 255, 0.055) 1px, transparent 1px),
+ linear-gradient(180deg, #f8fbff 0%, #fcfdff 100%);
+ background-size: 28px 28px, 100% 100%;
+}
+
+.sectionToneCore::before {
+ content: '';
+ position: absolute;
+ width: 420px;
+ height: 420px;
+ right: -130px;
+ top: -210px;
+ border-radius: 50%;
+ background: radial-gradient(circle, rgba(103, 144, 255, 0.12) 0%, rgba(103, 144, 255, 0) 70%);
+}
+
+.sectionToneCore::after {
+ content: '';
+ position: absolute;
+ left: 3%;
+ bottom: 12%;
+ width: 148px;
+ height: 148px;
+ border-radius: 50%;
+ background:
+ radial-gradient(circle at 32% 34%, rgba(251, 175, 66, 0.28) 0%, rgba(251, 175, 66, 0.1) 32%, transparent 65%),
+ radial-gradient(circle at 70% 70%, rgba(66, 178, 255, 0.2) 0%, transparent 60%);
+}
+
+/* Core section title — blue palette */
+.sectionToneCore .sectionTitleRow {
+ border-color: #c5d8ff;
+ background: linear-gradient(180deg, #ffffff 0%, #f0f6ff 100%);
+ box-shadow:
+ 0 0 0 4px rgba(47, 116, 255, 0.07),
+ 0 6px 18px rgba(21, 63, 131, 0.09);
+}
+
+.sectionToneCore .sectionIcon {
+ background: linear-gradient(135deg, #eef4ff 0%, #dde9ff 100%);
+}
+
+.sectionToneCore .sectionTitleRow h2 {
+ background: linear-gradient(135deg, #2f74ff 0%, #4db2ff 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+/* Core advantages: two-column editorial list */
+.advantagesList {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ column-gap: 0;
+ row-gap: 0;
+ position: relative;
+}
+
+/* Vertical center divider */
+.advantagesList::before {
+ content: '';
+ position: absolute;
+ top: 0; bottom: 0;
+ left: 50%;
+ width: 1px;
+ background: linear-gradient(
+ 180deg,
+ transparent 0%,
+ rgba(47, 116, 255, 0.12) 10%,
+ rgba(47, 116, 255, 0.12) 90%,
+ transparent 100%
+ );
+ pointer-events: none;
+}
+
+/* ═══════════════════════════════════════════════════════════════
+ § 2 · APPLICATION SCENARIOS — Soft Aurora style
+ Background: soft indigo/lavender fill
+ Cards: tinted lavender background, top purple accent
+ ═══════════════════════════════════════════════════════════════ */
+.sectionToneScenario {
+ background: linear-gradient(180deg, #f4f3ff 0%, #edeaff 100%);
+}
+
+.sectionToneScenario::before {
+ content: '';
+ position: absolute;
+ width: 480px;
+ height: 480px;
+ left: -180px;
+ bottom: -240px;
+ border-radius: 50%;
+ background: radial-gradient(circle, rgba(140, 109, 255, 0.15) 0%, rgba(140, 109, 255, 0) 70%);
+}
+
+.sectionToneScenario::after {
+ content: '';
+ position: absolute;
+ right: 2%;
+ top: 14%;
+ width: 150px;
+ height: 150px;
+ border-radius: 50%;
+ background:
+ radial-gradient(circle at 70% 28%, rgba(140, 109, 255, 0.2) 0%, transparent 58%),
+ radial-gradient(circle at 30% 70%, rgba(251, 175, 66, 0.22) 0%, rgba(251, 175, 66, 0.08) 35%, transparent 68%);
+}
+
+/* Scenario title — purple palette */
+.sectionToneScenario .sectionTitleRow {
+ border-color: #d9d5f5;
+ background: linear-gradient(180deg, #ffffff 0%, #f8f6ff 100%);
+ box-shadow:
+ 0 0 0 4px rgba(140, 109, 255, 0.07),
+ 0 6px 18px rgba(80, 50, 180, 0.08);
+}
+
+.sectionToneScenario .sectionIcon {
+ background: linear-gradient(135deg, #f3f0ff 0%, #e9e4ff 100%);
+}
+
+.sectionToneScenario .sectionTitleRow h2 {
+ background: linear-gradient(135deg, #8c6dff 0%, #b093ff 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.sectionToneScenario .sectionDescription {
+ color: #4e4a75;
+}
+
+/* Scenario grid — 2+3 editorial layout */
+.scenariosGrid {
+ display: grid;
+ grid-template-columns: repeat(6, 1fr);
+ gap: 20px;
+}
+
+/* Row 1: 2 wide cards */
+.scenariosGrid > article:nth-child(1),
+.scenariosGrid > article:nth-child(2) { grid-column: span 3; }
+
+/* Row 2: 3 medium cards */
+.scenariosGrid > article:nth-child(3),
+.scenariosGrid > article:nth-child(4),
+.scenariosGrid > article:nth-child(5) { grid-column: span 2; }
+
+/* ═══════════════════════════════════════════════════════════════
+ § 3 · INSTALLATION & DEPLOYMENT — Step Process style
+ Background: warm cream
+ Cards: step watermark numbers, teal accent
+ ═══════════════════════════════════════════════════════════════ */
+.sectionToneDeployment {
+ background: linear-gradient(180deg, #fdfbf5 0%, #fff9ed 100%);
+}
+
+.sectionToneDeployment::before {
+ content: '';
+ position: absolute;
+ right: 4%;
+ top: 18%;
+ width: 160px;
+ height: 160px;
+ border-radius: 28px;
+ background:
+ linear-gradient(145deg, rgba(58, 195, 159, 0.18) 0%, rgba(58, 195, 159, 0.06) 48%, rgba(251, 175, 66, 0.14) 100%);
+ transform: rotate(14deg);
+}
+
+/* Deployment title — teal palette */
+.sectionToneDeployment .sectionTitleRow {
+ border-color: #b8eede;
+ background: linear-gradient(180deg, #ffffff 0%, #f0fbf8 100%);
+ box-shadow:
+ 0 0 0 4px rgba(58, 195, 159, 0.08),
+ 0 6px 18px rgba(15, 110, 80, 0.08);
+}
+
+.sectionToneDeployment .sectionIcon {
+ background: linear-gradient(135deg, #edfbf7 0%, #d8f5ee 100%);
+}
+
+.sectionToneDeployment .sectionTitleRow h2 {
+ background: linear-gradient(135deg, #2aaa8a 0%, #3ac39f 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.sectionToneDeployment .sectionDescription {
+ color: #4a5e58;
+}
+
+/* Deployment grid */
+.deploymentGrid {
+ display: grid;
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ gap: 20px;
+ counter-reset: deploy-step;
+}
+
+/* ═══════════════════════════════════════════════════════════════
+ § 4 · ECOSYSTEM & TOOLS — Dark Universe style
+ Background: deep navy — dramatic contrast anchor
+ All child elements adjusted for dark mode
+ ═══════════════════════════════════════════════════════════════ */
+.sectionToneEcosystem {
+ background:
+ radial-gradient(circle at 80% 20%, rgba(100, 160, 255, 0.1) 0%, transparent 50%),
+ radial-gradient(circle at 15% 80%, rgba(251, 175, 66, 0.07) 0%, transparent 45%),
+ linear-gradient(180deg, #1e3578 0%, #1a2f6e 60%, #1c3480 100%);
+}
+
+.sectionToneEcosystem::before {
+ content: '';
+ position: absolute;
+ right: -60px;
+ bottom: -100px;
+ width: 320px;
+ height: 320px;
+ border-radius: 50%;
+ background: radial-gradient(circle, rgba(100, 160, 255, 0.12) 0%, transparent 68%);
+}
+
+.sectionToneEcosystem::after {
+ content: '';
+ position: absolute;
+ left: -40px;
+ top: 40px;
+ width: 240px;
+ height: 240px;
+ border-radius: 50%;
+ background: radial-gradient(circle, rgba(251, 175, 66, 0.09) 0%, transparent 65%);
+}
+
+/* Ecosystem title — amber on deep blue */
+.sectionToneEcosystem .sectionTitleRow {
+ border-color: rgba(251, 175, 66, 0.32);
+ background: rgba(255, 255, 255, 0.07);
+ box-shadow:
+ 0 0 0 4px rgba(251, 175, 66, 0.07),
+ 0 6px 18px rgba(0, 0, 0, 0.22);
+}
+
+.sectionToneEcosystem .sectionIcon {
+ background: rgba(251, 175, 66, 0.16);
+}
+
+.sectionToneEcosystem .sectionTitleRow h2 {
+ background: linear-gradient(135deg, #fbcf6a 0%, #ffd280 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+}
+
+.sectionToneEcosystem .sectionDescription {
+ color: rgba(195, 220, 255, 0.78);
+}
+
+/* ═══════════════════════════════════════════════════════════════
+ § 5 · COMPATIBILITY CERTIFICATES — Premium Warm style
+ Background: warm cream / gold undertone
+ Carousel: gold border treatment
+ ═══════════════════════════════════════════════════════════════ */
+.sectionToneCertificate {
+ background: linear-gradient(180deg, #fffdf8 0%, #fff9ee 100%);
+}
+
+.sectionToneCertificate::before {
+ content: '';
+ position: absolute;
+ right: 5%;
+ top: 20%;
+ width: 200px;
+ height: 200px;
+ border-radius: 50%;
+ background:
+ radial-gradient(circle at 48% 48%, rgba(251, 175, 66, 0.22) 0%, rgba(251, 175, 66, 0.08) 40%, transparent 68%),
+ radial-gradient(circle at 74% 30%, rgba(66, 178, 255, 0.12) 0%, transparent 58%);
+}
+
+/* Certificates title — gold/amber */
+.sectionToneCertificate .sectionTitleRow {
+ border-color: #f0d5a0;
+ background: linear-gradient(180deg, #ffffff 0%, #fffbf2 100%);
+ box-shadow:
+ 0 0 0 4px rgba(251, 175, 66, 0.08),
+ 0 6px 18px rgba(180, 100, 0, 0.08);
+}
+
+.sectionToneCertificate .sectionIcon {
+ background: linear-gradient(135deg, #fffbee 0%, #fff3d0 100%);
+}
+
+/* h2 keeps default amber gradient */
+
+.sectionToneCertificate .sectionDescription {
+ color: #5a4e2e;
+}
+
+/* ═══════════════════════════════════════════════════════════════
+ CARDS — Info (Core & Scenarios)
+ ═══════════════════════════════════════════════════════════════ */
+
+/* ── Core Advantages cards: LEFT border accent ── */
+.infoCard {
+ position: relative;
+ overflow: hidden;
+ min-height: 200px;
+ border-radius: 20px;
+ border: 1px solid #e1e9ff;
+ background: #ffffff;
+ box-shadow:
+ 0 0 0 1px rgba(17, 63, 132, 0.04),
+ 0 4px 16px rgba(17, 63, 132, 0.06);
+ padding: 28px 24px 24px;
+ transition: box-shadow 0.28s ease, border-color 0.28s ease, filter 0.28s ease;
+ display: flex;
+ flex-direction: column;
+ gap: 0;
+}
+
+/* Top color strip — default blue; overridden per card below */
+.infoCard::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 4px;
+ background: linear-gradient(90deg, #2f74ff 0%, #4db2ff 100%);
+ border-radius: 20px 20px 0 0;
+}
+
+/* Decorative large background number per card */
+.infoCard::after {
+ content: counter(bento-card);
+ counter-increment: bento-card;
+ position: absolute;
+ bottom: -10px;
+ right: 12px;
+ font-size: 5.5rem;
+ font-weight: 900;
+ line-height: 1;
+ color: rgba(47, 116, 255, 0.045);
+ pointer-events: none;
+ user-select: none;
+}
+
+/* ── Compact advantage cards ── */
+/* ── Feature list item ── */
+.advItem {
+ position: relative;
+ display: flex;
+ align-items: flex-start;
+ gap: 18px;
+ padding: 24px 32px 24px 0;
+ border-bottom: 1px solid rgba(47, 116, 255, 0.08);
+ transition: background 0.2s ease;
+ cursor: default;
+}
+
+/* Right column items: add left padding, remove right */
+.advantagesList > .advItem:nth-child(odd) {
+ padding-right: 40px;
+ padding-left: 0;
+}
+.advantagesList > .advItem:nth-child(even) {
+ padding-left: 40px;
+ padding-right: 0;
+}
+
+/* Remove bottom border on last row (items 7 & 8) */
+.advantagesList > .advItem:nth-child(7),
+.advantagesList > .advItem:nth-child(8) {
+ border-bottom: none;
+}
+
+.advItemIcon {
+ width: 48px;
+ height: 48px;
+ border-radius: 14px;
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ flex-shrink: 0;
+ background: linear-gradient(135deg, #2f74ff, #60a5fa);
+ box-shadow: 0 4px 14px rgba(47, 116, 255, 0.28);
+ transition: transform 0.22s cubic-bezier(0.22,1,0.36,1), box-shadow 0.22s ease;
+}
+
+.advItemIcon :global(svg) {
+ width: 22px;
+ height: 22px;
+ filter: brightness(0) invert(1);
+ opacity: 0.95;
+}
+
+.advItem:hover .advItemIcon {
+ transform: translateY(-3px);
+}
+
+.advItemContent {
+ flex: 1;
+ min-width: 0;
+}
+
+.advItemTitle {
+ margin: 0 0 6px;
+ font-size: 1rem;
+ font-weight: 700;
+ color: #12214c;
+ line-height: 1.3;
+}
+
+.advItemDesc {
+ margin: 0;
+ font-size: 0.875rem;
+ color: #5a6a8a;
+ line-height: 1.625;
+}
+
+/* ── Per-item accent colors (icon + hover glow) ── */
+.advantagesList > .advItem:nth-child(1) .advItemIcon { background: linear-gradient(135deg, #2f74ff, #60a5fa); box-shadow: 0 4px 14px rgba(47,116,255,0.28); }
+.advantagesList > .advItem:nth-child(2) .advItemIcon { background: linear-gradient(135deg, #0d9488, #2dd4bf); box-shadow: 0 4px 14px rgba(13,148,136,0.28); }
+.advantagesList > .advItem:nth-child(3) .advItemIcon { background: linear-gradient(135deg, #7c3aed, #a78bfa); box-shadow: 0 4px 14px rgba(124,58,237,0.28); }
+.advantagesList > .advItem:nth-child(4) .advItemIcon { background: linear-gradient(135deg, #d97706, #fbbf24); box-shadow: 0 4px 14px rgba(217,119,6,0.28); }
+.advantagesList > .advItem:nth-child(5) .advItemIcon { background: linear-gradient(135deg, #059669, #34d399); box-shadow: 0 4px 14px rgba(5,150,105,0.28); }
+.advantagesList > .advItem:nth-child(6) .advItemIcon { background: linear-gradient(135deg, #e11d48, #fb7185); box-shadow: 0 4px 14px rgba(225,29,72,0.28); }
+.advantagesList > .advItem:nth-child(7) .advItemIcon { background: linear-gradient(135deg, #4338ca, #818cf8); box-shadow: 0 4px 14px rgba(67,56,202,0.28); }
+.advantagesList > .advItem:nth-child(8) .advItemIcon { background: linear-gradient(135deg, #0891b2, #22d3ee); box-shadow: 0 4px 14px rgba(8,145,178,0.28); }
+
+.advantagesList > .advItem:nth-child(1):hover .advItemIcon { box-shadow: 0 8px 22px rgba(47,116,255,0.42); }
+.advantagesList > .advItem:nth-child(2):hover .advItemIcon { box-shadow: 0 8px 22px rgba(13,148,136,0.42); }
+.advantagesList > .advItem:nth-child(3):hover .advItemIcon { box-shadow: 0 8px 22px rgba(124,58,237,0.42); }
+.advantagesList > .advItem:nth-child(4):hover .advItemIcon { box-shadow: 0 8px 22px rgba(217,119,6,0.42); }
+.advantagesList > .advItem:nth-child(5):hover .advItemIcon { box-shadow: 0 8px 22px rgba(5,150,105,0.42); }
+.advantagesList > .advItem:nth-child(6):hover .advItemIcon { box-shadow: 0 8px 22px rgba(225,29,72,0.42); }
+.advantagesList > .advItem:nth-child(7):hover .advItemIcon { box-shadow: 0 8px 22px rgba(67,56,202,0.42); }
+.advantagesList > .advItem:nth-child(8):hover .advItemIcon { box-shadow: 0 8px 22px rgba(8,145,178,0.42); }
+
+.infoCard:hover {
+ box-shadow:
+ 0 0 0 1px rgba(17, 63, 132, 0.10),
+ 0 16px 36px rgba(17, 63, 132, 0.12);
+ filter: brightness(1.02);
+}
+
+/* ── Scenario cards: full gradient background, centered icon+text ── */
+.scenariosGrid .infoCard {
+ min-height: 260px;
+ padding: 36px 28px 28px;
+ border-radius: 20px;
+ align-items: center;
+ text-align: center;
+ border: none;
+}
+
+/* Per-card gradient themes */
+.scenariosGrid > article:nth-child(1).infoCard {
+ background: linear-gradient(145deg, #1a3a7a 0%, #2855b8 100%);
+ box-shadow: 0 8px 32px rgba(26, 58, 122, 0.28);
+}
+.scenariosGrid > article:nth-child(2).infoCard {
+ background: linear-gradient(145deg, #0d6e5a 0%, #13a882 100%);
+ box-shadow: 0 8px 32px rgba(13, 110, 90, 0.28);
+}
+.scenariosGrid > article:nth-child(3).infoCard {
+ background: linear-gradient(145deg, #5a22a8 0%, #8245e0 100%);
+ box-shadow: 0 8px 32px rgba(90, 34, 168, 0.28);
+}
+.scenariosGrid > article:nth-child(4).infoCard {
+ background: linear-gradient(145deg, #a84c00 0%, #e07020 100%);
+ box-shadow: 0 8px 32px rgba(168, 76, 0, 0.28);
+}
+.scenariosGrid > article:nth-child(5).infoCard {
+ background: linear-gradient(145deg, #8a1a4a 0%, #c23570 100%);
+ box-shadow: 0 8px 32px rgba(138, 26, 74, 0.28);
+}
+
+/* Override ::before (no top strip) and ::after (no counter) */
+.scenariosGrid .infoCard::before { display: none; }
+.scenariosGrid .infoCard::after { display: none; }
+
+.scenariosGrid .infoCard:hover {
+ filter: brightness(1.12);
+ box-shadow: 0 12px 40px rgba(0, 0, 0, 0.35);
+}
+
+.scenariosGrid .cardTitleRow {
+ align-items: center;
+}
+
+/* ── Shared card internals ── */
+.cardTitleRow {
+ display: flex;
+ flex-direction: column;
+ align-items: flex-start;
+ gap: 0;
+}
+
+.cardIcon {
+ width: 52px;
+ height: 52px;
+ flex-shrink: 0;
+ border-radius: 14px;
+ border: 1px solid #d7e5ff;
+ background: linear-gradient(145deg, #eef5ff 0%, #dce9ff 100%);
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ box-shadow: 0 0 0 4px rgba(47, 116, 255, 0.07);
+ margin-bottom: 16px;
+}
+
+.scenariosGrid .cardIcon {
+ border-color: rgba(255, 255, 255, 0.25);
+ background: rgba(255, 255, 255, 0.18);
+ box-shadow: 0 0 0 4px rgba(255, 255, 255, 0.08);
+ margin-bottom: 20px;
+ width: 60px;
+ height: 60px;
+ border-radius: 16px;
+}
+
+.scenariosGrid .cardIcon :global(svg) {
+ width: 30px;
+ height: 30px;
+ filter: brightness(0) invert(1);
+ opacity: 0.9;
+}
+
+.cardIcon :global(svg) {
+ width: 26px;
+ height: 26px;
+}
+
+.infoCard h3 {
+ margin: 0;
+ font-size: 1.08rem;
+ color: #12214c;
+}
+
+.infoCard p {
+ margin: 10px 0 0;
+ color: #4f5f84;
+ font-size: 0.95rem;
+ line-height: 1.625;
+}
+
+.scenariosGrid .infoCard h3 {
+ color: #ffffff;
+ font-size: 1.15rem;
+}
+
+.scenariosGrid .infoCard p {
+ color: rgba(255, 255, 255, 0.75);
+ font-size: 0.9rem;
+}
+
+/* ═══════════════════════════════════════════════════════════════
+ CARDS — Deployment (step watermark numbers)
+ ═══════════════════════════════════════════════════════════════ */
+.deploymentCard {
+ position: relative;
+ overflow: hidden;
+ min-height: 238px;
+ border-radius: 16px;
+ border: 1px solid #cde8e0;
+ background: linear-gradient(170deg, #ffffff 0%, #f5fdf9 100%);
+ box-shadow:
+ 0 0 0 1px rgba(58, 195, 159, 0.06),
+ 0 10px 28px rgba(15, 90, 65, 0.07);
+ padding: 24px 20px 20px;
+ transition: transform 0.25s ease, box-shadow 0.25s ease, border-color 0.25s ease;
+ display: flex;
+ flex-direction: column;
+ counter-increment: deploy-step;
+ animation: cardIn 0.5s cubic-bezier(0.22, 1, 0.36, 1) both;
+}
+
+.deploymentCard:nth-child(1) { animation-delay: 0.05s; }
+.deploymentCard:nth-child(2) { animation-delay: 0.12s; }
+.deploymentCard:nth-child(3) { animation-delay: 0.19s; }
+
+/* Teal top border */
+.deploymentCard::before {
+ content: '';
+ position: absolute;
+ top: 0;
+ left: 0;
+ right: 0;
+ height: 3px;
+ border-radius: 16px 16px 0 0;
+ background: linear-gradient(90deg, #2aaa8a 0%, #61d8bd 100%);
+}
+
+/* Watermark step number */
+.deploymentCard::after {
+ content: counter(deploy-step, decimal-leading-zero);
+ position: absolute;
+ bottom: 10px;
+ right: 18px;
+ font-size: 4.5rem;
+ font-weight: 900;
+ line-height: 1;
+ letter-spacing: -0.04em;
+ color: rgba(58, 195, 159, 0.1);
+ pointer-events: none;
+ font-variant-numeric: tabular-nums;
+}
+
+.deploymentCard:hover {
+ transform: translateY(-6px);
+ box-shadow:
+ 0 0 0 1px rgba(58, 195, 159, 0.12),
+ 0 18px 36px rgba(15, 90, 65, 0.12);
+ border-color: #a8ddd2;
+}
+
+.deploymentCard h3 {
+ margin: 0;
+ font-size: 1.06rem;
+ color: #0f3028;
+}
+
+.deploymentCard p {
+ margin: 10px 0 0;
+ color: #3d5a52;
+ font-size: 0.94rem;
+ line-height: 1.625;
+ flex-grow: 1;
+}
+
+.deployAction:focus-visible {
+ outline: 2px solid #2aaa8a;
+ outline-offset: 3px;
+}
+
+.deployAction {
+ margin-top: 16px;
+ align-self: flex-start;
+ cursor: pointer;
+ min-height: 44px;
+ min-width: 168px;
+ padding: 0.6rem 1.3rem;
+ border: 1px solid #b8ded5;
+ background: linear-gradient(180deg, #f2fdf9 0%, #e6f9f2 100%);
+ color: #1e7a5c;
+ font-size: 0.97rem;
+ border-radius: 12px;
+ font-weight: 600;
+ box-shadow:
+ 0 0 0 3px rgba(58, 195, 159, 0.08),
+ 0 4px 12px rgba(15, 90, 65, 0.08);
+ transition: color 0.2s ease, border-color 0.2s ease, box-shadow 0.2s ease, transform 0.2s ease;
+}
+
+.deployAction:hover {
+ color: #155f46;
+ border-color: #8fd4c4;
+ box-shadow:
+ 0 0 0 3px rgba(58, 195, 159, 0.14),
+ 0 6px 16px rgba(15, 90, 65, 0.12);
+ transform: translateY(-1px);
+}
+
+/* ═══════════════════════════════════════════════════════════════
+ ECOSYSTEM — Category Cards
+ ═══════════════════════════════════════════════════════════════ */
+
+.ecoCategoryGrid {
+ display: grid;
+ grid-template-columns: repeat(3, 1fr);
+ gap: 20px;
+ margin-top: 36px;
+}
+
+.ecoCatCard {
+ position: relative;
+ border-radius: 18px;
+ border: 1px solid rgba(255, 255, 255, 0.12);
+ background: rgba(255, 255, 255, 0.06);
+ padding: 24px 22px 18px;
+ display: flex;
+ flex-direction: column;
+ gap: 16px;
+ transition: transform 0.28s cubic-bezier(0.22,1,0.36,1), background 0.2s, border-color 0.2s;
+ overflow: hidden;
+}
+
+/* Top accent bar */
+.ecoCatCard::before {
+ content: '';
+ position: absolute;
+ top: -1px; left: -1px; right: -1px;
+ height: 4px;
+ border-radius: 18px 18px 0 0;
+}
+
+.ecoCatCard:hover {
+ transform: translateY(-5px);
+ background: rgba(255, 255, 255, 0.10);
+ border-color: rgba(255, 255, 255, 0.22);
+ z-index: 10;
+ overflow: visible; /* allow tooltip to escape on hover */
+}
+
+/* 6 accent themes */
+.ecoCatAccentblue::before { background: linear-gradient(90deg, #2f74ff, #60a5fa); }
+.ecoCatAccentteal::before { background: linear-gradient(90deg, #0d9488, #34d399); }
+.ecoCatAccentindigo::before { background: linear-gradient(90deg, #6366f1, #a78bfa); }
+.ecoCatAccentamber::before { background: linear-gradient(90deg, #f59e0b, #fbbf24); }
+.ecoCatAccentpurple::before { background: linear-gradient(90deg, #9333ea, #c084fc); }
+.ecoCatAccentrose::before { background: linear-gradient(90deg, #e11d48, #fb7185); }
+
+/* Glow on hover — subtle halo matching accent color */
+.ecoCatAccentblue:hover { box-shadow: 0 8px 32px rgba(47,116,255,0.20); }
+.ecoCatAccentteal:hover { box-shadow: 0 8px 32px rgba(13,148,136,0.20); }
+.ecoCatAccentindigo:hover { box-shadow: 0 8px 32px rgba(99,102,241,0.20); }
+.ecoCatAccentamber:hover { box-shadow: 0 8px 32px rgba(245,158,11,0.20); }
+.ecoCatAccentpurple:hover { box-shadow: 0 8px 32px rgba(147,51,234,0.20); }
+.ecoCatAccentrose:hover { box-shadow: 0 8px 32px rgba(225,29,72,0.20); }
+
+.ecoCatHead {
+ display: flex;
+ align-items: flex-start;
+ gap: 14px;
+}
+
+.ecoCatIconWrap {
+ width: 44px;
+ height: 44px;
+ flex-shrink: 0;
+ border-radius: 12px;
+ background: rgba(255, 255, 255, 0.10);
+ border: 1px solid rgba(255, 255, 255, 0.14);
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.ecoCatIconWrap :global(svg) {
+ width: 22px;
+ height: 22px;
+ opacity: 0.85;
+ filter: brightness(0) invert(1);
+}
+
+.ecoCatTitle {
+ margin: 0 0 4px;
+ font-size: 0.98rem;
+ font-weight: 700;
+ color: rgba(220, 235, 255, 0.95);
+ line-height: 1.3;
+}
+
+.ecoCatDesc {
+ margin: 0;
+ font-size: 0.78rem;
+ color: rgba(160, 185, 220, 0.7);
+ line-height: 1.4;
+}
+
+.ecoCatFooter {
+ margin-top: auto;
+ padding-top: 12px;
+ border-top: 1px solid rgba(255, 255, 255, 0.08);
+}
+
+.ecoCatCount {
+ font-size: 0.72rem;
+ color: rgba(140, 170, 210, 0.6);
+ font-weight: 500;
+}
+
+/* Platform coverage bar */
+.ecosystemPlatformBar {
+ margin-top: 28px;
+ padding: 16px 20px;
+ border-radius: 12px;
+ background: rgba(255, 255, 255, 0.05);
+ border: 1px solid rgba(255, 255, 255, 0.09);
+ display: flex;
+ flex-direction: column;
+ gap: 6px;
+}
+
+.ecosystemPlatformBar p {
+ margin: 0;
+ font-size: 0.78rem;
+ color: rgba(160, 185, 220, 0.65);
+ line-height: 1.5;
+}
+
+/* ═══════════════════════════════════════════════════════════════
+ ECOSYSTEM — (legacy frame kept for tooltip z-index reference)
+ ═══════════════════════════════════════════════════════════════ */
+.ecosystemFrame {
+ position: relative;
+ width: 100%;
+ margin: 0 auto;
+ border-radius: 22px;
+ border: 1px solid rgba(255, 255, 255, 0.14);
+ background:
+ radial-gradient(circle at 8% 0%, rgba(100, 160, 255, 0.1) 0%, transparent 40%),
+ radial-gradient(circle at 92% 100%, rgba(251, 175, 66, 0.08) 0%, transparent 38%),
+ rgba(255, 255, 255, 0.06);
+ box-shadow:
+ 0 0 0 1px rgba(255, 255, 255, 0.08),
+ 0 12px 36px rgba(0, 0, 0, 0.2);
+ padding: 18px;
+}
+
+.ecosystemGrid {
+ position: relative;
+ display: grid;
+ grid-template-columns: repeat(4, minmax(0, 1fr));
+ grid-auto-flow: dense;
+ gap: 10px;
+ margin-top: 2px;
+}
+
+.ecosystemGroup {
+ position: relative;
+ border-radius: 12px;
+ border: 1px solid rgba(255, 255, 255, 0.13);
+ background: rgba(255, 255, 255, 0.07);
+ box-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);
+ padding: 10px 10px 12px;
+ transition: background 0.2s ease, border-color 0.2s ease;
+}
+
+.ecosystemGroup:hover {
+ background: rgba(255, 255, 255, 0.11);
+ border-color: rgba(255, 255, 255, 0.2);
+}
+
+.ecosystemGroup h3 {
+ margin: 0;
+ font-size: 0.88rem;
+ color: rgba(190, 215, 255, 0.95);
+ line-height: 1.35;
+}
+
+.ecosystemGroupWide {
+ grid-column: span 2;
+}
+
+.ecosystemItems {
+ margin-top: 8px;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px;
+}
+
+/* Default tag — deep blue dark mode */
+.ecosystemItem {
+ display: inline-flex;
+ align-items: center;
+ padding: 4px 8px;
+ border-radius: 999px;
+ border: 1px solid rgba(255, 255, 255, 0.18);
+ background: rgba(255, 255, 255, 0.09);
+ font-size: 0.76rem;
+ line-height: 1.3;
+ color: rgba(210, 228, 255, 0.9);
+}
+
+.ecosystemItemsupported {
+ border-color: rgba(190, 160, 255, 0.35);
+ background: rgba(140, 109, 255, 0.18);
+ color: #c8b8ff;
+}
+
+.ecosystemItemprogress {
+ border-color: rgba(117, 199, 64, 0.35);
+ background: rgba(117, 199, 64, 0.14);
+ color: #b0e07a;
+}
+
+.ecosystemItemplanned {
+ border-color: rgba(0, 176, 240, 0.35);
+ background: rgba(0, 176, 240, 0.14);
+ color: #7dd8f5;
+}
+
+.ecosystemItemproprietary {
+ border-color: rgba(160, 170, 190, 0.25);
+ background: rgba(160, 170, 190, 0.1);
+ color: #a8b4c8;
+}
+
+/* ── Tooltip ── */
+.ecosystemItemHasTooltip {
+ position: relative;
+ cursor: default;
+}
+
+/* Underline hint on tags that have a tooltip */
+.ecosystemItemHasTooltip::after {
+ content: '';
+ position: absolute;
+ bottom: 3px;
+ left: 8px;
+ right: 8px;
+ height: 1px;
+ background: currentColor;
+ opacity: 0.35;
+ border-radius: 1px;
+}
+
+.ecosystemTooltip {
+ position: absolute;
+ bottom: calc(100% + 10px);
+ left: 50%;
+ transform: translateX(-50%) translateY(6px);
+ width: 240px;
+ background: #0f1e45;
+ border: 1px solid rgba(100, 140, 255, 0.3);
+ border-radius: 10px;
+ padding: 10px 12px;
+ box-shadow:
+ 0 0 0 1px rgba(80, 120, 255, 0.12),
+ 0 12px 32px rgba(0, 0, 0, 0.55);
+ pointer-events: none;
+ opacity: 0;
+ transition: opacity 0.18s ease, transform 0.18s ease;
+ z-index: 100;
+ text-align: left;
+}
+
+/* Keep visible when hovering the tooltip itself (to click the link) */
+.ecosystemItemHasTooltip:hover .ecosystemTooltip,
+.ecosystemTooltip:hover {
+ opacity: 1;
+ pointer-events: auto;
+ transform: translateX(-50%) translateY(0);
+}
+
+/* Arrow */
+.ecosystemTooltip::before {
+ content: '';
+ position: absolute;
+ top: 100%;
+ left: 50%;
+ transform: translateX(-50%);
+ border: 6px solid transparent;
+ border-top-color: rgba(100, 140, 255, 0.3);
+}
+.ecosystemTooltip::after {
+ content: '';
+ position: absolute;
+ top: calc(100% - 1px);
+ left: 50%;
+ transform: translateX(-50%);
+ border: 5px solid transparent;
+ border-top-color: #0f1e45;
+}
+
+.ecosystemTooltipText {
+ display: block;
+ font-size: 0.75rem;
+ line-height: 1.55;
+ color: rgba(200, 220, 255, 0.85);
+}
+
+.ecosystemTooltipLink {
+ display: inline-block;
+ margin-top: 7px;
+ font-size: 0.72rem;
+ font-weight: 600;
+ color: #7eb8ff;
+ text-decoration: none;
+ letter-spacing: 0.01em;
+ transition: color 0.15s;
+}
+
+.ecosystemTooltipLink:hover {
+ color: #aad4ff;
+ text-decoration: underline;
+}
+
+.ecosystemFooters {
+ margin-top: 10px;
+ display: grid;
+ gap: 8px;
+}
+
+.ecosystemFooters p {
+ margin: 0;
+ border-radius: 10px;
+ border: 1px solid rgba(180, 140, 255, 0.22);
+ background: rgba(140, 109, 255, 0.1);
+ color: rgba(210, 190, 255, 0.88);
+ font-size: 0.83rem;
+ line-height: 1.45;
+ padding: 8px 10px;
+ text-align: center;
+}
+
+.ecosystemLegend {
+ margin-top: 12px;
+ display: flex;
+ flex-wrap: wrap;
+ justify-content: center;
+ gap: 12px;
+ padding: 2px 6px 0;
+}
+
+.ecosystemLegendItem {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ padding: 4px 10px;
+ border-radius: 999px;
+ border: 1px solid rgba(255, 255, 255, 0.16);
+ background: rgba(255, 255, 255, 0.08);
+ font-size: 0.8rem;
+ color: rgba(210, 228, 255, 0.82);
+ white-space: nowrap;
+}
+
+.ecosystemLegendItem i {
+ width: 9px;
+ height: 9px;
+ border-radius: 999px;
+ display: inline-block;
+}
+
+.ecosystemDotsupported { background: #a07aff; }
+.ecosystemDotprogress { background: #75c740; }
+.ecosystemDotplanned { background: #00b0f0; }
+.ecosystemDotproprietary { background: #6a7a94; }
+
+/* "View all tools" footer link */
+.ecosystemViewAll {
+ margin-top: 32px;
+ text-align: center;
+}
+
+.ecosystemViewAllLink {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 0.95rem;
+ font-weight: 600;
+ color: rgba(180, 210, 255, 0.85);
+ text-decoration: none;
+ padding: 10px 24px;
+ border: 1px solid rgba(120, 170, 255, 0.28);
+ border-radius: 30px;
+ background: rgba(255, 255, 255, 0.08);
+ transition: color 0.2s, border-color 0.2s, background 0.2s, transform 0.2s;
+}
+
+.ecosystemViewAllLink:hover {
+ color: #ffffff;
+ border-color: rgba(150, 200, 255, 0.65);
+ background: rgba(255, 255, 255, 0.1);
+ transform: translateY(-1px);
+ text-decoration: none;
+}
+
+/* ═══════════════════════════════════════════════════════════════
+ CERTIFICATE CAROUSEL
+ ═══════════════════════════════════════════════════════════════ */
+.certCarouselContainer {
+ --cert-slide-width: 248px;
+ --cert-slide-height: 184px;
+ overflow: hidden;
+ padding: 16px 0 12px;
+ position: relative;
+ border-radius: 18px;
+ border: 1px solid #edd8a0;
+ background: linear-gradient(180deg, rgba(255, 255, 255, 0.9) 0%, rgba(255, 252, 238, 0.95) 100%);
+ box-shadow:
+ 0 0 0 1px rgba(251, 175, 66, 0.08),
+ 0 8px 24px rgba(160, 100, 0, 0.07);
+}
+
+.certCarouselContainer::before,
+.certCarouselContainer::after {
+ content: '';
+ position: absolute;
+ top: 0;
+ bottom: 0;
+ width: 42px;
+ z-index: 2;
+ pointer-events: none;
+}
+
+.certCarouselContainer::before {
+ left: 0;
+ background: linear-gradient(90deg, rgba(255, 253, 242, 1) 0%, rgba(255, 253, 242, 0) 100%);
+}
+
+.certCarouselContainer::after {
+ right: 0;
+ background: linear-gradient(270deg, rgba(255, 253, 242, 1) 0%, rgba(255, 253, 242, 0) 100%);
+}
+
+.certTrack {
+ display: flex;
+ width: calc(var(--cert-slide-width) * 10);
+ animation: certScroll 36s linear infinite;
+}
+
+.certTrack:hover {
+ animation-play-state: paused;
+}
+
+.certSlide {
+ width: var(--cert-slide-width);
+ height: var(--cert-slide-height);
+ box-sizing: border-box;
+ padding: 0 10px;
+ flex-shrink: 0;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.certSlideLink {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ width: 100%;
+ height: 100%;
+ border-radius: 12px;
+ border: 1px solid #f0ddb0;
+ background: #ffffff;
+ box-shadow:
+ 0 0 0 1px rgba(251, 175, 66, 0.06),
+ 0 8px 20px rgba(150, 90, 0, 0.07);
+ padding: 10px;
+ transition: box-shadow 0.25s ease, transform 0.25s ease;
+}
+
+.certSlideLink:hover {
+ box-shadow:
+ 0 0 0 1px rgba(251, 175, 66, 0.14),
+ 0 12px 28px rgba(150, 90, 0, 0.12);
+ transform: translateY(-2px);
+}
+
+.certSlideLink img {
+ max-width: 100%;
+ max-height: 100%;
+ object-fit: contain;
+ border-radius: 8px;
+}
+
+/* ─── Hero Trust Signals ─────────────────────────────────────── */
+.heroTrust {
+ margin: 0;
+ padding: 0;
+ list-style: none;
+ display: flex;
+ flex-wrap: wrap;
+ gap: 6px 20px;
+}
+
+.heroTrustItem {
+ display: inline-flex;
+ align-items: center;
+ gap: 6px;
+ font-size: 0.82rem;
+ color: rgba(200, 220, 255, 0.72);
+ line-height: 1.4;
+}
+
+.heroTrustIcon {
+ color: #61d8bd;
+ font-size: 0.78rem;
+ font-style: normal;
+}
+
+/* ── Stats Strip ── */
+.statsStrip {
+ background: #fff;
+ padding: 36px 0 48px;
+}
+
+.statsGrid {
+ display: grid;
+ grid-template-columns: repeat(4, 1fr);
+ gap: 0;
+}
+
+.statItem {
+ display: flex;
+ flex-direction: column;
+ align-items: center;
+ gap: 6px;
+ padding: 0 24px;
+ border-right: 1px solid #e8eef8;
+}
+
+.statItem:last-child {
+ border-right: none;
+}
+
+.statValue {
+ font-size: 1.5rem;
+ font-weight: 800;
+ background: linear-gradient(135deg, #2f74ff 0%, #6ca8ff 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ line-height: 1.2;
+}
+
+.statLabel {
+ font-size: 0.82rem;
+ color: #6b7a99;
text-align: center;
+ line-height: 1.3;
+}
+
+/* ── Oracle Compatibility Showcase ── */
+.sectionOracleShowcase {
+ background: linear-gradient(160deg, #f8fbff 0%, #eef5ff 50%, #f4f9ff 100%);
+ padding: 96px 0 96px;
position: relative;
-
- background-image: linear-gradient(134.3deg,#1f0c79,#5a43ca 39.99%,#ba74e3);
- /* 圣诞 */
- /* background-color: #0e2956; */
+ overflow: hidden;
+}
+
+.sectionOracleShowcase::before {
+ content: '';
+ position: absolute;
+ top: -80px;
+ left: -80px;
+ width: 400px;
+ height: 400px;
+ border-radius: 50%;
+ background: radial-gradient(circle, rgba(47, 116, 255, 0.07) 0%, transparent 70%);
+ pointer-events: none;
+}
+
+.showcaseLayout {
+ display: grid;
+ grid-template-columns: 1fr 1fr;
+ gap: 64px;
+ align-items: center;
+}
+
+.showcaseBadge {
+ display: inline-block;
+ padding: 4px 12px;
+ border-radius: 999px;
+ background: rgba(47, 116, 255, 0.2);
+ border: 1px solid rgba(47, 116, 255, 0.4);
+ color: #82aaff;
+ font-size: 0.78rem;
+ font-weight: 600;
+ letter-spacing: 0.04em;
+ text-transform: uppercase;
+ margin-bottom: 16px;
+}
+
+.showcaseTitle {
+ font-size: 2.2rem;
+ font-weight: 800;
+ color: #0d1f4e;
+ line-height: 1.2;
+ margin-bottom: 28px;
+ letter-spacing: -0.02em;
+}
+
+.showcasePoints {
+ list-style: none;
+ padding: 0;
+ margin: 0 0 36px;
+ display: flex;
+ flex-direction: column;
+ gap: 14px;
+}
+
+.showcasePoint {
+ display: flex;
+ align-items: flex-start;
+ gap: 10px;
+ font-size: 0.95rem;
+ color: #3a4e7a;
+ line-height: 1.5;
+}
+
+.showcaseCheck {
+ color: #c3e88d;
+ font-weight: 700;
+ flex-shrink: 0;
+ margin-top: 2px;
+}
- height: 500px;
+.showcaseCta {
+ background: #2f74ff;
+ color: #fff;
+ border: none;
+ border-radius: 8px;
+ font-weight: 600;
+ padding: 12px 28px;
+ transition: background 0.2s, transform 0.2s;
+}
+
+.showcaseCta:hover {
+ background: #1a5fdd;
+ transform: translateY(-2px);
+ color: #fff;
+}
+
+/* Code window inside showcase */
+.showcaseCode {
+ border-radius: 14px;
overflow: hidden;
+ box-shadow:
+ 0 0 0 1px rgba(100, 160, 255, 0.2),
+ 0 24px 64px rgba(0, 0, 0, 0.5);
+}
+
+.codeWindowBar {
+ display: flex;
+ align-items: center;
+ gap: 6px;
+ padding: 10px 14px;
+ background: #1e2433;
+ border-bottom: 1px solid rgba(255,255,255,0.06);
}
-.heroBanner_2 {
- padding: 4rem 4rem;
+
+.codeWindowTitle {
+ margin-left: 8px;
+ font-size: 0.72rem;
+ color: rgba(180, 200, 255, 0.45);
+ font-family: -apple-system, sans-serif;
+}
+
+.codeWindowBody {
+ background: #111827;
+ padding: 20px 22px;
+ font-family: 'Menlo', 'Monaco', 'Consolas', monospace;
+ font-size: 0.8rem;
+ line-height: 1.7;
+}
+
+.codeLine { display: block; white-space: pre; }
+.codeComment { color: #6b7a99; font-style: italic; }
+.codeKw { color: #c792ea; }
+.codeFn { color: #82aaff; }
+.codeParam { color: #f07178; }
+.codeType { color: #ffcb6b; }
+.codeStr { color: #c3e88d; }
+.codeNum { color: #f78c6c; }
+.codePunct { color: #89ddff; }
+.codeIndent { display: inline-block; }
+.codeSpacer { height: 10px; display: block; }
+.codeGreen { color: #c3e88d; }
+.codeSuccess { display: flex; align-items: center; gap: 4px; color: rgba(150, 180, 230, 0.7); font-style: italic; }
+
+/* ── CTA Banner ── */
+.ctaBanner {
+ /* Light cool-gray — clean and airy, distinct from warm-cream above */
+ background:
+ radial-gradient(ellipse at 30% 60%, rgba(47, 116, 255, 0.06) 0%, transparent 55%),
+ radial-gradient(ellipse at 72% 25%, rgba(47, 116, 255, 0.04) 0%, transparent 50%),
+ linear-gradient(160deg, #f0f4fc 0%, #eef2fb 55%, #f2f5fd 100%);
+ padding: 88px 0 92px;
text-align: center;
position: relative;
overflow: hidden;
}
-.heroBGImage {
- padding: 5rem 0;
- text-align: center;
- position: relative;
+/* Dot-grid texture */
+.ctaBanner::before {
+ content: '';
+ position: absolute;
+ inset: 0;
+ background-image: radial-gradient(circle, rgba(47, 116, 255, 0.13) 1px, transparent 1px);
+ background-size: 28px 28px;
+ pointer-events: none;
+}
+
+/* Centered soft glow */
+.ctaBanner::after {
+ content: '';
+ position: absolute;
+ top: -80px; left: 50%;
+ transform: translateX(-50%);
+ width: 640px; height: 400px;
+ border-radius: 50%;
+ background: radial-gradient(ellipse, rgba(47, 116, 255, 0.09) 0%, transparent 68%);
+ pointer-events: none;
+}
+
+/* Decorative SVG container */
+.ctaDecor {
+ position: absolute;
+ inset: 0;
overflow: hidden;
+ pointer-events: none;
+}
+
+.ctaDecorRings {
+ position: absolute;
+ right: -60px;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 420px;
+ height: 420px;
+ opacity: 0.55;
+}
+
+.ctaDecorCircuit {
+ position: absolute;
+ left: -30px;
+ top: 50%;
+ transform: translateY(-50%);
+ width: 280px;
+ height: 280px;
+ opacity: 0.45;
+}
- background-repeat: no-repeat;
- background-position: center;
- background-size: cover;
+.ctaBannerInner {
position: relative;
- background-blend-mode: darken;
- width: 100%;
+ max-width: 640px;
+ margin: 0 auto;
+ z-index: 1;
+}
+
+.ctaBannerTitle {
+ font-size: 2.4rem;
+ font-weight: 900;
+ background: linear-gradient(135deg, #0d2252 0%, #2f74ff 55%, #1a4fd6 100%);
+ -webkit-background-clip: text;
+ -webkit-text-fill-color: transparent;
+ background-clip: text;
+ margin-bottom: 14px;
+ letter-spacing: -0.03em;
+ line-height: 1.15;
}
-.row{
+
+.ctaBannerSub {
+ font-size: 1.05rem;
+ color: #4a5e84;
+ margin-bottom: 40px;
+ line-height: 1.65;
+}
+
+.ctaBannerActions {
display: flex;
- flex-wrap:nowrap;
+ justify-content: center;
+ gap: 16px;
+ flex-wrap: wrap;
}
-.heroCenterImage {
- padding: 5rem 0;
- text-align: center;
- position: relative;
- overflow: hidden;
- background-repeat: no-repeat;
- background-position: cover;
- background-size: cover;
- /* 圣诞 */
- /* margin-left: 300px; */
-}
-.heroLeftImage {
- padding: 4rem 4rem;
- text-align: center;
- position: relative;
- overflow: hidden;
- /* background: url("@site/static/img/fp_left_header.svg"); */
- background-repeat: no-repeat;
- background-size: cover;
- width: 25%;
-}
-.heroRightImage {
- /* 原图 */
- width: 43%;
- height: 100px;
- position: relative;
- top: -47px;
- /* 圣诞 */
- /* width: 160%;
- height: 100px;
- position: relative;
- top: -75px;
- left: 100px;
- overflow:visible;
- white-space:nowrap;
- margin-left: 30px; */
-}
-.tree{
- width: 40%;
- height: 100px;
- margin-left: -200px;
- margin-top: -50px;
- position: relative;
- top: 28px;
-}
-.indexImg{
- width: 100%;
- max-width: 1390px;
- height: 500px;
- margin: auto;
+
+.ctaPrimary {
+ background: #2f74ff;
+ color: #ffffff !important;
+ border: none;
+ border-radius: 8px;
+ font-weight: 700;
+ transition: background 0.2s, transform 0.2s, box-shadow 0.2s;
+ box-shadow: 0 4px 20px rgba(47, 116, 255, 0.32);
}
-.indexImgbug{
- object-fit: cover;
- width: 100%;
- max-width: 2391px;
- height: 502px;
- margin: 0px auto -30px auto;
-}
-.indexImgPhone{
- display: none;
- height: 500px;
- margin: auto;
-}
-.indexImgbugphone{
- /* object-fit: cover; */
- width: 1000px;
- width: 100%;
- /* min-width: 600px; */
- height: 502px;
- margin: 0px auto -30px auto;
+
+.ctaPrimary:hover {
+ background: #1a5fdd;
+ transform: translateY(-2px);
+ box-shadow: 0 8px 28px rgba(47, 116, 255, 0.4);
+ color: #ffffff !important;
}
-.recruitBanner{
- padding: 0;
- height: 500px;
- background-color: #3227d5;
+
+.ctaSecondary {
+ background: transparent;
+ color: #2f74ff !important;
+ border: 1.5px solid #2f74ff;
+ border-radius: 8px;
+ font-weight: 600;
+ transition: border-color 0.2s, color 0.2s, background 0.2s, transform 0.2s;
}
-.phonetree{
- display: none;
+
+.ctaSecondary:hover {
+ background: rgba(47, 116, 255, 0.06);
+ border-color: #1a5fdd;
+ color: #1a5fdd !important;
+ transform: translateY(-2px);
}
-@media screen and (max-width: 1440px) {
- .tree{
- position: relative;
- top: 140px;
+
+/* ─── Accessibility: prefers-reduced-motion ──────────────────── */
+@media (prefers-reduced-motion: reduce) {
+ .heroContent,
+ .heroVisual {
+ animation: none;
+ opacity: 1;
+ }
+
+ .heroVisual :global(svg) {
+ animation: none;
+ translate: none;
+ }
+
+ .infoCard,
+ .advItem,
+ .deploymentCard {
+ animation: none;
+ opacity: 1;
+ translate: none;
+ }
+
+ .latestVersion {
+ animation: none;
}
- .heroRightImage{
- width: 160%;
- margin-left: -20px;
- position: relative;
- left: 90px;
- top: -25px;
+
+ .certTrack {
+ animation: none;
}
- .heroCenterImage{
- margin-left: 200px;
- width: 400px;
- height: 500px;
+
+ .actionButton,
+ .deployAction,
+ .infoCard,
+ .advItem,
+ .deploymentCard,
+ .ecosystemGroup,
+ .certSlideLink {
+ transition: none;
}
}
-@media screen and (min-width: 997px) {
- /* Show inline table of contents on mobile only */
- div[class^='tableOfContentsInline'] {
- display: none;
+
+/* ─── Responsive: 1200px ─────────────────────────────────────── */
+@media (max-width: 1200px) {
+ .heroContainer {
+ grid-template-columns: minmax(0, 1fr) 380px;
+ gap: 22px;
+ }
+
+ .heroVisual :global(svg) {
+ width: 390px;
+ transform: translateX(0);
}
- div[class^='heroCenterImage'] {
- width: 50%;
+
+ .advantagesList {
+ column-gap: 0;
}
- div[class^='indexImg-phone'] {
- display: none;
+
+ .deploymentGrid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .ecosystemGrid {
+ grid-template-columns: repeat(3, minmax(0, 1fr));
+ }
+
+ .ecoCategoryGrid {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ .certCarouselContainer {
+ --cert-slide-width: 220px;
+ --cert-slide-height: 168px;
}
}
-@media screen and (max-width: 997px) {
- div[class^='heroRightImage'] {
- display: none;
+/* ─── Responsive: 996px ──────────────────────────────────────── */
+@media (max-width: 996px) {
+ /* Reduce stacking overlap on tablet */
+ .statsStrip,
+ .sectionOracleShowcase,
+ .sectionToneCore,
+ .sectionToneScenario,
+ .sectionToneDeployment,
+ .sectionToneEcosystem,
+ .sectionToneCertificate,
+ .ctaBanner {
+ border-radius: 32px 32px 0 0;
+ margin-top: -32px;
+ }
+
+ .heroSection {
+ padding-bottom: 120px;
}
- div[class^='heroLeftImage'] {
+
+ .heroVisual {
display: none;
}
- div[class^='heroCenterImage'] {
- width: 100%;
- margin-left:0px;
- margin-top: 50px;
+
+ .heroSection {
+ padding: 70px 0 100px;
+ }
+
+ .heroContainer {
+ grid-template-columns: 1fr;
+ }
+
+ .heroContent {
+ gap: 18px;
+ padding-right: 0;
+ text-align: center;
+ max-width: 100%;
+ }
+
+ .slogan {
+ margin-left: auto;
+ margin-right: auto;
+ }
+
+ .heroBadges {
+ justify-content: center;
+ }
+
+ .heroIntro {
+ margin-left: auto;
+ margin-right: auto;
+ text-align: left;
+ font-size: 0.96rem;
+ line-height: 1.625;
+ max-width: 100%;
+ }
+
+ .latestVersion {
+ margin-left: auto;
+ margin-right: auto;
}
- div[class^='indexImg'] {
+
+ .heroActions {
+ justify-content: center;
+ }
+
+ .heroActionsEn {
+ display: flex;
+ max-width: 100%;
+ }
+
+ .actionButtonEn {
+ width: auto;
+ min-width: 194px;
+ }
+
+ .section {
+ padding: 56px 0 48px;
+ }
+
+ .scenariosGrid {
+ grid-template-columns: repeat(2, 1fr);
+ }
+
+ /* Reset scenario spans on tablet */
+ .scenariosGrid > article:nth-child(1),
+ .scenariosGrid > article:nth-child(2),
+ .scenariosGrid > article:nth-child(3),
+ .scenariosGrid > article:nth-child(4),
+ .scenariosGrid > article:nth-child(5) { grid-column: span 1; }
+
+ .sectionToneCore::after,
+ .sectionToneScenario::after,
+ .sectionToneDeployment::before,
+ .sectionToneEcosystem::after,
+ .sectionToneCertificate::before {
display: none;
}
- div[class^='indexImg-phone'] {
- display: inline;
+
+ .certCarouselContainer {
+ overflow-x: auto;
+ overflow-y: visible;
+ -webkit-overflow-scrolling: touch;
+ scroll-snap-type: x mandatory;
+ padding: 10px 0 8px;
}
- div[class^='tree'] {
+
+ .certCarouselContainer::before,
+ .certCarouselContainer::after {
display: none;
}
- /* div[class^='phonetree'] {
- display: inline-block;
- width: 120%;
- position: relative;
- right: 90px;
- top: 200px;
- } */
-}
-.buttons {
- display: flex;
- flex-wrap: wrap;
- gap: 16px;
- align-items: center;
- justify-content: center;
+
+ .certTrack {
+ width: max-content;
+ animation: none;
+ gap: 10px;
+ padding: 0 6px;
+ }
+
+ .certSlide {
+ width: min(48vw, 220px);
+ height: min(36vw, 168px);
+ padding: 0;
+ scroll-snap-align: start;
+ }
+
+ .certSlideLink {
+ padding: 8px;
+ }
+
+ .ecosystemFrame {
+ padding: 14px;
+ }
+
+ .ecosystemGrid {
+ grid-template-columns: repeat(2, minmax(0, 1fr));
+ }
+
+ .ecosystemGroupWide {
+ grid-column: span 2;
+ }
+
+ .ecoCategoryGrid {
+ grid-template-columns: 1fr;
+ }
+
+ .ecosystemLegend {
+ justify-content: center;
+ gap: 10px;
+ }
}
+/* ─── Responsive: 640px ──────────────────────────────────────── */
+@media (max-width: 640px) {
+ /* Smaller radius on mobile */
+ .statsStrip,
+ .sectionOracleShowcase,
+ .sectionToneCore,
+ .sectionToneScenario,
+ .sectionToneDeployment,
+ .sectionToneEcosystem,
+ .sectionToneCertificate,
+ .ctaBanner {
+ border-radius: 20px 20px 0 0;
+ margin-top: -20px;
+ }
+
+ .heroSection {
+ padding: 62px 0 76px;
+ }
+
+ .heroTrustBar {
+ flex-direction: column;
+ align-items: center;
+ gap: 12px;
+ padding-bottom: 32px;
+ }
+
+ .heroTrustList {
+ justify-content: center;
+ gap: 8px 20px;
+ }
+
+ .heroTrustItem {
+ align-items: center;
+ }
+
+ .heroTrustList > li + li::before {
+ margin-right: 20px;
+ }
+
+ .heroContainer {
+ gap: 16px;
+ }
+
+ .heroContent {
+ gap: 16px;
+ }
+
+ .heroTitle {
+ font-size: clamp(2.1rem, 10vw, 2.6rem);
+ line-height: 1.14;
+ }
+
+ .slogan {
+ font-size: 1.06rem;
+ line-height: 1.58;
+ }
+
+ .heroBadges {
+ gap: 8px;
+ }
+
+ .heroBadge {
+ font-size: 0.78rem;
+ padding: 5px 11px;
+ }
+
+ .heroIntro {
+ font-size: 0.93rem;
+ line-height: 1.625;
+ padding: 16px;
+ border-radius: 14px;
+ }
+
+ .latestVersion {
+ width: 100%;
+ justify-content: center;
+ padding: 10px 12px;
+ }
+
+ .certCarouselContainer {
+ padding: 8px 0 4px;
+ }
+
+ .certTrack {
+ gap: 8px;
+ padding: 0 4px;
+ }
+
+ .certSlide {
+ width: min(72vw, 192px);
+ height: min(54vw, 146px);
+ }
+
+ .heroTrust {
+ justify-content: center;
+ gap: 4px 16px;
+ }
+
+ .heroTrustItem {
+ font-size: 0.78rem;
+ }
+
+ .heroActions {
+ flex-direction: column;
+ flex-wrap: nowrap;
+ width: 100%;
+ max-width: 360px;
+ margin-left: auto;
+ margin-right: auto;
+ align-items: center;
+ gap: 10px;
+ }
+
+ .actionButton {
+ width: 100%;
+ max-width: 360px;
+ min-width: 0;
+ }
+
+ .advantagesList {
+ grid-template-columns: 1fr;
+ }
+
+ .advantagesList::before { display: none; }
+
+ .advantagesList > .advItem:nth-child(odd),
+ .advantagesList > .advItem:nth-child(even) {
+ padding-left: 0;
+ padding-right: 0;
+ }
+
+ .advantagesList > .advItem:nth-child(7) {
+ border-bottom: 1px solid rgba(47, 116, 255, 0.08);
+ }
+
+ .scenariosGrid,
+ .deploymentGrid {
+ grid-template-columns: 1fr;
+ }
+
+ /* Reset scenario spans on mobile */
+ .scenariosGrid > article:nth-child(n) { grid-column: span 1; }
+
+ .ecosystemGrid {
+ grid-template-columns: 1fr;
+ }
+
+ .ecosystemGroup,
+ .ecosystemGroupWide {
+ grid-column: span 1;
+ }
+
+ .ecosystemGroup h3 {
+ font-size: 0.86rem;
+ }
+
+ .ecosystemItem {
+ font-size: 0.74rem;
+ padding: 4px 7px;
+ }
+
+ .ecosystemFooters p {
+ font-size: 0.8rem;
+ padding: 7px 9px;
+ }
+
+ .ecosystemLegend {
+ margin-top: 8px;
+ gap: 8px;
+ justify-content: flex-start;
+ padding: 2px 2px 0;
+ }
+
+ .ecosystemLegendItem {
+ font-size: 0.76rem;
+ white-space: normal;
+ }
+
+ .infoCard {
+ min-height: 0;
+ }
+
+ .deploymentCard {
+ min-height: 0;
+ }
+
+ .deployAction {
+ min-height: 42px;
+ min-width: 160px;
+ font-size: 0.94rem;
+ }
+
+ .statsGrid { grid-template-columns: repeat(2, 1fr); }
+ .statItem { border-right: none; border-bottom: 1px solid #e8eef8; padding: 16px; }
+ .statItem:nth-child(even) { border-bottom: 1px solid #e8eef8; }
+ .showcaseLayout { grid-template-columns: 1fr; gap: 40px; }
+ .showcaseTitle { font-size: 1.6rem; }
+ .sqlTerminal { max-width: 100%; }
+}
diff --git a/src/pages/releases-page.mdx b/src/pages/releases-page.mdx
index 11b2a28..74a90f0 100644
--- a/src/pages/releases-page.mdx
+++ b/src/pages/releases-page.mdx
@@ -5,36 +5,6 @@ title: IvorySQL Releases
import React, { useState } from 'react';
-export const Highlight = ({children, color}) => (
-
- {children}
-
-);
-
-export const TabButton = ({active, onClick, children}) => (
-
-);
-
export const VersionTable = () => {
const [activeTab, setActiveTab] = useState('currentTab');
@@ -42,216 +12,310 @@ export const VersionTable = () => {
{
date: 'Mar 26, 2025',
version: 'IvorySQL 1.17 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.17/v1.17/1.html'
- },
+ url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.17/v1.17/1.html',
+ pg: 'PostgreSQL 16',
+ highlight: false,
+ },
{
date: 'Dec 18, 2025',
version: 'IvorySQL 5.1 STABLE',
url: 'https://docs.ivorysql.org/en/ivorysql-doc/v5.1/v5.1/1.html',
- highlight: true
- },
+ pg: 'PostgreSQL 17',
+ highlight: true,
+ },
];
const historicalVersions = [
- {
- date: 'Dec 15, 2021',
- version: 'IvorySQL 1.0 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.0/v1.0/1.html'
- },
- {
- date: 'Jan 25, 2022',
- version: 'IvorySQL 1.1 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.1/v1.1/1.html'
- },
- {
- date: 'Feb 28, 2022',
- version: 'IvorySQL 1.2 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.2/v1.2/1.html'
- },
- {
- date: 'May 27, 2022',
- version: 'IvorySQL 1.3 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.3/v1.3/1.html'
- },
- {
- date: 'Jun 28, 2022',
- version: 'IvorySQL 1.4 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.4/v1.4/1.html'
- },
- {
- date: 'Sep 09, 2022',
- version: 'IvorySQL 1.5 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.5/v1.5/1.html'
- },
- {
- date: 'Dec 14, 2022',
- version: 'IvorySQL 2.1 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v2.1/v2.1/1.html'
- },
- {
- date: 'Mar 29, 2023',
- version: 'IvorySQL 2.2 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v2.2/v2.2/1.html'
- },
- {
- date: 'Jun 28, 2023',
- version: 'IvorySQL 2.3 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v2.3/v2.3/1.html'
- },
- {
- date: 'Nov 17, 2023',
- version: 'IvorySQL 3.0 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v3.0/v3.0/1.html'
- },
- {
- date: 'Jan 26, 2024',
- version: 'IvorySQL 3.1 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v3.1/v3.1/1.html'
- },
- {
- date: 'Apr 11, 2024',
- version: 'IvorySQL 3.2 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v3.2/v3.2/1.html'
- },
- {
- date: 'Jul 11, 2024',
- version: 'IvorySQL 3.3 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v3.3/v3.3/1.html'
- },
- {
- date: 'Sep 26, 2024',
- version: 'IvorySQL 3.4 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v3.4/v3.4/1.html'
- },
- {
- date: 'Nov 21, 2024',
- version: 'IvorySQL 1.8 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.8/v1.8/1.html'
- },
- {
- date: 'Dec 23, 2024',
- version: 'IvorySQL 4.0 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v4.0/v4.0/1.html'
- },
- {
- date: 'Jan 13, 2025',
- version: 'IvorySQL 4.2 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v4.2/v4.2/1.html'
- },
- {
- date: 'Mar 10, 2025',
- version: 'IvorySQL 4.4 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v4.4/v4.4/1.html'
- },
- {
- date: 'Jun 4, 2025',
- version: 'IvorySQL 4.5 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v4.5/v4.5/1.html'
- },
- {
- date: 'Sept 10, 2025',
- version: 'IvorySQL 4.6 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v4.6/v4.6/1.html'
- },
- {
- date: 'Nov 25, 2025',
- version: 'IvorySQL 5.0 STABLE',
- url: 'https://docs.ivorysql.org/en/ivorysql-doc/v5.0/v5.0/1.html'
- },
+ { date: 'Dec 15, 2021', version: 'IvorySQL 1.0 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.0/v1.0/1.html' },
+ { date: 'Jan 25, 2022', version: 'IvorySQL 1.1 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.1/v1.1/1.html' },
+ { date: 'Feb 28, 2022', version: 'IvorySQL 1.2 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.2/v1.2/1.html' },
+ { date: 'May 27, 2022', version: 'IvorySQL 1.3 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.3/v1.3/1.html' },
+ { date: 'Jun 28, 2022', version: 'IvorySQL 1.4 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.4/v1.4/1.html' },
+ { date: 'Sep 09, 2022', version: 'IvorySQL 1.5 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.5/v1.5/1.html' },
+ { date: 'Dec 14, 2022', version: 'IvorySQL 2.1 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v2.1/v2.1/1.html' },
+ { date: 'Mar 29, 2023', version: 'IvorySQL 2.2 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v2.2/v2.2/1.html' },
+ { date: 'Jun 28, 2023', version: 'IvorySQL 2.3 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v2.3/v2.3/1.html' },
+ { date: 'Nov 17, 2023', version: 'IvorySQL 3.0 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v3.0/v3.0/1.html' },
+ { date: 'Jan 26, 2024', version: 'IvorySQL 3.1 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v3.1/v3.1/1.html' },
+ { date: 'Apr 11, 2024', version: 'IvorySQL 3.2 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v3.2/v3.2/1.html' },
+ { date: 'Jul 11, 2024', version: 'IvorySQL 3.3 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v3.3/v3.3/1.html' },
+ { date: 'Sep 26, 2024', version: 'IvorySQL 3.4 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v3.4/v3.4/1.html' },
+ { date: 'Nov 21, 2024', version: 'IvorySQL 1.8 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v1.8/v1.8/1.html' },
+ { date: 'Dec 23, 2024', version: 'IvorySQL 4.0 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v4.0/v4.0/1.html' },
+ { date: 'Jan 13, 2025', version: 'IvorySQL 4.2 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v4.2/v4.2/1.html' },
+ { date: 'Mar 10, 2025', version: 'IvorySQL 4.4 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v4.4/v4.4/1.html' },
+ { date: 'Jun 4, 2025', version: 'IvorySQL 4.5 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v4.5/v4.5/1.html' },
+ { date: 'Sept 10, 2025', version: 'IvorySQL 4.6 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v4.6/v4.6/1.html' },
+ { date: 'Nov 25, 2025', version: 'IvorySQL 5.0 STABLE', url: 'https://docs.ivorysql.org/en/ivorysql-doc/v5.0/v5.0/1.html' },
];
- const packages = [
- {
- maintainer: 'HIGHGO',
- link: 'HIGHGO YUM REPOSITORY',
- url: 'https://yum.highgo.com/dists/ivorysql-rpms/'
- },
- ];
+ /* ── shared tokens ── */
+ const navy = '#0d1b3e';
+ const blue = '#2f74ff';
+ const blue2 = '#1e50c8';
+ const card = { background: '#fff', borderRadius: '12px', border: '1px solid #e5e9f2', boxShadow: '0 2px 12px rgba(15,35,100,0.07)' };
- const renderTable = (data, columns) => (
-
-
-
- {columns.map((col, idx) => (
- |
- {col}
- |
- ))}
-
-
-
- {data.map((row, idx) => (
-
- {columns.map((col, colIdx) => {
- const key = col.toLowerCase();
- let content = row[key];
- if (key === 'version' && row.highlight) {
- content = (
-
- {row.version.replace('STABLE', 'STABLE')} Latest Stable
-
- );
- } else if (row.url && (key === 'date' || key === 'version' || key === 'link')) {
- content = {content};
- }
- return (
- |
- {content}
- |
- );
- })}
-
- ))}
-
-
- );
+ /* ── Tab button ── */
+ const Tab = ({ id, label }) => {
+ const active = activeTab === id;
+ return (
+
+ );
+ };
- return (
-