updated website
This commit is contained in:
BIN
site/assets/screenshots/analytics-top.png
Normal file
BIN
site/assets/screenshots/analytics-top.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 207 KiB |
Binary file not shown.
|
Before Width: | Height: | Size: 292 KiB After Width: | Height: | Size: 293 KiB |
187
site/index.html
187
site/index.html
@@ -19,7 +19,7 @@
|
||||
<!-- Fonts -->
|
||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap" rel="stylesheet" />
|
||||
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800;900&display=swap" rel="stylesheet" />
|
||||
|
||||
<link rel="stylesheet" href="styles.css" />
|
||||
<script defer src="scripts.js"></script>
|
||||
@@ -31,145 +31,192 @@
|
||||
<header>
|
||||
<div class="container header-inner">
|
||||
<a href="#" class="logo">
|
||||
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2" stroke-linecap="round"
|
||||
stroke-linejoin="round" />
|
||||
<svg width="22" height="22" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
Caddy Proxy Manager
|
||||
</a>
|
||||
<nav class="nav-links">
|
||||
<a href="#features">Features</a>
|
||||
<a href="#architecture">Architecture</a>
|
||||
<a href="#deployment">Data</a>
|
||||
<a href="#spotlights">Showcase</a>
|
||||
<a href="#deployment">Install</a>
|
||||
<a href="https://github.com/fuomag9/caddy-proxy-manager" target="_blank">GitHub</a>
|
||||
</nav>
|
||||
</div>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<!-- Hero -->
|
||||
<section class="hero container">
|
||||
<div class="hero-eyebrow">Open Source · Docker · Next.js</div>
|
||||
<h1>Control Every Edge.</h1>
|
||||
<p>The modern, secure context for your reverse proxy. Manage Caddy with an intuitive interface, automatic HTTPS,
|
||||
geo blocking, and detailed audit logging.</p>
|
||||
<p>The modern web interface for Caddy Server. Automatic HTTPS, geo blocking, traffic analytics, and a full audit trail — all in one place.</p>
|
||||
|
||||
<div class="btn-group">
|
||||
<a href="#deployment" class="btn btn-primary">Get Started</a>
|
||||
<a href="https://github.com/fuomag9/caddy-proxy-manager" target="_blank" class="btn btn-secondary">View
|
||||
Source</a>
|
||||
<a href="https://github.com/fuomag9/caddy-proxy-manager" target="_blank" class="btn btn-secondary">
|
||||
<svg width="16" height="16" viewBox="0 0 24 24" fill="currentColor"><path d="M12 0C5.37 0 0 5.37 0 12c0 5.31 3.435 9.795 8.205 11.385.6.105.825-.255.825-.57 0-.285-.015-1.23-.015-2.235-3.015.555-3.795-.735-4.035-1.41-.135-.345-.72-1.41-1.23-1.695-.42-.225-1.02-.78-.015-.795.945-.015 1.62.87 1.845 1.23 1.08 1.815 2.805 1.305 3.495.99.105-.78.42-1.305.765-1.605-2.67-.3-5.46-1.335-5.46-5.925 0-1.305.465-2.385 1.23-3.225-.12-.3-.54-1.53.12-3.18 0 0 1.005-.315 3.3 1.23.96-.27 1.98-.405 3-.405s2.04.135 3 .405c2.295-1.56 3.3-1.23 3.3-1.23.66 1.65.24 2.88.12 3.18.765.84 1.23 1.905 1.23 3.225 0 4.605-2.805 5.625-5.475 5.925.435.375.81 1.095.81 2.22 0 1.605-.015 2.895-.015 3.3 0 .315.225.69.825.57A12.02 12.02 0 0024 12c0-6.63-5.37-12-12-12z"/></svg>
|
||||
View Source
|
||||
</a>
|
||||
</div>
|
||||
|
||||
<div class="showcase">
|
||||
<div class="screenshot-main">
|
||||
<img src="assets/screenshots/analytics.png" alt="Caddy Proxy Manager Analytics" loading="lazy" />
|
||||
<img src="assets/screenshots/dashboard-main.png" alt="Caddy Proxy Manager Dashboard" loading="lazy" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<!-- Features Grid -->
|
||||
<section id="features" class="container features">
|
||||
<div class="section-header">
|
||||
<div class="eyebrow">Everything included</div>
|
||||
<h2>Powerful Simplicity</h2>
|
||||
<p>Everything you need to manage your infrastructure, nothing you don't.</p>
|
||||
</div>
|
||||
|
||||
<div class="grid">
|
||||
<div class="card">
|
||||
<div class="card-icon">⇄</div>
|
||||
<h3>Reverse Proxy</h3>
|
||||
<p>Configure upstream pools, load balancing, custom headers, and per-host enable/disable with a clean editor.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-icon">🔒</div>
|
||||
<h3>Auto HTTPS</h3>
|
||||
<p>Automatic TLS certificates for every proxy host via Caddy ACME. Supports Let's Encrypt, ZeroSSL, and Cloudflare DNS-01.</p>
|
||||
<p>Automatic TLS for every proxy host via Caddy ACME. Let's Encrypt, ZeroSSL, and Cloudflare DNS-01 out of the box.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-icon">📈</div>
|
||||
<h3>Traffic Analytics</h3>
|
||||
<p>Live request charts, country-level traffic map, top user agents, and blocked request log — across any time range.</p>
|
||||
<p>Live request charts, country heatmap, top user agents, and blocked request log across any time range.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-icon">🌍</div>
|
||||
<h3>Geo Blocking</h3>
|
||||
<p>Block or allow traffic by country, continent, ASN, CIDR range, or exact IP — per proxy host, with allow-override rules.</p>
|
||||
<p>Block or allow by country, continent, ASN, CIDR, or exact IP — per host, with priority allow-override rules.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-icon">🔑</div>
|
||||
<h3>Access Control</h3>
|
||||
<p>Protect endpoints with HTTP basic auth lists or full OAuth2/OIDC SSO via any OIDC-compliant provider.</p>
|
||||
<p>HTTP basic auth lists or full OAuth2/OIDC SSO via Authentik, Keycloak, Auth0, and any OIDC provider.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-icon">📋</div>
|
||||
<h3>Audit Log</h3>
|
||||
<p>Every change is tracked and searchable. See who modified what and when, with full event history.</p>
|
||||
<p>Every configuration change is tracked and full-text searchable. See who did what and when.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-icon">🛡️</div>
|
||||
<h3>Certificate Visibility</h3>
|
||||
<p>See issuer, expiry status, and health for every ACME-managed certificate — no more guessing what Caddy obtained.</p>
|
||||
<p>Issuer, expiry status, and health for every ACME-managed cert — no more guessing what Caddy obtained.</p>
|
||||
</div>
|
||||
<div class="card">
|
||||
<div class="card-icon">🐳</div>
|
||||
<h3>Docker Ready</h3>
|
||||
<p>Deploys in seconds with a single docker-compose file. Persistent data via volumes, stateless app logic.</p>
|
||||
<p>Up in seconds with a single docker-compose file. Persistent volumes, stateless app, easy to backup.</p>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section id="architecture" class="container tech-stack">
|
||||
<div class="section-header">
|
||||
<h2>Designed for Reliability</h2>
|
||||
</div>
|
||||
<div class="tech-grid">
|
||||
<div class="secondary-screenshots">
|
||||
<img src="assets/screenshots/proxy-hosts.png" alt="Proxy Hosts" loading="lazy" />
|
||||
<img src="assets/screenshots/certificates.png" alt="Certificates" loading="lazy" />
|
||||
<img src="assets/screenshots/proxy-editor.png" alt="Proxy Editor" loading="lazy" />
|
||||
<img src="assets/screenshots/audit-log.png" alt="Audit Log" loading="lazy" />
|
||||
</div>
|
||||
<div>
|
||||
<ul class="tech-list">
|
||||
<li>
|
||||
<h4>Caddy Powered</h4>
|
||||
<p>Uses Caddy's native Admin API for real-time configuration updates without restarts.</p>
|
||||
</li>
|
||||
<li>
|
||||
<h4>Type-Safe & Secure</h4>
|
||||
<p>End-to-end type safety with TypeScript. Secure session management and input validation.</p>
|
||||
</li>
|
||||
<li>
|
||||
<h4>SQLite Database</h4>
|
||||
<p>Self-contained data storage. Easy to backup, migrate, and maintain.</p>
|
||||
</li>
|
||||
<li>
|
||||
<h4>React Interface</h4>
|
||||
<p>A responsive, dark-mode first UI built with the latest React patterns for a snappy experience.</p>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
<!-- Feature Spotlights -->
|
||||
<div id="spotlights">
|
||||
|
||||
<section class="spotlight-section">
|
||||
<div class="spotlight container">
|
||||
<div class="spotlight-text">
|
||||
<div class="eyebrow">Traffic Intelligence</div>
|
||||
<h2>See every request,<br>in real time.</h2>
|
||||
<p>Charts, country heatmaps, user agent breakdowns, and a paginated blocked-request log. Filter by host or pick any time range from the last hour to 30 days.</p>
|
||||
</div>
|
||||
<div class="spotlight-image">
|
||||
<img src="assets/screenshots/analytics-top.png" alt="Analytics dashboard" loading="lazy" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="spotlight-section spotlight-reverse">
|
||||
<div class="spotlight container">
|
||||
<div class="spotlight-text">
|
||||
<div class="eyebrow">Proxy Management</div>
|
||||
<h2>Every reverse proxy,<br>one interface.</h2>
|
||||
<p>Search across all hosts, toggle them on or off instantly, and configure upstreams, load balancing, and access lists — without touching a config file.</p>
|
||||
</div>
|
||||
<div class="spotlight-image">
|
||||
<img src="assets/screenshots/proxy-hosts.png" alt="Proxy Hosts" loading="lazy" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="spotlight-section">
|
||||
<div class="spotlight container">
|
||||
<div class="spotlight-text">
|
||||
<div class="eyebrow">TLS Certificates</div>
|
||||
<h2>HTTPS by default.<br>Visibility built in.</h2>
|
||||
<p>Caddy handles certificate issuance automatically. The Certificates page shows issuer, expiry, and status for every managed cert — and lets you import custom ones when needed.</p>
|
||||
</div>
|
||||
<div class="spotlight-image">
|
||||
<img src="assets/screenshots/certificates.png" alt="Certificates" loading="lazy" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="spotlight-section spotlight-reverse">
|
||||
<div class="spotlight container">
|
||||
<div class="spotlight-text">
|
||||
<div class="eyebrow">Configuration</div>
|
||||
<h2>Every option,<br>without the YAML.</h2>
|
||||
<p>The host editor exposes load balancing policies, Authentik forward auth, custom DNS resolvers, upstream DNS pinning, geo blocking rules, and HSTS — all from a single form.</p>
|
||||
</div>
|
||||
<div class="spotlight-image">
|
||||
<img src="assets/screenshots/proxy-editor.png" alt="Proxy Editor" loading="lazy" />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
</div>
|
||||
|
||||
<!-- Deploy -->
|
||||
<section id="deployment" class="deployment">
|
||||
<div class="container section-header">
|
||||
<h2>Deploy in Seconds</h2>
|
||||
<p>Get up and running with Docker Compose.</p>
|
||||
<div class="container deploy-inner">
|
||||
<div class="section-header">
|
||||
<div class="eyebrow">Open Source</div>
|
||||
<h2>Deploy in Seconds</h2>
|
||||
<p>A single docker-compose file is all you need.</p>
|
||||
</div>
|
||||
|
||||
<div class="code-block">
|
||||
<span class="comment"># Clone the repository</span>
|
||||
<span class="command">git clone https://github.com/fuomag9/caddy-proxy-manager.git</span>
|
||||
<span class="command">cd caddy-proxy-manager</span>
|
||||
<br>
|
||||
<span class="comment"># Setup environment</span>
|
||||
<span class="command">cp .env.example .env</span>
|
||||
<br>
|
||||
<span class="comment"># Start the stack</span>
|
||||
<span class="command">docker compose up -d</span>
|
||||
<div class="code-line"><span class="comment"># Clone and configure</span></div>
|
||||
<div class="code-line"><span class="command">git clone https://github.com/fuomag9/caddy-proxy-manager.git</span></div>
|
||||
<div class="code-line"><span class="command">cd caddy-proxy-manager && cp .env.example .env</span></div>
|
||||
<div class="code-line"> </div>
|
||||
<div class="code-line"><span class="comment"># Configure the environment</span></div>
|
||||
<div class="code-line"><span class="command">nano .env</span></div>
|
||||
<div class="code-line"> </div>
|
||||
<div class="code-line"><span class="comment"># Start</span></div>
|
||||
<div class="code-line"><span class="command">docker compose up -d</span></div>
|
||||
</div>
|
||||
|
||||
<p class="deploy-note">Access at <code>http://localhost:3000</code> · Data persists in Docker volumes</p>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
|
||||
<footer>
|
||||
<div class="container">
|
||||
<p>© <span id="year"></span> Caddy Proxy Manager. Released under the MIT License.</p>
|
||||
<div class="container footer-inner">
|
||||
<a href="#" class="logo footer-logo">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M12 2L2 7L12 12L22 7L12 2Z" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M2 17L12 22L22 17" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
<path d="M2 12L12 17L22 12" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" />
|
||||
</svg>
|
||||
Caddy Proxy Manager
|
||||
</a>
|
||||
<p>© <span id="year"></span> Released under the MIT License.</p>
|
||||
</div>
|
||||
</footer>
|
||||
</body>
|
||||
|
||||
</html>
|
||||
</html>
|
||||
|
||||
390
site/styles.css
390
site/styles.css
@@ -1,26 +1,22 @@
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
--bg: #09090b;
|
||||
--bg-subtle: #18181b;
|
||||
--fg: #fafafa;
|
||||
--fg-muted: #a1a1aa;
|
||||
--border: #27272a;
|
||||
|
||||
--primary: #4f46e5;
|
||||
--primary-hover: #4338ca;
|
||||
--primary-foreground: #ffffff;
|
||||
|
||||
--radius: 0.75rem;
|
||||
|
||||
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', Arial, sans-serif;
|
||||
--max-width: 1200px;
|
||||
--bg: #000;
|
||||
--bg-subtle: #0a0a0a;
|
||||
--bg-card: #111;
|
||||
--fg: #f5f5f7;
|
||||
--fg-muted: #86868b;
|
||||
--fg-subtle: #515154;
|
||||
--border: #1d1d1f;
|
||||
--primary: #6366f1;
|
||||
--primary-glow: rgba(99, 102, 241, 0.3);
|
||||
--radius: 1rem;
|
||||
--font-sans: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
||||
--max-width: 1100px;
|
||||
}
|
||||
|
||||
* {
|
||||
box-sizing: border-box;
|
||||
margin: 0;
|
||||
padding: 0;
|
||||
}
|
||||
* { box-sizing: border-box; margin: 0; padding: 0; }
|
||||
|
||||
html { scroll-behavior: smooth; }
|
||||
|
||||
body {
|
||||
background-color: var(--bg);
|
||||
@@ -28,153 +24,156 @@ body {
|
||||
font-family: var(--font-sans);
|
||||
line-height: 1.6;
|
||||
-webkit-font-smoothing: antialiased;
|
||||
min-height: 100vh;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
overflow-x: hidden;
|
||||
}
|
||||
|
||||
/* Aurora Backdrop */
|
||||
.aurora-bg {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
z-index: -1;
|
||||
background:
|
||||
radial-gradient(circle at 15% 50%, rgba(79, 70, 229, 0.15), transparent 25%),
|
||||
radial-gradient(circle at 85% 30%, rgba(147, 51, 234, 0.15), transparent 25%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* Layout */
|
||||
.container {
|
||||
width: 100%;
|
||||
max-width: var(--max-width);
|
||||
margin: 0 auto;
|
||||
padding: 0 1.5rem;
|
||||
padding: 0 2rem;
|
||||
}
|
||||
|
||||
/* ── Aurora ── */
|
||||
.aurora-bg {
|
||||
position: fixed;
|
||||
inset: 0;
|
||||
z-index: -1;
|
||||
background:
|
||||
radial-gradient(ellipse 80% 50% at 10% 0%, rgba(99,102,241,0.12) 0%, transparent 60%),
|
||||
radial-gradient(ellipse 60% 40% at 90% 10%, rgba(168,85,247,0.10) 0%, transparent 60%);
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
/* ── Header ── */
|
||||
header {
|
||||
border-bottom: 1px solid var(--border);
|
||||
backdrop-filter: blur(12px);
|
||||
-webkit-backdrop-filter: blur(12px);
|
||||
position: sticky;
|
||||
top: 0;
|
||||
z-index: 50;
|
||||
background-color: rgba(9, 9, 11, 0.8);
|
||||
z-index: 100;
|
||||
border-bottom: 1px solid var(--border);
|
||||
background: rgba(0, 0, 0, 0.72);
|
||||
backdrop-filter: blur(20px) saturate(180%);
|
||||
-webkit-backdrop-filter: blur(20px) saturate(180%);
|
||||
}
|
||||
|
||||
.header-inner {
|
||||
display: flex;
|
||||
justify-content: space-between;
|
||||
align-items: center;
|
||||
height: 4rem;
|
||||
height: 3.5rem;
|
||||
}
|
||||
|
||||
.logo {
|
||||
font-weight: 700;
|
||||
font-size: 1.125rem;
|
||||
color: var(--fg);
|
||||
text-decoration: none;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 0.5rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.9rem;
|
||||
color: var(--fg);
|
||||
text-decoration: none;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 2rem;
|
||||
}
|
||||
|
||||
.nav-links a {
|
||||
color: var(--fg-muted);
|
||||
text-decoration: none;
|
||||
font-size: 0.875rem;
|
||||
font-size: 0.85rem;
|
||||
font-weight: 500;
|
||||
transition: color 0.2s;
|
||||
transition: color 0.15s;
|
||||
}
|
||||
|
||||
.nav-links a:hover {
|
||||
color: var(--fg);
|
||||
}
|
||||
.nav-links a:hover { color: var(--fg); }
|
||||
|
||||
/* Hero Section */
|
||||
/* ── Hero ── */
|
||||
.hero {
|
||||
padding: 8rem 0 6rem;
|
||||
padding: 9rem 0 5rem;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: 3.5rem;
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.025em;
|
||||
line-height: 1.1;
|
||||
.hero-eyebrow {
|
||||
display: inline-block;
|
||||
font-size: 0.8rem;
|
||||
font-weight: 600;
|
||||
letter-spacing: 0.08em;
|
||||
text-transform: uppercase;
|
||||
color: var(--primary);
|
||||
margin-bottom: 1.5rem;
|
||||
background: linear-gradient(to right, #fff, #a1a1aa);
|
||||
}
|
||||
|
||||
.hero h1 {
|
||||
font-size: clamp(3rem, 7vw, 5.5rem);
|
||||
font-weight: 900;
|
||||
letter-spacing: -0.04em;
|
||||
line-height: 1.0;
|
||||
margin-bottom: 1.5rem;
|
||||
background: linear-gradient(160deg, #fff 0%, #86868b 100%);
|
||||
background-clip: text;
|
||||
-webkit-background-clip: text;
|
||||
-webkit-text-fill-color: transparent;
|
||||
}
|
||||
|
||||
.hero p {
|
||||
font-size: 1.25rem;
|
||||
.hero > p {
|
||||
font-size: 1.2rem;
|
||||
color: var(--fg-muted);
|
||||
max-width: 600px;
|
||||
max-width: 580px;
|
||||
margin: 0 auto 2.5rem;
|
||||
line-height: 1.7;
|
||||
}
|
||||
|
||||
.btn-group {
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
gap: 1rem;
|
||||
gap: 0.75rem;
|
||||
margin-bottom: 5rem;
|
||||
}
|
||||
|
||||
.btn {
|
||||
display: inline-flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
padding: 0.75rem 1.5rem;
|
||||
border-radius: var(--radius);
|
||||
gap: 0.4rem;
|
||||
padding: 0.7rem 1.4rem;
|
||||
border-radius: 2rem;
|
||||
font-weight: 600;
|
||||
font-size: 0.95rem;
|
||||
font-size: 0.9rem;
|
||||
text-decoration: none;
|
||||
transition: all 0.2s;
|
||||
white-space: nowrap;
|
||||
}
|
||||
|
||||
.btn-primary {
|
||||
background-color: var(--fg);
|
||||
color: var(--bg);
|
||||
background: var(--fg);
|
||||
color: #000;
|
||||
}
|
||||
|
||||
.btn-primary:hover {
|
||||
opacity: 0.9;
|
||||
}
|
||||
.btn-primary:hover { background: #e0e0e0; }
|
||||
|
||||
.btn-secondary {
|
||||
background-color: var(--bg-subtle);
|
||||
background: transparent;
|
||||
color: var(--fg);
|
||||
border: 1px solid var(--border);
|
||||
border: 1px solid rgba(255,255,255,0.15);
|
||||
}
|
||||
|
||||
.btn-secondary:hover {
|
||||
background-color: var(--border);
|
||||
}
|
||||
.btn-secondary:hover { background: rgba(255,255,255,0.06); }
|
||||
|
||||
/* Showcase - Screenshots */
|
||||
.showcase {
|
||||
margin: 4rem 0;
|
||||
perspective: 1000px;
|
||||
}
|
||||
/* ── Hero screenshot ── */
|
||||
.showcase { perspective: 1400px; }
|
||||
|
||||
.screenshot-main {
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: 1.25rem;
|
||||
border: 1px solid rgba(255,255,255,0.08);
|
||||
box-shadow:
|
||||
0 0 0 1px rgba(255, 255, 255, 0.05),
|
||||
0 20px 50px -10px rgba(0, 0, 0, 0.5);
|
||||
0 0 0 1px rgba(255,255,255,0.04),
|
||||
0 40px 80px -20px rgba(0,0,0,0.8),
|
||||
0 0 120px -30px var(--primary-glow);
|
||||
overflow: hidden;
|
||||
background: var(--bg-subtle);
|
||||
transform: rotateX(2deg);
|
||||
}
|
||||
|
||||
.screenshot-main img {
|
||||
@@ -183,10 +182,15 @@ header {
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Features Grid */
|
||||
.features {
|
||||
padding: 6rem 0;
|
||||
border-top: 1px solid var(--border);
|
||||
/* ── Section shared ── */
|
||||
.eyebrow {
|
||||
display: inline-block;
|
||||
font-size: 0.75rem;
|
||||
font-weight: 700;
|
||||
letter-spacing: 0.1em;
|
||||
text-transform: uppercase;
|
||||
color: var(--primary);
|
||||
margin-bottom: 1rem;
|
||||
}
|
||||
|
||||
.section-header {
|
||||
@@ -195,141 +199,203 @@ header {
|
||||
}
|
||||
|
||||
.section-header h2 {
|
||||
font-size: 2.25rem;
|
||||
font-weight: 700;
|
||||
font-size: clamp(2rem, 4vw, 3rem);
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
line-height: 1.1;
|
||||
margin-bottom: 1rem;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.section-header p {
|
||||
color: var(--fg-muted);
|
||||
font-size: 1.125rem;
|
||||
font-size: 1.05rem;
|
||||
max-width: 500px;
|
||||
margin: 0 auto;
|
||||
}
|
||||
|
||||
/* ── Features Grid ── */
|
||||
.features {
|
||||
padding: 8rem 0;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.grid {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(auto-fit, minmax(300px, 1fr));
|
||||
gap: 2rem;
|
||||
grid-template-columns: repeat(auto-fit, minmax(240px, 1fr));
|
||||
gap: 1px;
|
||||
background: var(--border);
|
||||
border: 1px solid var(--border);
|
||||
border-radius: var(--radius);
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.card {
|
||||
background: var(--bg-subtle);
|
||||
border: 1px solid var(--border);
|
||||
background: var(--bg-card);
|
||||
padding: 2rem;
|
||||
border-radius: var(--radius);
|
||||
transition: transform 0.2s, border-color 0.2s;
|
||||
transition: background 0.2s;
|
||||
}
|
||||
|
||||
.card:hover {
|
||||
border-color: var(--fg-muted);
|
||||
.card:hover { background: #161616; }
|
||||
|
||||
.card-icon {
|
||||
font-size: 1.5rem;
|
||||
margin-bottom: 1rem;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.card h3 {
|
||||
font-size: 1.25rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.75rem;
|
||||
font-size: 1rem;
|
||||
font-weight: 700;
|
||||
margin-bottom: 0.5rem;
|
||||
letter-spacing: -0.01em;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.card p {
|
||||
color: var(--fg-muted);
|
||||
font-size: 0.95rem;
|
||||
font-size: 0.9rem;
|
||||
line-height: 1.65;
|
||||
}
|
||||
|
||||
/* Architecture / Tech Stack */
|
||||
.tech-stack {
|
||||
padding: 6rem 0;
|
||||
/* ── Spotlight Sections ── */
|
||||
.spotlight-section {
|
||||
padding: 7rem 0;
|
||||
border-top: 1px solid var(--border);
|
||||
}
|
||||
|
||||
.tech-grid {
|
||||
.spotlight {
|
||||
display: grid;
|
||||
grid-template-columns: repeat(2, 1fr);
|
||||
gap: 4rem;
|
||||
grid-template-columns: 1fr 1fr;
|
||||
gap: 5rem;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.tech-list {
|
||||
list-style: none;
|
||||
.spotlight-reverse .spotlight {
|
||||
direction: rtl;
|
||||
}
|
||||
|
||||
.tech-list li {
|
||||
margin-bottom: 2rem;
|
||||
.spotlight-reverse .spotlight > * {
|
||||
direction: ltr;
|
||||
}
|
||||
|
||||
.tech-list h4 {
|
||||
font-size: 1.125rem;
|
||||
font-weight: 600;
|
||||
margin-bottom: 0.5rem;
|
||||
.spotlight-text { max-width: 440px; }
|
||||
|
||||
.spotlight-text h2 {
|
||||
font-size: clamp(2rem, 3.5vw, 2.75rem);
|
||||
font-weight: 800;
|
||||
letter-spacing: -0.03em;
|
||||
line-height: 1.1;
|
||||
margin-bottom: 1.25rem;
|
||||
color: var(--fg);
|
||||
}
|
||||
|
||||
.tech-list p {
|
||||
.spotlight-text p {
|
||||
font-size: 1.05rem;
|
||||
color: var(--fg-muted);
|
||||
line-height: 1.75;
|
||||
}
|
||||
|
||||
.secondary-screenshots {
|
||||
display: grid;
|
||||
gap: 1.5rem;
|
||||
.spotlight-image {
|
||||
border-radius: 1.25rem;
|
||||
border: 1px solid rgba(255,255,255,0.07);
|
||||
overflow: hidden;
|
||||
box-shadow:
|
||||
0 30px 70px -15px rgba(0,0,0,0.7),
|
||||
0 0 0 1px rgba(255,255,255,0.03);
|
||||
background: var(--bg-subtle);
|
||||
}
|
||||
|
||||
.secondary-screenshots img {
|
||||
border-radius: var(--radius);
|
||||
border: 1px solid var(--border);
|
||||
.spotlight-image img {
|
||||
display: block;
|
||||
width: 100%;
|
||||
height: auto;
|
||||
}
|
||||
|
||||
/* Deployment */
|
||||
/* ── Deployment ── */
|
||||
.deployment {
|
||||
padding: 6rem 0;
|
||||
padding: 8rem 0;
|
||||
border-top: 1px solid var(--border);
|
||||
background: linear-gradient(to bottom, transparent, rgba(79, 70, 229, 0.05));
|
||||
}
|
||||
|
||||
.deploy-inner {
|
||||
max-width: 700px;
|
||||
margin: 0 auto;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
.code-block {
|
||||
background: #1e1e24;
|
||||
padding: 1.5rem;
|
||||
border-radius: var(--radius);
|
||||
overflow-x: auto;
|
||||
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
|
||||
font-size: 0.9rem;
|
||||
color: #e2e8f0;
|
||||
background: #0d0d0d;
|
||||
border: 1px solid var(--border);
|
||||
margin-top: 2rem;
|
||||
border-radius: var(--radius);
|
||||
padding: 1.75rem 2rem;
|
||||
font-family: 'Menlo', 'Monaco', 'Courier New', monospace;
|
||||
font-size: 0.875rem;
|
||||
text-align: left;
|
||||
max-width: 800px;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
margin-top: 2.5rem;
|
||||
}
|
||||
|
||||
.command {
|
||||
display: block;
|
||||
margin-bottom: 0.5rem;
|
||||
.code-line { line-height: 2; }
|
||||
.command { color: #e2e8f0; }
|
||||
.comment { color: #4a4a52; }
|
||||
|
||||
.deploy-note {
|
||||
margin-top: 1.5rem;
|
||||
font-size: 0.875rem;
|
||||
color: var(--fg-subtle);
|
||||
}
|
||||
|
||||
.comment {
|
||||
color: #6b7280;
|
||||
.deploy-note code {
|
||||
font-family: 'Menlo', monospace;
|
||||
font-size: 0.82rem;
|
||||
color: var(--fg-muted);
|
||||
background: rgba(255,255,255,0.06);
|
||||
padding: 0.15em 0.4em;
|
||||
border-radius: 0.25rem;
|
||||
}
|
||||
|
||||
/* Footer */
|
||||
/* ── Footer ── */
|
||||
footer {
|
||||
border-top: 1px solid var(--border);
|
||||
padding: 3rem 0;
|
||||
text-align: center;
|
||||
color: var(--fg-muted);
|
||||
font-size: 0.875rem;
|
||||
padding: 2.5rem 0;
|
||||
}
|
||||
|
||||
/* Mobile */
|
||||
@media (max-width: 768px) {
|
||||
.hero h1 {
|
||||
font-size: 2.5rem;
|
||||
}
|
||||
.footer-inner {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: space-between;
|
||||
}
|
||||
|
||||
.tech-grid {
|
||||
.footer-logo { opacity: 0.4; }
|
||||
.footer-logo:hover { opacity: 0.7; }
|
||||
|
||||
footer p {
|
||||
font-size: 0.8rem;
|
||||
color: var(--fg-subtle);
|
||||
}
|
||||
|
||||
/* ── Mobile ── */
|
||||
@media (max-width: 860px) {
|
||||
.spotlight {
|
||||
grid-template-columns: 1fr;
|
||||
gap: 2rem;
|
||||
gap: 2.5rem;
|
||||
}
|
||||
|
||||
.nav-links {
|
||||
display: none;
|
||||
.spotlight-reverse .spotlight {
|
||||
direction: ltr;
|
||||
}
|
||||
}
|
||||
|
||||
.spotlight-text { max-width: 100%; }
|
||||
|
||||
.hero { padding: 6rem 0 4rem; }
|
||||
|
||||
.grid { grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); }
|
||||
|
||||
.footer-inner { flex-direction: column; gap: 1rem; text-align: center; }
|
||||
}
|
||||
|
||||
@media (max-width: 600px) {
|
||||
.nav-links { display: none; }
|
||||
.hero h1 { font-size: 2.75rem; }
|
||||
.btn-group { flex-direction: column; align-items: center; }
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user