Compare commits
7 Commits
v0.9.0
...
889b0f0cb8
| Author | SHA1 | Date | |
|---|---|---|---|
| 889b0f0cb8 | |||
| 0770da6c30 | |||
| 1bbb2dc128 | |||
| dc0c2a75df | |||
| 5594c6d21e | |||
| afe94234c8 | |||
| 34c9324b74 |
+2
-2
@@ -3,7 +3,7 @@ set -euo pipefail
|
|||||||
|
|
||||||
# ── Configuration ──────────────────────────────────────────────
|
# ── Configuration ──────────────────────────────────────────────
|
||||||
GITEA_URL="https://code.crashlabs.io"
|
GITEA_URL="https://code.crashlabs.io"
|
||||||
REPO="dave/huskies"
|
REPO="crashlabs/huskies"
|
||||||
BINARY_NAME="huskies"
|
BINARY_NAME="huskies"
|
||||||
|
|
||||||
# ── Load .env if present ───────────────────────────────────────
|
# ── Load .env if present ───────────────────────────────────────
|
||||||
@@ -98,7 +98,7 @@ cp "target/aarch64-unknown-linux-musl/release/${BINARY_NAME}" "${DIST}/${BINARY_
|
|||||||
chmod +x "${DIST}"/*
|
chmod +x "${DIST}"/*
|
||||||
|
|
||||||
echo "==> Binaries:"
|
echo "==> Binaries:"
|
||||||
ls -lh "${DIST}"/
|
ls -lh "${DIST}"/*
|
||||||
|
|
||||||
# ── Changelog ──────────────────────────────────────────────────
|
# ── Changelog ──────────────────────────────────────────────────
|
||||||
echo "==> Generating changelog..."
|
echo "==> Generating changelog..."
|
||||||
|
|||||||
+11
-3
@@ -577,9 +577,17 @@ async fn main() -> Result<(), std::io::Error> {
|
|||||||
let host = std::env::var("HUSKIES_HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
|
let host = std::env::var("HUSKIES_HOST").unwrap_or_else(|_| "127.0.0.1".to_string());
|
||||||
let addr = format!("{host}:{port}");
|
let addr = format!("{host}:{port}");
|
||||||
|
|
||||||
println!(
|
println!("\x1b[97;1m");
|
||||||
"\x1b[95;1m ____ _ _ ___ _ \n / ___|| |_ ___ _ __| | _|_ _| |_ \n \\___ \\| __/ _ \\| '__| |/ /| || __|\n ___) | || (_) | | | < | || |_ \n |____/ \\__\\___/|_| |_|\\_\\___|\\__|\n\x1b[0m"
|
println!(" /\\_/\\ \x1b[96;1m _ _ _ _ \x1b[97;1m");
|
||||||
);
|
println!(" / o o \\ \x1b[96;1m| | | |_ _ ___| | _(_) ___ ___\x1b[97;1m");
|
||||||
|
println!(" ( Y ) \x1b[96;1m| |_| | | | / __| |/ / |/ _ \\/ __|\x1b[97;1m");
|
||||||
|
println!(" \\ ^ / \x1b[96;1m| _ | |_| \\__ \\ <| | __/\\__ \\\x1b[97;1m");
|
||||||
|
println!(" )===( \\ \x1b[96;1m|_| |_|\\__,_|___/_|\\_\\_|\\___||___/\x1b[97;1m");
|
||||||
|
println!(" / \\ \\ \x1b[90mStory-driven development, powered by AI\x1b[97;1m");
|
||||||
|
println!(" | | | |");
|
||||||
|
println!(" /| | |\\|");
|
||||||
|
println!(" \\|__|__|/\x1b[0m");
|
||||||
|
println!();
|
||||||
println!("HUSKIES_PORT={port}");
|
println!("HUSKIES_PORT={port}");
|
||||||
println!("\x1b[96;1mFrontend:\x1b[0m \x1b[94mhttp://{addr}\x1b[0m");
|
println!("\x1b[96;1mFrontend:\x1b[0m \x1b[94mhttp://{addr}\x1b[0m");
|
||||||
println!("\x1b[92;1mOpenAPI Docs:\x1b[0m \x1b[94mhttp://{addr}/docs\x1b[0m");
|
println!("\x1b[92;1mOpenAPI Docs:\x1b[0m \x1b[94mhttp://{addr}/docs\x1b[0m");
|
||||||
|
|||||||
Binary file not shown.
|
After Width: | Height: | Size: 1.3 MiB |
@@ -0,0 +1,34 @@
|
|||||||
|
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 200 200" fill="none">
|
||||||
|
<!-- Husky head - geometric/angular style -->
|
||||||
|
<!-- Ears -->
|
||||||
|
<path d="M60 85 L45 35 L85 65 Z" fill="#8892a8" stroke="#e8ecf4" stroke-width="1.5"/>
|
||||||
|
<path d="M140 85 L155 35 L115 65 Z" fill="#8892a8" stroke="#e8ecf4" stroke-width="1.5"/>
|
||||||
|
<!-- Inner ears -->
|
||||||
|
<path d="M62 78 L52 45 L80 65 Z" fill="#4a5568"/>
|
||||||
|
<path d="M138 78 L148 45 L120 65 Z" fill="#4a5568"/>
|
||||||
|
<!-- Head shape -->
|
||||||
|
<path d="M55 80 Q55 60 75 60 L125 60 Q145 60 145 80 L145 120 Q145 155 120 165 L110 170 Q100 175 90 170 L80 165 Q55 155 55 120 Z" fill="#8892a8" stroke="#e8ecf4" stroke-width="1.5"/>
|
||||||
|
<!-- Face mask (white marking) -->
|
||||||
|
<path d="M75 70 L100 65 L125 70 L120 110 L110 135 Q100 142 90 135 L80 110 Z" fill="#e8ecf4"/>
|
||||||
|
<!-- Forehead stripe -->
|
||||||
|
<path d="M92 65 L100 62 L108 65 L104 95 L100 100 L96 95 Z" fill="#8892a8"/>
|
||||||
|
<!-- Eyes -->
|
||||||
|
<ellipse cx="82" cy="95" rx="7" ry="7.5" fill="#080c15"/>
|
||||||
|
<ellipse cx="118" cy="95" rx="7" ry="7.5" fill="#080c15"/>
|
||||||
|
<!-- Eye shine - cyan to match brand -->
|
||||||
|
<circle cx="80" cy="93" r="2.5" fill="#22d3ee"/>
|
||||||
|
<circle cx="116" cy="93" r="2.5" fill="#22d3ee"/>
|
||||||
|
<!-- Iris detail -->
|
||||||
|
<ellipse cx="82" cy="95" rx="4" ry="4.5" fill="none" stroke="#22d3ee" stroke-width="0.5" opacity="0.4"/>
|
||||||
|
<ellipse cx="118" cy="95" rx="4" ry="4.5" fill="none" stroke="#22d3ee" stroke-width="0.5" opacity="0.4"/>
|
||||||
|
<!-- Nose -->
|
||||||
|
<path d="M95 120 Q100 115 105 120 Q105 126 100 128 Q95 126 95 120 Z" fill="#080c15"/>
|
||||||
|
<!-- Nose highlight -->
|
||||||
|
<ellipse cx="100" cy="120" rx="2" ry="1" fill="#4a5568"/>
|
||||||
|
<!-- Mouth -->
|
||||||
|
<path d="M100 128 L100 135" stroke="#4a5568" stroke-width="1.5" stroke-linecap="round"/>
|
||||||
|
<path d="M92 138 Q100 143 108 138" stroke="#4a5568" stroke-width="1.5" fill="none" stroke-linecap="round"/>
|
||||||
|
<!-- Cheek fur tufts -->
|
||||||
|
<path d="M55 105 Q48 110 50 120" stroke="#e8ecf4" stroke-width="1" fill="none" opacity="0.5"/>
|
||||||
|
<path d="M145 105 Q152 110 150 120" stroke="#e8ecf4" stroke-width="1" fill="none" opacity="0.5"/>
|
||||||
|
</svg>
|
||||||
|
After Width: | Height: | Size: 2.0 KiB |
+119
-40
@@ -5,63 +5,142 @@
|
|||||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||||
<title>Huskies — Story-Driven Development for AI Agents</title>
|
<title>Huskies — Story-Driven Development for AI Agents</title>
|
||||||
<meta name="description" content="Huskies is an autonomous development pipeline that turns user stories into tested, shipped code using AI agents.">
|
<meta name="description" content="Huskies is an autonomous development pipeline that turns user stories into tested, shipped code using AI agents.">
|
||||||
|
<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=Bricolage+Grotesque:wght@400;500;600;700;800&family=Karla:ital,wght@0,300;0,400;0,500;1,300;1,400&display=swap" rel="stylesheet">
|
||||||
<link rel="stylesheet" href="style.css">
|
<link rel="stylesheet" href="style.css">
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
|
|
||||||
<div class="container">
|
<div class="page">
|
||||||
|
|
||||||
<header>
|
<!-- Nav -->
|
||||||
<h1>stor<span>kit</span></h1>
|
<header class="reveal r1">
|
||||||
<p class="tagline">Story-driven development, powered by AI agents.</p>
|
<a href="/" class="logo">huskies</a>
|
||||||
|
<nav>
|
||||||
|
<a href="#how">How it works</a>
|
||||||
|
<a href="#features">Features</a>
|
||||||
|
<a href="mailto:hello@huskies.dev" class="nav-cta">Get in touch</a>
|
||||||
|
</nav>
|
||||||
</header>
|
</header>
|
||||||
|
|
||||||
<section>
|
<!-- Hero -->
|
||||||
<h2>What is Huskies?</h2>
|
<section class="hero">
|
||||||
<p>Huskies is an autonomous development pipeline that turns user stories into tested, shipped code. You describe what you want. AI agents handle the rest — implementation, testing, code review, and merge.</p>
|
<div class="hero-graphic reveal r1">
|
||||||
<p>Talk to it from your IDE, a chat room, or WhatsApp. Stories flow through a structured pipeline: backlog, current, QA, merge, done.</p>
|
<img src="husky.png" alt="" class="hero-husky">
|
||||||
</section>
|
</div>
|
||||||
|
<p class="hero-kicker reveal r1">Story-driven development</p>
|
||||||
|
<h1 class="reveal r2">Coding agents are huskies,<br>not <span class="glow">labradors.</span></h1>
|
||||||
|
<p class="hero-sub reveal r3">They're enthusiastic, sometimes wild, and they'll happily wander off on their own. But put them in a harness and they'll take you anywhere. Huskies is the harness — a story-driven pipeline that turns coding agents into a disciplined team.</p>
|
||||||
|
|
||||||
<section>
|
<!-- Pipeline viz -->
|
||||||
<h2>How it works</h2>
|
<div class="pipeline reveal r4">
|
||||||
<ol class="steps">
|
<div class="pipe-stage">
|
||||||
<li>You write a user story with acceptance criteria.</li>
|
<span class="pipe-dot"></span>
|
||||||
<li>An AI agent picks it up, creates a feature branch, and implements the code.</li>
|
<span class="pipe-label">Story</span>
|
||||||
<li>A QA agent runs tests, linters, and quality gates automatically.</li>
|
|
||||||
<li>A merge agent resolves conflicts and lands it on your main branch.</li>
|
|
||||||
<li>You review the result. Accept or send it back.</li>
|
|
||||||
</ol>
|
|
||||||
</section>
|
|
||||||
|
|
||||||
<section>
|
|
||||||
<h2>Features</h2>
|
|
||||||
<div class="features">
|
|
||||||
<div class="feature">
|
|
||||||
<h3>Story-Driven Workflow</h3>
|
|
||||||
<p>Stories define the change. Tests define the truth. Code defines the reality. No code ships without acceptance criteria.</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div class="feature">
|
<span class="pipe-line"></span>
|
||||||
<h3>Multi-Agent Pipeline</h3>
|
<div class="pipe-stage">
|
||||||
<p>Coder, QA, and merge agents work in parallel across isolated git worktrees. Configure agent count, models, and budgets.</p>
|
<span class="pipe-dot active"></span>
|
||||||
|
<span class="pipe-label">Implement</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature">
|
<span class="pipe-line"></span>
|
||||||
<h3>Chat Anywhere</h3>
|
<div class="pipe-stage">
|
||||||
<p>Control the pipeline from Matrix, WhatsApp, Slack, or the built-in web UI. Create stories, start agents, check status.</p>
|
<span class="pipe-dot"></span>
|
||||||
|
<span class="pipe-label">QA</span>
|
||||||
</div>
|
</div>
|
||||||
<div class="feature">
|
<span class="pipe-line"></span>
|
||||||
<h3>Full Autonomy, Your Oversight</h3>
|
<div class="pipe-stage">
|
||||||
<p>Agents implement, test, and merge independently. You approve what ships. Every story is traceable from request to release.</p>
|
<span class="pipe-dot"></span>
|
||||||
|
<span class="pipe-label">Merge</span>
|
||||||
|
</div>
|
||||||
|
<span class="pipe-line"></span>
|
||||||
|
<div class="pipe-stage">
|
||||||
|
<span class="pipe-dot done"></span>
|
||||||
|
<span class="pipe-label">Done</span>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<section>
|
<!-- How it works -->
|
||||||
<h2>Get in touch</h2>
|
<section id="how" class="how-section">
|
||||||
<p>Huskies is built by <a href="https://crashlabs.io">Crashlabs</a>. Interested in early access or have questions? Reach out at <a href="mailto:hello@huskies.dev">hello@huskies.dev</a>.</p>
|
<h2 class="section-title reveal r5">How it works</h2>
|
||||||
|
<ol class="steps">
|
||||||
|
<li class="step reveal r5">
|
||||||
|
<span class="step-num">01</span>
|
||||||
|
<div class="step-body">
|
||||||
|
<h3>Write a story</h3>
|
||||||
|
<p>Describe what you want with acceptance criteria. From your IDE, a chat room, or WhatsApp.</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="step reveal r5">
|
||||||
|
<span class="step-num">02</span>
|
||||||
|
<div class="step-body">
|
||||||
|
<h3>Agent picks it up</h3>
|
||||||
|
<p>A coder agent creates a feature branch, implements the code, and writes tests against your criteria.</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="step reveal r6">
|
||||||
|
<span class="step-num">03</span>
|
||||||
|
<div class="step-body">
|
||||||
|
<h3>Quality gates run</h3>
|
||||||
|
<p>Linters, tests, and compilation checks run automatically. Nothing moves forward until everything passes.</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
<li class="step reveal r6">
|
||||||
|
<span class="step-num">04</span>
|
||||||
|
<div class="step-body">
|
||||||
|
<h3>Merge & land</h3>
|
||||||
|
<p>A merge agent resolves conflicts and squash-merges to your main branch. You review and accept.</p>
|
||||||
|
</div>
|
||||||
|
</li>
|
||||||
|
</ol>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
<footer>
|
<!-- Features -->
|
||||||
<p>© 2026 Libby Labs Ltd. All rights reserved. · <a href="privacy.html">Privacy Policy</a></p>
|
<section id="features" class="features-section">
|
||||||
|
<h2 class="section-title reveal r7">Features</h2>
|
||||||
|
<div class="feature-grid">
|
||||||
|
<div class="feature reveal r7">
|
||||||
|
<div class="feature-icon">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M9 5H7a2 2 0 00-2 2v12a2 2 0 002 2h10a2 2 0 002-2V7a2 2 0 00-2-2h-2M9 5a2 2 0 002 2h2a2 2 0 002-2M9 5a2 2 0 012-2h2a2 2 0 012 2m-6 9l2 2 4-4"/></svg>
|
||||||
|
</div>
|
||||||
|
<h3>The Harness</h3>
|
||||||
|
<p>Stories define the change. Tests define the truth. Code defines the reality. Every agent runs on rails — nothing ships without acceptance criteria.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature reveal r7">
|
||||||
|
<div class="feature-icon">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><circle cx="18" cy="5" r="3"/><circle cx="6" cy="12" r="3"/><circle cx="18" cy="19" r="3"/><path d="M8.59 13.51l6.83 3.98M15.41 6.51l-6.82 3.98"/></svg>
|
||||||
|
</div>
|
||||||
|
<h3>The Pack</h3>
|
||||||
|
<p>Coder, QA, and merge agents work in parallel across isolated git worktrees. A coordinated pack, not a lone wolf. Configure agent count, models, and budgets.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature reveal r8">
|
||||||
|
<div class="feature-icon">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M21 15a2 2 0 01-2 2H7l-4 4V5a2 2 0 012-2h14a2 2 0 012 2z"/></svg>
|
||||||
|
</div>
|
||||||
|
<h3>Chat Anywhere</h3>
|
||||||
|
<p>Control the pipeline from Matrix, WhatsApp, Slack, or the built-in web UI. Create stories, start agents, check status.</p>
|
||||||
|
</div>
|
||||||
|
<div class="feature reveal r8">
|
||||||
|
<div class="feature-icon">
|
||||||
|
<svg width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.5"><path d="M12 22s8-4 8-10V5l-8-3-8 3v7c0 6 8 10 8 10z"/></svg>
|
||||||
|
</div>
|
||||||
|
<h3>You're the Musher</h3>
|
||||||
|
<p>Agents implement, test, and merge independently. You set the direction and approve what ships. Every story is traceable from request to release.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<!-- CTA -->
|
||||||
|
<section class="cta-section reveal r8">
|
||||||
|
<h2>Interested?</h2>
|
||||||
|
<p>Huskies is built by <a href="https://crashlabs.io">Crash Labs</a>. Get in touch at <a href="mailto:hello@huskies.dev">hello@huskies.dev</a>.</p>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<footer class="reveal r8">
|
||||||
|
<span>© 2026 Libby Labs Ltd.</span>
|
||||||
|
<a href="privacy.html">Privacy Policy</a>
|
||||||
</footer>
|
</footer>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
+307
-90
@@ -1,140 +1,357 @@
|
|||||||
:root {
|
:root {
|
||||||
--bg: #0a0a0a;
|
--bg: #080c15;
|
||||||
--fg: #e8e8e8;
|
--surface: #0e1420;
|
||||||
--muted: #888;
|
--surface-hover: #131a28;
|
||||||
--accent: #4f9cf7;
|
--border: #1a2235;
|
||||||
--surface: #141414;
|
--text: #e8ecf4;
|
||||||
--border: #222;
|
--text-secondary: #8892a8;
|
||||||
--max-w: 720px;
|
--text-dim: #4a5568;
|
||||||
|
--cyan: #22d3ee;
|
||||||
|
--cyan-dim: rgba(34, 211, 238, 0.07);
|
||||||
|
--cyan-glow: rgba(34, 211, 238, 0.15);
|
||||||
|
--display: 'Bricolage Grotesque', sans-serif;
|
||||||
|
--body: 'Karla', sans-serif;
|
||||||
}
|
}
|
||||||
|
|
||||||
* { margin: 0; padding: 0; box-sizing: border-box; }
|
* { margin: 0; padding: 0; box-sizing: border-box; }
|
||||||
|
html { scroll-behavior: smooth; }
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
|
font-family: var(--body);
|
||||||
background: var(--bg);
|
background: var(--bg);
|
||||||
color: var(--fg);
|
color: var(--text);
|
||||||
line-height: 1.6;
|
line-height: 1.6;
|
||||||
|
min-height: 100vh;
|
||||||
|
overflow-x: hidden;
|
||||||
-webkit-font-smoothing: antialiased;
|
-webkit-font-smoothing: antialiased;
|
||||||
}
|
}
|
||||||
|
|
||||||
a { color: var(--accent); text-decoration: none; }
|
a { color: var(--cyan); text-decoration: none; transition: opacity 0.2s; }
|
||||||
a:hover { text-decoration: underline; }
|
a:hover { opacity: 0.7; }
|
||||||
|
|
||||||
.container {
|
/* Animations */
|
||||||
max-width: var(--max-w);
|
@keyframes fadeUp {
|
||||||
|
from { opacity: 0; transform: translateY(18px); }
|
||||||
|
to { opacity: 1; transform: translateY(0); }
|
||||||
|
}
|
||||||
|
@keyframes pulse {
|
||||||
|
0%, 100% { box-shadow: 0 0 0 0 var(--cyan-glow); }
|
||||||
|
50% { box-shadow: 0 0 12px 4px var(--cyan-glow); }
|
||||||
|
}
|
||||||
|
|
||||||
|
.reveal {
|
||||||
|
opacity: 0;
|
||||||
|
animation: fadeUp 0.7s cubic-bezier(0.16, 1, 0.3, 1) forwards;
|
||||||
|
}
|
||||||
|
.r1 { animation-delay: 0.05s; }
|
||||||
|
.r2 { animation-delay: 0.15s; }
|
||||||
|
.r3 { animation-delay: 0.3s; }
|
||||||
|
.r4 { animation-delay: 0.5s; }
|
||||||
|
.r5 { animation-delay: 0.65s; }
|
||||||
|
.r6 { animation-delay: 0.8s; }
|
||||||
|
.r7 { animation-delay: 0.95s; }
|
||||||
|
.r8 { animation-delay: 1.1s; }
|
||||||
|
|
||||||
|
/* Layout */
|
||||||
|
.page {
|
||||||
|
max-width: 960px;
|
||||||
margin: 0 auto;
|
margin: 0 auto;
|
||||||
padding: 0 24px;
|
padding: 0 3rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Header ── */
|
@media (max-width: 640px) {
|
||||||
|
.page { padding: 0 1.5rem; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Header */
|
||||||
header {
|
header {
|
||||||
padding: 48px 0 32px;
|
padding: 2rem 0;
|
||||||
border-bottom: 1px solid var(--border);
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
header h1 {
|
.logo {
|
||||||
font-size: 2rem;
|
font-family: var(--display);
|
||||||
font-weight: 700;
|
|
||||||
letter-spacing: -0.03em;
|
|
||||||
}
|
|
||||||
|
|
||||||
header h1 span { color: var(--accent); }
|
|
||||||
|
|
||||||
header p.tagline {
|
|
||||||
color: var(--muted);
|
|
||||||
font-size: 1.1rem;
|
font-size: 1.1rem;
|
||||||
margin-top: 8px;
|
font-weight: 800;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
color: var(--text) !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Sections ── */
|
header nav {
|
||||||
section {
|
display: flex;
|
||||||
padding: 48px 0;
|
align-items: center;
|
||||||
border-bottom: 1px solid var(--border);
|
gap: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
section:last-of-type { border-bottom: none; }
|
header nav a {
|
||||||
|
font-size: 0.82rem;
|
||||||
|
color: var(--text-dim);
|
||||||
|
}
|
||||||
|
|
||||||
section h2 {
|
header nav a:hover { color: var(--text); opacity: 1; }
|
||||||
font-size: 1.25rem;
|
|
||||||
|
.nav-cta {
|
||||||
|
color: var(--cyan) !important;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hero */
|
||||||
|
.hero {
|
||||||
|
padding: 10vh 0 6vh;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-graphic {
|
||||||
|
margin-bottom: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-husky {
|
||||||
|
width: 320px;
|
||||||
|
height: auto;
|
||||||
|
filter: drop-shadow(0 0 40px rgba(34, 211, 238, 0.2));
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-kicker {
|
||||||
|
font-family: var(--display);
|
||||||
|
font-size: 0.7rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 16px;
|
letter-spacing: 0.18em;
|
||||||
letter-spacing: -0.02em;
|
text-transform: uppercase;
|
||||||
|
color: var(--cyan);
|
||||||
|
margin-bottom: 2rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
section p { color: var(--muted); margin-bottom: 12px; }
|
.hero h1 {
|
||||||
|
font-family: var(--display);
|
||||||
|
font-size: clamp(2.5rem, 6vw, 4.2rem);
|
||||||
|
font-weight: 800;
|
||||||
|
line-height: 1.1;
|
||||||
|
letter-spacing: -0.03em;
|
||||||
|
margin-bottom: 1.8rem;
|
||||||
|
max-width: 700px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
}
|
||||||
|
|
||||||
/* ── Feature grid ── */
|
.glow {
|
||||||
.features {
|
color: var(--cyan);
|
||||||
|
text-shadow: 0 0 30px var(--cyan-glow);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero-sub {
|
||||||
|
font-size: 1.05rem;
|
||||||
|
font-weight: 300;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.8;
|
||||||
|
max-width: 520px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Pipeline visualisation */
|
||||||
|
.pipeline {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
justify-content: center;
|
||||||
|
gap: 0;
|
||||||
|
margin-top: 4rem;
|
||||||
|
padding: 2rem 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pipe-stage {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
gap: 0.8rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pipe-dot {
|
||||||
|
width: 12px;
|
||||||
|
height: 12px;
|
||||||
|
border-radius: 50%;
|
||||||
|
border: 2px solid var(--border);
|
||||||
|
background: var(--surface);
|
||||||
|
transition: all 0.3s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pipe-dot.active {
|
||||||
|
border-color: var(--cyan);
|
||||||
|
background: var(--cyan);
|
||||||
|
animation: pulse 2s ease-in-out infinite;
|
||||||
|
}
|
||||||
|
|
||||||
|
.pipe-dot.done {
|
||||||
|
border-color: var(--text-dim);
|
||||||
|
background: var(--text-dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pipe-label {
|
||||||
|
font-family: var(--display);
|
||||||
|
font-size: 0.65rem;
|
||||||
|
font-weight: 600;
|
||||||
|
letter-spacing: 0.08em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
color: var(--text-dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pipe-stage:has(.active) .pipe-label {
|
||||||
|
color: var(--cyan);
|
||||||
|
}
|
||||||
|
|
||||||
|
.pipe-line {
|
||||||
|
width: 60px;
|
||||||
|
height: 1px;
|
||||||
|
background: var(--border);
|
||||||
|
margin: 0 0.5rem;
|
||||||
|
margin-bottom: 2rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 500px) {
|
||||||
|
.pipe-line { width: 30px; }
|
||||||
|
.pipe-label { font-size: 0.55rem; }
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Sections */
|
||||||
|
.section-title {
|
||||||
|
font-family: var(--display);
|
||||||
|
font-size: 1.6rem;
|
||||||
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
margin-bottom: 2.5rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* How it works */
|
||||||
|
.how-section {
|
||||||
|
padding: 5rem 0;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.steps {
|
||||||
|
list-style: none;
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
gap: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: 56px 1fr;
|
||||||
|
gap: 1.5rem;
|
||||||
|
padding: 1.8rem 0;
|
||||||
|
border-bottom: 1px solid var(--border);
|
||||||
|
align-items: start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step:first-child {
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-num {
|
||||||
|
font-family: var(--display);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
font-weight: 700;
|
||||||
|
color: var(--text-dim);
|
||||||
|
padding-top: 0.15rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-body h3 {
|
||||||
|
font-family: var(--display);
|
||||||
|
font-size: 1rem;
|
||||||
|
font-weight: 600;
|
||||||
|
margin-bottom: 0.4rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.step-body p {
|
||||||
|
font-size: 0.88rem;
|
||||||
|
font-weight: 300;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Features */
|
||||||
|
.features-section {
|
||||||
|
padding: 5rem 0;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-grid {
|
||||||
display: grid;
|
display: grid;
|
||||||
grid-template-columns: 1fr 1fr;
|
grid-template-columns: 1fr 1fr;
|
||||||
gap: 24px;
|
gap: 1px;
|
||||||
margin-top: 16px;
|
background: var(--border);
|
||||||
|
border: 1px solid var(--border);
|
||||||
}
|
}
|
||||||
|
|
||||||
.feature {
|
.feature {
|
||||||
background: var(--surface);
|
background: var(--surface);
|
||||||
border: 1px solid var(--border);
|
padding: 2rem;
|
||||||
border-radius: 8px;
|
transition: background 0.3s;
|
||||||
padding: 20px;
|
}
|
||||||
|
|
||||||
|
.feature:hover {
|
||||||
|
background: var(--surface-hover);
|
||||||
|
}
|
||||||
|
|
||||||
|
.feature-icon {
|
||||||
|
color: var(--cyan);
|
||||||
|
margin-bottom: 1.2rem;
|
||||||
|
opacity: 0.8;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feature h3 {
|
.feature h3 {
|
||||||
|
font-family: var(--display);
|
||||||
font-size: 0.95rem;
|
font-size: 0.95rem;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
margin-bottom: 6px;
|
margin-bottom: 0.5rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
.feature p {
|
.feature p {
|
||||||
font-size: 0.875rem;
|
font-size: 0.82rem;
|
||||||
color: var(--muted);
|
font-weight: 300;
|
||||||
margin: 0;
|
color: var(--text-secondary);
|
||||||
|
line-height: 1.7;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── How it works ── */
|
@media (max-width: 600px) {
|
||||||
.steps {
|
.feature-grid { grid-template-columns: 1fr; }
|
||||||
list-style: none;
|
|
||||||
counter-reset: step;
|
|
||||||
margin-top: 16px;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.steps li {
|
/* CTA */
|
||||||
counter-increment: step;
|
.cta-section {
|
||||||
padding: 12px 0;
|
padding: 5rem 0;
|
||||||
padding-left: 36px;
|
border-top: 1px solid var(--border);
|
||||||
position: relative;
|
|
||||||
color: var(--muted);
|
|
||||||
font-size: 0.95rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.steps li::before {
|
|
||||||
content: counter(step);
|
|
||||||
position: absolute;
|
|
||||||
left: 0;
|
|
||||||
top: 12px;
|
|
||||||
width: 24px;
|
|
||||||
height: 24px;
|
|
||||||
background: var(--surface);
|
|
||||||
border: 1px solid var(--border);
|
|
||||||
border-radius: 50%;
|
|
||||||
font-size: 0.75rem;
|
|
||||||
font-weight: 600;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
color: var(--accent);
|
|
||||||
}
|
|
||||||
|
|
||||||
/* ── Footer ── */
|
|
||||||
footer {
|
|
||||||
padding: 32px 0;
|
|
||||||
color: var(--muted);
|
|
||||||
font-size: 0.8rem;
|
|
||||||
text-align: center;
|
text-align: center;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* ── Responsive ── */
|
.cta-section h2 {
|
||||||
@media (max-width: 540px) {
|
font-family: var(--display);
|
||||||
.features { grid-template-columns: 1fr; }
|
font-size: 1.8rem;
|
||||||
header h1 { font-size: 1.5rem; }
|
font-weight: 700;
|
||||||
|
letter-spacing: -0.02em;
|
||||||
|
margin-bottom: 1rem;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.cta-section p {
|
||||||
|
font-size: 0.95rem;
|
||||||
|
color: var(--text-secondary);
|
||||||
|
font-weight: 300;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Footer */
|
||||||
|
footer {
|
||||||
|
padding: 2rem 0;
|
||||||
|
border-top: 1px solid var(--border);
|
||||||
|
display: flex;
|
||||||
|
justify-content: space-between;
|
||||||
|
align-items: center;
|
||||||
|
font-size: 0.75rem;
|
||||||
|
color: var(--text-dim);
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a {
|
||||||
|
color: var(--text-dim);
|
||||||
|
font-size: 0.75rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
footer a:hover { color: var(--text-secondary); }
|
||||||
|
|||||||
Reference in New Issue
Block a user