<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Graft — Pricing</title>
<meta name="description" content="Graft pricing: preview environments for every pull request. Free for hobby projects, $20/mo for pros, $60/seat/mo for teams.">
<style>
:root{
--bg:#0a0c10;
--surface:#10131a;
--surface-2:#131824;
--border:#1f2531;
--border-strong:#2c3547;
--text:#e9edf4;
--muted:#9aa4b5;
--faint:#6d7688;
--accent:#7ee787;
--accent-ink:#06120a;
--accent-border:rgba(126,231,135,.4);
--sans:-apple-system,BlinkMacSystemFont,"Segoe UI",Roboto,"Helvetica Neue",Arial,sans-serif;
--mono:ui-monospace,SFMono-Regular,"SF Mono",Menlo,Consolas,"Liberation Mono",monospace;
}
*{box-sizing:border-box;margin:0;padding:0}
html{color-scheme:dark;-webkit-text-size-adjust:100%}
body{
font-family:var(--sans);
background:
radial-gradient(1000px 520px at 50% -180px, rgba(126,231,135,.09), transparent 70%),
var(--bg);
color:var(--text);
line-height:1.5;
-webkit-font-smoothing:antialiased;
text-rendering:optimizeLegibility;
}
body::before{
content:"";position:fixed;inset:0;pointer-events:none;
background-image:radial-gradient(rgba(255,255,255,.045) 1px, transparent 1.3px);
background-size:26px 26px;
-webkit-mask-image:linear-gradient(180deg,#000 0%,transparent 72%);
mask-image:linear-gradient(180deg,#000 0%,transparent 72%);
}
::selection{background:rgba(126,231,135,.28)}
:focus-visible{outline:2px solid var(--accent);outline-offset:2px;border-radius:6px}
.container{width:100%;max-width:1120px;margin:0 auto;padding:0 24px;position:relative}
/* ---------- Header ---------- */
.topbar{display:flex;align-items:center;justify-content:space-between;padding:22px 0}
.brand{display:flex;align-items:center;gap:10px;text-decoration:none;color:var(--text)}
.brand svg{color:var(--accent);display:block}
.brand-name{font-family:var(--mono);font-weight:700;font-size:17px;letter-spacing:-.02em}
.nav{display:flex;align-items:center;gap:26px}
.nav a{color:var(--muted);text-decoration:none;font-size:14px;transition:color .15s ease}
.nav a:hover{color:var(--text)}
.nav a.active{color:var(--text)}
.nav .signin{border:1px solid var(--border-strong);padding:7px 14px;border-radius:8px;color:var(--text);transition:border-color .15s ease,background .15s ease}
.nav .signin:hover{border-color:var(--faint);background:rgba(255,255,255,.04)}
/* ---------- Hero ---------- */
.hero{text-align:center;padding:64px 0 8px}
.eyebrow{font-family:var(--mono);font-size:12px;letter-spacing:.16em;color:var(--accent);text-transform:uppercase}
.hero h1{font-size:clamp(34px,5vw,52px);letter-spacing:-.03em;line-height:1.08;margin:14px 0 16px;font-weight:700}
.hero .sub{color:var(--muted);font-size:17px;max-width:560px;margin:0 auto}
.cli{display:inline-flex;align-items:center;gap:9px;margin-top:28px;font-family:var(--mono);font-size:13px;background:var(--surface);border:1px solid var(--border);border-radius:8px;padding:9px 15px}
.cli .prompt{color:var(--accent)}
.cli .cmd{color:var(--text)}
.cursor{width:7px;height:15px;background:var(--accent);opacity:.9;animation:blink 1.1s steps(1) infinite}
@keyframes blink{50%{opacity:0}}
/* ---------- Billing toggle ---------- */
.toggle-row{display:flex;justify-content:center;margin-top:34px}
.billing-toggle{display:inline-flex;gap:4px;padding:4px;background:var(--surface);border:1px solid var(--border);border-radius:999px}
.billing-toggle button{
appearance:none;border:0;background:transparent;color:var(--muted);
font-family:inherit;font-size:13.5px;padding:8px 18px;border-radius:999px;
cursor:pointer;display:inline-flex;align-items:center;gap:8px;
transition:color .15s ease,background .15s ease,box-shadow .15s ease;
}
.billing-toggle button:hover{color:var(--text)}
.billing-toggle button[aria-pressed="true"]{background:var(--surface-2);color:var(--text);box-shadow:inset 0 0 0 1px var(--border-strong)}
.billing-toggle .save{font-family:var(--mono);font-size:11px;color:var(--accent)}
/* ---------- Plans ---------- */
.plans{display:grid;grid-template-columns:repeat(3,minmax(0,1fr));gap:20px;margin-top:48px}
.plan{
position:relative;overflow:hidden;
display:flex;flex-direction:column;
background:linear-gradient(180deg,rgba(255,255,255,.02),rgba(255,255,255,0)),var(--surface);
border:1px solid var(--border);
border-radius:16px;
padding:26px;
transition:transform .22s ease,border-color .22s ease,box-shadow .22s ease;
}
.plan:hover{transform:translateY(-3px);border-color:var(--border-strong)}
.plan-tag{font-family:var(--mono);font-size:12px;letter-spacing:.02em;color:var(--accent);min-height:18px;margin-bottom:10px}
.plan-name{font-size:19px;font-weight:650;letter-spacing:-.01em}
.plan-pos{color:var(--muted);font-size:13.5px;margin-top:4px;min-height:42px}
.price{display:flex;align-items:baseline;gap:6px;margin-top:16px;font-family:var(--mono)}
.amount{font-size:42px;font-weight:600;letter-spacing:-.04em}
.per{color:var(--muted);font-size:14px}
.bill-note{font-family:var(--mono);font-size:11.5px;color:var(--faint);margin-top:7px;min-height:17px}
.features{
list-style:none;margin:22px 0 24px;padding:20px 0 0;
border-top:1px dashed var(--border);
display:grid;gap:10px;
font-size:14px;color:#c4cbd8;
}
.features li{display:flex;gap:10px;align-items:flex-start}
.features li::before{content:"✓";font-family:var(--mono);font-size:13px;line-height:1.55;color:var(--accent)}
.features li.carry{color:var(--muted)}
.features li.carry::before{content:"+";color:var(--faint)}
.plan-cta{margin-top:auto}
.btn{
display:block;width:100%;text-align:center;text-decoration:none;cursor:pointer;
font-family:inherit;font-weight:600;font-size:14.5px;
padding:12px 18px;border-radius:10px;border:1px solid transparent;
transition:background .15s ease,border-color .15s ease,filter .15s ease;
}
.btn-primary{background:var(--accent);color:var(--accent-ink)}
.btn-primary:hover{filter:brightness(1.08)}
.btn-ghost{border-color:var(--border-strong);color:var(--text);background:rgba(255,255,255,.02)}
.btn-ghost:hover{border-color:var(--faint);background:rgba(255,255,255,.05)}
.cta-note{text-align:center;font-size:12px;color:var(--faint);margin-top:10px;min-height:15px}
/* Featured (Pro) — emphasis through elevation, accent border and glow */
@media (min-width:981px){
.plan--featured{transform:translateY(-10px)}
.plan--featured:hover{transform:translateY(-13px)}
}
.plan--featured{
background:linear-gradient(180deg,rgba(126,231,135,.07),rgba(126,231,135,.015) 55%),var(--surface-2);
border-color:var(--accent-border);
box-shadow:0 24px 70px -28px rgba(126,231,135,.28),0 0 0 1px rgba(126,231,135,.05);
}
.plan--featured:hover{border-color:rgba(126,231,135,.6)}
.plan--featured::before{
content:"";position:absolute;top:0;left:0;right:0;height:2px;
background:linear-gradient(90deg,transparent,rgba(126,231,135,.9),transparent);
}
/* ---------- Assurance row ---------- */
.assurance{display:flex;flex-wrap:wrap;justify-content:center;gap:8px 28px;margin-top:46px;color:var(--faint);font-size:13px}
.assurance span::before{content:"✓ ";font-family:var(--mono);color:var(--accent)}
/* ---------- FAQ ---------- */
.faq{max-width:680px;margin:90px auto 0}
.faq .eyebrow{display:block;text-align:center}
.faq h2{text-align:center;font-size:24px;letter-spacing:-.02em;margin:10px 0 24px}
details{background:var(--surface);border:1px solid var(--border);border-radius:12px;padding:16px 18px}
details+details{margin-top:12px}
summary{cursor:pointer;list-style:none;display:flex;justify-content:space-between;align-items:center;gap:16px;font-weight:600;font-size:15px}
summary::-webkit-details-marker{display:none}
summary::after{content:"+";font-family:var(--mono);font-size:16px;color:var(--faint);transition:transform .18s ease}
details[open] summary::after{transform:rotate(45deg);color:var(--accent)}
details p{color:var(--muted);font-size:14px;margin-top:10px;max-width:56ch}
/* ---------- Footer ---------- */
footer{border-top:1px solid var(--border);margin-top:96px}
.foot{display:flex;justify-content:space-between;align-items:center;gap:14px;flex-wrap:wrap;padding:26px 0;color:var(--faint);font-size:13px}
.foot-links{display:flex;align-items:center;gap:20px}
.foot-links a{color:var(--faint);text-decoration:none;transition:color .15s ease}
.foot-links a:hover{color:var(--text)}
.status{display:inline-flex;align-items:center;gap:8px;font-family:var(--mono);font-size:12px}
.dot{width:8px;height:8px;border-radius:50%;background:var(--accent);box-shadow:0 0 8px rgba(126,231,135,.8)}
/* ---------- Responsive ---------- */
@media (max-width:980px){
.plans{grid-template-columns:1fr;max-width:460px;margin-left:auto;margin-right:auto}
.plan-pos{min-height:0}
.hero{padding:48px 0 4px}
.faq{margin-top:70px}
}
@media (max-width:720px){
.nav a:not(.signin){display:none}
}
@media (prefers-reduced-motion:reduce){
*{animation:none!important;transition:none!important}
}
</style>
</head>
<body>
<div class="container">
<header class="topbar">
<a class="brand" href="#">
<svg width="20" height="20" viewBox="0 0 20 20" fill="none" aria-hidden="true">
<rect x="1" y="1" width="18" height="18" rx="4.5" stroke="currentColor" stroke-width="1.6"/>
<path d="M5.5 6.5l3.5 3.5-3.5 3.5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round" stroke-linejoin="round"/>
<line x1="10.5" y1="13.5" x2="14.5" y2="13.5" stroke="currentColor" stroke-width="1.6" stroke-linecap="round"/>
</svg>
<span class="brand-name">graft</span>
</a>
<nav class="nav" aria-label="Primary">
<a href="#" class="active">Pricing</a>
<a href="#">Docs</a>
<a href="#">Changelog</a>
<a href="#">GitHub</a>
<a href="#" class="signin">Sign in</a>
</nav>
</header>
<main>
<section class="hero">
<span class="eyebrow">Pricing</span>
<h1>Pricing that scales with your pipeline.</h1>
<p class="sub">Graft builds a throwaway preview environment for every pull request. Start free, upgrade when your team does.</p>
<div class="cli" aria-hidden="true">
<span class="prompt">$</span>
<span class="cmd">graft preview --open</span>
<span class="cursor"></span>
</div>
<div class="toggle-row">
<div class="billing-toggle" role="group" aria-label="Billing period">
<button type="button" data-mode="monthly" aria-pressed="true">Monthly</button>
<button type="button" data-mode="annual" aria-pressed="false">Annual <span class="save">-20%</span></button>
</div>
</div>
</section>
<section class="plans" aria-label="Plans">
<!-- Hobby -->
<article class="plan">
<p class="plan-tag" aria-hidden="true"></p>
<h2 class="plan-name">Hobby</h2>
<p class="plan-pos">For side projects and late-night experiments.</p>
<div class="price">
<span class="amount" data-monthly="$0" data-annual="$0">$0</span>
<span class="per">/mo</span>
</div>
<p class="bill-note" data-monthly="free forever · no card required" data-annual="free forever · no card required">free forever · no card required</p>
<ul class="features">
<li>1 project</li>
<li>100 build minutes / month</li>
<li>Preview deploys on every PR</li>
<li>7-day log & artifact retention</li>
<li>CLI + GitHub app</li>
<li>Community support</li>
</ul>
<div class="plan-cta">
<a href="#" class="btn btn-ghost">Start for free</a>
<p class="cta-note"></p>
</div>
</article>
<!-- Pro (featured) -->
<article class="plan plan--featured">
<p class="plan-tag">// most popular</p>
<h2 class="plan-name">Pro</h2>
<p class="plan-pos">For solo developers shipping production software.</p>
<div class="price">
<span class="amount" data-monthly="$20" data-annual="$16">$20</span>
<span class="per">/mo</span>
</div>
<p class="bill-note" data-monthly="billed monthly · cancel anytime" data-annual="billed annually · $192/yr">billed monthly · cancel anytime</p>
<ul class="features">
<li>Unlimited projects</li>
<li>2,000 build minutes / month</li>
<li>Custom domains & persistent previews</li>
<li>2× build concurrency</li>
<li>Secrets & environment management</li>
<li>30-day retention</li>
<li>Priority email support</li>
</ul>
<div class="plan-cta">
<a href="#" class="btn btn-primary">Start 14-day trial</a>
<p class="cta-note">Free for 14 days · cancel anytime</p>
</div>
</article>
<!-- Team -->
<article class="plan">
<p class="plan-tag" aria-hidden="true"></p>
<h2 class="plan-name">Team</h2>
<p class="plan-pos">For teams that review, stage, and ship together.</p>
<div class="price">
<span class="amount" data-monthly="$60" data-annual="$48">$60</span>
<span class="per">/seat/mo</span>
</div>
<p class="bill-note" data-monthly="per seat · billed monthly" data-annual="per seat · billed annually · $576/yr">per seat · billed monthly</p>
<ul class="features">
<li class="carry">Everything in Pro, plus</li>
<li>Pooled build minutes for the whole org</li>
<li>SSO / SAML & role-based access</li>
<li>Shared staging environments</li>
<li>Audit logs</li>
<li>Slack, Linear & Jira integrations</li>
<li>99.9% uptime SLA · dedicated support</li>
</ul>
<div class="plan-cta">
<a href="#" class="btn btn-ghost">Start with Team</a>
<p class="cta-note">Pilot free for 30 days</p>
</div>
</article>
</section>
<div class="assurance">
<span>No credit card to start</span>
<span>Cancel anytime</span>
<span>SOC 2 Type II</span>
<span>Prices in USD</span>
</div>
<section class="faq">
<span class="eyebrow">// faq</span>
<h2>Questions, answered.</h2>
<details>
<summary>What counts as a build minute?</summary>
<p>One minute of one build container running. A typical preview build takes 2–4 minutes, and cache hits don't count against your quota. You can watch usage live from the dashboard or via <code>graft usage</code>.</p>
</details>
<details>
<summary>Can I change plans later?</summary>
<p>Yes. Upgrades apply instantly and downgrades take effect at the end of your billing period. We prorate everything to the day — no emails to support required.</p>
</details>
<details>
<summary>Do you offer discounts for open source?</summary>
<p>Public repositories run free on the Pro plan, forever. Student and nonprofit discounts are also available — just ask.</p>
</details>
</section>
</main>
<footer>
<div class="foot">
<span>© 2025 Graft Systems, Inc.</span>
<div class="foot-links">
<a href="#">Security</a>
<a href="#">Terms</a>
<a href="#">Privacy</a>
<span class="status"><span class="dot"></span>all systems normal</span>
</div>
</div>
</footer>
</div>
<script>
(function () {
var toggle = document.querySelector('.billing-toggle');
if (!toggle) return;
var buttons = toggle.querySelectorAll('button[data-mode]');
var dynamic = document.querySelectorAll('[data-monthly]');
function setMode(mode) {
for (var i = 0; i < buttons.length; i++) {
buttons[i].setAttribute('aria-pressed', String(buttons[i].getAttribute('data-mode') === mode));
}
for (var j = 0; j < dynamic.length; j++) {
var value = dynamic[j].getAttribute('data-' + mode);
if (value !== null) dynamic[j].textContent = value;
}
}
for (var i = 0; i < buttons.length; i++) {
buttons[i].addEventListener('click', function () {
setMode(this.getAttribute('data-mode'));
});
}
})();
</script>
</body>
</html>