Implement use cases page

This commit is contained in:
adilallo
2026-05-17 21:41:54 -06:00
parent b6b9b63608
commit 450da4d8ab
78 changed files with 1870 additions and 118 deletions
@@ -110,7 +110,7 @@ const ContentLockupContainer = memo<ContentLockupProps>(
titleGroup: "flex flex-col gap-[var(--spacing-scale-008)]",
titleContainer: "flex gap-[var(--spacing-scale-008)] items-center",
title:
"font-bricolage-grotesque font-medium text-[36px] leading-[110%] tracking-[0] md:text-[52px] md:leading-[110%] text-[var(--color-content-default-brand-primary)]",
"font-bricolage-grotesque font-medium text-[36px] leading-[110%] tracking-[0] lg:text-[44px] lg:leading-[1.1] text-[var(--color-content-default-brand-primary)]",
subtitle:
"font-inter font-normal text-[18px] leading-[130%] tracking-[0] md:text-[24px] md:leading-[32px] text-[var(--color-content-default-primary)]",
shape:
@@ -122,7 +122,7 @@ const ContentLockupContainer = memo<ContentLockupProps>(
titleGroup: "flex flex-col gap-[var(--spacing-scale-008)]",
titleContainer: "flex gap-[var(--spacing-scale-008)] items-center",
title:
"font-bricolage-grotesque font-medium text-[36px] leading-[110%] tracking-[0] md:text-[52px] md:leading-[110%] text-[var(--color-content-inverse-primary)]",
"font-bricolage-grotesque font-medium text-[36px] leading-[110%] tracking-[0] lg:text-[44px] lg:leading-[1.1] text-[var(--color-content-inverse-primary)]",
subtitle:
"font-inter font-normal text-[18px] leading-[130%] tracking-[0] md:text-[24px] md:leading-[32px] text-[var(--color-content-inverse-primary)]",
shape:
@@ -0,0 +1,46 @@
"use client";
import { memo, useId } from "react";
import PageHeaderView from "./PageHeader.view";
import type { PageHeaderProps } from "./PageHeader.types";
/**
* Figma: "Type / PageHeader" (21004-15902).
* Minimal headline-only: Section/PageHeader (22112-871523); md density **22085-862431** when `sectionMinimal` is set;
* Use cases **`lg`** single-line title **21004-24825** when `singleLineTitleFromLg` is set;
* **`xl`** headline scale **22085-860408** when `sectionMinimal` (X Large/Display / `--sizing-1600`).
*/
const PageHeaderContainer = memo<PageHeaderProps>(
({
title,
description,
ctaText,
ctaHref,
headingAlign = "start",
sectionMinimal = false,
singleLineTitleFromLg = false,
titleId: titleIdProp,
className = "",
}) => {
const reactId = useId();
const titleId = titleIdProp ?? `${reactId}-page-header-title`;
return (
<PageHeaderView
title={title}
description={description}
ctaText={ctaText}
ctaHref={ctaHref}
headingAlign={headingAlign}
sectionMinimal={sectionMinimal}
singleLineTitleFromLg={singleLineTitleFromLg}
titleId={titleId}
className={className}
/>
);
},
);
PageHeaderContainer.displayName = "PageHeader";
export default PageHeaderContainer;
@@ -0,0 +1,24 @@
export interface PageHeaderProps {
/** Single line or stacked lines inside one `<h1>` (matches Figma line breaks when centered). */
title: string | readonly string[];
description?: string;
ctaText?: string;
ctaHref?: string;
/** `center` stacks and centers the headline (Section/PageHeader minimal / use cases). */
headingAlign?: "start" | "center";
/**
* Section/PageHeader minimal density ([22085-862431](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=22085-862431&m=dev)):
* md+ **52px** display type and **56px** vertical padding (with **64px** horizontal).
*/
sectionMinimal?: boolean;
/**
* When `title` is multiple lines, use one centered line from **`lg`** ([21004-24825](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=21004-24825&m=dev)).
*/
singleLineTitleFromLg?: boolean;
titleId?: string;
className?: string;
}
export type PageHeaderViewProps = Omit<PageHeaderProps, "titleId"> & {
titleId: string;
};
@@ -0,0 +1,106 @@
"use client";
import { Fragment, memo } from "react";
import Button from "../../buttons/Button";
import type { PageHeaderViewProps } from "./PageHeader.types";
function PageHeaderView({
title,
description,
ctaText,
ctaHref,
headingAlign = "start",
sectionMinimal = false,
singleLineTitleFromLg = false,
titleId,
className = "",
}: PageHeaderViewProps) {
const hasCta = Boolean(ctaText?.trim() && ctaHref?.trim());
const hasDescription = Boolean(description?.trim());
const isCenter = headingAlign === "center";
const titleLines = typeof title === "string" ? [title] : title;
const collapseTitleAtLg =
singleLineTitleFromLg && titleLines.length > 1;
const lockupAlign = isCenter
? "items-center text-center"
: "items-start text-[var(--color-content-default-primary)]";
const h1Align = isCenter ? "text-center" : "";
const sectionPadding = sectionMinimal
? "py-[var(--spacing-scale-032)] md:py-[var(--spacing-scale-056)]"
: "py-[var(--spacing-scale-032)] md:py-[var(--spacing-scale-032)]";
const titleTypeClasses = sectionMinimal
? "font-bricolage-grotesque text-[32px] font-medium leading-[1.1] text-[var(--color-content-default-primary)] md:text-[52px] md:leading-[1.1] lg:text-[52px] lg:leading-[1.1] xl:text-[length:var(--sizing-1600)] xl:leading-[1.1]"
: "font-bricolage-grotesque text-[32px] font-medium leading-[1.1] text-[var(--color-content-default-primary)] md:text-[44px] md:leading-[110%] lg:text-[52px]";
const sectionFigmaNode =
sectionMinimal && collapseTitleAtLg
? "21004-24825"
: sectionMinimal
? "22085-862431"
: "21004-22394";
return (
<section
data-figma-node={sectionFigmaNode}
className={`bg-[var(--color-surface-default-primary)] px-[var(--spacing-scale-020)] md:px-[var(--spacing-scale-064)] ${sectionPadding} ${className}`.trim()}
>
<div
className={`mx-auto flex w-full max-w-[1440px] flex-col gap-[var(--spacing-scale-024)] ${isCenter ? "items-center" : ""}`}
>
<div
className={`flex w-full flex-col gap-[var(--spacing-scale-020)] ${lockupAlign}`}
>
<h1
id={titleId}
className={`${titleTypeClasses} ${h1Align}${collapseTitleAtLg ? " lg:whitespace-nowrap" : ""}`.trim()}
>
{titleLines.length === 1 ? (
titleLines[0]
) : collapseTitleAtLg ? (
titleLines.map((line, index) => (
<Fragment key={`${index}-${line}`}>
{index > 0 ? (
<span className="hidden lg:inline">{" "}</span>
) : null}
<span className="block lg:inline">{line}</span>
</Fragment>
))
) : (
titleLines.map((line, index) => (
<span key={`${index}-${line}`} className="block">
{line}
</span>
))
)}
</h1>
{hasDescription ? (
<p className="font-inter text-[18px] font-normal leading-[28px] text-[var(--color-content-default-primary)] lg:text-[24px] lg:leading-[28px]">
{description}
</p>
) : null}
</div>
{hasCta ? (
<div
className={`flex ${isCenter ? "justify-center" : "justify-start"}`}
>
<Button
href={ctaHref}
buttonType="filled"
palette="inverse"
size="large"
>
{ctaText}
</Button>
</div>
) : null}
</div>
</section>
);
}
PageHeaderView.displayName = "PageHeaderView";
export default memo(PageHeaderView);
+2
View File
@@ -0,0 +1,2 @@
export { default } from "./PageHeader.container";
export type { PageHeaderProps } from "./PageHeader.types";
@@ -10,6 +10,11 @@ interface SectionHeaderProps {
variant?: SectionHeaderVariantValue;
/** When set with `variant="multi-line"`, large screens show three title lines (Figma SectionCardSteps). */
stackedDesktopLines?: readonly [string, string, string];
/**
* With `variant="multi-line"`, keep **Rule stack** desktop type: title **32/40** at `lg`, **40/52** at `xl`;
* subtitle **18 / 1.3** at `lg`, **24/32** at `xl`, **left-aligned** in its column from `lg` (Figma **22085:860413**).
*/
ruleStackDesktopTypeScale?: boolean;
}
/**
@@ -23,6 +28,7 @@ const SectionHeader = memo<SectionHeaderProps>(
titleLg,
variant: variantProp = "default",
stackedDesktopLines,
ruleStackDesktopTypeScale = false,
}) => {
const variant = variantProp;
const useStackedDesktop =
@@ -47,7 +53,9 @@ const SectionHeader = memo<SectionHeaderProps>(
<h2
className={
variant === "multi-line"
? "font-bricolage-grotesque font-bold text-[28px] leading-[36px] md:text-[32px] md:leading-[40px] lg:w-[410px] lg:text-left xl:text-[40px] xl:leading-[52px] text-[var(--color-content-default-primary)]"
? ruleStackDesktopTypeScale
? "font-bricolage-grotesque font-bold text-[28px] leading-[36px] md:text-[32px] md:leading-[40px] lg:w-full lg:max-w-none lg:text-left lg:text-[32px] lg:leading-[40px] xl:text-[40px] xl:leading-[52px] text-[var(--color-content-default-primary)]"
: "font-bricolage-grotesque font-bold text-[28px] leading-[36px] md:text-[32px] md:leading-[40px] lg:w-[410px] lg:text-left xl:text-[40px] xl:leading-[52px] text-[var(--color-content-default-primary)]"
: "font-bricolage-grotesque font-bold text-[28px] leading-[36px] sm:text-[32px] sm:leading-[40px] lg:text-[32px] lg:leading-[40px] lg:w-[369px] lg:pr-[var(--spacing-scale-096)] xl:text-[40px] xl:leading-[52px] xl:w-[452px] xl:pr-[var(--spacing-scale-096)] text-[var(--color-content-default-primary)]"
}
>
@@ -68,14 +76,18 @@ const SectionHeader = memo<SectionHeaderProps>(
<div
className={
variant === "multi-line"
? "lg:w-[50%] lg:h-[var(--spacing-scale-120)] lg:flex lg:items-center lg:justify-end lg:ml-[var(--spacing-scale-016)] xl:ml-0 xl:w-[50%] xl:h-[156px] xl:flex xl:items-center xl:justify-end"
? ruleStackDesktopTypeScale
? "lg:w-[50%] lg:h-[var(--spacing-scale-120)] lg:flex lg:items-center lg:justify-start lg:ml-[var(--spacing-scale-016)] xl:ml-0 xl:w-[50%] xl:h-[156px] xl:flex xl:items-center xl:justify-start"
: "lg:w-[50%] lg:h-[var(--spacing-scale-120)] lg:flex lg:items-center lg:justify-end lg:ml-[var(--spacing-scale-016)] xl:ml-0 xl:w-[50%] xl:h-[156px] xl:flex xl:items-center xl:justify-end"
: "lg:w-[928px] lg:h-[var(--spacing-scale-120)] lg:flex lg:items-center lg:justify-end xl:h-[156px] xl:flex xl:items-center xl:justify-end"
}
>
<p
className={
variant === "multi-line"
? "font-inter font-normal text-[14px] leading-[20px] md:text-[18px] md:leading-[130%] xl:text-[24px] xl:leading-[32px] text-[var(--color-content-default-tertiary)] lg:text-right"
? ruleStackDesktopTypeScale
? "font-inter font-normal text-[14px] leading-[20px] md:text-[18px] md:leading-[130%] lg:text-left lg:text-[18px] lg:leading-[130%] text-[var(--color-content-default-tertiary)] xl:text-[24px] xl:leading-[32px]"
: "font-inter font-normal text-[14px] leading-[20px] md:text-[18px] md:leading-[130%] xl:text-[24px] xl:leading-[32px] text-[var(--color-content-default-tertiary)] lg:text-right"
: "font-inter font-normal text-[18px] leading-[130%] sm:text-[18px] sm:leading-[32px] lg:text-[24px] lg:leading-[32px] xl:text-[32px] xl:leading-[40px] xl:text-right text-[#484848] sm:text-[var(--color-content-default-tertiary)] lg:text-[var(--color-content-default-tertiary)] xl:text-[var(--color-content-default-tertiary)] tracking-[0px]"
}
>
@@ -0,0 +1,19 @@
"use client";
import { memo, useId } from "react";
import TripleStepView from "./TripleStep.view";
import type { TripleStepProps } from "./TripleStep.types";
/**
* Figma: **Section / Triple Step** ([22084-859405](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=22084-859405&m=dev)); type baseline ([22112-871527](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=22112-871527&m=dev)); **md+** two-column + **`triple-step.svg`**.
*/
const TripleStepContainer = memo<TripleStepProps>((props) => {
const reactId = useId();
const headingId = `${reactId}-triple-step-heading`;
return <TripleStepView {...props} headingId={headingId} />;
});
TripleStepContainer.displayName = "TripleStep";
export default TripleStepContainer;
@@ -0,0 +1,16 @@
export interface TripleStepStep {
title: string;
body: string;
}
export interface TripleStepProps {
heading: string;
steps: TripleStepStep[];
ctaText: string;
ctaHref: string;
className?: string;
}
export interface TripleStepViewProps extends TripleStepProps {
headingId: string;
}
@@ -0,0 +1,95 @@
"use client";
import Image from "next/image";
import { memo } from "react";
import { getAssetPath } from "../../../../lib/assetUtils";
import AssetIcon from "../../asset/icon";
import Button from "../../buttons/Button";
import type { TripleStepViewProps } from "./TripleStep.types";
const TRIPLE_STEP_NUMERIC_ICONS = [
"numeric_1_circle",
"numeric_2_circle",
"numeric_3_circle",
] as const;
function TripleStepView({
heading,
steps,
ctaText,
ctaHref,
headingId,
className = "",
}: TripleStepViewProps) {
/** Decorative column art — `public/assets/shapes/triple-step.svg` (288×576 viewBox). */
const shapeSrc = getAssetPath("assets/shapes/triple-step.svg");
return (
<section
data-figma-node="22084-859405"
aria-labelledby={headingId}
className={`bg-transparent p-[var(--spacing-scale-032)] md:px-[var(--spacing-scale-032)] md:py-[var(--spacing-scale-048)] lg:px-[var(--spacing-scale-064)] lg:py-[var(--spacing-scale-048)] ${className}`.trim()}
>
<div className="mx-auto grid w-full min-w-0 max-w-[560px] grid-cols-1 gap-[var(--spacing-scale-032)] md:max-w-[1400px] md:grid-cols-[minmax(0,1fr)_minmax(0,1fr)] md:items-stretch md:gap-[var(--spacing-scale-060)] lg:items-center">
<div className="flex w-full min-w-0 flex-col gap-[var(--spacing-scale-040)] break-words md:self-start lg:self-center">
<h2
id={headingId}
className="font-bricolage-grotesque text-[length:var(--text-medium-heading)] font-bold leading-[length:var(--text-medium-heading--line-height)] text-[var(--color-content-default-primary)] md:text-[length:var(--text-large-heading)] md:leading-[length:var(--text-large-heading--line-height)]"
>
{heading}
</h2>
{steps.map((step, index) => (
<div
key={step.title}
className="flex flex-col items-start gap-[var(--spacing-scale-016)]"
>
<AssetIcon
name={
TRIPLE_STEP_NUMERIC_ICONS[Math.min(index, 2)]
}
size={32}
className="shrink-0"
/>
<div className="flex min-w-0 flex-col gap-1 text-[var(--color-content-default-primary)]">
<p className="font-bricolage-grotesque text-[18px] font-medium leading-[22px]">
{step.title}
</p>
<p className="font-inter text-[length:var(--text-small-paragraph)] font-normal leading-[length:var(--text-small-paragraph--line-height)]">
{step.body}
</p>
</div>
</div>
))}
<div className="flex justify-start">
<Button
href={ctaHref}
buttonType="outline"
palette="default"
size="medium"
className="max-md:!px-[var(--spacing-scale-012)] max-md:!py-[var(--spacing-scale-010)] max-md:!text-[14px] max-md:!leading-[18px] md:!p-[var(--spacing-scale-012)] md:!text-[16px] md:!leading-5 md:!gap-[var(--spacing-scale-006)]"
>
{ctaText}
</Button>
</div>
</div>
<div
className="hidden min-h-0 min-w-0 w-full md:flex md:items-center md:justify-center"
aria-hidden
>
<Image
src={shapeSrc}
alt=""
width={288}
height={576}
unoptimized
className="pointer-events-none h-auto w-full max-w-full min-w-0 select-none object-contain"
/>
</div>
</div>
</section>
);
}
TripleStepView.displayName = "TripleStepView";
export default memo(TripleStepView);
+2
View File
@@ -0,0 +1,2 @@
export { default } from "./TripleStep.container";
export type { TripleStepProps, TripleStepStep } from "./TripleStep.types";
@@ -5,7 +5,8 @@ import TripleTextBlockView from "./TripleTextBlock.view";
import type { TripleTextBlockProps } from "./TripleTextBlock.types";
/**
* Figma: "Type / TripleTextBlock" stacked 22137:890676; lg 22128:888715; xl 22135:889705.
* Figma: "Type / TripleTextBlock" — use cases **`lg` 22037-26994**, **`xl` 22085-860414**;
* **`md` 22085-862437**; stacked 22137:890676; lg 22128:888715; xl 22135:889705 (default).
*/
const TripleTextBlockContainer = memo<TripleTextBlockProps>((props) => {
const headingId = useId();
@@ -1,6 +1,8 @@
export interface TripleTextBlockColumn {
title: string;
description: string;
/** Optional second paragraph under `description` (e.g. use cases baseline multi-paragraph lockup). */
descriptionSecondary?: string;
/**
* lg+ three-column layout (Figma 22128:888715). When either `lgTitle` or `lgDescription`
* is set, stacked breakpoints use `title`/`description` and lg uses these (missing side falls back).
@@ -16,6 +18,12 @@ export interface TripleTextBlockProps {
ctaText?: string;
ctaHref?: string;
className?: string;
/**
* `useCases`: Figma use cases TripleText **`lg`** ([22037-26994](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=22037-26994&m=dev));
* **`xl`** ([22085-860414](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=22085-860414&m=dev));
* `md` ([22085-862437](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=22085-862437&m=dev)); lg 3-col **22128-888715**.
*/
layoutPreset?: "default" | "useCases";
}
export interface TripleTextBlockViewProps extends TripleTextBlockProps {
@@ -12,11 +12,35 @@ function columnUsesLargeBreakpointCopy(column: TripleTextBlockColumn): boolean {
return column.lgTitle !== undefined || column.lgDescription !== undefined;
}
function TripleTextUseCasesColumn({ column }: { column: TripleTextBlockColumn }) {
return (
<div className="flex w-full flex-col gap-[var(--spacing-scale-020)] lg:gap-0 xl:gap-[var(--spacing-scale-020)]">
<div className="flex flex-col gap-[var(--spacing-scale-008)] lg:gap-[var(--spacing-scale-004)] xl:gap-[var(--spacing-scale-008)]">
<h3 className="text-left font-bricolage-grotesque text-[24px] font-medium leading-8 text-[var(--color-content-default-primary,white)] md:text-[32px] md:leading-[1.1] lg:text-[18px] lg:leading-[var(--spacing-scale-022)] xl:text-[32px] xl:leading-[1.1]">
{column.title}
</h3>
<div className="flex flex-col gap-[var(--spacing-scale-024)] font-inter text-[16px] font-normal leading-6 text-[var(--color-content-default-secondary)] md:text-[24px] md:leading-8 lg:gap-[var(--spacing-scale-020)] lg:text-[14px] lg:leading-5 xl:gap-[var(--spacing-scale-032)] xl:text-[24px] xl:leading-8">
<p>{column.description}</p>
{column.descriptionSecondary ? (
<p>{column.descriptionSecondary}</p>
) : null}
</div>
</div>
</div>
);
}
function TripleTextBlockColumnLockup({
column,
layoutPreset,
}: {
column: TripleTextBlockColumn;
layoutPreset: "default" | "useCases";
}) {
if (layoutPreset === "useCases") {
return <TripleTextUseCasesColumn column={column} />;
}
const dual = columnUsesLargeBreakpointCopy(column);
const lgSubtitle = column.lgTitle ?? column.title;
const lgBody = column.lgDescription ?? column.description;
@@ -55,7 +79,11 @@ function TripleTextBlockColumnLockup({
}
/**
* Figma: "Type / TripleTextBlock" stacked **22137:890676**; lg 3-col **22128-888715**; xl typography + horizontal inset scale/160 **22135:889705** (Subtitle 32 Small/Display, Body X Large/Paragraph 24 / lh 32; section px scale/160, py scale/064).
* Section horizontal padding adds **+ Scale/096** below `xl` (outer frame inset); **use cases `xl`** uses **Scale/160** only ([22085:860414](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=22085-860414&m=dev)).
*
* Figma: use cases **`lg`** [22037:26994](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=22037-26994&m=dev);
* **`md`** [22085:862437](https://www.figma.com/design/agv0VBLiBlcnSAaiAORgPR/Community-Rule-System?node-id=22085-862437&m=dev); stacked **22137:890676**;
* lg 3-col **22128:888715**; xl **22135:889705** (default preset).
*/
function TripleTextBlockView({
title = "",
@@ -64,39 +92,71 @@ function TripleTextBlockView({
ctaHref,
headingId,
className = "",
layoutPreset = "default",
}: TripleTextBlockViewProps) {
const sectionTitle = title.trim();
const hasSectionTitle = sectionTitle.length > 0;
const isUseCases = layoutPreset === "useCases";
return (
<section
{...(isUseCases ? { "data-figma-node": "22085-860414" } : {})}
aria-labelledby={hasSectionTitle ? headingId : undefined}
className={`bg-black px-[var(--spacing-scale-032)] py-[var(--spacing-scale-064)] md:px-[var(--spacing-scale-096)] md:py-[var(--spacing-scale-064)] xl:px-[var(--spacing-scale-160)] ${className}`.trim()}
className={`bg-black px-[calc(var(--spacing-scale-032)+var(--spacing-scale-096))] py-[var(--spacing-scale-064)] md:px-[calc(var(--spacing-scale-096)+var(--spacing-scale-096))] md:py-[var(--spacing-scale-064)] lg:px-[calc(var(--spacing-scale-096)+var(--spacing-scale-096))] lg:py-[var(--spacing-scale-064)] ${
isUseCases
? "xl:px-[var(--spacing-scale-160)]"
: "xl:px-[calc(var(--spacing-scale-160)+var(--spacing-scale-096))]"
} xl:py-[var(--spacing-scale-064)] ${className}`.trim()}
>
<div className="mx-auto flex w-full max-w-[1440px] flex-col items-start gap-[var(--spacing-scale-032)]">
<div
className={
isUseCases
? "mx-auto flex w-full max-w-[1440px] flex-col items-start gap-[var(--spacing-scale-032)] md:gap-[var(--spacing-scale-048)] lg:items-center lg:gap-[var(--spacing-scale-064)]"
: "mx-auto flex w-full max-w-[1440px] flex-col items-start gap-[var(--spacing-scale-032)]"
}
>
{hasSectionTitle ? (
<h2
id={headingId}
className="w-full text-left font-bricolage-grotesque text-[32px] font-medium leading-[1.1] text-[var(--color-content-default-primary,white)]"
className={
isUseCases
? "w-full text-left font-bricolage-grotesque text-[28px] font-bold leading-9 text-[var(--color-content-default-primary,white)] md:text-[32px] md:leading-[40px] lg:mx-auto lg:max-w-[693px] lg:text-center lg:text-[36px] lg:font-extrabold lg:leading-[44px] xl:text-[40px] xl:leading-[52px] xl:font-bold"
: "w-full text-left font-bricolage-grotesque text-[32px] font-medium leading-[1.1] text-[var(--color-content-default-primary,white)]"
}
>
{sectionTitle}
</h2>
) : null}
<div className="flex w-full flex-col gap-[var(--spacing-scale-032)] lg:flex-row lg:items-start lg:gap-[var(--spacing-scale-032)]">
<div
className={
isUseCases
? "flex w-full flex-col gap-[var(--spacing-scale-048)] lg:flex-row lg:items-start lg:gap-[var(--spacing-scale-032)]"
: "flex w-full flex-col gap-[var(--spacing-scale-032)] lg:flex-row lg:items-start lg:gap-[var(--spacing-scale-032)]"
}
>
{columns.map((column, index) => (
<div
key={`${column.title}-${column.lgTitle ?? ""}-${index}`}
className="w-full min-w-0 lg:flex-1"
>
<TripleTextBlockColumnLockup column={column} />
<TripleTextBlockColumnLockup
column={column}
layoutPreset={layoutPreset}
/>
</div>
))}
</div>
{ctaText ? (
<div className="flex w-full justify-start">
<div
className={
isUseCases
? "flex w-full justify-start lg:justify-center"
: "flex w-full justify-start"
}
>
<Button
buttonType="filled"
palette="inverse"
buttonType={isUseCases ? "outline" : "filled"}
palette={isUseCases ? "default" : "inverse"}
size="large"
href={ctaHref}
>