d2-relay-pricing--openai-gpt-6-astra
Build a single-file HTML pricing page for 'Relay', a fictional developer tool for running background jobs. Three tiers (Solo, Team, Business) with prices, feature lists, and one highlighted recommendation. Self-contained .html file (inline CSS/JS, no external dependencies, no build step). Restrained, legible design; responsive down to 360px. Deliver the complete file with no placeholders. Accompany the code with a brief explanation of your design choices.
| Model | GPT-6 Astra (OpenAI) openai/gpt-6-astra |
|---|---|
| Task | d2-relay-pricing · web-app · javascript · tests out of scope |
| Harness | openrouter-chat-completions openrouter-chat-2026-09-22 at temperature 0.3 |
| Generated | 2026-09-22T14:14:32.424Z (generated) |
| License | MIT · demo-eligible |
| Contamination | Not previously public · No viral exposure recorded |
Prompt
Build a single-file HTML pricing page for 'Relay', a fictional developer tool for running background jobs. Three tiers (Solo, Team, Business) with prices, feature lists, and one highlighted recommendation. Self-contained .html file (inline CSS/JS, no external dependencies, no build step). Restrained, legible design; responsive down to 360px. Deliver the complete file with no placeholders. Accompany the code with a brief explanation of your design choices. ## Output contract First, write a brief explanation of your design choices — plain prose, no code fences. Then emit exactly one fenced code block per file, and no other text between or after the blocks: - The FIRST line of every block is that file's marker line: - TypeScript or JavaScript: `// FILE: <path>` - Python: `# FILE: <path>` - A single-file web app is one file named `index.html`, so its marker line is `// FILE: index.html`. - Everything after the marker line is that file complete, from its first line to its last — no diffs, no omissions, no placeholders. - Tag each fence with the file's language, for example ```html, ```typescript, ```python.
Artifact
index.html
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#f8f8f5">
<meta name="description" content="Simple, predictable pricing for Relay, the background job platform for developers.">
<title>Pricing — Relay</title>
<style>
:root {
--bg: #f8f8f5;
--surface: #fff;
--ink: #202824;
--muted: #626b65;
--line: #dce0d9;
--accent: #5541b8;
--accent-dark: #41308f;
--accent-soft: #f0edfc;
--radius: 14px;
}
* { box-sizing: border-box; }
html { scroll-behavior: smooth; }
body {
margin: 0;
background: var(--bg);
color: var(--ink);
font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", sans-serif;
font-size: 16px;
line-height: 1.6;
-webkit-font-smoothing: antialiased;
}
button, a { -webkit-tap-highlight-color: transparent; }
button { font: inherit; cursor: pointer; }
a { color: inherit; text-underline-offset: 4px; }
button:focus-visible, a:focus-visible, summary:focus-visible {
outline: 3px solid var(--accent);
outline-offset: 5px;
}
.wrap { width: min(1120px, calc(100% - 48px)); margin-inline: auto; }
.skip-link {
position: absolute;
left: 20px;
top: -100px;
padding: 10px 16px;
background: var(--ink);
color: white;
z-index: 5;
}
.skip-link:focus { top: 12px; }
header {
min-height: 88px;
display: flex;
align-items: center;
justify-content: space-between;
border-bottom: 1px solid var(--line);
}
.brand {
display: inline-flex;
align-items: center;
gap: 10px;
text-decoration: none;
font-size: 24px;
font-weight: 750;
letter-spacing: -1px;
}
.brand svg { width: 30px; height: 30px; }
nav { display: flex; gap: 28px; font-size: 14px; }
nav a { text-decoration: none; }
nav a:hover { color: var(--accent); }
nav a[aria-current] { font-weight: 650; }
.hero { text-align: center; padding: 68px 0 32px; }
.eyebrow {
margin: 0 0 16px;
color: var(--accent);
font-size: 11px;
font-weight: 750;
letter-spacing: 1.8px;
text-transform: uppercase;
}
h1 {
margin: 0;
font-size: clamp(36px, 5vw, 58px);
font-weight: 650;
line-height: 1.12;
letter-spacing: -2.5px;
}
.hero-copy {
max-width: 530px;
margin: 20px auto 27px;
color: var(--muted);
font-size: 18px;
}
.billing {
display: inline-flex;
align-items: center;
gap: 3px;
padding: 5px;
background: #eaece6;
border: 1px solid var(--line);
border-radius: 10px;
}
.billing button {
min-height: 40px;
padding: 8px 16px;
border: 0;
border-radius: 6px;
color: var(--muted);
background: transparent;
font-size: 14px;
font-weight: 600;
}
.billing button[aria-pressed="true"] {
color: var(--ink);
background: white;
box-shadow: 0 1px 4px #20282412;
}
.saving {
display: inline-block;
margin-left: 6px;
color: var(--accent);
font-size: 11px;
font-weight: 750;
}
.billing-note { margin: 10px 0 0; color: var(--muted); font-size: 12px; }
.plans {
display: grid;
grid-template-columns: repeat(3, minmax(0, 1fr));
gap: 18px;
padding-top: 24px;
scroll-margin-top: 24px;
}
.plan {
position: relative;
display: flex;
flex-direction: column;
padding: 29px 27px;
border: 1px solid var(--line);
border-radius: var(--radius);
background: var(--surface);
}
.plan.recommended {
border: 2px solid var(--accent);
padding: 28px 26px;
box-shadow: 0 8px 28px #5541b80a;
}
.recommendation {
position: absolute;
top: 0;
left: 50%;
transform: translate(-50%, -50%);
padding: 4px 13px;
border-radius: 20px;
background: var(--accent);
color: white;
font-size: 11px;
font-weight: 650;
white-space: nowrap;
letter-spacing: .2px;
}
.plan h2 { margin: 0; font-size: 21px; font-weight: 650; letter-spacing: -.5px; }
.plan-description { margin: 5px 0 25px; color: var(--muted); font-size: 14px; }
.price { display: flex; align-items: baseline; gap: 6px; line-height: 1.2; }
.amount { font-size: 48px; font-weight: 650; letter-spacing: -2px; }
.period { color: var(--muted); font-size: 14px; }
.charge { margin: 8px 0 23px; color: var(--muted); font-size: 12px; }
.button {
display: inline-flex;
align-items: center;
justify-content: center;
gap: 10px;
width: 100%;
min-height: 46px;
padding: 10px 16px;
border: 1px solid var(--line);
border-radius: 7px;
color: var(--ink);
background: white;
font-size: 14px;
font-weight: 650;
transition: background .15s, border-color .15s;
}
.button:hover { background: var(--bg); border-color: #a4aca5; }
.button.primary { color: white; background: var(--accent); border-color: var(--accent); }
.button.primary:hover { background: var(--accent-dark); border-color: var(--accent-dark); }
.features {
flex: 1;
margin-top: 26px;
padding-top: 23px;
border-top: 1px solid var(--line);
}
.features-label { margin: 0 0 15px; font-size: 12px; font-weight: 650; }
.features ul { list-style: none; margin: 0; padding: 0; }
.features li {
position: relative;
margin: 12px 0;
padding-left: 23px;
font-size: 14px;
color: #465049;
}
.features li::before {
content: "";
position: absolute;
top: 7px;
left: 2px;
width: 6px;
height: 10px;
border: solid var(--accent);
border-width: 0 1.5px 1.5px 0;
transform: rotate(45deg);
}
.features strong { color: var(--ink); font-weight: 650; }
.plan-footnote { margin: 18px 0 0; font-size: 12px; color: var(--muted); }
.shared-note {
display: flex;
align-items: center;
justify-content: center;
gap: 9px;
margin: 25px 0 0;
color: var(--muted);
text-align: center;
font-size: 13px;
}
.shared-note svg { flex: 0 0 16px; width: 16px; height: 16px; }
.included {
display: grid;
grid-template-columns: 1fr 1fr 1fr;
gap: 35px;
padding: 42px 0;
margin-top: 42px;
border-top: 1px solid var(--line);
border-bottom: 1px solid var(--line);
}
.included h3 { margin: 0 0 6px; font-size: 15px; font-weight: 650; }
.included p { margin: 0; color: var(--muted); font-size: 14px; }
.faq {
display: grid;
grid-template-columns: 1fr 1.7fr;
gap: 60px;
padding: 64px 0 72px;
scroll-margin-top: 30px;
}
.faq h2 { margin: 0 0 10px; font-size: 28px; font-weight: 650; letter-spacing: -.8px; }
.faq-intro { margin: 0; color: var(--muted); font-size: 14px; }
details { border-bottom: 1px solid var(--line); }
details:first-child { border-top: 1px solid var(--line); }
summary {
display: flex;
justify-content: space-between;
align-items: center;
gap: 20px;
padding: 18px 0;
list-style: none;
cursor: pointer;
font-size: 14px;
font-weight: 600;
}
summary::-webkit-details-marker { display: none; }
summary::after { content: "+"; color: var(--muted); font-size: 20px; font-weight: 400; }
details[open] summary::after { content: "−"; }
details p { margin: 0 28px 20px 0; color: var(--muted); font-size: 14px; }
footer {
display: flex;
align-items: center;
justify-content: space-between;
gap: 20px;
padding: 23px 0 30px;
border-top: 1px solid var(--line);
color: var(--muted);
font-size: 12px;
}
footer p { margin: 0; }
dialog {
width: min(440px, calc(100% - 32px));
max-height: calc(100dvh - 48px);
padding: 30px;
border: 1px solid var(--line);
border-radius: var(--radius);
background: var(--surface);
color: var(--ink);
box-shadow: 0 20px 80px #20282430;
}
dialog::backdrop { background: #17201980; }
dialog h2 { margin: 0 0 20px; font-size: 26px; letter-spacing: -.7px; }
.summary-row { display: flex; justify-content: space-between; gap: 20px; padding: 12px 0; border-bottom: 1px solid var(--line); font-size: 14px; }
.summary-row dt { color: var(--muted); }
.summary-row dd { margin: 0; text-align: right; font-weight: 600; }
.demo-note { margin: 22px 0; color: var(--muted); font-size: 13px; }
dialog form { margin: 0; }
@media (max-width: 900px) {
.plan { padding: 27px 19px; }
.plan.recommended { padding: 26px 18px; }
.plan-description { min-height: 45px; }
.features li { font-size: 13px; }
}
@media (max-width: 700px) {
.wrap { width: calc(100% - 36px); }
header { min-height: 74px; }
nav { gap: 20px; }
.hero { padding-top: 45px; }
h1 { letter-spacing: -1.5px; }
.hero-copy { font-size: 16px; }
.plans { grid-template-columns: 1fr; gap: 30px; max-width: 460px; margin-inline: auto; }
.plan { padding: 27px; }
.plan.recommended { padding: 26px; }
.plan-description { min-height: auto; margin-bottom: 20px; }
.features li { font-size: 14px; }
.included { grid-template-columns: 1fr; gap: 25px; margin-top: 32px; padding-block: 30px; }
.faq { grid-template-columns: 1fr; gap: 26px; padding-block: 42px; }
footer { align-items: flex-start; flex-direction: column; gap: 8px; }
}
@media (prefers-reduced-motion: reduce) {
html { scroll-behavior: auto; }
.button { transition: none; }
}
</style>
</head>
<body>
<a class="skip-link" href="#main">Skip to content</a>
<div class="wrap">
<header>
<a class="brand" href="#main" aria-label="Relay home">
<svg viewBox="0 0 32 32" fill="none" aria-hidden="true">
<rect width="32" height="32" rx="9" fill="#202824"/>
<path d="M8 11h9l-4 5h11M24 21h-9l4-5H8" stroke="#fff" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
Relay
</a>
<nav aria-label="Main navigation">
<a href="#plans" aria-current="page">Pricing</a>
<a href="#faq">FAQs</a>
</nav>
</header>
<main id="main">
<section class="hero" aria-labelledby="page-title">
<p class="eyebrow">Small jobs. Big possibilities.</p>
<h1>Ship the code.<br>We’ll run the jobs.</h1>
<p class="hero-copy">Reliable background jobs, without the infrastructure work. Simple pricing that grows with your queue.</p>
<div class="billing" role="group" aria-label="Billing frequency">
<button type="button" data-billing="monthly" aria-pressed="true">Monthly</button>
<button type="button" data-billing="annual" aria-pressed="false">Annually <span class="saving">Save up to 20%</span></button>
</div>
<p class="billing-note" id="billing-note" aria-live="polite">Prices in USD. Billed monthly.</p>
</section>
<section class="plans" id="plans" aria-label="Compare pricing plans">
<article class="plan" aria-labelledby="solo-title">
<h2 id="solo-title">Solo</h2>
<p class="plan-description">For side projects finding their stride.</p>
<div class="price"><span class="amount" data-price="Solo">$12</span><span class="period">/ month</span></div>
<p class="charge" data-charge="Solo">$12 billed monthly</p>
<button class="button" type="button" data-plan="Solo">Review Solo <span aria-hidden="true">↗</span></button>
<div class="features">
<p class="features-label">The essentials, done right.</p>
<ul>
<li><strong>50,000</strong> job runs / month</li>
<li>5 concurrent jobs</li>
<li>1 workspace member</li>
<li>Automatic retries & scheduling</li>
<li>7-day log retention</li>
<li>Community support</li>
</ul>
</div>
<p class="plan-footnote">A little less ops. A lot more building.</p>
</article>
<article class="plan recommended" aria-labelledby="team-title">
<span class="recommendation">Recommended</span>
<h2 id="team-title">Team</h2>
<p class="plan-description">For teams shipping to production.</p>
<div class="price"><span class="amount" data-price="Team">$49</span><span class="period">/ month</span></div>
<p class="charge" data-charge="Team">$49 billed monthly</p>
<button class="button primary" type="button" data-plan="Team">Review Team <span aria-hidden="true">↗</span></button>
<div class="features">
<p class="features-label">Everything in Solo, with more room.</p>
<ul>
<li><strong>500,000</strong> job runs / month</li>
<li>25 concurrent jobs</li>
<li>10 workspace members</li>
<li>Preview environments</li>
<li>30-day log retention</li>
<li>Priority email support</li>
</ul>
</div>
<p class="plan-footnote">Built for your next big release.</p>
</article>
<article class="plan" aria-labelledby="business-title">
<h2 id="business-title">Business</h2>
<p class="plan-description">For critical workflows at scale.</p>
<div class="price"><span class="amount" data-price="Business">$149</span><span class="period">/ month</span></div>
<p class="charge" data-charge="Business">$149 billed monthly</p>
<button class="button" type="button" data-plan="Business">Review Business <span aria-hidden="true">↗</span></button>
<div class="features">
<p class="features-label">Everything in Team, plus control.</p>
<ul>
<li><strong>2 million</strong> job runs / month</li>
<li>100 concurrent jobs</li>
<li>Unlimited workspace members</li>
<li>SSO & audit logs</li>
<li>90-day log retention</li>
<li>Dedicated onboarding</li>
</ul>
</div>
<p class="plan-footnote">More confidence. Same simple setup.</p>
</article>
</section>
<p class="shared-note">
<svg viewBox="0 0 20 20" fill="none" aria-hidden="true">
<path d="M10 2 3.5 4.5V10c0 4 6.5 7.5 6.5 7.5s6.5-3.5 6.5-7.5V4.5L10 2Z" stroke="currentColor" stroke-width="1.4"/>
<path d="m6.5 9.5 2.5 2.5 4.5-4.5" stroke="currentColor" stroke-width="1.4" stroke-linecap="round" stroke-linejoin="round"/>
</svg>
No surprise overages. You decide when to upgrade.
</p>
<section class="included" aria-label="Included with every plan">
<div>
<h3>Retries, handled.</h3>
<p>Transient failures shouldn’t become your to-do list. Automatic retries keep work moving.</p>
</div>
<div>
<h3>Visibility built in.</h3>
<p>Inspect job runs, read logs, and trace failures from one straightforward dashboard.</p>
</div>
<div>
<h3>Your code. Your schedule.</h3>
<p>Run a job now, at a specific time, or on a recurring schedule. No extra services needed.</p>
</div>
</section>
<section class="faq" id="faq" aria-labelledby="faq-title">
<div>
<p class="eyebrow">The useful details</p>
<h2 id="faq-title">Good questions.</h2>
<p class="faq-intro">A few things to know before you pick a plan.</p>
</div>
<div>
<details>
<summary>What counts as a job run?</summary>
<p>A job run is one execution of a background task. Scheduled tasks count when they execute, and each retry counts as another run. Queued or canceled tasks that never start don’t count. Each run includes up to 5 minutes of execution time with 512 MB of memory.</p>
</details>
<details>
<summary>What happens if I reach my limit?</summary>
<p>Relay alerts you at 80% and 100% of your monthly allowance. At the limit, new runs pause without additional charges. Queued jobs are retained for up to 30 days and resume when your allowance resets or you upgrade.</p>
</details>
<details>
<summary>How does annual billing work?</summary>
<p>You pay for 12 months upfront: $120 for Solo, $468 for Team, or $1,428 for Business, before applicable taxes. Job allowances still reset monthly and unused runs don’t roll over. The displayed monthly price is the annual total divided by 12.</p>
</details>
<details>
<summary>Can I change or cancel my plan?</summary>
<p>Upgrade at any time and pay the prorated difference for the remainder of your billing period. Downgrades and cancellations take effect at your next renewal. Your plan stays available through the period you’ve already paid for; unused time is not refunded.</p>
</details>
</div>
</section>
</main>
<footer>
<p>© 2026 Relay. Less infrastructure, more momentum.</p>
<p>Fictional product · Interactive pricing demo</p>
</footer>
</div>
<dialog id="plan-dialog" aria-labelledby="dialog-title" aria-describedby="demo-note">
<p class="eyebrow">Your plan at a glance</p>
<h2 id="dialog-title">Team plan</h2>
<dl>
<div class="summary-row"><dt>Billing</dt><dd id="summary-billing">Monthly</dd></div>
<div class="summary-row"><dt>Plan cost</dt><dd id="summary-cost">$49 / month</dd></div>
<div class="summary-row"><dt>Job runs / month</dt><dd id="summary-runs">500,000</dd></div>
<div class="summary-row"><dt>Workspace members</dt><dd id="summary-members">10</dd></div>
</dl>
<p class="demo-note" id="demo-note">Relay is a fictional product. This summary is a preview, not a checkout. No account is created and no payment is collected. Prices exclude applicable taxes.</p>
<form method="dialog">
<button class="button primary" autofocus>Back to pricing</button>
</form>
</dialog>
<script>
(() => {
const plans = {
Solo: { monthly: 12, annual: 10, runs: "50,000", members: "1" },
Team: { monthly: 49, annual: 39, runs: "500,000", members: "10" },
Business: { monthly: 149, annual: 119, runs: "2,000,000", members: "Unlimited" }
};
const money = value => "$" + value.toLocaleString("en-US");
let billing = "monthly";
const dialog = document.getElementById("plan-dialog");
document.querySelectorAll("[data-billing]").forEach(button => {
button.addEventListener("click", () => {
billing = button.dataset.billing;
document.querySelectorAll("[data-billing]").forEach(option => {
option.setAttribute("aria-pressed", String(option.dataset.billing === billing));
});
document.querySelectorAll("[data-price]").forEach(element => {
element.textContent = money(plans[element.dataset.price][billing]);
});
document.querySelectorAll("[data-charge]").forEach(element => {
const plan = plans[element.dataset.charge];
element.textContent = billing === "annual"
? money(plan.annual * 12) + " billed annually"
: money(plan.monthly) + " billed monthly";
});
document.getElementById("billing-note").textContent = billing === "annual"
? "Prices in USD. Monthly equivalent, billed annually."
: "Prices in USD. Billed monthly.";
});
});
document.querySelectorAll("[data-plan]").forEach(button => {
button.addEventListener("click", () => {
const name = button.dataset.plan;
const plan = plans[name];
document.getElementById("dialog-title").textContent = name + " plan";
document.getElementById("summary-billing").textContent =
billing === "annual" ? "Annual, paid upfront" : "Monthly";
document.getElementById("summary-cost").textContent = billing === "annual"
? money(plan.annual * 12) + " / year"
: money(plan.monthly) + " / month";
document.getElementById("summary-runs").textContent = plan.runs;
document.getElementById("summary-members").textContent = plan.members;
dialog.showModal();
});
});
dialog.addEventListener("click", event => {
if (event.target !== dialog) return;
const bounds = dialog.getBoundingClientRect();
if (
event.clientX < bounds.left || event.clientX > bounds.right ||
event.clientY < bounds.top || event.clientY > bounds.bottom
) dialog.close();
});
})();
</script>
</body>
</html>
Explanation
The page uses warm neutrals, clear typography, and a restrained violet accent to recommend Team without overwhelming the other tiers. It includes an accessible monthly/annual billing switch, transparent annual totals, plan-summary dialogs, and FAQs. The layout stacks cleanly on small screens, and everything runs locally in one file.
Judge detail
No raw judge output is published for this item yet. When it is, it lands under results/raw/ and appears here verbatim; the rubric and protocol are already documented on the Methodology page.