Skip to content

Commit 30fc648

Browse files
authored
fix(landing): remove duplicate pricing capability block (#6913)
* fix(landing): remove duplicate pricing capability block * test(landing): guard single pricing capability block
1 parent cf094aa commit 30fc648

3 files changed

Lines changed: 90 additions & 188 deletions

File tree

apps/landing-page/app/_lib/pricing-cloud-capability-content.ts

Lines changed: 0 additions & 93 deletions
This file was deleted.

apps/landing-page/app/pages/pricing/index.astro

Lines changed: 44 additions & 95 deletions
Original file line numberDiff line numberDiff line change
@@ -41,7 +41,6 @@ import { getCatalogCounts } from '../../_lib/catalog';
4141
import { localeFromPath, localizedHref } from '../../i18n';
4242
import { DEEPSEEK_V4_PRO_CAMPAIGN } from '../../_lib/deepseek-v4-pro-campaign';
4343
import { getPricingCampaignContent } from '../../_lib/pricing-campaign-content';
44-
import { getPricingCloudCapabilityContent } from '../../_lib/pricing-cloud-capability-content';
4544
4645
const locale = localeFromPath(Astro.url.pathname);
4746
const href = (path: string) => localizedHref(path, locale);
@@ -115,7 +114,10 @@ const FREE_PREMIUM_MODELS = [...PREMIUM_MODELS].sort(
115114
);
116115
const renderCatalogLabel = (label: string) => fillTemplate(label, catalogLabelVars);
117116
const deepSeekCampaign = getPricingCampaignContent(locale);
118-
const cloudCapability = getPricingCloudCapabilityContent(locale);
117+
const comingSoonLabel = L.comingSoon
118+
.trim()
119+
.replace(/^[((]\s*/, '')
120+
.replace(/\s*[))]$/, '');
119121
120122
// Vela's grant already includes the advertised Pro/Max uplift. The percentage
121123
// is a presentation badge only; applying it again would inflate $120/$300 to
@@ -474,15 +476,24 @@ const jsonLd = [
474476
<div class="pr-multimodal-modes" aria-label={L.multimodalTitle}>
475477
<div class="pr-mode">
476478
<svg viewBox="0 0 24 24" aria-hidden="true"><path d="M5 5h14M5 9h9M5 13h14M5 17h9" /></svg>
477-
<span>{L.designAgent}</span>
479+
<span class="pr-mode-copy">
480+
<small aria-hidden="true"></small>
481+
<strong>{L.designAgent}</strong>
482+
</span>
478483
</div>
479484
<div class="pr-mode">
480485
<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="4" width="17" height="16" rx="2" /><circle cx="9" cy="9" r="1.5" /><path d="m5.5 17 4-4 3 3 2-2 4 3" /></svg>
481-
<span>{L.imageGeneration}</span>
486+
<span class="pr-mode-copy">
487+
<small aria-hidden="true"></small>
488+
<strong>{L.imageGeneration}</strong>
489+
</span>
482490
</div>
483491
<div class="pr-mode is-soon">
484492
<svg viewBox="0 0 24 24" aria-hidden="true"><rect x="3.5" y="5" width="17" height="14" rx="2" /><path d="m10 9 5 3-5 3Z" /></svg>
485-
<span>{L.videoGeneration}<span class="pr-soon-tag">{L.comingSoon}</span></span>
493+
<span class="pr-mode-copy">
494+
<small>{comingSoonLabel}</small>
495+
<strong>{L.videoGeneration}</strong>
496+
</span>
486497
</div>
487498
</div>
488499
</section>
@@ -626,33 +637,6 @@ const jsonLd = [
626637
</div>
627638
</div>
628639

629-
<section class="pr-cloud-capability" data-pricing-cloud-capability aria-labelledby="pr-cloud-capability-title">
630-
<div class="pr-cloud-capability-copy">
631-
<p class="pr-cloud-capability-eyebrow">{cloudCapability.eyebrow}</p>
632-
<h2 id="pr-cloud-capability-title">{cloudCapability.title}</h2>
633-
<p class="pr-cloud-capability-body">{cloudCapability.body}</p>
634-
</div>
635-
<div class="pr-cloud-capability-cards">
636-
{cloudCapability.cards.map((card, index) => (
637-
<article class:list={['pr-cloud-capability-card', { 'is-upcoming': card.note }]}>
638-
<svg viewBox="0 0 24 24" aria-hidden="true">
639-
{index === 0 ? (
640-
<><path d="M4 6h16M4 12h11M4 18h8" /><path d="m17 15 3 3-3 3" /></>
641-
) : index === 1 ? (
642-
<><rect x="3" y="4" width="18" height="16" rx="2" /><circle cx="9" cy="9" r="2" /><path d="m4 17 5-5 4 4 2-2 5 5" /></>
643-
) : (
644-
<><rect x="3" y="5" width="18" height="14" rx="2" /><path d="m10 9 5 3-5 3Z" /></>
645-
)}
646-
</svg>
647-
<div class="pr-cloud-capability-card-copy">
648-
{card.note && <small>{card.note}</small>}
649-
<strong>{card.label}</strong>
650-
</div>
651-
</article>
652-
))}
653-
</div>
654-
</section>
655-
656640
<p class="pr-foot" set:html={footnoteHtml} />
657641
<p class="pr-campaign-disclaimer" data-pricing-campaign-surface hidden>{deepSeekCampaign.disclaimer}</p>
658642
</article>
@@ -1267,73 +1251,20 @@ const jsonLd = [
12671251
color: inherit;
12681252
background: color-mix(in srgb, #68f22e 7%, transparent);
12691253
}
1254+
.pr-campaign-model-benefit > div {
1255+
display: grid;
1256+
gap: 2px;
1257+
min-width: 0;
1258+
}
12701259
.pr-campaign-model-benefit strong { font-weight: 780; }
12711260
.pr-campaign-model-benefit small { color: var(--muted); font-size: .72rem; font-weight: 500; }
12721261
/* The highlighted row expands 8px beyond the regular list. Offset its
12731262
checkmark back by the same amount so it shares the column below. */
12741263
.pr-campaign-model-benefit::before { left: 8px; }
1275-
.pr-page .pr-cloud-capability {
1276-
position: relative;
1277-
display: grid;
1278-
grid-template-columns: minmax(0, 1.15fr) minmax(320px, .85fr);
1279-
gap: 28px;
1280-
margin: 32px 0 0;
1281-
padding: 32px;
1282-
overflow: hidden;
1283-
border: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
1284-
border-radius: 24px;
1285-
background: color-mix(in srgb, var(--surface, #fff) 82%, transparent);
1286-
}
1287-
.pr-cloud-capability::after {
1288-
content: '';
1289-
position: absolute;
1290-
right: 4%;
1291-
bottom: -100px;
1292-
width: 280px;
1293-
height: 280px;
1294-
border-radius: 50%;
1295-
background: color-mix(in srgb, #68f22e 14%, transparent);
1296-
filter: blur(3px);
1297-
pointer-events: none;
1298-
}
1299-
.pr-cloud-capability-copy,
1300-
.pr-cloud-capability-cards { position: relative; z-index: 1; }
1301-
.pr-cloud-capability-eyebrow {
1302-
margin: 0 0 16px;
1303-
color: var(--olive, #218c00);
1304-
font-size: .72rem;
1305-
font-weight: 800;
1306-
letter-spacing: .12em;
1307-
}
1308-
.pr-cloud-capability h2 { margin: 0; max-width: 760px; font-size: clamp(1.6rem, 3vw, 2.5rem); line-height: 1.18; }
1309-
.pr-cloud-capability-body { margin: 20px 0 0; max-width: 780px; color: var(--muted); line-height: 1.75; }
1310-
.pr-cloud-capability-cards { display: grid; gap: 10px; }
1311-
.pr-cloud-capability-card {
1312-
display: flex;
1313-
min-height: 112px;
1314-
align-items: flex-start;
1315-
gap: 14px;
1316-
padding: 20px;
1317-
border: 1px solid color-mix(in srgb, var(--ink) 10%, transparent);
1318-
border-radius: 16px;
1319-
background: color-mix(in srgb, var(--surface, #fff) 92%, transparent);
1320-
}
1321-
.pr-cloud-capability-card svg { width: 24px; height: 24px; flex: 0 0 auto; fill: none; stroke: currentColor; stroke-width: 1.7; stroke-linecap: round; stroke-linejoin: round; }
1322-
.pr-cloud-capability-card-copy { display: grid; min-width: 0; gap: 4px; }
1323-
.pr-cloud-capability-card strong { overflow-wrap: anywhere; }
1324-
.pr-cloud-capability-card small { color: var(--muted); font-size: .75rem; }
1325-
.pr-cloud-capability-card.is-upcoming { color: var(--ink-soft, #777); }
13261264
@media (max-width: 760px) {
13271265
.pr-campaign { align-items: flex-start; flex-wrap: wrap; }
13281266
.pr-campaign-window { width: 100%; text-align: left; }
13291267
}
1330-
@media (max-width: 980px) {
1331-
.pr-page .pr-cloud-capability { grid-template-columns: 1fr; }
1332-
}
1333-
@media (max-width: 620px) {
1334-
.pr-page .pr-cloud-capability { margin-top: 24px; padding: 24px 20px; border-radius: 18px; }
1335-
.pr-cloud-capability-card { min-height: 92px; }
1336-
}
13371268

13381269
/* ---- Hero ---- */
13391270
.pr-hero {
@@ -1715,11 +1646,29 @@ const jsonLd = [
17151646
line-height: 1.3;
17161647
color: var(--ink);
17171648
}
1718-
/* Modality that is presented but not yet purchasable. Reads as a
1719-
parenthetical on the label rather than a badge, so it never competes
1720-
with the campaign/bonus pills for attention. */
1721-
.pr-mode.is-soon svg { stroke: color-mix(in srgb, var(--ink, #262626) 48%, transparent); }
1722-
.pr-mode.is-soon > span { color: color-mix(in srgb, var(--ink, #262626) 48%, transparent); }
1649+
.pr-mode-copy {
1650+
display: grid;
1651+
grid-template-rows: 0.82rem auto;
1652+
gap: 4px;
1653+
}
1654+
.pr-mode-copy small {
1655+
grid-row: 1;
1656+
transform: translateY(-2px);
1657+
color: var(--ink-soft, #777);
1658+
font-size: 0.68rem;
1659+
font-weight: 500;
1660+
line-height: 1.2;
1661+
}
1662+
.pr-mode-copy small:empty {
1663+
visibility: hidden;
1664+
}
1665+
.pr-mode-copy strong {
1666+
grid-row: 2;
1667+
color: var(--ink);
1668+
font-size: 0.78rem;
1669+
font-weight: 650;
1670+
line-height: 1.3;
1671+
}
17231672
/* No margin: each locale's string carries its own separator (a leading
17241673
space for Latin/Hangul, the full-width bracket's side bearing for CJK). */
17251674
.pr-soon-tag {

apps/landing-page/tests/pricing-contract.test.ts

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,11 @@ describe("pricing contract", () => {
183183
it("aligns the highlighted campaign checkmark with the benefit list below", async () => {
184184
const page = await readFile(PRICING_PAGE_PATH, "utf8");
185185

186+
assert.match(
187+
page,
188+
/\.pr-campaign-model-benefit > div\s*\{[\s\S]*display:\s*grid;[\s\S]*gap:\s*2px;/,
189+
"the campaign date note must render on its own line below the model benefit",
190+
);
186191
assert.match(page, /\.pr-campaign-model-benefit::before\s*\{\s*left:\s*8px;\s*\}/);
187192
assert.match(
188193
page,
@@ -196,6 +201,47 @@ describe("pricing contract", () => {
196201
);
197202
});
198203

204+
it("keeps the multimodal coming-soon note above the video label", async () => {
205+
const page = await readFile(PRICING_PAGE_PATH, "utf8");
206+
207+
assert.match(
208+
page,
209+
/<span class="pr-mode-copy">\s*<small>\{comingSoonLabel\}<\/small>\s*<strong>\{L\.videoGeneration\}<\/strong>/,
210+
);
211+
assert.match(
212+
page,
213+
/<span class="pr-mode-copy">\s*<small aria-hidden="true"><\/small>\s*<strong>\{L\.imageGeneration\}<\/strong>/,
214+
"image and video labels must share the same copy grid",
215+
);
216+
assert.match(
217+
page,
218+
/<span class="pr-mode-copy">\s*<small aria-hidden="true"><\/small>\s*<strong>\{L\.designAgent\}<\/strong>/,
219+
"design and video labels must share the same reserved note row",
220+
);
221+
assert.match(
222+
page,
223+
/\.pr-mode-copy\s*\{[\s\S]*display:\s*grid;[\s\S]*grid-template-rows:\s*0\.82rem auto;[\s\S]*gap:\s*4px;/,
224+
);
225+
assert.match(page, /\.pr-mode-copy strong\s*\{\s*grid-row:\s*2;/);
226+
assert.match(page, /\.pr-mode-copy small:empty\s*\{\s*visibility:\s*hidden;/);
227+
assert.doesNotMatch(page, /\{L\.videoGeneration\}<span class="pr-soon-tag">/);
228+
});
229+
230+
it("renders exactly one Open Design Cloud capability section", async () => {
231+
const page = await readFile(PRICING_PAGE_PATH, "utf8");
232+
233+
assert.doesNotMatch(
234+
page,
235+
/data-pricing-cloud-capability/,
236+
"the superseded duplicate capability block must stay removed",
237+
);
238+
assert.equal(
239+
page.match(/<section class="pr-multimodal"/g)?.length,
240+
1,
241+
"the retained Cloud capability section must render exactly once",
242+
);
243+
});
244+
199245
it("points the public pricing URL at the landing-page JSON contract", () => {
200246
assert.equal(PLANS_JSON_URL, "/pricing/plans.json");
201247
});

0 commit comments

Comments
 (0)