Point color, radius, stroke, focus, and type tokens at the Figma scale so later sections use the same values.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
adilalloandCursor committed 2026-11-02 17:03:43 -07:00
1 parent 63d5d21ae0
commit e808fe70bf
162 files changed
+1385 -1377

No files matched your search

+6 -6
View File
@@ -29,13 +29,13 @@ export interface AvatarProps {
const SIZE_CLASS: Record<AvatarSizeValue, string> = {
small:
"h-[var(--spacing-scale-016)] w-[var(--spacing-scale-016)] text-xx-small-label",
"h-[var(--space-400)] w-[var(--space-400)] text-xx-small-label",
medium:
"h-[var(--spacing-scale-018)] w-[var(--spacing-scale-018)] text-xx-small-label",
"h-[var(--sizing-450)] w-[var(--sizing-450)] text-xx-small-label",
large:
"h-[var(--spacing-scale-024)] w-[var(--spacing-scale-024)] text-xx-small-label",
"h-[var(--space-600)] w-[var(--space-600)] text-xx-small-label",
xlarge:
"h-[var(--spacing-scale-032)] w-[var(--spacing-scale-032)] text-x-small-label",
"h-[var(--space-800)] w-[var(--space-800)] text-x-small-label",
};
function formatAvatarInitials(value: string): string {
@@ -92,8 +92,8 @@ const Avatar = memo<AvatarProps>(
const radiusClass =
shape === "rounded-square"
? "rounded-[var(--measures-radius-200,8px)]"
: "rounded-[var(--radius-measures-radius-full)]";
? "rounded-[var(--radius-200)]"
: "rounded-[var(--radius-full)]";
const fallbackChrome =
variant === "outlined"
? "border-[1.5px] border-solid border-[var(--color-content-default-brand-primary)] bg-transparent text-[var(--color-content-default-brand-primary)]"
@@ -12,9 +12,9 @@ const AvatarContainer = memo<AvatarContainerProps>(
({ children, size: sizeProp = "small", className = "", ...props }) => {
const size = sizeProp;
const sizeStyles: Record<string, string> = {
small: "flex -space-x-[var(--spacing-scale-008)]",
small: "flex -space-x-[var(--space-200)]",
medium: "flex -space-x-[9px]",
large: "flex -space-x-[var(--spacing-scale-010)]",
large: "flex -space-x-[var(--space-250)]",
xlarge: "flex -space-x-[13px]",
};
+7 -7
View File
@@ -40,8 +40,8 @@ const Logo = memo<LogoProps>(
// instances scale that lockup.
const sizes: Record<string, SizeConfig> = {
default: {
containerHeight: "h-[var(--spacing-scale-040)]",
gap: "gap-[var(--spacing-scale-006)]",
containerHeight: "h-[var(--space-1000)]",
gap: "gap-[var(--space-150)]",
textSize: "text-[21.97px]",
lineHeight: "leading-[27.05px]",
iconSize: "w-[27px] h-[27px]",
@@ -57,16 +57,16 @@ const Logo = memo<LogoProps>(
"w-[27.96px] h-[27.96px] md:w-[38.18px] md:h-[38.18px] lg:w-[55.91px] lg:h-[55.91px]",
},
createFlow: {
containerHeight: "h-[30px] md:h-[var(--spacing-scale-040)]",
gap: "gap-[4.5px] md:gap-[var(--spacing-scale-006)]",
containerHeight: "h-[30px] md:h-[var(--space-1000)]",
gap: "gap-[4.5px] md:gap-[var(--space-150)]",
textSize: "text-[16.48px] md:text-[21.97px]",
lineHeight: "leading-[20.28px] md:leading-[27.05px]",
iconSize: "w-[20.25px] h-[20.25px] md:w-[27px] md:h-[27px]",
},
topNavFolderTop: {
containerHeight:
"h-[14.1px] sm:h-[21.35px] md:h-[var(--spacing-scale-032)] lg:h-[var(--spacing-scale-040)] xl:h-[50.35px]",
gap: "gap-0 sm:gap-[3.2px] md:gap-[4.8px] lg:gap-[var(--spacing-scale-006)] xl:gap-[7.5px]",
"h-[14.1px] sm:h-[21.35px] md:h-[var(--space-800)] lg:h-[var(--space-1000)] xl:h-[50.35px]",
gap: "gap-0 sm:gap-[3.2px] md:gap-[4.8px] lg:gap-[var(--space-150)] xl:gap-[7.5px]",
textSize:
"text-[11.57px] sm:text-[11.72px] md:text-[17.58px] lg:text-[21.97px] xl:text-[27.47px]",
lineHeight:
@@ -76,7 +76,7 @@ const Logo = memo<LogoProps>(
},
topNavHeader: {
containerHeight:
"h-[14.2px] sm:h-[21.22px] md:h-[var(--spacing-scale-032)] lg:h-[40.69px] xl:h-[50.35px]",
"h-[14.2px] sm:h-[21.22px] md:h-[var(--space-800)] lg:h-[40.69px] xl:h-[50.35px]",
gap: "gap-0 sm:gap-[3.18px] md:gap-[4.85px] lg:gap-[6.06px] xl:gap-[7.5px]",
textSize:
"text-[11.57px] sm:text-[11.66px] md:text-[17.76px] lg:text-[22.2px] xl:text-[27.47px]",
+26 -19
View File
@@ -28,6 +28,11 @@ interface ButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
* @default "default"
*/
state?: ButtonStateValue;
/**
* Danger treatment beside Type. Renders the outline button in red.
* @default false
*/
danger?: boolean;
/**
* Whether to show a leading icon (Figma prop).
* @default false
@@ -62,6 +67,7 @@ const Button = memo<ButtonProps>(
palette: paletteProp,
size: sizeProp = "xsmall",
state: _stateProp,
danger = false,
hasIconLeading = false,
hasIconFollowing = false,
hasText = true,
@@ -89,20 +95,21 @@ const Button = memo<ButtonProps>(
if (type === "outline" && palette === "default") return "outline";
if (type === "outline" && palette === "inverse") return "outline-inverse";
if (type === "ghost" && palette === "default") return "ghost";
if (type === "ghost" && palette === "inverse") return "ghost-inverse";
if (type === "danger" && palette === "default") return "danger";
// danger + inverse
return "danger-inverse";
return "ghost-inverse";
};
const variant = getVariantFromTypeAndPalette(buttonType, buttonPalette);
const variant = danger
? buttonPalette === "inverse"
? "danger-inverse"
: "danger"
: getVariantFromTypeAndPalette(buttonType, buttonPalette);
const sizeStyles: Record<string, string> = {
xsmall: "p-[var(--spacing-scale-004)] gap-[var(--spacing-scale-002)]",
small: "p-[var(--spacing-scale-008)] gap-[var(--spacing-scale-002)]",
medium: "p-[var(--spacing-scale-010)] gap-[var(--spacing-scale-004)]",
large: "p-[var(--spacing-scale-012)] gap-[var(--spacing-scale-006)]",
xlarge: "p-[var(--spacing-scale-016)] gap-[var(--spacing-scale-008)]",
xsmall: "p-[var(--space-100)] gap-[var(--space-050)]",
small: "p-[var(--space-200)] gap-[var(--space-050)]",
medium: "p-[var(--space-250)] gap-[var(--space-100)]",
large: "p-[var(--space-300)] gap-[var(--space-150)]",
xlarge: "p-[var(--space-400)] gap-[var(--space-200)]",
};
const fontStyles: Record<string, string> = {
@@ -115,21 +122,21 @@ const Button = memo<ButtonProps>(
const variantStyles: Record<string, string> = {
filled:
"bg-[var(--color-surface-inverse-primary)] text-[var(--color-content-inverse-primary)] border-[1.5px] border-transparent hover:bg-[var(--color-surface-inverse-primary)] hover:text-[var(--color-content-invert-brand-primary)] hover:border-[var(--color-border-invert-brand-primary)] focus-visible:bg-[var(--color-surface-inverse-primary)] focus-visible:text-[var(--color-content-invert-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[0_0_0px_2px_var(--color-border-default-primary),0_0_0px_4px_var(--color-border-invert-primary)] active:bg-[var(--color-surface-invert-brand-primary)] active:text-[var(--color-content-invert-primary)] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"bg-[var(--color-surface-invert-primary)] text-[var(--color-content-invert-primary)] border-[1.5px] border-transparent hover:bg-[var(--color-surface-invert-primary)] hover:text-[var(--color-content-invert-brand-primary)] hover:border-[var(--color-border-invert-brand-primary)] focus-visible:bg-[var(--color-surface-invert-primary)] focus-visible:text-[var(--color-content-invert-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-default)] active:bg-[var(--color-surface-invert-brand-primary)] active:text-[var(--color-content-invert-primary)] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"filled-inverse":
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border-[1.5px] border-transparent hover:bg-[var(--color-surface-default-primary)] hover:text-[var(--color-content-default-brand-primary)] hover:border-[var(--color-border-default-brand-primary)] focus-visible:bg-[var(--color-surface-default-primary)] focus-visible:text-[var(--color-content-default-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[0_0_0px_2px_var(--color-border-invert-primary),0_0_0px_4px_var(--color-border-default-primary)] active:bg-[var(--color-surface-default-brand-primary)] active:text-[var(--color-content-default-primary)] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border-[1.5px] border-transparent hover:bg-[var(--color-surface-default-primary)] hover:text-[var(--color-content-default-brand-primary)] hover:border-[var(--color-border-default-brand-primary)] focus-visible:bg-[var(--color-surface-default-primary)] focus-visible:text-[var(--color-content-default-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-[var(--color-surface-default-brand-primary)] active:text-[var(--color-content-default-primary)] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
outline:
"bg-transparent text-[var(--color-content-default-primary)] border-[1.5px] border-[var(--color-border-invert-primary)] hover:bg-transparent hover:text-[var(--color-content-default-brand-primary)] hover:border-[1.5px] hover:border-[var(--color-border-default-brand-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-default-primary)] focus-visible:outline-none focus-visible:border-[1.5px] focus-visible:border-[var(--color-border-invert-primary)] focus-visible:shadow-[0_0_0px_2px_var(--color-border-default-primary),0_0_0px_4px_var(--color-border-invert-primary)] active:bg-transparent active:text-[var(--color-content-default-primary)] active:border-[1.5px] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-[1.5px] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"bg-transparent text-[var(--color-content-default-primary)] border-[1.5px] border-[var(--color-border-invert-primary)] hover:bg-transparent hover:text-[var(--color-content-default-brand-primary)] hover:border-[1.5px] hover:border-[var(--color-border-default-brand-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-default-primary)] focus-visible:outline-none focus-visible:border-[1.5px] focus-visible:border-[var(--color-border-invert-primary)] focus-visible:shadow-[var(--shadow-focus-default)] active:bg-transparent active:text-[var(--color-content-default-primary)] active:border-[1.5px] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-[1.5px] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"outline-inverse":
"bg-transparent text-[var(--color-content-invert-primary)] border-[1.5px] border-[var(--color-border-default-primary)] hover:bg-transparent hover:text-[var(--color-content-invert-brand-primary)] hover:border-[1.5px] hover:border-[var(--color-border-invert-brand-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-primary)] focus-visible:outline-none focus-visible:border-[1.5px] focus-visible:border-[var(--color-border-default-primary)] focus-visible:shadow-[0_0_0px_2px_var(--color-border-invert-primary),0_0_0px_4px_var(--color-border-default-primary)] active:bg-transparent active:text-[var(--color-content-invert-primary)] active:border-[1.5px] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-[1.5px] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"bg-transparent text-[var(--color-content-invert-primary)] border-[1.5px] border-[var(--color-border-default-primary)] hover:bg-transparent hover:text-[var(--color-content-invert-brand-primary)] hover:border-[1.5px] hover:border-[var(--color-border-invert-brand-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-primary)] focus-visible:outline-none focus-visible:border-[1.5px] focus-visible:border-[var(--color-border-default-primary)] focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-transparent active:text-[var(--color-content-invert-primary)] active:border-[1.5px] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-[1.5px] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
ghost:
"bg-transparent text-[var(--color-content-default-brand-primary)] border-[1.5px] border-transparent hover:bg-transparent hover:text-[var(--color-content-default-primary)] hover:border-transparent focus-visible:bg-transparent focus-visible:text-[var(--color-content-default-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[0_0_0px_2px_var(--color-border-default-primary),0_0_0px_4px_var(--color-border-invert-primary)] active:bg-transparent active:text-[var(--color-content-default-primary)] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"bg-transparent text-[var(--color-content-default-brand-primary)] border-[1.5px] border-transparent hover:bg-transparent hover:text-[var(--color-content-default-primary)] hover:border-transparent focus-visible:bg-transparent focus-visible:text-[var(--color-content-default-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-default)] active:bg-transparent active:text-[var(--color-content-default-primary)] active:border-[var(--color-border-default-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"ghost-inverse":
"bg-transparent text-[var(--color-content-invert-primary)] border-[1.5px] border-transparent hover:bg-transparent hover:text-[var(--color-content-invert-primary)] hover:border-transparent focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[0_0_0px_2px_var(--color-border-invert-primary),0_0_0px_4px_var(--color-border-default-primary)] active:bg-[var(--color-surface-invert-brand-primary)] active:text-[var(--color-content-invert-primary)] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"bg-transparent text-[var(--color-content-invert-primary)] border-[1.5px] border-transparent hover:bg-transparent hover:text-[var(--color-content-invert-primary)] hover:border-transparent focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-brand-primary)] focus-visible:outline-none focus-visible:border-transparent focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-[var(--color-surface-invert-brand-primary)] active:text-[var(--color-content-invert-primary)] active:border-[var(--color-border-invert-brand-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
danger:
"bg-transparent text-[var(--color-border-default-negative-primary)] border border-[var(--color-border-default-negative-primary)] hover:bg-[var(--color-surface-invert-negative-secondary)] hover:text-[var(--color-border-default-negative-primary)] hover:border-[var(--color-border-default-negative-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-border-default-negative-primary)] focus-visible:outline-none focus-visible:border-[var(--color-border-default-negative-primary)] focus-visible:shadow-[0_0_0px_2px_var(--color-border-default-primary),0_0_0px_4px_var(--color-border-invert-primary)] active:bg-[var(--color-surface-invert-negative-primary)] active:text-[var(--color-content-invert-negative-primary)] active:border-[1.5px] active:border-[var(--color-border-default-negative-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-inverse-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"bg-transparent text-[var(--color-content-default-negative-primary)] border border-[var(--color-border-default-negative-primary)] hover:bg-[var(--color-surface-invert-negative-secondary)] hover:text-[var(--color-content-invert-negative-primary)] hover:border-[var(--color-border-default-negative-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-default-negative-primary)] focus-visible:outline-none focus-visible:border-[var(--color-border-default-negative-primary)] focus-visible:shadow-[var(--shadow-focus-default)] active:bg-[var(--color-surface-invert-negative-primary)] active:text-[var(--color-content-invert-primary)] active:border-[1.5px] active:border-[var(--color-border-default-negative-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-invert-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"danger-inverse":
"bg-transparent text-[var(--color-content-invert-negative-primary)] border border-[var(--color-border-invert-negative-primary)] hover:bg-transparent hover:text-[var(--color-content-invert-negative-primary)] hover:border-[var(--color-border-invert-negative-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-negative-primary)] focus-visible:outline-none focus-visible:border-[var(--color-border-invert-negative-primary)] focus-visible:shadow-[0_0_0px_2px_var(--color-border-invert-primary),0_0_0px_4px_var(--color-border-default-primary)] active:bg-[var(--color-surface-default-negative-primary)] active:text-[var(--color-content-default-primary)] active:border-[1.5px] active:border-[var(--color-border-default-negative-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-inverse-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
"bg-transparent text-[var(--color-content-invert-negative-primary)] border border-[var(--color-border-invert-negative-primary)] hover:bg-transparent hover:text-[var(--color-content-invert-negative-primary)] hover:border-[var(--color-border-invert-negative-primary)] focus-visible:bg-transparent focus-visible:text-[var(--color-content-invert-negative-primary)] focus-visible:outline-none focus-visible:border-[var(--color-border-invert-negative-primary)] focus-visible:shadow-[var(--shadow-focus-invert)] active:bg-[var(--color-surface-default-negative-primary)] active:text-[var(--color-content-default-primary)] active:border-[1.5px] active:border-[var(--color-border-default-negative-primary)] active:shadow-none active:scale-[0.98] disabled:bg-[var(--color-surface-invert-secondary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-transparent disabled:cursor-not-allowed disabled:opacity-50 disabled:active:scale-100",
};
// Hover/focus: color + border only — no scale and no extra outline (those
@@ -137,7 +144,7 @@ const Button = memo<ButtonProps>(
// and cards: color, opacity, or shadow on hover; scale only on press.
// State prop is informational for Figma alignment; CSS pseudo-classes own
// the actual interaction states.
const baseStyles = `inline-flex items-center justify-start box-border whitespace-nowrap shrink-0 touch-manipulation [-webkit-tap-highlight-color:transparent] ${sizeStyles[size]} rounded-[var(--radius-measures-radius-full)] ${fontStyles[size]} transition-[transform,color,background-color,border-color,box-shadow] duration-150 ease-out cursor-pointer ${variantStyles[variant]}`;
const baseStyles = `inline-flex items-center justify-start box-border whitespace-nowrap shrink-0 touch-manipulation [-webkit-tap-highlight-color:transparent] ${sizeStyles[size]} rounded-[var(--radius-full)] ${fontStyles[size]} transition-[transform,color,background-color,border-color,box-shadow] duration-150 ease-out cursor-pointer ${variantStyles[variant]}`;
const combinedStyles = `${baseStyles} ${className}`;
const sharedA11y = {
+1 -1
View File
@@ -28,7 +28,7 @@ function VerticalComponent({
"data-testid": dataTestId,
}: VerticalProps) {
const base =
"box-border flex w-full min-w-[90px] cursor-pointer flex-col items-center gap-[var(--spacing-scale-008)] rounded-[var(--spacing-scale-004)] border border-solid border-[var(--color-border-default-brand-primary)] bg-transparent px-[var(--spacing-scale-008)] py-[var(--spacing-scale-012)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-invert-primary)] disabled:cursor-not-allowed disabled:opacity-60";
"box-border flex w-full min-w-[90px] cursor-pointer flex-col items-center gap-[var(--space-200)] rounded-[var(--space-100)] border border-solid border-[var(--color-border-default-brand-primary)] bg-transparent px-[var(--space-200)] py-[var(--space-300)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-invert-primary)] disabled:cursor-not-allowed disabled:opacity-60";
return (
<button
@@ -52,7 +52,7 @@ function CardStackAddCardButton({
type="button"
onClick={onClick}
aria-label={ariaLabel}
className="flex min-h-[88px] w-full shrink-0 items-center justify-center rounded-[var(--measures-radius-medium,8px)] bg-[var(--color-surface-default-secondary)] text-medium-label text-[var(--color-content-default-primary)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-invert-primary)]"
className="flex min-h-[88px] w-full shrink-0 items-center justify-center rounded-[var(--radius-400)] bg-[var(--color-surface-default-secondary)] text-medium-label text-[var(--color-content-default-primary)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-invert-primary)]"
>
<span className="flex items-center gap-2">
<svg
+1 -1
View File
@@ -19,7 +19,7 @@ export function IconView({
return (
<div
data-figma-node="22084-859659"
className={`relative flex h-[350px] w-full min-w-[240px] max-w-[480px] flex-col items-start justify-between border border-solid border-[var(--color-border-default-secondary)] bg-transparent p-[var(--measures-spacing-020)] ${interactionClass} ${className}`}
className={`relative flex h-[350px] w-full min-w-[240px] max-w-[480px] flex-col items-start justify-between border border-solid border-[var(--color-border-default-secondary)] bg-transparent p-[var(--space-500)] ${interactionClass} ${className}`}
tabIndex={interactive ? 0 : undefined}
role={interactive ? "button" : "article"}
aria-label={interactive ? `${title}: ${description}` : undefined}
+3 -3
View File
@@ -13,7 +13,7 @@ const MiniContainer = memo<MiniProps>(
({
children,
className = "",
backgroundColor = "bg-[var(--color-surface-default-brand-royal)]",
backgroundColor = "bg-[var(--color-surface-invert-brand-royal)]",
panelContent,
label,
labelLine1,
@@ -51,7 +51,7 @@ const MiniContainer = memo<MiniProps>(
...baseProps,
href,
className:
"block focus:outline-none focus:ring-2 focus:ring-[var(--color-surface-default-brand-royal)] focus:ring-offset-2 rounded-[var(--radius-measures-radius-xlarge)]",
"block focus:outline-none focus:ring-2 focus:ring-[var(--color-surface-invert-brand-royal)] focus:ring-offset-2 rounded-[var(--radius-500)]",
tabIndex: 0,
},
};
@@ -64,7 +64,7 @@ const MiniContainer = memo<MiniProps>(
...baseProps,
onClick,
className:
"block w-full text-left focus:outline-none focus:ring-2 focus:ring-[var(--color-surface-default-brand-royal)] focus:ring-offset-2 rounded-[var(--radius-measures-radius-xlarge)]",
"block w-full text-left focus:outline-none focus:ring-2 focus:ring-[var(--color-surface-invert-brand-royal)] focus:ring-offset-2 rounded-[var(--radius-500)]",
tabIndex: 0,
onKeyDown: (e: React.KeyboardEvent<HTMLButtonElement>) => {
if (e.key === "Enter" || e.key === " ") {
+2 -2
View File
@@ -30,8 +30,8 @@ function MiniView({
: `h-[186px] flex flex-col gap-[7px] ${className}`;
const panelClass = featureGridShell
? `h-[138px] shrink-0 rounded-[var(--measures-radius-400,16px)] px-[24px] py-[32px] ${backgroundColor} flex items-center justify-center`
: `flex-1 rounded-[var(--radius-measures-radius-xlarge)] border border-[1px] py-[var(--spacing-scale-032)] px-[var(--spacing-scale-024)] ${backgroundColor} flex items-center justify-center transition-shadow duration-200 hover:shadow-lg`;
? `h-[138px] shrink-0 rounded-[var(--radius-400)] px-[24px] py-[32px] ${backgroundColor} flex items-center justify-center`
: `flex-1 rounded-[var(--radius-500)] border border-[1px] py-[var(--space-800)] px-[var(--space-600)] ${backgroundColor} flex items-center justify-center transition-shadow duration-200 hover:shadow-lg`;
const imageClass = featureGridShell
? `max-h-[48px] max-w-[56px] w-auto h-auto object-contain${panelImageClassName ? ` ${panelImageClassName}` : ""}`
+3 -3
View File
@@ -233,10 +233,10 @@ export function RuleView({
const borderRadiusClass = className?.includes("rounded-")
? "" // If className already has border radius, don't add size-based one
: isExtraSmall
? "rounded-[var(--measures-radius-200,8px)]"
? "rounded-[var(--radius-200)]"
: isSmall
? "rounded-[var(--measures-radius-300,12px)]"
: "rounded-[var(--radius-measures-radius-small)]";
? "rounded-[var(--radius-300)]"
: "rounded-[var(--radius-300)]";
function renderBottomLink(link: RuleBottomLink) {
const shared = {
@@ -7,7 +7,7 @@ import type { SelectionViewProps } from "./Selection.types";
function InfoIcon() {
return (
<span
className="flex h-[var(--spacing-scale-016)] w-[var(--spacing-scale-016)] shrink-0 items-center justify-center rounded-full border border-[var(--color-content-invert-brand-secondary)] bg-transparent text-[10px] font-medium leading-none text-[var(--color-content-invert-brand-secondary)]"
className="flex h-[var(--space-400)] w-[var(--space-400)] shrink-0 items-center justify-center rounded-full border border-[var(--color-content-invert-brand-secondary)] bg-transparent text-[10px] font-medium leading-none text-[var(--color-content-invert-brand-secondary)]"
aria-hidden
>
?
@@ -65,7 +65,7 @@ export function SelectionView({
const cardIdProp = selectionId ? { "data-card-id": selectionId } : {};
if (size === "m") {
const baseClasses = `select-none rounded-[var(--measures-radius-200,8px)] bg-[var(--color-gray-000)] px-4 py-3 transition-[border-color,box-shadow,outline] duration-200 cursor-pointer ${borderClass} ${selectedBorder} ${className}`;
const baseClasses = `select-none rounded-[var(--radius-200)] bg-[var(--color-gray-000)] px-4 py-3 transition-[border-color,box-shadow,outline] duration-200 cursor-pointer ${borderClass} ${selectedBorder} ${className}`;
return (
<div
@@ -92,7 +92,7 @@ export function SelectionView({
);
}
const baseClasses = `select-none rounded-[var(--measures-radius-200,8px)] bg-[var(--color-gray-000)] p-4 transition-[border-color,box-shadow,outline] duration-200 cursor-pointer ${borderClass} ${selectedBorder} ${className}`;
const baseClasses = `select-none rounded-[var(--radius-200)] bg-[var(--color-gray-000)] p-4 transition-[border-color,box-shadow,outline] duration-200 cursor-pointer ${borderClass} ${selectedBorder} ${className}`;
return (
<div
+1 -1
View File
@@ -21,7 +21,7 @@ function StatView({
return (
<article
className={`relative flex h-auto min-h-[182px] w-full flex-col items-start justify-between rounded-[var(--radius-measures-radius-xlarge,20px)] bg-[var(--color-surface-invert-primary,white)] px-[var(--spacing-scale-024)] py-[var(--spacing-scale-032)] sm:h-[170px] sm:min-h-0 sm:p-[var(--spacing-scale-024)] ${className}`.trim()}
className={`relative flex h-auto min-h-[182px] w-full flex-col items-start justify-between rounded-[var(--radius-500)] bg-[var(--color-surface-invert-primary,white)] px-[var(--space-600)] py-[var(--space-800)] sm:h-[170px] sm:min-h-0 sm:p-[var(--space-600)] ${className}`.trim()}
>
<div className="relative flex w-full flex-col items-start">
<div className="relative flex items-center">
+1 -1
View File
@@ -14,7 +14,7 @@ interface StepProps {
const Step = memo<StepProps>(({ number, text, size: sizeProp }) => {
const baseClasses =
"bg-[var(--color-surface-inverse-primary)] rounded-[12px] shadow-lg";
"bg-[var(--color-surface-invert-primary)] rounded-[12px] shadow-lg";
if (sizeProp) {
const size = sizeProp;
@@ -54,7 +54,7 @@ export function TemplateChipDetailModal({
nextButtonText={t("closeButton")}
ariaLabel={resolved?.title || "Template entry details"}
>
<div className="flex flex-col gap-[var(--measures-spacing-600,24px)] pb-2">
<div className="flex flex-col gap-[var(--space-600)] pb-2">
{resolved?.body ?? (
<p className="text-small-paragraph text-[color:var(--color-content-default-secondary,#a3a3a3)]">
{t("fallback.bodyLabel")}
@@ -31,10 +31,10 @@ const ContentContainerContainer = memo<ContentContainerProps>(
const onLight = tone === "onLight";
const titleColor = onLight
? "text-[var(--color-content-default-primary)] group-hover:text-[var(--color-content-default-brand-primary)]"
: "text-[var(--color-content-inverse-brand-royal)] group-hover:text-blue-200";
: "text-[var(--color-content-invert-brand-royal)] group-hover:text-blue-200";
const bodyColor = onLight
? "text-[var(--color-content-default-secondary)]"
: "text-[var(--color-content-inverse-brand-royal)]";
: "text-[var(--color-content-invert-brand-royal)]";
const getIconImage = (slug: string): string => {
const resolvedSlug =
@@ -63,24 +63,24 @@ const ContentContainerContainer = memo<ContentContainerProps>(
const containerClasses =
size === "xs"
? "relative z-20 flex h-full flex-col gap-[var(--measures-spacing-012)]"
? "relative z-20 flex h-full flex-col gap-[var(--space-300)]"
: isUseCase
? "relative z-20 flex h-full w-full min-w-0 flex-col gap-[var(--measures-spacing-024)]"
: "relative z-20 h-full flex flex-col gap-[var(--measures-spacing-012)] sm:gap-[var(--measures-spacing-016)] md:gap-[18px] lg:gap-[var(--measures-spacing-024)]";
? "relative z-20 flex h-full w-full min-w-0 flex-col gap-[var(--space-600)]"
: "relative z-20 h-full flex flex-col gap-[var(--space-300)] sm:gap-[var(--space-400)] md:gap-[18px] lg:gap-[var(--space-600)]";
const contentGapClasses =
size === "xs"
? "flex flex-col gap-[var(--measures-spacing-008)]"
? "flex flex-col gap-[var(--space-200)]"
: isUseCase
? "flex w-full min-w-0 flex-col gap-[var(--measures-spacing-016)]"
: "flex flex-col gap-[var(--measures-spacing-008)] sm:gap-[var(--measures-spacing-012)] md:gap-[var(--measures-spacing-008)] lg:gap-[var(--measures-spacing-016)] xl:gap-[var(--measures-spacing-004)]";
? "flex w-full min-w-0 flex-col gap-[var(--space-400)]"
: "flex flex-col gap-[var(--space-200)] sm:gap-[var(--space-300)] md:gap-[var(--space-200)] lg:gap-[var(--space-400)] xl:gap-[var(--space-100)]";
const textGapClasses =
size === "xs"
? "flex flex-col gap-[var(--measures-spacing-004)]"
? "flex flex-col gap-[var(--space-100)]"
: isUseCase
? "flex w-full min-w-0 flex-col gap-[var(--measures-spacing-004)]"
: "flex flex-col gap-[var(--measures-spacing-004)] md:gap-[var(--measures-spacing-002)] lg:gap-[var(--measures-spacing-004)]";
? "flex w-full min-w-0 flex-col gap-[var(--space-100)]"
: "flex flex-col gap-[var(--space-100)] md:gap-[var(--space-050)] lg:gap-[var(--space-100)]";
const titleClasses =
size === "xs"
@@ -45,7 +45,7 @@ function ContentContainerView({
</div>
</div>
<div className="flex min-w-0 items-end gap-[var(--measures-spacing-008)]">
<div className="flex min-w-0 items-end gap-[var(--space-200)]">
{/* Author Name */}
<span className={authorClasses}>{post.frontmatter.author}</span>
@@ -51,9 +51,9 @@ function AddCustomFieldViewComponent({
<button
type="button"
onClick={onPressAdd}
className={`flex h-[88px] w-full shrink-0 cursor-pointer items-center justify-center rounded-[var(--measures-radius-medium,8px)] bg-[var(--color-surface-default-secondary)] px-6 text-medium-label text-[var(--color-content-default-primary)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-invert-primary)] ${className ?? ""}`.trim()}
className={`flex h-[88px] w-full shrink-0 cursor-pointer items-center justify-center rounded-[var(--radius-400)] bg-[var(--color-surface-default-secondary)] px-6 text-medium-label text-[var(--color-content-default-primary)] focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-invert-primary)] ${className ?? ""}`.trim()}
>
<span className="flex items-center gap-[var(--spacing-scale-006)] rounded-full px-4 py-3">
<span className="flex items-center gap-[var(--space-150)] rounded-full px-4 py-3">
<svg
width="20"
height="20"
@@ -56,7 +56,7 @@ const CheckboxContainer = memo<CheckboxProps>(
// Default state: tertiary border, with hover and focus states via CSS
// Hover changes border to brand primary color
// Focus removes border and shows shadow (double ring: 2px white inner, 4px dark outer)
return `${baseBox} bg-[var(--color-surface-default-primary)] border border-solid border-[var(--color-border-default-tertiary,#464646)] hover:border-[var(--color-border-default-brand-primary,#fdfaa8)] focus:border-transparent focus:shadow-[0px_0px_0px_2px_var(--color-border-invert-primary,white),0px_0px_0px_4px_var(--color-border-default-primary,#141414)] focus:outline-none`;
return `${baseBox} bg-[var(--color-surface-default-primary)] border border-solid border-[var(--color-border-default-control)] hover:border-[var(--color-border-default-brand-primary,#fdfaa8)] focus:border-transparent focus:shadow-[var(--shadow-focus-invert)] focus:outline-none`;
}
// Inverse mode styles per Figma
@@ -64,7 +64,7 @@ const CheckboxContainer = memo<CheckboxProps>(
// Inverse: transparent background, white border
// Hover changes border to brand primary color
// Focus shows shadow (2px dark inner, 4px white outer) - note: reversed from standard
return `${baseBox} bg-transparent border border-solid border-[var(--color-border-invert-primary,white)] hover:border-[var(--color-border-default-brand-primary,#fdfaa8)] focus:shadow-[0px_0px_0px_2px_var(--color-border-default-primary,#141414),0px_0px_0px_4px_var(--color-border-invert-primary,white)] focus:outline-none`;
return `${baseBox} bg-transparent border border-solid border-[var(--color-border-invert-primary,white)] hover:border-[var(--color-border-default-brand-primary,#fdfaa8)] focus:shadow-[var(--shadow-focus-default)] focus:outline-none`;
}
return baseBox;
@@ -76,12 +76,12 @@ const CheckboxContainer = memo<CheckboxProps>(
const checkGlyphColor = checked
? isStandard
? "var(--color-content-default-brand-primary, #fefcc9)" // Light yellow/cream for standard mode
: "var(--color-content-inverse-primary, #000000)" // Black for inverse mode
: "var(--color-content-invert-primary, #000000)" // Black for inverse mode
: "transparent";
// Label color
const labelColor = isInverse
? "var(--color-content-inverse-primary)"
? "var(--color-content-invert-primary)"
: "var(--color-content-default-primary)";
const handleToggle = (e: React.MouseEvent | React.KeyboardEvent) => {
@@ -39,7 +39,7 @@ export function CheckboxGroupView({
<span
className={`text-small-paragraph ${
mode === "inverse"
? "text-[var(--color-content-inverse-primary)]"
? "text-[var(--color-content-invert-primary)]"
: "text-[var(--color-content-default-primary)]"
}`}
>
@@ -48,7 +48,7 @@ export function CheckboxGroupView({
<span
className={`text-small-paragraph ${
mode === "inverse"
? "text-[var(--color-content-inverse-secondary,#1f1f1f)]"
? "text-[var(--color-content-invert-secondary,#1f1f1f)]"
: "text-[var(--color-content-default-tertiary,#b4b4b4)]"
}`}
>
+15 -15
View File
@@ -32,20 +32,20 @@ function chipSurfaceStyle(
if (palette === "inverse") {
if (state === "disabled") {
return paint(
"var(--color-surface-inverse-tertiary)",
"var(--color-content-inverse-primary)",
"var(--color-surface-invert-tertiary)",
"var(--color-content-invert-primary)",
);
}
if (state === "selected") {
return paint(
"var(--color-surface-default-semi-opaque)",
"var(--color-content-inverse-primary)",
"var(--color-content-invert-primary)",
"var(--color-border-default-primary)",
);
}
return paint(
"transparent",
"var(--color-content-inverse-primary)",
"var(--color-content-invert-primary)",
"var(--color-border-default-primary)",
);
}
@@ -72,7 +72,7 @@ function chipSurfaceStyle(
return paint(
"transparent",
"var(--color-content-default-brand-primary, #fefcc9)",
"var(--color-border-default-tertiary, #464646)",
"var(--color-border-default-control)",
);
}
@@ -110,11 +110,11 @@ function ChipView({
// Custom state has different padding
const sizeClasses = isCustom
? isSmall
? "px-[var(--measures-spacing-100,4px)] py-[3px] text-x-small-paragraph"
: "px-[var(--measures-spacing-150,6px)] py-[10px] text-medium-paragraph"
? "px-[var(--space-100)] py-[3px] text-x-small-paragraph"
: "px-[var(--space-150)] py-[10px] text-medium-paragraph"
: isSmall
? "h-[30px] px-[var(--measures-spacing-200,8px)] gap-[var(--measures-spacing-050,2px)] text-x-small-label"
: "px-[var(--measures-spacing-300,12px)] py-[var(--measures-spacing-300,12px)] gap-[var(--measures-spacing-150,6px)] text-medium-label";
? "h-[30px] px-[var(--space-200)] gap-[var(--space-050)] text-x-small-label"
: "px-[var(--space-300)] py-[var(--space-300)] gap-[var(--space-150)] text-medium-label";
const baseClasses = `
appearance-none
@@ -122,7 +122,7 @@ function ChipView({
max-w-full
items-center
justify-center
rounded-[var(--measures-radius-full,9999px)]
rounded-[var(--radius-full)]
overflow-clip
box-border
focus:outline-none
@@ -185,7 +185,7 @@ function ChipView({
{onCheck && (
<button
type="button"
className="flex items-center justify-center p-[var(--measures-spacing-150,6px)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque,rgba(0,0,0,0.1))] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
className="flex items-center justify-center p-[var(--space-150)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque,rgba(0,0,0,0.1))] transition-colors disabled:opacity-50 disabled:cursor-not-allowed"
aria-label={confirmAriaLabel}
disabled={!inputValue || !inputValue.trim()}
onClick={(event) => {
@@ -227,8 +227,8 @@ function ChipView({
className="bg-transparent border-none outline-none flex-1 min-w-0 font-normal text-[color:var(--color-content-default-tertiary,#b4b4b4)] placeholder:text-[color:var(--color-content-default-tertiary,#b4b4b4)]"
style={{
fontSize: isSmall
? "var(--sizing-300,12px)"
: "var(--sizing-400,16px)",
? "var(--sizing-300)"
: "var(--sizing-400)",
lineHeight: isSmall ? "16px" : "24px",
}}
onClick={(e) => e.stopPropagation()}
@@ -240,7 +240,7 @@ function ChipView({
{onClose && (
<button
type="button"
className="flex items-center justify-center p-[var(--measures-spacing-150,6px)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque,rgba(0,0,0,0.1))] transition-colors"
className="flex items-center justify-center p-[var(--space-150)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque,rgba(0,0,0,0.1))] transition-colors"
aria-label={closeAriaLabel}
onClick={(event) => {
event.stopPropagation();
@@ -309,7 +309,7 @@ function ChipView({
{onRemove && !isDisabled && (
<button
type="button"
className="ml-[var(--measures-spacing-050,2px)] p-[var(--measures-spacing-050,2px)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque,rgba(0,0,0,0.05))]"
className="ml-[var(--space-050)] p-[var(--space-050)] rounded-full hover:bg-[var(--color-surface-default-semi-opaque,rgba(0,0,0,0.05))]"
aria-label={`Remove ${label}`}
onClick={(event) => {
event.stopPropagation();
@@ -4,7 +4,7 @@ import { memo } from "react";
import type { IncrementerViewProps } from "./Incrementer.types";
const STEP_BUTTON_CLASSES =
"bg-[var(--color-surface-default-secondary,#141414)] text-[var(--color-content-default-primary,#fff)] inline-flex shrink-0 items-center justify-center overflow-clip rounded-[var(--measures-radius-full,9999px)] px-[var(--space-200,8px)] py-[var(--measures-spacing-150,6px)] transition-[background,color,opacity] duration-200 ease-in-out hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-invert-primary,#fff)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-surface-default-primary,#000)] disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:opacity-50";
"bg-[var(--color-surface-default-secondary,#141414)] text-[var(--color-content-default-primary,#fff)] inline-flex shrink-0 items-center justify-center overflow-clip rounded-[var(--radius-full)] px-[var(--space-200)] py-[var(--space-150)] transition-[background,color,opacity] duration-200 ease-in-out hover:opacity-90 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-border-invert-primary,#fff)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-surface-default-primary,#000)] disabled:cursor-not-allowed disabled:opacity-50 disabled:hover:opacity-50";
function MinusIcon() {
return (
@@ -75,7 +75,7 @@ function IncrementerView({
</button>
<span
aria-live="polite"
className={`shrink-0 whitespace-nowrap text-[length:var(--sizing-350,14px)] font-medium leading-[18px] ${valueColor}`}
className={`shrink-0 whitespace-nowrap text-[length:var(--sizing-350)] font-medium leading-[18px] ${valueColor}`}
>
{displayValue}
</span>
@@ -17,8 +17,11 @@ const IncrementerBlockContainer = ({
labelSize = "s",
palette = "default",
blockClassName = "",
state = "default",
disabled,
...incrementerProps
}: IncrementerBlockProps) => {
const isDisabled = state === "disabled" || Boolean(disabled);
return (
<IncrementerBlockView
label={label}
@@ -28,6 +31,8 @@ const IncrementerBlockContainer = ({
labelSize={labelSize}
palette={palette}
blockClassName={blockClassName}
state={state}
disabled={isDisabled}
{...incrementerProps}
/>
);
@@ -1,3 +1,4 @@
import type { IncrementerBlockStateValue } from "../../../../lib/propNormalization";
import type { IncrementerProps } from "../Incrementer/Incrementer.types";
import type {
InputLabelPaletteValue,
@@ -5,6 +6,11 @@ import type {
} from "../../type/InputLabel/InputLabel.types";
export interface IncrementerBlockProps extends IncrementerProps {
/**
* One state axis. Disabled dims the block and turns off both buttons.
* @default "default"
*/
state?: IncrementerBlockStateValue;
/** Label text displayed above the incrementer. */
label: string;
/** Show the help "?" icon next to the label. Defaults to `true`. */
@@ -31,6 +37,7 @@ export interface IncrementerBlockProps extends IncrementerProps {
}
export interface IncrementerBlockViewProps extends IncrementerProps {
state: IncrementerBlockStateValue;
label: string;
helpIcon: boolean;
helperText: boolean | string | undefined;
@@ -13,12 +13,14 @@ function IncrementerBlockView({
labelSize,
palette,
blockClassName,
state: _state,
disabled,
className,
...incrementerProps
}: IncrementerBlockViewProps) {
return (
<div
className={`flex flex-col items-start gap-[var(--measures-spacing-300,12px)] py-[8px] ${blockClassName}`.trim()}
className={`flex flex-col items-start gap-[var(--space-300)] py-[8px] ${disabled ? "opacity-60" : ""} ${blockClassName}`.trim()}
data-figma-node="19883:13283"
>
<InputLabel
@@ -29,7 +31,11 @@ function IncrementerBlockView({
size={labelSize}
palette={palette}
/>
<Incrementer {...incrementerProps} className={className} />
<Incrementer
{...incrementerProps}
disabled={disabled}
className={className}
/>
</div>
);
}
@@ -45,7 +45,7 @@ function InfoMessageBoxView({
return (
<div
className={`flex w-full min-w-0 items-start gap-[var(--measures-spacing-200,8px)] p-[var(--spacing-measures-spacing-500,20px)] rounded-[var(--measures-radius-300,12px)] border-l-2 border-solid border-[var(--color-border-default-secondary,#1f1f1f)] bg-[var(--color-content-inverse-secondary,#1f1f1f)] ${className}`}
className={`flex w-full min-w-0 items-start gap-[var(--space-200)] p-[var(--space-500)] rounded-[var(--radius-300)] border-l-2 border-solid border-[var(--color-border-default-secondary,#1f1f1f)] bg-[var(--color-content-invert-secondary,#1f1f1f)] ${className}`}
role="region"
aria-label={title}
>
@@ -15,10 +15,10 @@ export function InputWithCounterView({
}: InputWithCounterProps) {
const inputId = useId();
return (
<div className={`space-y-[var(--spacing-scale-008)] ${className}`}>
<div className={`space-y-[var(--space-200)] ${className}`}>
{/* Label with help icon */}
{label && (
<div className="flex items-center gap-[var(--spacing-scale-002)]">
<div className="flex items-center gap-[var(--space-050)]">
<label
htmlFor={inputId}
className="text-[14px] leading-[20px] font-medium text-[var(--color-content-default-primary)]"
@@ -43,12 +43,12 @@ export function InputWithCounterView({
width="12"
height="12"
>
<rect width="12" height="12" fill="#D9D9D9" />
<rect width="12" height="12" fill="var(--color-gray-200)" />
</mask>
<g mask="url(#mask0_21296_8257)">
<path
d="M5.99449 8.80766C6.13725 8.80766 6.25784 8.75838 6.35624 8.6598C6.45463 8.56123 6.50383 8.44055 6.50383 8.29779C6.50383 8.15502 6.45454 8.03444 6.35596 7.93605C6.25739 7.83765 6.13672 7.78845 5.99395 7.78845C5.85118 7.78845 5.7306 7.83774 5.63221 7.93631C5.53381 8.03489 5.48461 8.15556 5.48461 8.29833C5.48461 8.44109 5.5339 8.56168 5.63248 8.66008C5.73105 8.75847 5.85172 8.80766 5.99449 8.80766ZM5.64038 7.01729H6.34421C6.35062 6.77114 6.38668 6.5745 6.45239 6.42739C6.51809 6.28028 6.67754 6.08525 6.93075 5.8423C7.15062 5.62243 7.31905 5.41938 7.43604 5.23316C7.55302 5.04695 7.61151 4.82703 7.61151 4.57343C7.61151 4.14307 7.45687 3.80689 7.14759 3.5649C6.8383 3.32292 6.47243 3.20193 6.04999 3.20193C5.63269 3.20193 5.28734 3.3133 5.01394 3.53606C4.74055 3.75881 4.54552 4.02115 4.42885 4.32306L5.07114 4.58075C5.13204 4.41473 5.2362 4.25303 5.38364 4.09566C5.53108 3.93829 5.74999 3.8596 6.04038 3.8596C6.33589 3.8596 6.55432 3.94053 6.69566 4.1024C6.83701 4.26426 6.90769 4.4423 6.90769 4.63654C6.90769 4.80641 6.85929 4.96185 6.76249 5.10288C6.6657 5.2439 6.5423 5.38012 6.3923 5.51154C6.0641 5.80769 5.85673 6.0439 5.77019 6.22019C5.68365 6.39647 5.64038 6.66217 5.64038 7.01729ZM6.00082 10.75C5.34386 10.75 4.72634 10.6253 4.14828 10.376C3.5702 10.1266 3.06736 9.78827 2.63975 9.36085C2.21213 8.93343 1.8736 8.43081 1.62416 7.85299C1.37472 7.27518 1.25 6.65779 1.25 6.00083C1.25 5.34386 1.37467 4.72634 1.624 4.14828C1.87333 3.5702 2.21171 3.06736 2.63913 2.63975C3.06655 2.21213 3.56917 1.8736 4.14699 1.62416C4.7248 1.37472 5.34218 1.25 5.99915 1.25C6.65612 1.25 7.27363 1.37467 7.8517 1.624C8.42978 1.87333 8.93262 2.21171 9.36023 2.63913C9.78784 3.06655 10.1264 3.56917 10.3758 4.14699C10.6253 4.7248 10.75 5.34218 10.75 5.99915C10.75 6.65612 10.6253 7.27363 10.376 7.8517C10.1266 8.42978 9.78827 8.93262 9.36085 9.36023C8.93343 9.78784 8.43081 10.1264 7.85299 10.3758C7.27518 10.6253 6.65779 10.75 6.00082 10.75ZM5.99999 9.99999C7.11665 9.99999 8.06249 9.61249 8.83749 8.83749C9.61249 8.06249 9.99999 7.11665 9.99999 5.99999C9.99999 4.88332 9.61249 3.93749 8.83749 3.16249C8.06249 2.38749 7.11665 1.99999 5.99999 1.99999C4.88332 1.99999 3.93749 2.38749 3.16249 3.16249C2.38749 3.93749 1.99999 4.88332 1.99999 5.99999C1.99999 7.11665 2.38749 8.06249 3.16249 8.83749C3.93749 9.61249 4.88332 9.99999 5.99999 9.99999Z"
fill="var(--color-content-brand-darker-accent-2)"
fill="var(--color-content-default-brand-secondary)"
/>
</g>
</svg>
@@ -69,7 +69,7 @@ export function InputWithCounterView({
}
}}
maxLength={maxLength}
className={`w-full h-[36px] px-[12px] py-[8px] bg-[var(--color-surface-default-primary)] border-2 border-[var(--color-border-default-tertiary)] rounded-[var(--measures-radius-medium,8px)] text-medium-paragraph text-[var(--color-content-default-primary)] placeholder:text-[var(--color-content-default-tertiary)] focus:outline-none ${inputClassName}`}
className={`w-full h-[36px] px-[12px] py-[8px] bg-[var(--color-surface-default-primary)] border-2 border-[var(--color-border-default-tertiary)] rounded-[var(--radius-400)] text-medium-paragraph text-[var(--color-content-default-primary)] placeholder:text-[var(--color-content-default-tertiary)] focus:outline-none ${inputClassName}`}
/>
</div>
@@ -31,8 +31,8 @@ function MultiSelectView({
// Size-based spacing
const gapClass = isSmall
? "gap-[var(--measures-spacing-200,8px)]"
: "gap-[var(--measures-spacing-300,12px)]";
? "gap-[var(--space-200)]"
: "gap-[var(--space-300)]";
const chipSize = size;
const selectedCount = options.filter((o) => o.state === "selected").length;
@@ -43,7 +43,7 @@ function MultiSelectView({
return (
<div
className={`flex flex-col ${isSmall ? "gap-[var(--measures-spacing-200,8px)]" : "gap-[var(--measures-spacing-300,12px)]"} items-start relative w-full ${className}`}
className={`flex flex-col ${isSmall ? "gap-[var(--space-200)]" : "gap-[var(--space-300)]"} items-start relative w-full ${className}`}
>
{/* Label using InputLabel component */}
{formHeader && label && (
@@ -133,12 +133,12 @@ function MultiSelectView({
className={
!addButtonText
? // Circular button with border (Rule style)
`${atLimit ? "cursor-not-allowed opacity-60" : "cursor-pointer hover:opacity-80"} bg-[var(--color-surface-default-transparent,rgba(0,0,0,0))] border-[1.25px] ${isInverse ? "border-[var(--color-border-default-primary,#141414)]" : "border-[var(--color-border-default-tertiary,#464646)]"} border-solid flex items-center justify-center ${isSmall ? "size-[30px]" : "size-[40px]"} rounded-[var(--measures-radius-full,9999px)] shrink-0 transition-opacity`
`${atLimit ? "cursor-not-allowed opacity-60" : "cursor-pointer hover:opacity-80"} bg-[var(--color-surface-default-transparent,rgba(0,0,0,0))] border-[1.25px] ${isInverse ? "border-[var(--color-border-default-primary,#141414)]" : "border-[var(--color-border-default-control)]"} border-solid flex items-center justify-center ${isSmall ? "size-[30px]" : "size-[40px]"} rounded-[var(--radius-full)] shrink-0 transition-opacity`
: // Text add control (default palette: white label + brand “+”; inverse: inverse primary for both)
`${atLimit ? "cursor-not-allowed opacity-60" : "cursor-pointer hover:opacity-80"} flex items-center justify-center overflow-hidden rounded-[var(--measures-radius-full,9999px)] shrink-0 transition-opacity ${
`${atLimit ? "cursor-not-allowed opacity-60" : "cursor-pointer hover:opacity-80"} flex items-center justify-center overflow-hidden rounded-[var(--radius-full)] shrink-0 transition-opacity ${
isSmall
? "gap-[var(--measures-spacing-100,4px)] px-[var(--measures-spacing-300,12px)] py-[var(--measures-spacing-200,8px)]"
: "gap-[var(--measures-spacing-150,6px)] px-[var(--space-400,16px)] py-[var(--measures-spacing-300,12px)]"
? "gap-[var(--space-100)] px-[var(--space-300)] py-[var(--space-200)]"
: "gap-[var(--space-150)] px-[var(--space-400)] py-[var(--space-300)]"
}`
}
>
@@ -151,7 +151,7 @@ function MultiSelectView({
xmlns="http://www.w3.org/2000/svg"
className={`shrink-0 ${
!addButtonText && isInverse
? "text-[var(--color-content-inverse-primary,black)]"
? "text-[var(--color-content-invert-primary,black)]"
: "text-[var(--color-content-default-brand-primary,#fefcc9)]"
}`}
>
@@ -165,9 +165,9 @@ function MultiSelectView({
</svg>
{addButtonText && (
<span
className={`font-medium ${isSmall ? "text-[length:var(--sizing-300,12px)] leading-[14px]" : "text-medium-label"} ${
className={`font-medium ${isSmall ? "text-[length:var(--sizing-300)] leading-[14px]" : "text-medium-label"} ${
isInverse
? "text-[color:var(--color-content-inverse-primary,black)]"
? "text-[color:var(--color-content-invert-primary,black)]"
: "text-[color:var(--color-content-default-primary,white)]"
}`}
>
@@ -54,14 +54,14 @@ const RadioButtonContainer = ({
// When checked, border is brand primary (but changes to invert tertiary on focus)
const defaultBorder = checked
? "border-[var(--color-border-default-brand-primary,#fdfaa8)]"
: "border-[var(--color-border-default-tertiary,#464646)]";
: "border-[var(--color-border-default-control)]";
// When focused and checked, border should be invert tertiary (#2d2d2d) per Figma
const focusBorder = checked
? "focus:border-[var(--color-content-invert-tertiary,#2d2d2d)]"
: "focus:border-[var(--color-border-default-tertiary,#464646)]";
: "focus:border-[var(--color-border-default-control)]";
return `${baseBox} bg-[var(--color-surface-default-primary)] border border-solid ${defaultBorder} hover:border-[var(--color-border-default-brand-primary,#fdfaa8)] ${focusBorder} focus:shadow-[0px_0px_0px_2px_var(--color-border-invert-primary,white),0px_0px_0px_4px_var(--color-border-default-primary,#141414)] focus:outline-none`;
return `${baseBox} bg-[var(--color-surface-default-primary)] border border-solid ${defaultBorder} hover:border-[var(--color-border-default-brand-primary,#fdfaa8)] ${focusBorder} focus:shadow-[var(--shadow-focus-invert)] focus:outline-none`;
}
// Inverse mode styles
@@ -83,7 +83,7 @@ const RadioButtonContainer = ({
? "focus:border-[var(--color-border-invert-primary,white)]"
: "focus:border-[var(--color-border-invert-primary,white)]";
return `${baseBox} bg-transparent border border-solid ${defaultBorder} ${hoverBorder} ${focusBorder} focus:shadow-[0px_0px_0px_2px_var(--color-border-default-primary,#141414),0px_0px_0px_4px_var(--color-border-invert-primary,white)] focus:outline-none`;
return `${baseBox} bg-transparent border border-solid ${defaultBorder} ${hoverBorder} ${focusBorder} focus:shadow-[var(--shadow-focus-default)] focus:outline-none`;
}
return baseBox;
@@ -93,7 +93,7 @@ const RadioButtonContainer = ({
// Label color
const labelColor = isInverse
? "var(--color-content-inverse-primary)"
? "var(--color-content-invert-primary)"
: "var(--color-content-default-primary)";
// Generate unique ID for accessibility if not provided
@@ -43,7 +43,7 @@ export function RadioGroupView({
<span
className={`text-small-paragraph ${
mode === "inverse"
? "text-[var(--color-content-inverse-primary)]"
? "text-[var(--color-content-invert-primary)]"
: "text-[var(--color-content-default-primary)]"
}`}
>
@@ -52,7 +52,7 @@ export function RadioGroupView({
<span
className={`text-small-paragraph ${
mode === "inverse"
? "text-[var(--color-content-inverse-secondary,#1f1f1f)]"
? "text-[var(--color-content-invert-secondary,#1f1f1f)]"
: "text-[var(--color-content-default-secondary,#b4b4b4)]"
}`}
>
@@ -11,9 +11,9 @@ interface SelectDropdownProps extends React.HTMLAttributes<HTMLDivElement> {
const SelectDropdown = forwardRef<HTMLDivElement, SelectDropdownProps>(
({ className = "", children, ariaLabel, ...props }, ref) => {
const menuClasses = `
bg-black
bg-[var(--color-surface-default-primary)]
border border-[var(--color-border-default-tertiary)]
rounded-[var(--measures-radius-medium)]
rounded-[var(--radius-400)]
shadow-lg
p-[4px]
min-w-[200px]
@@ -29,7 +29,6 @@ const SelectDropdown = forwardRef<HTMLDivElement, SelectDropdownProps>(
className={menuClasses}
role="listbox"
aria-label={ariaLabel}
style={{ backgroundColor: "#000000" }}
{...props}
>
{children}
@@ -109,7 +109,7 @@ export function SelectInputView({
.replace(/\s+/g, " ");
if (disabled) {
return `${baseClasses} bg-[var(--color-surface-default-secondary)] text-[var(--color-content-inverse-tertiary,#2d2d2d)] border-[var(--color-border-default-primary)] cursor-not-allowed opacity-40`;
return `${baseClasses} bg-[var(--color-surface-default-secondary)] text-[var(--color-content-invert-tertiary,#2d2d2d)] border-[var(--color-border-default-primary)] cursor-not-allowed opacity-40`;
}
if (error) {
@@ -118,16 +118,16 @@ export function SelectInputView({
if (state === "focus") {
// Focus state: secondary background, tertiary border, with focus ring
return `${baseClasses} bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-primary)] border border-solid border-[var(--color-border-default-tertiary)]`;
return `${baseClasses} bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-primary)] border border-solid border-[var(--color-border-default-control)]`;
}
if (state === "active" || isOpen) {
// Active state per Figma: secondary background, tertiary border
return `${baseClasses} bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-primary)] border-[var(--color-border-default-tertiary)]`;
return `${baseClasses} bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-primary)] border-[var(--color-border-default-control)]`;
}
// Default state per Figma: secondary background, primary border (subtle)
return `${baseClasses} bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-primary)] border-[var(--color-border-default-primary)]`;
return `${baseClasses} bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-primary)] border-[var(--color-border-default-control)]`;
};
const buttonClasses = getButtonClasses();
@@ -145,8 +145,8 @@ export function SelectInputView({
return (
<div className={containerClasses}>
{label && (
<div className="flex flex-wrap gap-[var(--measures-spacing-200,4px_8px)] items-baseline pr-[var(--measures-spacing-100,4px)] relative shrink-0 w-full">
<div className="flex gap-[var(--measures-spacing-050,2px)] items-center relative shrink-0">
<div className="flex flex-wrap gap-[var(--space-100)_var(--space-200)] items-baseline pr-[var(--space-100)] relative shrink-0 w-full">
<div className="flex gap-[var(--space-050)] items-center relative shrink-0">
<label id={labelId} className={labelClasses}>
{label}
</label>
@@ -214,7 +214,7 @@ export function SelectInputView({
</button>
{state === "focus" && (
<div
className="absolute border-2 border-solid border-[var(--color-border-inverse-primary)] inset-0 rounded-[8px] shadow-[0px_0px_0px_2px_var(--color-border-default-primary)] pointer-events-none z-10"
className="absolute border-2 border-solid border-[var(--color-border-invert-primary)] inset-0 rounded-[8px] shadow-[0px_0px_0px_2px_var(--color-border-default-primary)] pointer-events-none z-10"
aria-hidden="true"
/>
)}
@@ -269,7 +269,13 @@ export function SelectInputView({
</div>
{textHint && (
<div className="flex items-start relative shrink-0 w-full">
<p className="flex-[1_0_0] text-x-small-paragraph min-h-px min-w-px relative text-[color:var(--color-content-default-tertiary,#b4b4b4)]">
<p
className={`flex-[1_0_0] text-x-small-paragraph min-h-px min-w-px relative ${
ariaInvalid
? "text-[color:var(--color-content-default-negative-primary)]"
: "text-[color:var(--color-content-default-tertiary)]"
}`}
>
{hintDefault}
</p>
</div>
@@ -44,13 +44,13 @@ const SelectOptionContainer = forwardRef<HTMLDivElement, SelectOptionProps>(
transition-colors duration-150
${
selected
? "bg-[var(--color-surface-default-secondary)] rounded-[var(--measures-radius-small)]"
? "bg-[var(--color-surface-default-secondary)] rounded-[var(--radius-300)]"
: ""
}
${
disabled
? "opacity-50 cursor-not-allowed"
: "hover:!bg-[var(--color-surface-default-secondary)] hover:!rounded-[var(--measures-radius-small)]"
: "hover:!bg-[var(--color-surface-default-secondary)] hover:!rounded-[var(--radius-300)]"
}
${className}
`
@@ -69,7 +69,7 @@ const SwitchContainer = memo(
// Switch track styles based on propSwitch state
const getTrackStyles = useCallback(() => {
return propSwitch
? "bg-[var(--color-surface-inverse-tertiary)]"
? "bg-[var(--color-surface-invert-tertiary)]"
: "bg-[var(--color-surface-default-tertiary)]";
}, [propSwitch]);
@@ -81,7 +81,7 @@ const SwitchContainer = memo(
// Focus styles
const getFocusStyles = useCallback(() => {
if (state === "focus") {
return "shadow-[0_0_5px_3px_#3281F8] rounded-full";
return "shadow-[var(--shadow-focus-default)] rounded-full";
}
return "";
}, [state]);
@@ -98,7 +98,7 @@ const SwitchContainer = memo(
transition-all
duration-200
focus:outline-none
focus-visible:shadow-[0_0_5px_3px_#3281F8]
focus-visible:shadow-[var(--shadow-focus-default)]
focus-visible:rounded-full
${focusStyles}
${className}
@@ -123,9 +123,9 @@ const SwitchContainer = memo(
const thumbClasses = `
${thumbStyles}
w-[var(--measures-sizing-020)]
h-[var(--measures-sizing-020)]
rounded-[var(--measures-radius-xlarge)]
w-[var(--space-500)]
h-[var(--space-500)]
rounded-[var(--radius-500)]
transition-all
duration-200
shadow-sm
@@ -134,7 +134,7 @@ const SwitchContainer = memo(
.replace(/\s+/g, " ");
const labelClasses = `
ml-[var(--measures-spacing-008)]
ml-[var(--space-200)]
text-small-paragraph
text-[var(--color-content-default-primary)]
`
@@ -61,7 +61,7 @@ const TextAreaContainer = forwardRef<HTMLTextAreaElement, TextAreaProps>(
: "h-[60px] px-[12px] py-[8px] text-xx-small-paragraph",
label: "text-x-small-label",
container: "gap-[4px]",
radius: "var(--measures-radius-xsmall)",
radius: "var(--radius-200)",
},
medium: {
textarea:
@@ -70,13 +70,13 @@ const TextAreaContainer = forwardRef<HTMLTextAreaElement, TextAreaProps>(
: "h-[100px] px-[12px] py-[8px] text-small-paragraph",
label: "text-small-label",
container: "gap-[8px]",
radius: "var(--measures-radius-xsmall)",
radius: "var(--radius-200)",
},
large: {
textarea: "h-[150px] px-[12px] py-[8px] text-medium-paragraph",
label: "text-medium-label",
container: "gap-[12px]",
radius: "var(--measures-radius-small)",
radius: "var(--radius-300)",
},
};
@@ -90,13 +90,13 @@ const TextAreaContainer = forwardRef<HTMLTextAreaElement, TextAreaProps>(
if (disabled) {
return {
textarea:
"border-0 bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-tertiary,#b4b4b4)] cursor-not-allowed opacity-60 min-h-[356px] h-[356px] px-[var(--measures-spacing-300,12px)] py-[var(--space-250,10px)]",
"border-0 bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-tertiary,#b4b4b4)] cursor-not-allowed opacity-60 min-h-[356px] h-[356px] px-[var(--space-300)] py-[var(--space-250)]",
label: "text-[var(--color-content-default-secondary)]",
};
}
return {
textarea:
"border-0 bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] placeholder:text-[var(--color-content-default-tertiary,#b4b4b4)] min-h-[356px] h-[356px] px-[var(--measures-spacing-300,12px)] py-[var(--space-250,10px)] focus:outline-none focus:ring-0",
"border-0 bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] placeholder:text-[var(--color-content-default-tertiary,#b4b4b4)] min-h-[356px] h-[356px] px-[var(--space-300)] py-[var(--space-250)] focus:outline-none focus:ring-0",
label: "text-[var(--color-content-default-secondary)]",
};
}
@@ -111,7 +111,7 @@ const TextAreaContainer = forwardRef<HTMLTextAreaElement, TextAreaProps>(
}
return {
textarea:
"border-0 bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-tertiary,#b4b4b4)] placeholder:text-[var(--color-content-default-tertiary,#b4b4b4)] focus:text-[var(--color-content-default-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-default-tertiary)] focus:ring-inset",
"border-0 bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-tertiary,#b4b4b4)] placeholder:text-[var(--color-content-default-tertiary,#b4b4b4)] focus:text-[var(--color-content-default-primary)] focus:outline-none focus:ring-2 focus:ring-[var(--color-border-default-control)] focus:ring-inset",
label: "text-[var(--color-content-default-secondary)]",
};
}
@@ -119,7 +119,7 @@ const TextAreaContainer = forwardRef<HTMLTextAreaElement, TextAreaProps>(
if (disabled) {
return {
textarea:
"bg-[var(--color-content-default-secondary)] text-[var(--color-content-default-primary)] border border-[var(--color-border-default-tertiary)] cursor-not-allowed",
"bg-[var(--color-content-default-secondary)] text-[var(--color-content-default-primary)] border border-[var(--color-border-default-control)] cursor-not-allowed",
label: "text-[var(--color-content-default-secondary)]",
};
}
@@ -136,25 +136,25 @@ const TextAreaContainer = forwardRef<HTMLTextAreaElement, TextAreaProps>(
case "active":
return {
textarea:
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border border-[var(--color-border-default-tertiary)]",
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border border-[var(--color-border-default-control)]",
label: "text-[var(--color-content-default-secondary)]",
};
case "hover":
return {
textarea:
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border border-[var(--color-border-default-tertiary)] shadow-[0_0_0_2px_var(--color-border-default-tertiary)]",
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border border-[var(--color-border-default-control)] shadow-[0_0_0_2px_var(--color-border-default-control)]",
label: "text-[var(--color-content-default-secondary)]",
};
case "focus":
return {
textarea:
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border border-[var(--color-border-default-utility-info)] shadow-[0_0_5px_3px_#3281F8]",
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border border-[var(--color-border-default-control)] shadow-[var(--shadow-focus-default)]",
label: "text-[var(--color-content-default-secondary)]",
};
default:
return {
textarea:
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border border-[var(--color-border-default-tertiary)] hover:shadow-[0_0_0_2px_var(--color-border-default-tertiary)]",
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border border-[var(--color-border-default-control)] hover:shadow-[0_0_0_2px_var(--color-border-default-control)]",
label: "text-[var(--color-content-default-secondary)]",
};
}
@@ -176,7 +176,7 @@ const TextAreaContainer = forwardRef<HTMLTextAreaElement, TextAreaProps>(
const textareaClasses = `
scrollbar-design w-full transition-all duration-200 ease-in-out resize-none
${appearance === "embedded" || appearance === "compose" ? "rounded-[var(--radius-300,12px)]" : "border"}
${appearance === "embedded" || appearance === "compose" ? "rounded-[var(--radius-300)]" : "border"}
${appearance === "compose" ? "text-medium-paragraph" : currentSize.textarea}
${stateStyles.textarea}
${className}
@@ -31,15 +31,15 @@ export const TextAreaView = forwardRef<HTMLTextAreaElement, TextAreaViewProps>(
size: _size,
labelVariant: _labelVariant,
state: _state,
error: _error,
error = false,
...props
},
ref,
) => {
const labelEl = label ? (
formHeader ? (
<div className="flex flex-wrap gap-[var(--measures-spacing-200,4px_8px)] items-baseline pr-[var(--measures-spacing-100,4px)] relative shrink-0 w-full">
<div className="flex gap-[var(--measures-spacing-050,2px)] items-center relative shrink-0">
<div className="flex flex-wrap gap-[var(--space-100)_var(--space-200)] items-baseline pr-[var(--space-100)] relative shrink-0 w-full">
<div className="flex gap-[var(--space-050)] items-center relative shrink-0">
<label
id={labelId}
htmlFor={textareaId}
@@ -90,7 +90,13 @@ export const TextAreaView = forwardRef<HTMLTextAreaElement, TextAreaViewProps>(
</div>
{textHint ? (
<div className="flex items-start relative shrink-0 w-full">
<p className="flex-[1_0_0] text-x-small-paragraph min-h-px min-w-px relative text-[color:var(--color-content-default-tertiary,#b4b4b4)]">
<p
className={`flex-[1_0_0] text-x-small-paragraph min-h-px min-w-px relative ${
error
? "text-[color:var(--color-content-default-negative-primary)]"
: "text-[color:var(--color-content-default-tertiary)]"
}`}
>
{typeof textHint === "string" ? textHint : hintDefault}
</p>
</div>
@@ -83,13 +83,13 @@ const TextInputContainer = forwardRef<HTMLInputElement, TextInputProps>(
"h-[32px] px-[10px] py-[6px] text-[16px] md:text-[14px]",
label: "text-[12px] leading-[16px] font-medium",
container: "gap-[6px]",
radius: "var(--measures-radius-200,8px)",
radius: "var(--radius-200)",
}
: {
input: "h-[40px] px-[12px] py-[8px] text-[16px]",
label: "text-[14px] leading-[20px] font-medium",
container: "gap-[8px]",
radius: "var(--measures-radius-200,8px)",
radius: "var(--radius-200)",
};
// State styles based on Figma designs
@@ -102,7 +102,7 @@ const TextInputContainer = forwardRef<HTMLInputElement, TextInputProps>(
if (disabled) {
return {
input:
"bg-[var(--color-surface-default-secondary)] text-[var(--color-content-inverse-tertiary,#2d2d2d)] border border-solid border-[var(--color-border-default-primary)] cursor-not-allowed",
"bg-[var(--color-surface-default-secondary)] text-[var(--color-content-invert-tertiary,#2d2d2d)] border border-solid border-[var(--color-border-default-primary)] cursor-not-allowed",
label: "text-[var(--color-content-default-secondary)]",
inputWrapper: "relative",
focusRing: "",
@@ -127,7 +127,7 @@ const TextInputContainer = forwardRef<HTMLInputElement, TextInputProps>(
? "font-medium leading-[20px]"
: "font-normal leading-[24px]";
return {
input: `bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border-2 border-solid border-[var(--color-border-default-tertiary)] ${filledStyles}`,
input: `bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] border-2 border-solid border-[var(--color-border-default-control)] ${filledStyles}`,
label: "text-[var(--color-content-default-secondary)]",
inputWrapper: "relative",
focusRing: "",
@@ -138,11 +138,11 @@ const TextInputContainer = forwardRef<HTMLInputElement, TextInputProps>(
? "font-medium leading-[20px]"
: "font-normal leading-[24px]";
return {
input: `bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-primary)] border border-solid border-[var(--color-border-default-tertiary)] ${filledStyles}`,
input: `bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-primary)] border border-solid border-[var(--color-border-default-control)] ${filledStyles}`,
label: "text-[var(--color-content-default-secondary)]",
inputWrapper: "relative",
focusRing:
"absolute border-2 border-solid border-[var(--color-border-inverse-primary)] inset-0 rounded-[var(--measures-radius-200,8px)] shadow-[0px_0px_0px_2px_var(--color-border-default-primary)] pointer-events-none",
"absolute inset-0 rounded-[var(--radius-200)] shadow-[var(--shadow-focus-default)] pointer-events-none",
};
}
default: {
@@ -151,7 +151,7 @@ const TextInputContainer = forwardRef<HTMLInputElement, TextInputProps>(
: "font-normal leading-[24px]";
// Default state uses primary border (matches Figma - border color same as background, so border is subtle)
return {
input: `bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-primary)] border border-solid border-[var(--color-border-default-primary)] ${filledStyles}`,
input: `bg-[var(--color-surface-default-secondary)] text-[var(--color-content-default-primary)] border border-solid border-[var(--color-border-default-control)] ${filledStyles}`,
label: "text-[var(--color-content-default-secondary)]",
inputWrapper: "relative",
focusRing: "",
@@ -43,8 +43,8 @@ export const TextInputView = forwardRef<HTMLInputElement, TextInputViewProps>(
) => {
const labelEl = label ? (
formHeader ? (
<div className="flex flex-wrap gap-[var(--measures-spacing-200,4px_8px)] items-baseline pr-[var(--measures-spacing-100,4px)] relative shrink-0 w-full">
<div className="flex gap-[var(--measures-spacing-050,2px)] items-center relative shrink-0">
<div className="flex flex-wrap gap-[var(--space-100)_var(--space-200)] items-baseline pr-[var(--space-100)] relative shrink-0 w-full">
<div className="flex gap-[var(--space-050)] items-center relative shrink-0">
<label
id={labelId}
htmlFor={inputId}
@@ -106,7 +106,13 @@ export const TextInputView = forwardRef<HTMLInputElement, TextInputViewProps>(
</div>
{textHint && (
<div className="flex items-start relative shrink-0 w-full">
<p className="flex-[1_0_0] text-x-small-paragraph min-h-px min-w-px relative text-[color:var(--color-content-default-tertiary,#b4b4b4)]">
<p
className={`flex-[1_0_0] text-x-small-paragraph min-h-px min-w-px relative ${
error
? "text-[color:var(--color-content-default-negative-primary)]"
: "text-[color:var(--color-content-default-tertiary)]"
}`}
>
{typeof textHint === "string" ? textHint : hintDefault}
</p>
</div>
@@ -33,7 +33,7 @@ const ToggleContainer = forwardRef<HTMLButtonElement, ToggleProps>(
// Size styles - single size with specific dimensions
const sizeStyles = {
toggle: "h-[var(--measures-sizing-032)] px-[16px] py-[8px] gap-[4px]",
toggle: "h-[var(--space-800)] px-[16px] py-[8px] gap-[4px]",
label: "text-[12px] leading-[16px]",
};
@@ -61,7 +61,7 @@ const ToggleContainer = forwardRef<HTMLButtonElement, ToggleProps>(
case "focus":
return {
toggle:
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] shadow-[0_0_5px_1px_#3281F8]",
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] shadow-[var(--shadow-focus-default)]",
label: "text-[var(--color-content-default-secondary)]",
};
default:
@@ -82,7 +82,7 @@ const ToggleContainer = forwardRef<HTMLButtonElement, ToggleProps>(
case "focus":
return {
toggle:
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] shadow-[0_0_5px_1px_#3281F8]",
"bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] shadow-[var(--shadow-focus-default)]",
label: "text-[var(--color-content-default-secondary)]",
};
default:
@@ -112,7 +112,7 @@ const ToggleContainer = forwardRef<HTMLButtonElement, ToggleProps>(
transition-all
duration-200
focus:outline-none
focus-visible:shadow-[0_0_5px_1px_#3281F8]
focus-visible:shadow-[var(--shadow-focus-default)]
${!checked ? "hover:!bg-[var(--color-surface-default-secondary)]" : ""}
flex
items-center
@@ -34,13 +34,13 @@ const ToggleGroupContainer = memo(
const getPositionStyles = useCallback((pos: string): string => {
switch (pos) {
case "left":
return "rounded-l-[var(--measures-radius-medium)] rounded-r-none";
return "rounded-l-[var(--radius-400)] rounded-r-none";
case "middle":
return "rounded-none";
case "right":
return "rounded-r-[var(--measures-radius-medium)] rounded-l-none";
return "rounded-r-[var(--radius-400)] rounded-l-none";
default:
return "rounded-[var(--measures-radius-medium)]";
return "rounded-[var(--radius-400)]";
}
}, []);
@@ -50,7 +50,7 @@ const ToggleGroupContainer = memo(
case "hover":
return "bg-[var(--color-magenta-magenta100)] text-[var(--color-content-default-primary)]";
case "focus":
return "bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] shadow-[0_0_5px_1px_#3281F8]";
return "bg-[var(--color-surface-default-primary)] text-[var(--color-content-default-primary)] shadow-[var(--shadow-focus-default)]";
case "selected":
return "bg-[var(--color-magenta-magenta100)] text-[var(--color-content-default-primary)] shadow-[inset_0_0_0_1px_var(--color-border-default-secondary)]";
case "default":
@@ -104,9 +104,9 @@ const ToggleGroupContainer = memo(
const toggleClasses = `
${positionStyles}
${stateStyles}
py-[var(--measures-spacing-008)]
px-[var(--measures-spacing-008)]
gap-[var(--measures-spacing-008)]
py-[var(--space-200)]
px-[var(--space-200)]
gap-[var(--space-200)]
font-medium
text-[12px]
leading-[12px]
@@ -114,7 +114,7 @@ const ToggleGroupContainer = memo(
transition-all
duration-200
focus:outline-none
focus-visible:shadow-[0_0_5px_1px_#3281F8]
focus-visible:shadow-[var(--shadow-focus-default)]
hover:bg-[var(--color-magenta-magenta100)]
flex
items-center
@@ -3,6 +3,7 @@
import { memo } from "react";
import { useTranslation } from "../../../contexts/MessagesContext";
import UploadView from "./Upload.view";
import type { UploadStateValue } from "../../../../lib/propNormalization";
import type { UploadProps } from "./Upload.types";
/**
@@ -12,6 +13,8 @@ import type { UploadProps } from "./Upload.types";
const UploadContainer = memo<UploadProps>(
({
active = true,
state,
hasLabel,
label,
showHelpIcon = true,
hintText,
@@ -19,10 +22,13 @@ const UploadContainer = memo<UploadProps>(
className = "",
}) => {
const t = useTranslation("controlsChrome");
const resolvedState: UploadStateValue =
state ?? (active ? "default" : "disabled");
return (
<UploadView
active={active}
state={resolvedState}
hasLabel={hasLabel ?? Boolean(label)}
label={label}
showHelpIcon={showHelpIcon}
hintText={hintText ?? t("uploadHintDefault")}
+14 -1
View File
@@ -1,11 +1,23 @@
import type { UploadStateValue } from "../../../../lib/propNormalization";
export interface UploadProps {
/**
* Whether the upload component is in active state.
* When active, button has white background with black text.
* When inactive, button has dark background with gray text.
* Prefer `state`. `active={false}` maps to `disabled`.
* @default true
*/
active?: boolean;
/**
* Figma state axis. Disabled dims the control and turns the button off.
*/
state?: UploadStateValue;
/**
* Show the label. The upload step uses the control with this off.
* Defaults to true when `label` is set.
*/
hasLabel?: boolean;
/**
* Label text displayed above the upload component
*/
@@ -31,7 +43,8 @@ export interface UploadProps {
}
export interface UploadViewProps {
active: boolean;
state: UploadStateValue;
hasLabel: boolean;
label?: string;
showHelpIcon: boolean;
hintText: string;
+20 -9
View File
@@ -5,7 +5,8 @@ import InputLabel from "../../type/InputLabel";
import type { UploadViewProps } from "./Upload.types";
function UploadView({
active = true,
state,
hasLabel,
label,
showHelpIcon = true,
hintText,
@@ -14,7 +15,8 @@ function UploadView({
onClick,
className = "",
}: UploadViewProps) {
const isActive = active;
const isActive = state !== "disabled";
const isDisabled = state === "disabled";
// Button styles based on active state
const buttonBgClass = isActive
@@ -37,10 +39,10 @@ function UploadView({
return (
<div
className={`flex flex-col gap-[var(--measures-spacing-300,12px)] items-start relative w-full ${className}`}
className={`flex flex-col gap-[var(--space-300)] items-start relative w-full ${className}`}
>
{/* Label using InputLabel component */}
{label && (
{hasLabel && label ? (
<InputLabel
label={label}
helpIcon={showHelpIcon}
@@ -49,15 +51,24 @@ function UploadView({
size="s"
palette="default"
/>
)}
) : null}
{/* Upload container — max width per create-flow spec */}
<div className="bg-[var(--color-surface-default-secondary,#141414)] mx-auto flex w-full max-w-[474px] shrink-0 items-center justify-center gap-[24px] rounded-[var(--measures-radius-200,8px)] px-[var(--measures-spacing-600,24px)] py-[var(--measures-spacing-1200,48px)]">
<div
className={`bg-[var(--color-surface-default-secondary,#141414)] mx-auto flex w-full max-w-[474px] shrink-0 items-center justify-center gap-[24px] rounded-[var(--radius-200)] px-[var(--space-600)] py-[var(--space-1200)] ${
state === "error"
? "border border-[var(--color-border-default-utility-negative)]"
: ""
} ${state === "focus" ? "shadow-[var(--shadow-focus-default)]" : ""}`}
>
{/* Upload button */}
<button
type="button"
onClick={onClick}
className={`${buttonBgClass} flex gap-[var(--measures-spacing-150,6px)] items-center justify-center overflow-clip px-[var(--space-400,16px)] py-[var(--measures-spacing-300,12px)] rounded-[var(--measures-radius-full,9999px)] shrink-0 hover:opacity-80 transition-opacity`}
disabled={isDisabled}
className={`${buttonBgClass} flex gap-[var(--space-150)] items-center justify-center overflow-clip px-[var(--space-400)] py-[var(--space-300)] rounded-[var(--radius-full)] shrink-0 hover:opacity-80 transition-opacity ${
state === "hover" ? "opacity-80" : ""
} ${state === "active" ? "scale-[0.98]" : ""}`}
aria-label={uploadAriaLabel}
>
{/* Upload icon */}
@@ -98,7 +109,7 @@ function UploadView({
</div>
{/* Button text */}
<div
className={`flex flex-col font-medium justify-center leading-[0] relative shrink-0 text-[length:var(--sizing-400,16px)] whitespace-nowrap ${buttonTextColor}`}
className={`flex flex-col font-medium justify-center leading-[0] relative shrink-0 text-[length:var(--sizing-400)] whitespace-nowrap ${buttonTextColor}`}
>
<p className="leading-[20px]">{uploadButtonLabel}</p>
</div>
@@ -106,7 +117,7 @@ function UploadView({
{/* Description text */}
<div
className={`flex flex-[1_0_0] flex-col font-normal h-[32px] justify-center leading-[0] min-h-px min-w-px relative text-[length:var(--sizing-350,14px)] ${descriptionTextColor}`}
className={`flex flex-[1_0_0] flex-col font-normal h-[32px] justify-center leading-[0] min-h-px min-w-px relative text-[length:var(--sizing-350)] ${descriptionTextColor}`}
>
<p className="leading-[20px] whitespace-pre-wrap">{hintText}</p>
</div>
@@ -11,20 +11,20 @@ const SIZE_CLASSES: Record<
> = {
s: {
header:
"min-h-[88px] gap-[var(--spacing-scale-016)] px-[var(--spacing-scale-016)] py-[var(--spacing-scale-020)] items-center",
"min-h-[88px] gap-[var(--space-400)] px-[var(--space-400)] py-[var(--space-500)] items-center",
title: "text-[14px] font-medium leading-[18px]",
subhead: "text-x-small-label",
},
/** Figma: Layout / Accordion — Medium (22135-890258; header gap/px/py + Large/Label 18/24). */
m: {
header:
"min-h-[104px] gap-[var(--spacing-scale-024)] px-[var(--spacing-scale-016)] py-[var(--spacing-scale-024)] items-center",
"min-h-[104px] gap-[var(--space-600)] px-[var(--space-400)] py-[var(--space-600)] items-center",
title: "text-large-label font-medium leading-6",
subhead: "text-[14px] leading-[18px] font-medium",
},
l: {
header:
"min-h-[135px] gap-[var(--spacing-scale-048)] px-[var(--spacing-scale-016)] py-[var(--spacing-scale-032)] items-center",
"min-h-[135px] gap-[var(--space-1200)] px-[var(--space-400)] py-[var(--space-800)] items-center",
/** Figma Large: X Large Label 24 Regular, lh 28 (21842-2869). */
title: "text-x-large-label font-normal leading-7",
subhead: "text-large-label",
@@ -32,9 +32,9 @@ const SIZE_CLASSES: Record<
};
const PANEL_CLASSES: Record<AccordionSizeValue, string> = {
s: "px-[var(--spacing-scale-016)] pb-[var(--spacing-scale-020)] text-small-paragraph text-[var(--color-content-default-secondary,#d2d2d2)]",
m: "px-[var(--spacing-scale-016)] pb-[var(--spacing-scale-024)] text-medium-paragraph text-[var(--color-content-default-secondary,#d2d2d2)]",
l: "px-[var(--spacing-scale-016)] pb-[var(--spacing-scale-032)] text-[18px] font-normal leading-[26px] text-[var(--color-content-default-secondary,#d2d2d2)]",
s: "px-[var(--space-400)] pb-[var(--space-500)] text-small-paragraph text-[var(--color-content-default-secondary,#d2d2d2)]",
m: "px-[var(--space-400)] pb-[var(--space-600)] text-medium-paragraph text-[var(--color-content-default-secondary,#d2d2d2)]",
l: "px-[var(--space-400)] pb-[var(--space-800)] text-[18px] font-normal leading-[26px] text-[var(--color-content-default-secondary,#d2d2d2)]",
};
function withLgClasses(base: string, lg: string): string {
@@ -122,7 +122,7 @@ function AccordionView({
onClick={onToggle}
className={`flex w-full ${sizeClass.header} text-left focus:outline-none focus-visible:ring-2 focus-visible:ring-[var(--color-content-default-primary)] focus-visible:ring-offset-2 focus-visible:ring-offset-[var(--color-surface-default-secondary)]`}
>
<span className="flex min-w-0 flex-1 flex-col gap-[var(--spacing-scale-004)]">
<span className="flex min-w-0 flex-1 flex-col gap-[var(--space-100)]">
<span
className={`text-[var(--color-content-default-primary,white)] ${sizeClass.title}`}
>
+4 -4
View File
@@ -39,7 +39,7 @@ type RowLayout = {
export const listEntrySizeLayout: Record<ListSize, RowLayout> = {
s: {
shell: `${rowShellBase} min-h-0 gap-1.5 py-[var(--spacing-scale-012)]`,
shell: `${rowShellBase} min-h-0 gap-1.5 py-[var(--space-300)]`,
textCol: "flex min-w-0 flex-1 flex-col items-start justify-center",
title:
"min-w-0 flex-1 text-sm font-medium leading-[18px] text-[var(--color-content-default-primary)]",
@@ -48,7 +48,7 @@ export const listEntrySizeLayout: Record<ListSize, RowLayout> = {
rowFigma: FIGMA_LIST_ENTRY_ROW.s,
},
m: {
shell: `${rowShellBase} min-h-16 gap-[var(--spacing-scale-008)] py-[var(--spacing-scale-012)]`,
shell: `${rowShellBase} min-h-16 gap-[var(--space-200)] py-[var(--space-300)]`,
textCol: "flex min-w-0 flex-1 flex-col items-start justify-center",
title:
"min-w-0 flex-1 text-large-label text-[var(--color-content-default-primary)]",
@@ -57,9 +57,9 @@ export const listEntrySizeLayout: Record<ListSize, RowLayout> = {
rowFigma: FIGMA_LIST_ENTRY_ROW.m,
},
l: {
shell: `${rowShellBase} min-h-16 gap-[var(--spacing-scale-012)] py-[var(--spacing-scale-016)]`,
shell: `${rowShellBase} min-h-16 gap-[var(--space-300)] py-[var(--space-400)]`,
textCol:
"flex min-w-0 flex-1 flex-col items-start justify-center gap-[var(--spacing-scale-004)]",
"flex min-w-0 flex-1 flex-col items-start justify-center gap-[var(--space-100)]",
title:
"min-w-0 flex-1 text-x-large-label text-[var(--color-content-default-primary)]",
description:
@@ -23,14 +23,14 @@ function layoutFor(
size === "s"
? "px-[var(--space-500)]"
: "px-[var(--space-1200)]";
const containerClasses = `flex gap-[var(--space-300)] items-center ${padH} pb-[var(--space-500)] pt-[var(--space-400)] rounded-tl-[var(--radius-200,8px)] rounded-tr-[var(--radius-200,8px)] border-solid`;
const containerClasses = `flex gap-[var(--space-300)] items-center ${padH} pb-[var(--space-500)] pt-[var(--space-400)] rounded-tl-[var(--radius-200)] rounded-tr-[var(--radius-200)] border-solid`;
if (size === "s") {
return {
containerClasses,
titleClasses:
"text-[14px] leading-[18px] font-medium tracking-[0%]",
descriptionClasses:
"text-small-paragraph mt-[var(--spacing-scale-004)]",
"text-small-paragraph mt-[var(--space-100)]",
};
}
return {
@@ -38,27 +38,27 @@ function layoutFor(
titleClasses:
"text-large-label",
descriptionClasses:
"text-large-paragraph mt-[var(--spacing-scale-004)]",
"text-large-paragraph mt-[var(--space-100)]",
};
}
if (size === "s") {
return {
containerClasses:
"flex gap-[var(--space-300)] items-center p-[var(--space-300)] rounded-[var(--radius-200,8px)] border-solid",
"flex gap-[var(--space-300)] items-center p-[var(--space-300)] rounded-[var(--radius-200)] border-solid",
titleClasses:
"text-[14px] leading-[18px] font-medium tracking-[0%]",
descriptionClasses:
"text-small-paragraph mt-[var(--spacing-scale-004)]",
"text-small-paragraph mt-[var(--space-100)]",
};
}
return {
containerClasses:
"flex gap-[var(--space-300)] items-center px-[var(--space-600)] py-[var(--space-400)] rounded-[var(--radius-200,8px)] border-solid",
"flex gap-[var(--space-300)] items-center px-[var(--space-600)] py-[var(--space-400)] rounded-[var(--radius-200)] border-solid",
titleClasses:
"text-medium-label",
descriptionClasses:
"text-medium-paragraph mt-[var(--spacing-scale-004)]",
"text-medium-paragraph mt-[var(--space-100)]",
};
}
+1 -1
View File
@@ -81,7 +81,7 @@ export function AlertView({
width="20"
height="20"
>
<rect width="20" height="20" fill="#D9D9D9" />
<rect width="20" height="20" fill="var(--color-gray-200)" />
</mask>
<g mask="url(#mask0_21296_8285)">
<path
+1 -1
View File
@@ -72,7 +72,7 @@ export function CreateView({
</div>
) : null}
<div className="scrollbar-design flex min-h-0 flex-1 flex-col gap-[var(--spacing-scale-024)] overflow-x-clip overflow-y-auto px-[24px] pb-6 pt-0">
<div className="scrollbar-design flex min-h-0 flex-1 flex-col gap-[var(--space-600)] overflow-x-clip overflow-y-auto px-[24px] pb-6 pt-0">
{children}
</div>
@@ -9,7 +9,7 @@ export type CreateModalBackdropVariant = "default" | "blurredYellow";
const backdropOverlayClasses: Record<CreateModalBackdropVariant, string> = {
default: "fixed inset-0 bg-black/50 z-[9998]",
blurredYellow:
"fixed inset-0 z-[9998] bg-[var(--color-surface-inverse-brand-primary)]/85 backdrop-blur-md supports-[backdrop-filter]:bg-[var(--color-surface-inverse-brand-primary)]/75",
"fixed inset-0 z-[9998] bg-[var(--color-surface-invert-brand-primary)]/85 backdrop-blur-md supports-[backdrop-filter]:bg-[var(--color-surface-invert-brand-primary)]/75",
};
export type CreateModalFrameViewProps = {
@@ -56,7 +56,7 @@ export function CreateModalFrameView({
aria-modal="true"
aria-label={ariaLabel}
aria-labelledby={ariaLabelledBy}
className={`flex min-h-0 max-h-[90vh] w-full max-w-[560px] shrink-0 flex-col overflow-hidden rounded-[var(--radius-500,20px)] bg-[var(--color-surface-default-primary)] shadow-[0px_0px_48px_0px_rgba(0,0,0,0.1)] z-[9999] ${className}`}
className={`flex min-h-0 max-h-[90vh] w-full max-w-[560px] shrink-0 flex-col overflow-hidden rounded-[var(--radius-500)] bg-[var(--color-surface-default-primary)] shadow-[0px_0px_48px_0px_rgba(0,0,0,0.1)] z-[9999] ${className}`}
onClick={(e) => e.stopPropagation()}
>
{children}
+1 -1
View File
@@ -46,7 +46,7 @@ export const DialogView = memo(function DialogView({
</div>
{children ? (
<div className="scrollbar-design flex min-h-0 flex-1 flex-col gap-[var(--spacing-scale-024)] overflow-x-clip overflow-y-auto px-[24px] pb-6 pt-0">
<div className="scrollbar-design flex min-h-0 flex-1 flex-col gap-[var(--space-600)] overflow-x-clip overflow-y-auto px-[24px] pb-6 pt-0">
{children}
</div>
) : null}
+3 -3
View File
@@ -5,9 +5,9 @@ import ModalHeader from "../ModalHeader";
import type { LoginBackdropVariant, LoginViewProps } from "./Login.types";
const backdropClasses: Record<LoginBackdropVariant, string> = {
solid: "bg-[var(--color-surface-inverse-brand-primary)]",
solid: "bg-[var(--color-surface-invert-brand-primary)]",
blurredYellow:
"bg-[var(--color-surface-inverse-brand-primary)]/85 backdrop-blur-md supports-[backdrop-filter]:bg-[var(--color-surface-inverse-brand-primary)]/75",
"bg-[var(--color-surface-invert-brand-primary)]/85 backdrop-blur-md supports-[backdrop-filter]:bg-[var(--color-surface-invert-brand-primary)]/75",
};
export function LoginView({
@@ -43,7 +43,7 @@ export function LoginView({
aria-modal="true"
aria-label={ariaLabel}
aria-labelledby={ariaLabelledBy}
className={`flex min-h-0 max-h-[90vh] w-full max-w-[560px] shrink-0 flex-col overflow-hidden rounded-[var(--radius-500,20px)] bg-[var(--color-surface-default-primary)] shadow-[0px_0px_48px_0px_rgba(0,0,0,0.1)] z-[9999] ${className}`}
className={`flex min-h-0 max-h-[90vh] w-full max-w-[560px] shrink-0 flex-col overflow-hidden rounded-[var(--radius-500)] bg-[var(--color-surface-default-primary)] shadow-[0px_0px_48px_0px_rgba(0,0,0,0.1)] z-[9999] ${className}`}
onClick={(e) => e.stopPropagation()}
>
<ModalHeader onClose={onClose} showMoreOptionsButton={false} />
+3 -3
View File
@@ -183,7 +183,7 @@ export default function LoginForm({
return (
<div className="flex flex-col gap-6 pt-2">
<div className="flex flex-col gap-3">
<div className="relative flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-[var(--color-surface-inverse-brand-primary)]">
<div className="relative flex h-12 w-12 shrink-0 items-center justify-center rounded-full bg-[var(--color-surface-invert-brand-primary)]">
<MailIconInline />
</div>
<ContentLockup
@@ -272,7 +272,7 @@ export default function LoginForm({
buttonType="filled"
palette="default"
disabled={submitting}
className="w-full !justify-center text-center px-[var(--spacing-scale-016)] py-[var(--spacing-scale-012)]"
className="w-full !justify-center text-center px-[var(--space-400)] py-[var(--space-300)]"
>
{t("sendMagicLink")}
</Button>
@@ -284,7 +284,7 @@ export default function LoginForm({
palette="default"
disabled={submitting}
onClick={onDismiss}
className="w-full !justify-center text-center px-[var(--spacing-scale-016)] py-[var(--spacing-scale-012)]"
className="w-full !justify-center text-center px-[var(--space-400)] py-[var(--space-300)]"
>
{t("continueWithoutSaving")}
</Button>
@@ -29,12 +29,13 @@ export function ModalFooterView({
return (
<div
className={`h-[64px] bg-[var(--color-surface-default-primary)] rounded-bl-[var(--radius-300,12px)] rounded-br-[var(--radius-300,12px)] shrink-0 relative ${className}`}
className={`h-[64px] bg-[var(--color-surface-default-primary)] rounded-bl-[var(--radius-300)] rounded-br-[var(--radius-300)] shrink-0 relative ${className}`}
>
{showRemoveButton && (
<div className="absolute left-[16px] top-[12px]">
<Button
buttonType="danger"
buttonType="outline"
danger
palette="default"
size="medium"
onClick={onRemove}
+3 -3
View File
@@ -130,8 +130,8 @@ export const ShareView = memo(function ShareView({
copied={linkCopied}
circleClassName={
linkCopied
? "border-2 border-[#444444] bg-[#333333]"
: "border-[#444444] bg-[#333333] group-hover:border-2 group-hover:border-[var(--color-border-default-positive-primary)] group-hover:bg-[#444444]"
? "border-2 border-[var(--color-gray-600)] bg-[var(--color-gray-700)]"
: "border-[var(--color-gray-600)] bg-[var(--color-gray-700)] group-hover:border-2 group-hover:border-[var(--color-border-default-positive-primary)] group-hover:bg-[var(--color-gray-600)]"
}
icon={
<ShareAssetIcon
@@ -162,7 +162,7 @@ export const ShareView = memo(function ShareView({
<ShareChannelTile
label={emailLabel}
onClick={onEmailShare}
circleClassName="border-[var(--color-surface-default-brand-kiwi)] bg-[var(--color-surface-default-brand-kiwi)] group-hover:brightness-110"
circleClassName="border-[var(--color-surface-invert-brand-kiwi)] bg-[var(--color-surface-invert-brand-kiwi)] group-hover:brightness-110"
icon={<ShareAssetIcon name="mail" width={24} height={24} />}
/>
</div>
@@ -23,7 +23,7 @@ const TooltipContainer = memo<TooltipProps>(
return <>{children}</>;
}
const tooltipClasses = `absolute z-50 bg-[var(--color-surface-default-primary)] px-[var(--space-300)] py-[var(--space-200)] rounded-[var(--radius-300,12px)] shadow-[0px_0px_48px_0px_rgba(0,0,0,0.1)] flex items-center whitespace-nowrap ${
const tooltipClasses = `absolute z-50 bg-[var(--color-surface-default-primary)] px-[var(--space-300)] py-[var(--space-200)] rounded-[var(--radius-300)] shadow-[0px_0px_48px_0px_rgba(0,0,0,0.1)] flex items-center whitespace-nowrap ${
position === "top" ? "bottom-full mb-[7px]" : "top-full mt-[7px]"
} left-1/2 -translate-x-1/2 ${isVisible ? "opacity-100 visible" : "opacity-0 invisible pointer-events-none"} transition-all duration-200`;
@@ -28,7 +28,7 @@ export function CreateFlowFooterView({
<div className={CREATE_FLOW_PAGE_GUTTER_CLASS}>
<div className={`mx-auto w-full ${contentMaxClass}`}>
{progressBar && (
<div className="pt-[var(--spacing-measures-spacing-300,12px)]">
<div className="pt-[var(--space-300)]">
<ProportionBar
progress={proportionBarProgress}
variant={proportionBarVariant}
@@ -36,12 +36,12 @@ export function CreateFlowFooterView({
</div>
)}
<div className="flex items-center justify-between py-[var(--spacing-measures-spacing-300,12px)] gap-[var(--spacing-measures-spacing-300,12px)]">
<div className="flex items-center justify-between py-[var(--space-300)] gap-[var(--space-300)]">
<Button
buttonType="ghost"
palette="default"
size="xsmall"
className="!text-x-small-label md:!text-small-label !px-[var(--spacing-measures-spacing-200,8px)] md:!px-[var(--spacing-measures-spacing-250,10px)] !py-[var(--spacing-measures-spacing-200,8px)] md:!py-[var(--spacing-measures-spacing-250,10px)]"
className="!text-x-small-label md:!text-small-label !px-[var(--space-200)] md:!px-[var(--space-250)] !py-[var(--space-200)] md:!py-[var(--space-250)]"
onClick={onBackClick}
disabled={!onBackClick}
>
@@ -8,10 +8,10 @@ import type { CreateFlowTopNavViewProps } from "./CreateFlowTopNav.types";
import { CREATE_FLOW_PAGE_GUTTER_CLASS } from "../../../(app)/create/components/createFlowLayoutTokens";
const outlineButtonClass =
"md:!text-x-small-label !text-xx-small-label !px-[var(--spacing-scale-006,6px)] md:!px-[var(--spacing-scale-008,8px)] !py-[6px] md:!py-[8px] !border md:!border-[1.5px]";
"md:!text-x-small-label !text-xx-small-label !px-[var(--space-150)] md:!px-[var(--space-200)] !py-[6px] md:!py-[8px] !border md:!border-[1.5px]";
const exitButtonFigmaClass =
"!rounded-[var(--radius-measures-radius-full,9999px)] !border-[1.25px] !px-[var(--spacing-measures-spacing-250,10px)] !py-[var(--spacing-measures-spacing-200,8px)] md:!text-x-small-label";
"!rounded-[var(--radius-full)] !border-[1.25px] !px-[var(--space-250)] !py-[var(--space-200)] md:!text-x-small-label";
function KebabIcon({ className = "" }: { className?: string }) {
return (
@@ -110,7 +110,7 @@ export function CreateFlowTopNavView({
aria-expanded={exportMenuOpen}
aria-controls={exportMenuId}
onClick={() => setExportMenuOpen((o) => !o)}
className={`justify-center gap-[var(--spacing-scale-002,2px)] !pl-[var(--spacing-scale-012,12px)] !pr-[var(--spacing-scale-006,6px)] md:!pr-[var(--spacing-scale-006,6px)] ${outlineButtonClass}`}
className={`justify-center gap-[var(--space-050)] !pl-[var(--space-300)] !pr-[var(--space-150)] md:!pr-[var(--space-150)] ${outlineButtonClass}`}
>
<span>{exportLabel}</span>
<svg
@@ -129,7 +129,7 @@ export function CreateFlowTopNavView({
</svg>
</Button>
{exportMenuOpen ? (
<div className="absolute right-0 top-[calc(100%+var(--spacing-measures-spacing-200,8px))] z-[300]">
<div className="absolute right-0 top-[calc(100%+var(--space-200))] z-[300]">
<Popover
id={exportMenuId}
menuAriaLabel={exportPopoverMenuAriaLabel}
@@ -230,13 +230,13 @@ export function CreateFlowTopNavView({
aria-label={bannerAriaLabel}
>
<nav
className={`flex items-center justify-between mx-auto w-full max-w-[1920px] ${CREATE_FLOW_PAGE_GUTTER_CLASS} py-[var(--spacing-measures-spacing-300,12px)] md:py-[var(--spacing-measures-spacing-016,16px)]`}
className={`flex items-center justify-between mx-auto w-full max-w-[1920px] ${CREATE_FLOW_PAGE_GUTTER_CLASS} py-[var(--space-300)] md:py-[var(--space-400)]`}
role="navigation"
aria-label={navAriaLabel}
>
<Logo size="createFlow" wordmark palette={buttonPalette} />
<div className="flex flex-wrap items-center justify-end gap-[var(--spacing-scale-012,12px)]">
<div className="flex flex-wrap items-center justify-end gap-[var(--space-300)]">
{useKebabMenu ? (
<div className="relative" ref={actionsWrapRef}>
<Button
@@ -249,12 +249,12 @@ export function CreateFlowTopNavView({
aria-expanded={actionsMenuOpen}
aria-controls={actionsMenuId}
onClick={() => setActionsMenuOpen((open) => !open)}
className={`!px-[var(--spacing-scale-010,10px)] ${outlineButtonClass}`}
className={`!px-[var(--space-250)] ${outlineButtonClass}`}
>
<KebabIcon />
</Button>
{actionsMenuOpen ? (
<div className="absolute right-0 top-[calc(100%+var(--spacing-measures-spacing-200,8px))] z-[300]">
<div className="absolute right-0 top-[calc(100%+var(--space-200))] z-[300]">
<Popover id={actionsMenuId} menuAriaLabel={actionsMenuAriaLabel}>
{actionMenuItems.map((item, index) => (
<ListItem
+26 -26
View File
@@ -53,39 +53,39 @@ const Footer = memo(() => {
<footer className="bg-[var(--color-surface-default-primary)] w-full">
<div
className="mx-auto flex max-w-[1920px] flex-col
gap-[var(--spacing-measures-spacing-040)]
px-[var(--spacing-measures-spacing-016)]
py-[var(--spacing-measures-spacing-040)]
md:gap-[var(--spacing-measures-spacing-024)]
md:px-[var(--spacing-measures-spacing-032)]
md:py-[var(--spacing-measures-spacing-024)]
lg:gap-[var(--spacing-measures-spacing-060,60px)]
lg:px-[var(--spacing-scale-064)]
lg:py-[var(--spacing-scale-096)]"
gap-[var(--space-1000)]
px-[var(--space-400)]
py-[var(--space-1000)]
md:gap-[var(--space-600)]
md:px-[var(--space-800)]
md:py-[var(--space-600)]
lg:gap-[var(--space-1500)]
lg:px-[var(--space-1800)]
lg:py-[var(--space-2400)]"
>
<div
className="flex w-full flex-col
gap-[var(--spacing-scale-032)]
md:gap-[var(--spacing-scale-048)]
lg:gap-[var(--spacing-measures-spacing-060,60px)]"
gap-[var(--space-800)]
md:gap-[var(--space-1200)]
lg:gap-[var(--space-1500)]"
>
<Logo size="footer" wordmark />
<div
className="flex w-full flex-col
gap-[var(--spacing-scale-048)]
gap-[var(--space-1200)]
md:flex-row md:items-start md:justify-between md:gap-0"
>
<div
className="order-2 flex flex-col
gap-[var(--spacing-scale-048)]
gap-[var(--space-1200)]
md:order-1 md:max-w-[min(100%,334px)]
lg:max-w-[min(100%,334px)]
lg:gap-[var(--spacing-scale-064)]"
lg:gap-[var(--space-1800)]"
>
<div
className="flex flex-col
gap-[var(--spacing-measures-spacing-016,16px)]"
gap-[var(--space-400)]"
>
<div className={orgNameClass}>{t("organization.name")}</div>
<a
@@ -98,11 +98,11 @@ const Footer = memo(() => {
<div
className="flex flex-col
gap-[var(--spacing-measures-spacing-016,16px)]"
gap-[var(--space-400)]"
>
<a
href={t("social.bluesky.url")}
className={`group inline-flex w-fit max-w-full items-center gap-[var(--spacing-measures-spacing-06,6px)] ${linkFocusClass} p-2 -m-2 cursor-pointer`}
className={`group inline-flex w-fit max-w-full items-center gap-[var(--space-150)] ${linkFocusClass} p-2 -m-2 cursor-pointer`}
aria-label={t("social.bluesky.ariaLabel")}
>
{/* eslint-disable-next-line @next/next/no-img-element -- social logo */}
@@ -117,7 +117,7 @@ const Footer = memo(() => {
</a>
<a
href={t("social.gitea.url")}
className={`group inline-flex w-fit max-w-full items-center gap-[var(--spacing-measures-spacing-06,6px)] ${linkFocusClass} p-2 -m-2 cursor-pointer`}
className={`group inline-flex w-fit max-w-full items-center gap-[var(--space-150)] ${linkFocusClass} p-2 -m-2 cursor-pointer`}
aria-label={t("social.gitea.ariaLabel")}
>
{/* eslint-disable-next-line @next/next/no-img-element -- social icon */}
@@ -132,7 +132,7 @@ const Footer = memo(() => {
</a>
<a
href={t("social.mastodon.url")}
className={`group inline-flex w-fit max-w-full items-center gap-[var(--spacing-measures-spacing-06,6px)] ${linkFocusClass} p-2 -m-2 cursor-pointer`}
className={`group inline-flex w-fit max-w-full items-center gap-[var(--space-150)] ${linkFocusClass} p-2 -m-2 cursor-pointer`}
aria-label={t("social.mastodon.ariaLabel")}
>
{/* eslint-disable-next-line @next/next/no-img-element -- social icon */}
@@ -153,9 +153,9 @@ const Footer = memo(() => {
aria-label={tChrome("footerAriaLabel")}
className="order-1 flex w-full max-w-full flex-col
items-start
gap-[var(--spacing-scale-032)]
gap-[var(--space-800)]
md:order-2 md:ml-auto md:w-auto md:items-end md:text-right
md:gap-[var(--spacing-scale-032)]"
md:gap-[var(--space-800)]"
>
<Link href="/use-cases" className={primaryLinkClass}>
{t("navigation.useCases")}
@@ -174,9 +174,9 @@ const Footer = memo(() => {
<div
className="flex w-full flex-col
gap-[var(--spacing-scale-032)]
gap-[var(--space-800)]
text-[var(--color-content-default-primary)]
md:flex-row md:items-start md:justify-between md:gap-[var(--spacing-scale-040)]
md:flex-row md:items-start md:justify-between md:gap-[var(--space-1000)]
md:whitespace-nowrap
md:text-x-small-paragraph
lg:text-small-paragraph"
@@ -198,12 +198,12 @@ const Footer = memo(() => {
</p>
<div
className="flex w-full min-w-0 flex-col flex-wrap
gap-[var(--spacing-scale-032)]
gap-[var(--space-800)]
text-small-paragraph
text-[var(--color-content-default-primary)]
md:max-w-[min(100%,396px)]
md:flex-row md:flex-nowrap md:content-center md:items-center md:justify-end
md:gap-[var(--spacing-scale-040)]
md:gap-[var(--space-1000)]
md:text-x-small-paragraph
lg:max-w-none
lg:gap-10
+5 -5
View File
@@ -31,15 +31,15 @@ const Menu = memo<MenuProps>(
string
> = {
"X Small":
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-001)] rounded-[var(--spacing-scale-004)]",
"px-[var(--space-100)] py-[var(--space-100)] gap-[var(--space-025)] rounded-[var(--space-100)]",
Small:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-004)] rounded-[var(--spacing-scale-004)]",
"px-[var(--space-100)] py-[var(--space-100)] gap-[var(--space-100)] rounded-[var(--space-100)]",
Medium:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-004)] rounded-[var(--spacing-scale-004)]",
"px-[var(--space-100)] py-[var(--space-100)] gap-[var(--space-100)] rounded-[var(--space-100)]",
Large:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-012)] rounded-[var(--spacing-scale-004)]",
"px-[var(--space-100)] py-[var(--space-100)] gap-[var(--space-300)] rounded-[var(--space-100)]",
"X Large":
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-012)] rounded-[var(--spacing-scale-004)]",
"px-[var(--space-100)] py-[var(--space-100)] gap-[var(--space-300)] rounded-[var(--space-100)]",
};
const baseStyles = `flex items-center ${sizeStyles[size]} ${className}`;
@@ -33,16 +33,16 @@ const MenuItemContainer = memo<MenuItemProps>(
string
> = {
"X Small": reducedPadding
? "px-[var(--spacing-scale-004)] py-[var(--spacing-scale-002)]"
: "px-[var(--spacing-scale-004)] py-[var(--spacing-scale-002)]",
Small: "px-[var(--spacing-scale-004)] py-[var(--spacing-scale-002)]",
? "px-[var(--space-100)] py-[var(--space-050)]"
: "px-[var(--space-100)] py-[var(--space-050)]",
Small: "px-[var(--space-100)] py-[var(--space-050)]",
Medium: reducedPadding
? "px-[var(--spacing-scale-002)] py-[var(--spacing-scale-008)] h-[32px]"
: "px-[var(--spacing-scale-008)] py-[var(--spacing-scale-008)] h-[32px]",
? "px-[var(--space-050)] py-[var(--space-200)] h-[32px]"
: "px-[var(--space-200)] py-[var(--space-200)] h-[32px]",
Large:
"px-[var(--spacing-scale-016)] py-[var(--spacing-scale-016)] h-[44px]",
"px-[var(--space-400)] py-[var(--space-400)] h-[44px]",
"X Large":
"px-[var(--spacing-scale-016)] py-[var(--spacing-scale-016)] h-[44px]",
"px-[var(--space-400)] py-[var(--space-400)] h-[44px]",
};
// Text styles based on Figma specifications
@@ -74,11 +74,11 @@ const MenuItemContainer = memo<MenuItemProps>(
const inverseModeStyles: Record<"default" | "hover" | "selected", string> =
{
default:
"bg-transparent text-[var(--color-content-inverse-primary,black)] hover:bg-[var(--color-surface-inverse-brand-secondary)] hover:text-[var(--color-content-inverse-primary,black)]",
"bg-transparent text-[var(--color-content-invert-primary,black)] hover:bg-[var(--color-surface-invert-brand-secondary)] hover:text-[var(--color-content-invert-primary,black)]",
hover:
"bg-[var(--color-surface-inverse-brand-secondary)] text-[var(--color-content-inverse-primary,black)]",
"bg-[var(--color-surface-invert-brand-secondary)] text-[var(--color-content-invert-primary,black)]",
selected:
"border border-[var(--color-border-default-primary,#141414)] text-[var(--color-content-inverse-primary,black)] bg-transparent hover:bg-[var(--color-surface-inverse-brand-secondary)]",
"border border-[var(--color-border-default-primary,#141414)] text-[var(--color-content-invert-primary,black)] bg-transparent hover:bg-[var(--color-surface-invert-brand-secondary)]",
};
// Get state styles based on mode
@@ -86,7 +86,7 @@ const MenuItemContainer = memo<MenuItemProps>(
mode === "inverse" ? inverseModeStyles : defaultModeStyles;
// Base styles
const baseStyles = `inline-flex items-center whitespace-nowrap ${sizeStyles[size]} ${textStyles[size]} rounded-[var(--radius-measures-radius-full)] transition-all duration-200 ease-in-out cursor-pointer`;
const baseStyles = `inline-flex items-center whitespace-nowrap ${sizeStyles[size]} ${textStyles[size]} rounded-[var(--radius-full)] transition-all duration-200 ease-in-out cursor-pointer`;
// Interactive styles
const interactiveStyles =
@@ -30,9 +30,9 @@ const NavigationItemContainer = memo<NavigationItemProps>(
// Size styles
const sizeStyles: Record<string, string> = {
default:
"px-[var(--spacing-scale-016)] py-[var(--spacing-scale-016)] gap-[var(--spacing-scale-004)]",
"px-[var(--space-400)] py-[var(--space-400)] gap-[var(--space-100)]",
xsmall:
"px-[var(--spacing-scale-004)] py-[var(--spacing-scale-002)] gap-[var(--spacing-scale-004)]",
"px-[var(--space-100)] py-[var(--space-050)] gap-[var(--space-100)]",
};
// Text styles based on size
@@ -42,7 +42,7 @@ const NavigationItemContainer = memo<NavigationItemProps>(
xsmall: "text-xx-small-label",
};
const baseStyles = `inline-flex items-center ${sizeStyles[size]} rounded-[var(--radius-measures-radius-full)] ${textStyles[size]} transition-all duration-200 cursor-pointer`;
const baseStyles = `inline-flex items-center ${sizeStyles[size]} rounded-[var(--radius-full)] ${textStyles[size]} transition-all duration-200 cursor-pointer`;
// Determine which variant to use
let finalVariant = variant;
@@ -32,16 +32,16 @@ export const avatarImages = avatarImageSources.map((src, index) => ({
/** Padding/type that tracks lg/xl Menu sizes without cloning the items per breakpoint. */
const NAV_ITEM_RESPONSIVE_CLASS =
"lg:px-[var(--spacing-scale-016)] lg:py-[var(--spacing-scale-016)] lg:h-[44px] lg:text-medium-label xl:text-x-large-label";
"lg:px-[var(--space-400)] lg:py-[var(--space-400)] lg:h-[44px] lg:text-medium-label xl:text-x-large-label";
const FOLDER_NAV_ITEM_RESPONSIVE_CLASS =
"md:px-[var(--spacing-scale-008)] md:py-[var(--spacing-scale-008)] md:h-[32px] md:text-x-small-label lg:px-[var(--spacing-scale-016)] lg:py-[var(--spacing-scale-016)] lg:h-[44px] lg:text-medium-label xl:text-x-large-label";
"md:px-[var(--space-200)] md:py-[var(--space-200)] md:h-[32px] md:text-x-small-label lg:px-[var(--space-400)] lg:py-[var(--space-400)] lg:h-[44px] lg:text-medium-label xl:text-x-large-label";
const CREATE_RULE_RESPONSIVE_CLASS =
"lg:p-[var(--spacing-scale-012)] lg:gap-[var(--spacing-scale-006)] lg:text-medium-label xl:p-[var(--spacing-scale-016)] xl:gap-[var(--spacing-scale-008)] xl:text-x-large-label";
"lg:p-[var(--space-300)] lg:gap-[var(--space-150)] lg:text-medium-label xl:p-[var(--space-400)] xl:gap-[var(--space-200)] xl:text-x-large-label";
const FOLDER_CREATE_RULE_RESPONSIVE_CLASS =
"md:p-[var(--spacing-scale-008)] md:gap-[var(--spacing-scale-002)] md:text-x-small-label lg:p-[var(--spacing-scale-012)] lg:gap-[var(--spacing-scale-006)] lg:text-medium-label xl:p-[var(--spacing-scale-016)] xl:gap-[var(--spacing-scale-008)] xl:text-x-large-label";
"md:p-[var(--space-200)] md:gap-[var(--space-050)] md:text-x-small-label lg:p-[var(--space-300)] lg:gap-[var(--space-150)] lg:text-medium-label xl:p-[var(--space-400)] xl:gap-[var(--space-200)] xl:text-x-large-label";
const TopContainer = memo<TopProps>(
({ folderTop = false, loggedIn = false, profile = false, logIn = true }) => {
@@ -182,8 +182,8 @@ const TopContainer = memo<TopProps>(
size="small"
className={
folderTop
? "md:-space-x-[9px] lg:-space-x-[var(--spacing-scale-010)] xl:-space-x-[13px]"
: "lg:-space-x-[var(--spacing-scale-010)] xl:-space-x-[13px]"
? "md:-space-x-[9px] lg:-space-x-[var(--space-250)] xl:-space-x-[13px]"
: "lg:-space-x-[var(--space-250)] xl:-space-x-[13px]"
}
>
{avatarImageSources.map((src, index) => (
@@ -194,8 +194,8 @@ const TopContainer = memo<TopProps>(
size="small"
className={
folderTop
? "md:h-[var(--spacing-scale-018)] md:w-[var(--spacing-scale-018)] lg:h-[var(--spacing-scale-024)] lg:w-[var(--spacing-scale-024)] xl:h-[var(--spacing-scale-032)] xl:w-[var(--spacing-scale-032)]"
: "lg:h-[var(--spacing-scale-024)] lg:w-[var(--spacing-scale-024)] xl:h-[var(--spacing-scale-032)] xl:w-[var(--spacing-scale-032)]"
? "md:h-[var(--sizing-450)] md:w-[var(--sizing-450)] lg:h-[var(--space-600)] lg:w-[var(--space-600)] xl:h-[var(--space-800)] xl:w-[var(--space-800)]"
: "lg:h-[var(--space-600)] lg:w-[var(--space-600)] xl:h-[var(--space-800)] xl:w-[var(--space-800)]"
}
/>
))}
+9 -9
View File
@@ -23,7 +23,7 @@ function TopView({
const t = useTranslation(folderTop ? "homeHeader" : "header");
const loginControl = logIn ? (
<Menu size="X Small" className="lg:gap-[var(--spacing-scale-012)]">
<Menu size="X Small" className="lg:gap-[var(--space-300)]">
{renderLoginButton()}
</Menu>
) : null;
@@ -42,11 +42,11 @@ function TopView({
aria-label={t("ariaLabels.homePageNavigationHeader")}
>
<nav
className="relative mx-auto flex h-[50px] items-end justify-between pl-[var(--spacing-scale-008)] pr-[var(--spacing-scale-016)] pt-[var(--spacing-scale-010)] sm:h-[62px] sm:px-[var(--spacing-scale-010)] sm:pr-[var(--spacing-scale-020)] sm:pt-[var(--spacing-scale-010)] md:h-[68px] md:px-[var(--spacing-scale-016)] md:pr-[var(--spacing-scale-032)] md:pt-[var(--spacing-scale-016)] lg:h-[68px] lg:pl-[var(--spacing-scale-024)] lg:pr-[var(--spacing-scale-056)] lg:pt-[var(--spacing-scale-016)] xl:h-[88px] xl:pl-[var(--spacing-scale-048)] xl:pr-[var(--spacing-scale-056)] xl:pt-[var(--spacing-scale-024)]"
className="relative mx-auto flex h-[50px] items-end justify-between pl-[var(--space-200)] pr-[var(--space-400)] pt-[var(--space-250)] sm:h-[62px] sm:px-[var(--space-250)] sm:pr-[var(--space-500)] sm:pt-[var(--space-250)] md:h-[68px] md:px-[var(--space-400)] md:pr-[var(--space-800)] md:pt-[var(--space-400)] lg:h-[68px] lg:pl-[var(--space-600)] lg:pr-[var(--space-1400)] lg:pt-[var(--space-400)] xl:h-[88px] xl:pl-[var(--space-1200)] xl:pr-[var(--space-1400)] xl:pt-[var(--space-600)]"
role="navigation"
aria-label={t("ariaLabels.mainNavigation")}
>
<div className="HeaderTab header-breakpoint-transition relative flex h-[var(--spacing-scale-040)] w-fit min-w-0 items-center self-end overflow-visible rounded-tl-[var(--radius-measures-radius-medium)] rounded-tr-[var(--radius-measures-radius-medium)] bg-[var(--color-surface-inverse-brand-primary)] pl-[var(--spacing-scale-012)] pr-[var(--spacing-scale-012)] sm:mr-[var(--spacing-scale-008)] sm:h-[52px] sm:w-auto sm:flex-1 sm:rounded-t-[var(--radius-measures-radius-xlarge)] sm:pr-[var(--spacing-scale-006)] md:h-[52px] md:min-w-0 md:rounded-t-[var(--radius-measures-radius-xlarge)] md:pl-[var(--spacing-scale-024)] md:pr-[var(--spacing-scale-012)] lg:mr-[var(--spacing-scale-024)] lg:h-[52px] lg:rounded-t-[var(--radius-measures-radius-xlarge)] lg:pl-[var(--spacing-scale-024)] lg:pr-[var(--spacing-scale-048)] xl:mr-[var(--spacing-scale-032)] xl:h-[64px] xl:rounded-t-[var(--radius-measures-radius-xlarge)] xl:pl-[var(--spacing-scale-032)] xl:pr-[var(--spacing-scale-120)]">
<div className="HeaderTab header-breakpoint-transition relative flex h-[var(--space-1000)] w-fit min-w-0 items-center self-end overflow-visible rounded-tl-[var(--radius-400)] rounded-tr-[var(--radius-400)] bg-[var(--color-surface-invert-brand-primary)] pl-[var(--space-300)] pr-[var(--space-300)] sm:mr-[var(--space-200)] sm:h-[52px] sm:w-auto sm:flex-1 sm:rounded-t-[var(--radius-500)] sm:pr-[var(--space-150)] md:h-[52px] md:min-w-0 md:rounded-t-[var(--radius-500)] md:pl-[var(--space-600)] md:pr-[var(--space-300)] lg:mr-[var(--space-600)] lg:h-[52px] lg:rounded-t-[var(--radius-500)] lg:pl-[var(--space-600)] lg:pr-[var(--space-1200)] xl:mr-[var(--space-800)] xl:h-[64px] xl:rounded-t-[var(--radius-500)] xl:pl-[var(--space-800)] xl:pr-[var(--space-3000)]">
<div className="relative z-[1] shrink-0">
<Logo
size={logoSize}
@@ -56,12 +56,12 @@ function TopView({
</div>
<div
className="relative z-[1] shrink-0 md:absolute md:top-1/2 md:left-[calc(50vw-var(--spacing-scale-016))] md:-translate-x-1/2 md:-translate-y-1/2 lg:left-[calc(50vw-var(--spacing-scale-024))] xl:left-[calc(50vw-var(--spacing-scale-048))]"
className="relative z-[1] shrink-0 md:absolute md:top-1/2 md:left-[calc(50vw-var(--space-400))] md:-translate-x-1/2 md:-translate-y-1/2 lg:left-[calc(50vw-var(--space-600))] xl:left-[calc(50vw-var(--space-1200))]"
data-top="nav"
>
<Menu
size="X Small"
className="md:gap-[var(--spacing-scale-004)] lg:gap-[var(--spacing-scale-012)]"
className="md:gap-[var(--space-100)] lg:gap-[var(--space-300)]"
>
{renderNavigationItems()}
</Menu>
@@ -91,7 +91,7 @@ function TopView({
</div>
<div
className="flex shrink-0 items-center gap-[var(--spacing-scale-004)] self-center md:gap-[var(--spacing-scale-010)]"
className="flex shrink-0 items-center gap-[var(--space-100)] self-center md:gap-[var(--space-250)]"
data-top="auth"
>
{loginControl}
@@ -123,7 +123,7 @@ function TopView({
aria-label={t("ariaLabels.mainNavigationHeader")}
>
<nav
className="grid w-full grid-cols-[auto_minmax(0,1fr)_auto] items-center px-[var(--spacing-scale-016)] py-[var(--spacing-scale-008)] sm:px-[var(--spacing-measures-spacing-016)] md:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] lg:px-[var(--spacing-measures-spacing-64,64px)] lg:py-[var(--spacing-scale-016)]"
className="grid w-full grid-cols-[auto_minmax(0,1fr)_auto] items-center px-[var(--space-400)] py-[var(--space-200)] sm:px-[var(--space-400)] md:grid-cols-[minmax(0,1fr)_auto_minmax(0,1fr)] lg:px-[var(--space-1800)] lg:py-[var(--space-400)]"
role="navigation"
aria-label={t("ariaLabels.mainNavigation")}
>
@@ -141,14 +141,14 @@ function TopView({
>
<Menu
size="X Small"
className="min-w-0 lg:gap-[var(--spacing-scale-012)]"
className="min-w-0 lg:gap-[var(--space-300)]"
>
{renderNavigationItems()}
</Menu>
</div>
<div
className="flex shrink-0 items-center justify-self-end gap-[var(--spacing-scale-004)] md:gap-[var(--spacing-measures-spacing-010)] lg:gap-[var(--spacing-measures-spacing-004)]"
className="flex shrink-0 items-center justify-self-end gap-[var(--space-100)] md:gap-[var(--space-250)] lg:gap-[var(--space-100)]"
data-top="auth"
>
{loginControl}
@@ -65,7 +65,7 @@ export function ProportionBarView({
aria-label={ariaLabelText}
>
{/* Background layer - 3 segments */}
<div className="absolute inset-0 flex gap-[var(--spacing-scale-008)] px-[4px]">
<div className="absolute inset-0 flex gap-[var(--space-200)] px-[4px]">
<div className="flex-1 h-full bg-[var(--color-surface-default-secondary)] rounded-l-[var(--radius-full)]" />
<div className="flex-1 h-full bg-[var(--color-surface-default-secondary)]" />
<div className="flex-1 h-full bg-[var(--color-surface-default-secondary)] rounded-r-[var(--radius-full)]" />
@@ -77,7 +77,7 @@ export function ProportionBarView({
only the outermost left/right edges of the whole bar can round to match the
background capsule.
*/}
<div className="absolute inset-0 flex gap-[var(--spacing-scale-008)] px-[4px] overflow-hidden">
<div className="absolute inset-0 flex gap-[var(--space-200)] px-[4px] overflow-hidden">
{/* First section - for 1-X: (X+1)/6 filled, for 2-X and 3-X: fully filled */}
<div className="flex-1 h-full relative">
{fullSegments === 1 ? (
@@ -10,7 +10,7 @@ import type { StepperProps } from "./Stepper.types";
const StepperContainer = memo<StepperProps>(
({ active = 1, totalSteps = 5, className = "" }) => {
const stepperClasses = `flex gap-[var(--spacing-scale-012)] items-center relative`;
const stepperClasses = `flex gap-[var(--space-300)] items-center relative`;
return (
<StepperView
@@ -37,8 +37,8 @@ export function StepperView({
cx="6"
cy="6"
r="5.5"
fill="var(--color-surface-inverse-secondary)"
stroke="var(--color-surface-inverse-secondary)"
fill="var(--color-surface-invert-secondary)"
stroke="var(--color-surface-invert-secondary)"
strokeWidth="1"
/>
</svg>
@@ -22,9 +22,9 @@ function FaqAccordionView({
return (
<section
aria-labelledby={headingId}
className={`bg-[var(--color-surface-default-secondary)] px-[var(--spacing-scale-004)] py-[var(--spacing-scale-032)] md:px-[var(--spacing-scale-096)] md:py-[var(--spacing-scale-064)] lg:px-[var(--spacing-scale-160)] lg:py-[var(--spacing-scale-096)] ${className}`.trim()}
className={`bg-[var(--color-surface-default-secondary)] px-[var(--space-100)] py-[var(--space-800)] md:px-[var(--space-2400)] md:py-[var(--space-1800)] lg:px-[var(--space-4000)] lg:py-[var(--space-2400)] ${className}`.trim()}
>
<div className="mx-auto flex w-full flex-col items-center gap-[var(--spacing-scale-096)] md:gap-[var(--spacing-scale-040)]">
<div className="mx-auto flex w-full flex-col items-center gap-[var(--space-2400)] md:gap-[var(--space-1000)]">
<h2
id={headingId}
className="w-full text-center font-bricolage-grotesque text-[length:var(--text-large-heading)] font-bold leading-[length:var(--text-large-heading--line-height)] text-[var(--color-content-default-brand-primary,#fefcc9)] lg:text-[length:var(--text-x-large-heading)] lg:leading-[length:var(--text-x-large-heading--line-height)] xl:text-[length:var(--text-xx-large-heading)] xl:leading-[length:var(--text-xx-large-heading--line-height)] xl:tracking-[var(--text-xx-large-heading--letter-spacing)]"
@@ -62,17 +62,17 @@ const AskOrganizerContainer = memo<AskOrganizerProps>(
const sectionPadding =
resolvedVariant === "compact"
? "py-[var(--spacing-scale-016)] px-[var(--spacing-scale-016)] md:py-[var(--spacing-scale-032)] md:px-[var(--spacing-scale-032)]"
? "py-[var(--space-400)] px-[var(--space-400)] md:py-[var(--space-800)] md:px-[var(--space-800)]"
: resolvedVariant === "use-case-detail" || resolvedVariant === "inverse"
? "w-full py-[var(--spacing-scale-032)] px-[var(--spacing-scale-032)] md:py-[var(--spacing-scale-096)] md:px-[var(--spacing-scale-064)]"
: "py-[var(--spacing-scale-040)] px-[var(--spacing-scale-032)] md:py-[var(--spacing-scale-096)] md:px-[var(--spacing-scale-064)]";
? "w-full py-[var(--space-800)] px-[var(--space-800)] md:py-[var(--space-2400)] md:px-[var(--space-1800)]"
: "py-[var(--space-1000)] px-[var(--space-800)] md:py-[var(--space-2400)] md:px-[var(--space-1800)]";
const contentGap =
resolvedVariant === "compact"
? "gap-[var(--spacing-scale-020)]"
? "gap-[var(--space-500)]"
: resolvedVariant === "use-case-detail"
? "gap-[var(--spacing-scale-040)]"
: "gap-[var(--spacing-scale-040)]";
? "gap-[var(--space-1000)]"
: "gap-[var(--space-1000)]";
const labelledBy = title ? "ask-organizer-headline" : undefined;
@@ -47,13 +47,13 @@ function AskOrganizerView({
/>
<div
className={`${buttonContainerClass} flex-wrap gap-y-[var(--spacing-scale-016)]`}
className={`${buttonContainerClass} flex-wrap gap-y-[var(--space-400)]`}
>
<Button
size="small"
buttonType="filled"
palette={buttonPalette}
className="!px-[var(--spacing-scale-010)] md:!px-[var(--spacing-scale-016)] md:!py-[var(--spacing-scale-012)] md:!text-medium-label"
className="!px-[var(--space-250)] md:!px-[var(--space-400)] md:!py-[var(--space-300)] md:!text-medium-label"
onClick={onContactClick}
ariaLabel={ctaAriaLabel}
data-testid="ask-organizer-cta"
+3 -3
View File
@@ -25,10 +25,10 @@ function BookView({
return (
<section
aria-labelledby={headingId}
className={`px-[var(--spacing-scale-008)] py-[var(--spacing-scale-064)] md:px-[var(--spacing-scale-064)] lg:px-[var(--spacing-scale-160)] lg:py-[var(--spacing-scale-064)] ${className}`.trim()}
className={`px-[var(--space-200)] py-[var(--space-1800)] md:px-[var(--space-1800)] lg:px-[var(--space-4000)] lg:py-[var(--space-1800)] ${className}`.trim()}
>
<div className="mx-auto flex w-full max-w-[1440px] flex-col items-center">
<div className="flex w-full flex-col items-center gap-[var(--spacing-scale-032)] rounded-[var(--radius-measures-radius-xlarge,20px)] bg-[var(--color-surface-default-secondary)] p-[var(--spacing-scale-048)] shadow-[0_0_48px_rgba(0,0,0,0.1)] md:flex-row md:items-center lg:gap-[var(--spacing-scale-040)] lg:p-[var(--spacing-scale-064)] xl:mx-auto xl:max-w-[1280px] xl:gap-[var(--spacing-scale-032)] xl:p-[var(--spacing-scale-048)]">
<div className="flex w-full flex-col items-center gap-[var(--space-800)] rounded-[var(--radius-500)] bg-[var(--color-surface-default-secondary)] p-[var(--space-1200)] shadow-[0_0_48px_rgba(0,0,0,0.1)] md:flex-row md:items-center lg:gap-[var(--space-1000)] lg:p-[var(--space-1800)] xl:mx-auto xl:max-w-[1280px] xl:gap-[var(--space-800)] xl:p-[var(--space-1200)]">
<div className="relative aspect-[375/580] w-full shrink-0 overflow-hidden rounded-[4px] shadow-[0_0_24px_rgba(0,0,0,0.25)] md:aspect-auto md:h-[495px] md:w-[320px]">
{/* eslint-disable-next-line @next/next/no-img-element -- marketing cover art */}
<img
@@ -37,7 +37,7 @@ function BookView({
className="size-full object-cover"
/>
</div>
<div className="flex min-w-0 flex-1 flex-col gap-[var(--spacing-scale-016)] lg:gap-[var(--spacing-scale-024)] xl:gap-[var(--spacing-scale-020)]">
<div className="flex min-w-0 flex-1 flex-col gap-[var(--space-400)] lg:gap-[var(--space-600)] xl:gap-[var(--space-500)]">
<ContentLockup
variant="book"
alignment="left"
@@ -22,9 +22,9 @@ function CardStepsView({
type="application/ld+json"
dangerouslySetInnerHTML={{ __html: schemaJson }}
/>
<section className="bg-transparent py-[var(--spacing-scale-032)] px-[var(--spacing-scale-020)] sm:py-[var(--spacing-scale-048)] sm:px-[var(--spacing-scale-032)] lg:py-[var(--spacing-scale-064)] lg:px-[var(--spacing-scale-064)] xl:py-[var(--spacing-scale-076)] xl:px-[var(--spacing-scale-064)]">
<section className="bg-transparent py-[var(--space-800)] px-[var(--space-500)] sm:py-[var(--space-1200)] sm:px-[var(--space-800)] lg:py-[var(--space-1800)] lg:px-[var(--space-1800)] xl:py-[var(--space-2100)] xl:px-[var(--space-1800)]">
<div className="max-w-[var(--spacing-measures-max-width-lg)] mx-auto">
<div className="grid grid-cols-1 gap-y-[var(--spacing-scale-024)] sm:gap-y-[var(--spacing-scale-032)] lg:gap-y-[var(--spacing-scale-056)]">
<div className="grid grid-cols-1 gap-y-[var(--space-600)] sm:gap-y-[var(--space-800)] lg:gap-y-[var(--space-1400)]">
<div>
<SectionHeader
variant="multi-line"
@@ -35,7 +35,7 @@ function CardStepsView({
/>
</div>
<div className="grid grid-cols-1 gap-y-[var(--spacing-scale-024)] lg:grid-cols-3 lg:gap-[var(--spacing-scale-024)]">
<div className="grid grid-cols-1 gap-y-[var(--space-600)] lg:grid-cols-3 lg:gap-[var(--space-600)]">
{steps.map((item, index) => (
<Step
key={index}
@@ -23,18 +23,18 @@ function ContentBannerGuideView({
return (
<section
className="relative w-full overflow-clip px-[var(--spacing-scale-020)] py-[var(--spacing-scale-024)] sm:px-[var(--spacing-scale-032)] sm:py-[var(--spacing-scale-032)] lg:px-[var(--spacing-scale-048)] lg:py-[var(--spacing-scale-040)] xl:px-[var(--spacing-scale-064)] xl:py-[var(--spacing-scale-076)]"
className="relative w-full overflow-clip px-[var(--space-500)] py-[var(--space-600)] sm:px-[var(--space-800)] sm:py-[var(--space-800)] lg:px-[var(--space-1200)] lg:py-[var(--space-1000)] xl:px-[var(--space-1800)] xl:py-[var(--space-2100)]"
aria-labelledby="content-banner-title"
>
<div
className="mx-auto flex w-full max-w-[1024px] flex-col items-start gap-[var(--spacing-scale-024)] md:flex-row md:items-start md:gap-[var(--spacing-scale-024)] lg:items-center lg:gap-[var(--spacing-scale-032)] xl:max-w-[1312px] xl:gap-[var(--spacing-scale-056)]"
className="mx-auto flex w-full max-w-[1024px] flex-col items-start gap-[var(--space-600)] md:flex-row md:items-start md:gap-[var(--space-600)] lg:items-center lg:gap-[var(--space-800)] xl:max-w-[1312px] xl:gap-[var(--space-1400)]"
data-node-id="19189:9358"
>
<div
className="flex w-full shrink-0 flex-col items-start justify-center gap-[var(--measures-spacing-016)] md:max-w-[280px] lg:max-w-[365px] xl:max-w-[623px]"
className="flex w-full shrink-0 flex-col items-start justify-center gap-[var(--space-400)] md:max-w-[280px] lg:max-w-[365px] xl:max-w-[623px]"
data-node-id="19189:9171"
>
<div className="flex w-full flex-col items-start gap-[var(--measures-spacing-004)] text-left text-[var(--color-content-default-primary)]">
<div className="flex w-full flex-col items-start gap-[var(--space-100)] text-left text-[var(--color-content-default-primary)]">
<h1
id="content-banner-title"
className="w-full font-bricolage font-medium text-[32px] leading-[110%] sm:text-[40px] lg:text-medium-display"
@@ -49,7 +49,7 @@ function ContentBannerGuideView({
</div>
{updatedLabel ? (
<div
className="flex w-full flex-wrap items-end gap-[var(--measures-spacing-008,8px)] text-xx-small-paragraph text-[var(--color-content-default-secondary)] md:text-x-small-paragraph lg:text-small-paragraph xl:text-large-paragraph"
className="flex w-full flex-wrap items-end gap-[var(--space-200)] text-xx-small-paragraph text-[var(--color-content-default-secondary)] md:text-x-small-paragraph lg:text-small-paragraph xl:text-large-paragraph"
data-name="Metadata Container"
>
<span>{author}</span>
@@ -59,7 +59,7 @@ function ContentBannerGuideView({
</div>
<div
className="flex w-full shrink-0 items-center justify-center max-sm:pb-[var(--spacing-scale-024)] md:flex-1 md:justify-end"
className="flex w-full shrink-0 items-center justify-center max-sm:pb-[var(--space-600)] md:flex-1 md:justify-end"
data-node-id="22078:806960"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
@@ -96,18 +96,18 @@ function ContentBannerArticleView({
className="
relative z-[1] w-full overflow-visible
min-h-[275px]
pt-[var(--spacing-scale-016)] px-[var(--spacing-scale-016)]
pb-[var(--spacing-scale-064)]
sm:min-h-[326px] sm:pb-[var(--spacing-scale-048)]
md:min-h-[224px] md:px-[var(--spacing-scale-024)] md:pb-0
md:pt-[var(--spacing-scale-008)]
lg:min-h-[358.4px] lg:px-[var(--spacing-scale-048)] lg:py-[var(--spacing-scale-040)]
xl:min-h-[504px] xl:px-[var(--spacing-scale-064)] xl:py-[var(--spacing-scale-076)]
pt-[var(--space-400)] px-[var(--space-400)]
pb-[var(--space-1800)]
sm:min-h-[326px] sm:pb-[var(--space-1200)]
md:min-h-[224px] md:px-[var(--space-600)] md:pb-0
md:pt-[var(--space-200)]
lg:min-h-[358.4px] lg:px-[var(--space-1200)] lg:py-[var(--space-1000)]
xl:min-h-[504px] xl:px-[var(--space-1800)] xl:py-[var(--space-2100)]
"
>
<div
aria-hidden
className="pointer-events-none absolute inset-x-0 top-0 -bottom-[var(--spacing-scale-024)] sm:-bottom-[var(--spacing-scale-032)] md:hidden"
className="pointer-events-none absolute inset-x-0 top-0 -bottom-[var(--space-600)] sm:-bottom-[var(--space-800)] md:hidden"
data-name="ContentBannerBackgroundHorizontal"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
@@ -120,7 +120,7 @@ function ContentBannerArticleView({
<div
aria-hidden
className="pointer-events-none absolute inset-x-0 top-0 -bottom-[var(--spacing-scale-032)] hidden md:block"
className="pointer-events-none absolute inset-x-0 top-0 -bottom-[var(--space-800)] hidden md:block"
data-name="ContentBannerBackgroundSection"
>
{/* eslint-disable-next-line @next/next/no-img-element */}
@@ -22,7 +22,7 @@ const FeatureGridContainer = memo<FeatureGridProps>(
description: t(
"pages.home.featureGrid.features.decisionMaking.description",
),
descriptionClassName: "text-[#3a3273]",
descriptionClassName: "text-[var(--color-content-invert-brand-lavender)]",
iconSrc: getAssetPath(featureIconPath("git-branch")),
},
{
@@ -31,7 +31,7 @@ const FeatureGridContainer = memo<FeatureGridProps>(
description: t(
"pages.home.featureGrid.features.valuesAlignment.description",
),
descriptionClassName: "text-[#424f1a]",
descriptionClassName: "text-[var(--color-content-invert-brand-lime)]",
iconSrc: getAssetPath(featureIconPath("arrow-left-right")),
},
{
@@ -40,7 +40,7 @@ const FeatureGridContainer = memo<FeatureGridProps>(
description: t(
"pages.home.featureGrid.features.membershipGuidance.description",
),
descriptionClassName: "text-[#5e2e23]",
descriptionClassName: "text-[var(--color-content-invert-brand-rust)]",
iconSrc: getAssetPath(featureIconPath("door-open")),
},
{
@@ -49,7 +49,7 @@ const FeatureGridContainer = memo<FeatureGridProps>(
description: t(
"pages.home.featureGrid.features.conflictResolution.description",
),
descriptionClassName: "text-[#1f4d47]",
descriptionClassName: "text-[var(--color-content-invert-brand-teal)]",
iconSrc: getAssetPath(featureIconPath("message-square-share")),
},
],
@@ -19,15 +19,15 @@ function FeatureGridView({
return (
<section
className={`p-0 md:px-[var(--spacing-scale-024)] lg:p-[var(--spacing-scale-064)] ${className}`}
className={`p-0 md:px-[var(--space-600)] lg:p-[var(--space-1800)] ${className}`}
aria-labelledby={labelledBy}
aria-label={labelledBy ? undefined : ariaLabel}
>
<div
data-figma-node="18632-10668"
className="rounded-none bg-[var(--color-surface-default-secondary)] px-[var(--spacing-scale-016)] py-[var(--spacing-scale-032)] md:rounded-[var(--radius-measures-radius-large)] md:p-[var(--spacing-scale-048)] lg:p-[var(--spacing-scale-064)]"
className="rounded-none bg-[var(--color-surface-default-secondary)] px-[var(--space-400)] py-[var(--space-800)] md:rounded-[var(--radius-500)] md:p-[var(--space-1200)] lg:p-[var(--space-1800)]"
>
<div className="mx-auto flex w-full flex-col gap-[var(--spacing-scale-040)] md:gap-[var(--spacing-scale-048)] lg:flex-row lg:items-center lg:gap-[var(--spacing-scale-064)]">
<div className="mx-auto flex w-full flex-col gap-[var(--space-1000)] md:gap-[var(--space-1200)] lg:flex-row lg:items-center lg:gap-[var(--space-1800)]">
<div className="lg:min-w-0 lg:flex-1">
<ContentLockup
title={title}
@@ -39,11 +39,11 @@ function FeatureGridView({
/>
</div>
<div className="grid w-full grid-cols-1 gap-[var(--spacing-scale-008)] md:grid-cols-2 md:gap-[var(--spacing-scale-016)] lg:flex-1">
<div className="grid w-full grid-cols-1 gap-[var(--space-200)] md:grid-cols-2 md:gap-[var(--space-400)] lg:flex-1">
{features.map((feature) => (
<div
key={feature.title}
className={`flex flex-col gap-[var(--spacing-scale-016)] p-[var(--spacing-scale-024)] ${feature.backgroundColor} rounded-[var(--radius-200)] md:rounded-[var(--radius-400)] lg:rounded-[var(--radius-measures-radius-large)]`}
className={`flex flex-col gap-[var(--space-400)] p-[var(--space-600)] ${feature.backgroundColor} rounded-[var(--radius-200)] md:rounded-[var(--radius-400)] lg:rounded-[var(--radius-500)]`}
>
<div className="size-[40px] shrink-0 overflow-clip">
{/* eslint-disable-next-line @next/next/no-img-element -- decorative Figma glyph */}
@@ -56,8 +56,8 @@ function FeatureGridView({
role="presentation"
/>
</div>
<div className="flex w-full flex-col gap-[var(--spacing-scale-008)]">
<p className="font-semibold text-[17px] leading-[22px] text-[var(--color-content-inverse-primary)]">
<div className="flex w-full flex-col gap-[var(--space-200)]">
<p className="font-semibold text-[17px] leading-[22px] text-[var(--color-content-invert-primary)]">
{feature.title}
</p>
<p
@@ -84,9 +84,9 @@ export function GovernanceTemplateGrid({
className={`
select-none
cursor-pointer
max-[639px]:rounded-[var(--measures-radius-200,8px)]
min-[640px]:max-[1023px]:rounded-[var(--measures-radius-300,12px)]
min-[1024px]:rounded-[var(--radius-measures-radius-large)]
max-[639px]:rounded-[var(--radius-200)]
min-[640px]:max-[1023px]:rounded-[var(--radius-300)]
min-[1024px]:rounded-[var(--radius-500)]
max-[639px]:pb-[24px] max-[639px]:pt-[12px] max-[639px]:px-[12px]
min-[640px]:max-[1023px]:p-[24px]
min-[1024px]:max-[1439px]:p-[24px]
@@ -35,10 +35,10 @@ export function GovernanceTemplateGridSkeleton({
<div
key={i}
className="
flex min-h-[120px] animate-pulse flex-col gap-3 rounded-[var(--measures-radius-200,8px)]
flex min-h-[120px] animate-pulse flex-col gap-3 rounded-[var(--radius-200)]
bg-[var(--color-surface-default-secondary,#262626)] p-4
min-[640px]:min-h-[140px] min-[640px]:rounded-[var(--measures-radius-300,12px)]
min-[1024px]:min-h-[160px] min-[1024px]:rounded-[var(--radius-measures-radius-small)]
min-[640px]:min-h-[140px] min-[640px]:rounded-[var(--radius-300)]
min-[1024px]:min-h-[160px] min-[1024px]:rounded-[var(--radius-300)]
"
>
<div className="h-10 w-10 rounded bg-[var(--color-surface-default-tertiary,#404040)] min-[640px]:h-14 min-[640px]:w-14" />
@@ -9,9 +9,9 @@ function GroupsView({ title, items, headingId, className = "" }: GroupsViewProps
<section
data-figma-node="22085-860411"
aria-labelledby={headingId}
className={`bg-transparent px-0 py-[var(--spacing-scale-064)] lg:px-[var(--spacing-scale-064)] xl:px-[var(--spacing-scale-160)] ${className}`.trim()}
className={`bg-transparent px-0 py-[var(--space-1800)] lg:px-[var(--space-1800)] xl:px-[var(--space-4000)] ${className}`.trim()}
>
<div className="mx-auto flex w-full max-w-[560px] flex-col items-center gap-[var(--spacing-scale-032)] md:max-w-[1280px] md:gap-[var(--spacing-scale-048)]">
<div className="mx-auto flex w-full max-w-[560px] flex-col items-center gap-[var(--space-800)] md:max-w-[1280px] md:gap-[var(--space-1200)]">
<h2
id={headingId}
className="w-full shrink-0 text-center font-bricolage-grotesque text-medium-heading text-[var(--color-content-default-primary)] md:text-large-heading lg:text-xx-large-heading"
@@ -35,10 +35,10 @@ const HeroBanner = memo<HeroBannerProps>(
imageAlt = "Hero illustration",
}) => {
return (
<section className="bg-transparent px-[var(--spacing-scale-008)] sm:px-[var(--spacing-scale-010)] md:px-[var(--spacing-scale-016)] lg:px-[var(--spacing-scale-024)] xl:px-[var(--spacing-scale-048)]">
<div className="flex flex-col gap-[var(--spacing-scale-010)]">
<section className="bg-transparent px-[var(--space-200)] sm:px-[var(--space-250)] md:px-[var(--space-400)] lg:px-[var(--space-600)] xl:px-[var(--space-1200)]">
<div className="flex flex-col gap-[var(--space-250)]">
{/* Frame container for content */}
<div className="bg-[var(--color-surface-inverse-brand-primary)] p-[var(--spacing-scale-012)] sm:p-[var(--spacing-scale-016)] md:p-[var(--spacing-scale-064)] lg:py-[var(--spacing-scale-096)] lg:px-[var(--spacing-scale-064)] rounded-tl-none rounded-tr-[var(--radius-measures-radius-medium)] rounded-br-[var(--radius-measures-radius-medium)] rounded-bl-[var(--radius-measures-radius-medium)] flex flex-col gap-[var(--spacing-scale-024)] sm:gap-[var(--spacing-scale-024)] md:flex-row md:gap-[var(--spacing-scale-048)] relative overflow-hidden">
<div className="bg-[var(--color-surface-invert-brand-primary)] p-[var(--space-300)] sm:p-[var(--space-400)] md:p-[var(--space-1800)] lg:py-[var(--space-2400)] lg:px-[var(--space-1800)] rounded-tl-none rounded-tr-[var(--radius-400)] rounded-br-[var(--radius-400)] rounded-bl-[var(--radius-400)] flex flex-col gap-[var(--space-600)] sm:gap-[var(--space-600)] md:flex-row md:gap-[var(--space-1200)] relative overflow-hidden">
{/* DECORATIONS (behind content) */}
<HeroDecor
className="pointer-events-none absolute z-0
@@ -7,7 +7,7 @@ interface HeroDecorProps {
const HeroDecor = memo<HeroDecorProps>(({ className = "" }) => {
return (
<svg
className={`text-[var(--color-surface-default-brand-darker-accent)] ${className}`}
className={`text-[var(--color-content-default-brand-secondary)] ${className}`}
viewBox="0 0 1540 645"
aria-hidden="true"
overflow="visible"
@@ -11,14 +11,14 @@ function LogoWallView({
}: LogoWallViewProps) {
return (
<section
className={`bg-[var(--color-surface-default-primary)] p-[var(--spacing-scale-032)] md:px-[var(--spacing-scale-024)] md:py-[var(--spacing-scale-032)] lg:px-[var(--spacing-scale-064)] lg:py-[var(--spacing-scale-048)] xl:px-[160px] xl:py-[var(--spacing-scale-064)] ${className}`}
className={`bg-[var(--color-surface-default-primary)] p-[var(--space-800)] md:px-[var(--space-600)] md:py-[var(--space-800)] lg:px-[var(--space-1800)] lg:py-[var(--space-1200)] xl:px-[160px] xl:py-[var(--space-1800)] ${className}`}
>
<div className="flex flex-col items-center gap-[var(--spacing-scale-032)] md:gap-[var(--spacing-scale-024)] xl:gap-[var(--spacing-scale-032)]">
<div className="flex flex-col items-center gap-[var(--space-800)] md:gap-[var(--space-600)] xl:gap-[var(--space-800)]">
<p className="font-inter text-center text-[10px] font-medium uppercase leading-[12px] text-[var(--color-content-default-primary)] xl:text-[14px] xl:leading-[12px]">
{heading}
</p>
<div className="w-full opacity-60">
<div className="grid grid-cols-2 grid-rows-3 sm:grid-cols-3 sm:grid-rows-2 md:flex md:w-full md:flex-nowrap md:items-center md:justify-between gap-[38.4px] lg:gap-[var(--spacing-scale-048)]">
<div className="grid grid-cols-2 grid-rows-3 sm:grid-cols-3 sm:grid-rows-2 md:flex md:w-full md:flex-nowrap md:items-center md:justify-between gap-[38.4px] lg:gap-[var(--space-1200)]">
{displayLogos.map((logo, index) => (
<div
key={index}
@@ -26,10 +26,10 @@ const QuoteBlockContainer = memo<QuoteBlockProps>(
const variants: Record<string, VariantConfig> = {
compact: {
container:
"py-[var(--spacing-scale-032)] px-[var(--spacing-scale-016)]",
card: "py-[var(--spacing-scale-032)] px-[var(--spacing-scale-016)] md:py-[var(--spacing-scale-040)] md:px-[var(--spacing-scale-024)] rounded-[var(--radius-measures-radius-small)]",
gap: "gap-[var(--spacing-scale-016)] md:gap-[var(--spacing-scale-024)]",
avatarGap: "gap-[var(--spacing-scale-012)]",
"py-[var(--space-800)] px-[var(--space-400)]",
card: "py-[var(--space-800)] px-[var(--space-400)] md:py-[var(--space-1000)] md:px-[var(--space-600)] rounded-[var(--radius-300)]",
gap: "gap-[var(--space-400)] md:gap-[var(--space-600)]",
avatarGap: "gap-[var(--space-300)]",
avatar: "w-[48px] h-[48px] md:w-[64px] md:h-[64px]",
quote: "text-[16px] leading-[120%] md:text-[20px] md:leading-[110%]",
author: "text-[10px] leading-[120%] md:text-[12px]",
@@ -38,11 +38,11 @@ const QuoteBlockContainer = memo<QuoteBlockProps>(
},
standard: {
container:
"md:py-[var(--spacing-scale-032)] md:px-[var(--spacing-scale-016)] lg:p-[var(--spacing-scale-064)]",
card: "py-[var(--spacing-scale-064)] px-[var(--spacing-scale-020)] md:py-[var(--spacing-scale-064)] md:px-[var(--spacing-scale-048)] md:rounded-[var(--radius-measures-radius-medium)] lg:py-[var(--spacing-scale-064)] lg:pl-[120px] lg:pr-[320px]",
gap: "gap-[var(--spacing-scale-024)] md:gap-[var(--spacing-scale-048)] lg:gap-[var(--spacing-scale-064)] xl:gap-[105px]",
"md:py-[var(--space-800)] md:px-[var(--space-400)] lg:p-[var(--space-1800)]",
card: "py-[var(--space-1800)] px-[var(--space-500)] md:py-[var(--space-1800)] md:px-[var(--space-1200)] md:rounded-[var(--radius-400)] lg:py-[var(--space-1800)] lg:pl-[120px] lg:pr-[320px]",
gap: "gap-[var(--space-600)] md:gap-[var(--space-1200)] lg:gap-[var(--space-1800)] xl:gap-[105px]",
avatarGap:
"gap-[var(--spacing-scale-020)] lg:gap-[var(--spacing-scale-018)] xl:gap-[var(--spacing-scale-032)]",
"gap-[var(--space-500)] lg:gap-[var(--sizing-450)] xl:gap-[var(--space-800)]",
avatar:
"md:w-[120px] md:h-[120px] lg:w-[150px] lg:h-[150px] xl:w-[200px] xl:h-[200px]",
quote:
@@ -55,11 +55,11 @@ const QuoteBlockContainer = memo<QuoteBlockProps>(
},
extended: {
container:
"py-[var(--spacing-scale-048)] px-[var(--spacing-scale-024)] md:py-[var(--spacing-scale-064)] md:px-[var(--spacing-scale-032)] lg:py-[var(--spacing-scale-080)] lg:px-[var(--spacing-scale-048)]",
card: "py-[var(--spacing-scale-080)] px-[var(--spacing-scale-032)] md:py-[var(--spacing-scale-096)] md:px-[var(--spacing-scale-064)] md:rounded-[var(--radius-measures-radius-large)] lg:py-[var(--spacing-scale-112)] lg:pl-[160px] lg:pr-[400px]",
gap: "gap-[var(--spacing-scale-032)] md:gap-[var(--spacing-scale-064)] lg:gap-[var(--spacing-scale-080)] xl:gap-[140px]",
"py-[var(--space-1200)] px-[var(--space-600)] md:py-[var(--space-1800)] md:px-[var(--space-800)] lg:py-[var(--spacing-scale-080)] lg:px-[var(--space-1200)]",
card: "py-[var(--spacing-scale-080)] px-[var(--space-800)] md:py-[var(--space-2400)] md:px-[var(--space-1800)] md:rounded-[var(--radius-500)] lg:py-[var(--spacing-scale-112)] lg:pl-[160px] lg:pr-[400px]",
gap: "gap-[var(--space-800)] md:gap-[var(--space-1800)] lg:gap-[var(--spacing-scale-080)] xl:gap-[140px]",
avatarGap:
"gap-[var(--spacing-scale-032)] lg:gap-[var(--spacing-scale-040)] xl:gap-[var(--spacing-scale-048)]",
"gap-[var(--space-800)] lg:gap-[var(--space-1000)] xl:gap-[var(--space-1200)]",
avatar:
"w-[80px] h-[80px] md:w-[140px] md:h-[140px] lg:w-[180px] lg:h-[180px] xl:w-[240px] xl:h-[240px]",
quote:
@@ -72,7 +72,7 @@ const QuoteBlockContainer = memo<QuoteBlockProps>(
},
statement: {
container:
"flex w-full flex-col items-center px-[var(--spacing-scale-032)] py-[var(--spacing-scale-048)] md:px-[var(--spacing-scale-096)] md:py-[var(--space-1200)]",
"flex w-full flex-col items-center px-[var(--space-800)] py-[var(--space-1200)] md:px-[var(--space-2400)] md:py-[var(--space-1200)]",
card: "",
gap: "",
avatarGap: "",
@@ -35,7 +35,7 @@ function QuoteBlockView({
role="region"
>
<div
className="relative box-border flex w-full max-w-[1440px] shrink-0 flex-col items-center justify-center gap-[var(--space-800)] overflow-hidden rounded-[var(--spacing-scale-020)] bg-[var(--color-surface-invert-brand-primary,#fefcc9)] px-[var(--spacing-scale-032)] py-[var(--spacing-scale-048)] md:px-[var(--space-1800)] md:py-[var(--space-2400)]"
className="relative box-border flex w-full max-w-[1440px] shrink-0 flex-col items-center justify-center gap-[var(--space-800)] overflow-hidden rounded-[var(--space-500)] bg-[var(--color-surface-invert-brand-primary,#fefcc9)] px-[var(--space-800)] py-[var(--space-1200)] md:px-[var(--space-1800)] md:py-[var(--space-2400)]"
>
<QuoteStatementDecor />
<div className="relative z-10 flex w-full min-w-0 shrink-0 flex-col items-center text-center">
@@ -64,11 +64,11 @@ function QuoteBlockView({
role="region"
>
<div
className={`${config.card} bg-[var(--color-surface-default-brand-darker-accent)] relative overflow-hidden`}
className={`${config.card} bg-[var(--color-surface-invert-brand-secondary)] relative overflow-hidden`}
>
{/* Background with noise texture */}
<div
className="absolute inset-0 bg-[var(--color-surface-default-brand-darker-accent)]"
className="absolute inset-0 bg-[var(--color-surface-invert-brand-secondary)]"
style={{
filter:
'url(\'data:image/svg+xml;charset=utf-8,<svg xmlns="http://www.w3.org/2000/svg"><defs><filter id="grain" filterUnits="objectBoundingBox" x="0" y="0" width="1" height="1" colorInterpolationFilters="sRGB"><feTurbulence type="fractalNoise" baseFrequency="0.4" numOctaves="3" seed="7" stitchTiles="stitch" result="noise"/><feColorMatrix in="noise" result="softNoise" type="matrix" values="0.8 0 0 0 0.3 0 0.6 0 0 0.2 0 0 1.0 0 0.4 0 0 0 0.25 0"/><feComposite in="softNoise" in2="SourceAlpha" operator="in" result="maskedNoise"/><feBlend in="SourceGraphic" in2="maskedNoise" mode="multiply"/></filter></defs></svg>#grain\')',
@@ -101,7 +101,7 @@ function QuoteBlockView({
/>
) : (
<div
className={`flex items-center justify-center bg-gray-300 rounded-full ${config.avatar} text-gray-600 font-bold`}
className={`flex items-center justify-center bg-[var(--color-gray-300)] rounded-full ${config.avatar} text-[var(--color-gray-600)] font-bold`}
>
<span className="text-sm md:text-base lg:text-lg xl:text-xl">
{author
@@ -125,7 +125,7 @@ function QuoteBlockView({
className={[
"font-bricolage-grotesque font-normal",
config.quote,
"text-[var(--color-content-inverse-primary)]",
"text-[var(--color-content-invert-primary)]",
// give space for the hanging open-quote so it's not clipped:
"pl-[0.6em] -indent-[0.6em]",
// inject quotes
@@ -139,10 +139,10 @@ function QuoteBlockView({
</p>
</blockquote>
</div>
<footer className="flex flex-col gap-[var(--spacing-scale-008)] md:gap-[var(--spacing-scale-012)] xl:gap-[var(--spacing-scale-020)]">
<footer className="flex flex-col gap-[var(--space-200)] md:gap-[var(--space-300)] xl:gap-[var(--space-500)]">
<cite
id={authorId}
className={`font-normal ${config.author} text-[var(--color-content-inverse-primary)] uppercase not-italic`}
className={`font-normal ${config.author} text-[var(--color-content-invert-primary)] uppercase not-italic`}
>
{author}
</cite>
@@ -153,7 +153,7 @@ function QuoteBlockView({
className={[
"font-normal",
config.source,
"text-[var(--color-content-inverse-primary)] uppercase",
"text-[var(--color-content-invert-primary)] uppercase",
"pl-[0.6em] -indent-[0.6em]",
"relative before:content-[attr(data-qopen)] after:content-[attr(data-qclose)]",
"before:[font-family:var(--font-inter)] after:[font-family:var(--font-inter)]",
@@ -9,7 +9,7 @@ interface QuoteDecorProps {
const QuoteDecor = memo<QuoteDecorProps>(({ className = "" }) => {
return (
<svg
className={`text-[var(--color-surface-inverse-brand-primary)] opacity-100 ${className}`}
className={`text-[var(--color-surface-invert-brand-primary)] opacity-100 ${className}`}
viewBox="400 0 442 163"
aria-hidden="true"
overflow="visible"
@@ -24,8 +24,8 @@ export function RelatedArticlesView({
<section
className={
isUseCases
? "px-[var(--spacing-scale-020)] py-[var(--spacing-scale-032)] md:px-[var(--spacing-scale-024)] md:py-[var(--spacing-scale-048)] lg:px-[var(--spacing-scale-120)] lg:py-[var(--spacing-scale-064)]"
: "py-[var(--spacing-scale-032)] lg:py-[var(--spacing-scale-064)]"
? "px-[var(--space-500)] py-[var(--space-800)] md:px-[var(--space-600)] md:py-[var(--space-1200)] lg:px-[var(--space-3000)] lg:py-[var(--space-1800)]"
: "py-[var(--space-800)] lg:py-[var(--space-1800)]"
}
data-testid="related-articles"
{...(isUseCases ? { "data-figma-node": "20711-14231" } : {})}
@@ -33,8 +33,8 @@ export function RelatedArticlesView({
<div
className={
isUseCases
? "mx-auto flex w-full max-w-[1440px] flex-col items-center gap-[var(--spacing-scale-024)] md:gap-[var(--spacing-scale-032)]"
: "flex flex-col gap-[var(--spacing-scale-032)] lg:gap-[51px]"
? "mx-auto flex w-full max-w-[1440px] flex-col items-center gap-[var(--space-600)] md:gap-[var(--space-800)]"
: "flex flex-col gap-[var(--space-800)] lg:gap-[51px]"
}
>
{isUseCases && useCasesHeadingLines?.length ? (
@@ -56,7 +56,7 @@ export function RelatedArticlesView({
className={`text-center font-medium text-[32px] leading-[110%] lg:text-medium-display ${
headingSurface === "onLight"
? "text-[var(--color-content-default-primary)]"
: "text-[var(--color-content-inverse-primary)]"
: "text-[var(--color-content-invert-primary)]"
}`}
>
{heading}
@@ -74,7 +74,7 @@ export function RelatedArticlesView({
<div
className={`flex gap-0 transition-transform duration-500 ease-in-out ${
isUseCases
? "lg:gap-[var(--spacing-scale-012)] lg:pl-[var(--spacing-scale-024)]"
? "lg:gap-[var(--space-300)] lg:pl-[var(--space-600)]"
: ""
} ${
manualScroll
@@ -103,14 +103,14 @@ export function RelatedArticlesView({
</div>
{isMobile && !isUseCases && (
<div className="flex justify-center gap-[var(--measures-spacing-008)] px-[var(--measures-spacing-064)]">
<div className="flex justify-center gap-[var(--space-200)] px-[var(--space-1800)]">
{filteredPosts.map((relatedPost, index) => (
<div
key={relatedPost.slug}
className="max-w-[var(--measures-spacing-056)] w-full h-[var(--measures-spacing-004)] bg-gray-200 rounded-full overflow-hidden"
className="max-w-[var(--space-1400)] w-full h-[var(--space-100)] bg-gray-200 rounded-full overflow-hidden"
>
<div
className="h-full bg-gray-600 rounded-full transition-all duration-75 ease-linear"
className="h-full bg-[var(--color-gray-600)] rounded-full transition-all duration-75 ease-linear"
style={getProgressStyle(index)}
/>
</div>
+4 -4
View File
@@ -33,12 +33,12 @@ function StatsView({
return (
<section
aria-labelledby={headingId}
className={`bg-black px-[var(--spacing-scale-032)] py-[var(--spacing-scale-048)] md:px-[var(--spacing-scale-064)] md:py-[var(--spacing-scale-064)] lg:px-[var(--spacing-scale-160)] ${className}`.trim()}
className={`bg-black px-[var(--space-800)] py-[var(--space-1200)] md:px-[var(--space-1800)] md:py-[var(--space-1800)] lg:px-[var(--space-4000)] ${className}`.trim()}
>
<div className="mx-auto flex w-full max-w-[1440px] flex-col items-start gap-[var(--spacing-scale-010)] sm:gap-[var(--spacing-scale-032)]">
<div className="mx-auto flex w-full max-w-[1440px] flex-col items-start gap-[var(--space-250)] sm:gap-[var(--space-800)]">
<h2
id={headingId}
className="max-w-[116px] text-x-large-paragraph md:text-[length:var(--spacing-scale-016)] md:leading-[length:var(--spacing-scale-020)] md:translate-y-24 lg:translate-y-0"
className="max-w-[116px] text-x-large-paragraph md:text-[length:var(--space-400)] md:leading-[length:var(--space-500)] md:translate-y-24 lg:translate-y-0"
>
<span className="-mb-1 block whitespace-nowrap md:-mb-0 md:inline md:whitespace-normal md:leading-[inherit]">
{titlePrefix ? (
@@ -67,7 +67,7 @@ function StatsView({
</>
) : null}
</h2>
<ul className="grid w-full flex-1 grid-cols-1 gap-[var(--spacing-scale-014)] md:grid-cols-2 md:gap-[var(--spacing-scale-016)] lg:grid-cols-4">
<ul className="grid w-full flex-1 grid-cols-1 gap-[var(--sizing-350)] md:grid-cols-2 md:gap-[var(--space-400)] lg:grid-cols-4">
{items.map((item, index) => {
/* Figma mobile Card / Stat rows: 182px (1st, 4th) vs 260px (2nd, 3rd) */
const isShortCard = index === 0 || index === items.length - 1;
@@ -7,9 +7,9 @@ function UseCasesOrgsView({ children, className = "" }: UseCasesOrgsViewProps) {
return (
<section
data-figma-node="21993-33687"
className={`bg-[var(--color-surface-default-primary)] px-[var(--spacing-scale-024)] pb-[var(--spacing-scale-048)] ${className}`.trim()}
className={`bg-[var(--color-surface-default-primary)] px-[var(--space-600)] pb-[var(--space-1200)] ${className}`.trim()}
>
<div className="mx-auto flex w-full max-w-[1440px] flex-wrap content-center items-center justify-center gap-[var(--spacing-scale-008)] lg:flex-nowrap">
<div className="mx-auto flex w-full max-w-[1440px] flex-wrap content-center items-center justify-center gap-[var(--space-200)] lg:flex-nowrap">
{children}
</div>
</section>
@@ -19,7 +19,7 @@ function AboutHeaderView({
}: AboutHeaderViewProps) {
return (
<section
className={`bg-black px-[var(--spacing-scale-020)] py-[var(--spacing-scale-032)] md:px-[var(--spacing-scale-064)] md:py-[var(--spacing-scale-032)] ${className}`.trim()}
className={`bg-black px-[var(--space-500)] py-[var(--space-800)] md:px-[var(--space-1800)] md:py-[var(--space-800)] ${className}`.trim()}
>
<ContentLockup
variant="about"
@@ -10,7 +10,7 @@ import type { CommunityRuleProps } from "./CommunityRule.types";
* **`Section`** (22002:30757) + **`TextBlock`** (22001:29793); canonical code under **`type/CommunityRule`**.
*/
const SECTION_GAP = "var(--measures-spacing-1200, 64px)";
const SECTION_GAP = "var(--space-1800)";
const TEAL_BG = "var(--color-teal-teal50, #c9fef9)";
function CommunityRuleView({
@@ -29,28 +29,28 @@ const ContentLockupContainer = memo<ContentLockupProps>(
const variantStyles: Record<string, VariantStyle> = {
hero: {
container:
"flex flex-col gap-[var(--spacing-scale-006)] sm:gap-[var(--spacing-scale-012)] md:gap-[var(--spacing-scale-020)] lg:gap-[var(--spacing-scale-020)] relative z-10",
"flex flex-col gap-[var(--space-150)] sm:gap-[var(--space-300)] md:gap-[var(--space-500)] lg:gap-[var(--space-500)] relative z-10",
textContainer:
"flex flex-col md:gap-[var(--spacing-scale-004)] lg:gap-[var(--spacing-scale-008)] xl:gap-[var(--spacing-scale-020)]",
"flex flex-col md:gap-[var(--space-100)] lg:gap-[var(--space-200)] xl:gap-[var(--space-500)]",
titleGroup: "flex flex-col xl:gap-0",
titleContainer:
"flex gap-[var(--spacing-scale-008)] xl:gap-[var(--spacing-scale-010)] items-center",
"flex gap-[var(--space-200)] xl:gap-[var(--space-250)] items-center",
title:
"font-bricolage-grotesque font-medium max-sm:text-[32px] max-sm:leading-[110%] sm:text-large-display md:text-medium-display lg:text-x-large-display xl:text-xx-large-display text-[var(--color-content-inverse-primary)] [font-variation-settings:'opsz'_14,'wdth'_100]",
"font-bricolage-grotesque font-medium max-sm:text-[32px] max-sm:leading-[110%] sm:text-large-display md:text-medium-display lg:text-x-large-display xl:text-xx-large-display text-[var(--color-content-invert-primary)] [font-variation-settings:'opsz'_14,'wdth'_100]",
subtitle:
"font-bricolage-grotesque font-medium max-sm:text-[32px] max-sm:leading-[110%] sm:text-large-display md:text-medium-display lg:text-x-large-display xl:text-xx-large-display text-[var(--color-content-inverse-primary)] [font-variation-settings:'opsz'_14,'wdth'_100]",
"font-bricolage-grotesque font-medium max-sm:text-[32px] max-sm:leading-[110%] sm:text-large-display md:text-medium-display lg:text-x-large-display xl:text-xx-large-display text-[var(--color-content-invert-primary)] [font-variation-settings:'opsz'_14,'wdth'_100]",
description:
"text-small-paragraph sm:text-large-paragraph lg:text-x-large-paragraph xl:text-xx-large-paragraph text-[var(--color-content-inverse-primary)]",
"text-small-paragraph sm:text-large-paragraph lg:text-x-large-paragraph xl:text-xx-large-paragraph text-[var(--color-content-invert-primary)]",
shape:
"w-[27.2px] h-[27.2px] md:w-[34px] md:h-[34px] lg:w-[50px] lg:h-[50px]",
},
feature: {
container: "flex flex-col gap-[var(--space-400,16px)] md:gap-[var(--space-500,20px)] relative z-10",
textContainer: "flex flex-col gap-[var(--space-100,4px)] md:gap-[var(--space-150,6px)]",
titleGroup: "flex flex-col gap-[var(--space-100,4px)] md:gap-[var(--space-150,6px)]",
container: "flex flex-col gap-[var(--space-400)] md:gap-[var(--space-500)] relative z-10",
textContainer: "flex flex-col gap-[var(--space-100)] md:gap-[var(--space-150)]",
titleGroup: "flex flex-col gap-[var(--space-100)] md:gap-[var(--space-150)]",
titleContainer: "flex items-center",
title:
"font-bricolage-grotesque font-medium text-[18px] leading-[22px] md:text-[length:var(--sizing-600,24px)] md:leading-[32px] text-[var(--color-content-default-primary)]",
"font-bricolage-grotesque font-medium text-[18px] leading-[22px] md:text-[length:var(--sizing-600)] md:leading-[32px] text-[var(--color-content-default-primary)]",
subtitle:
"text-small-paragraph md:text-medium-paragraph text-[var(--color-content-default-secondary)]",
description:
@@ -60,13 +60,13 @@ const ContentLockupContainer = memo<ContentLockupProps>(
},
about: {
container:
"flex flex-col gap-[var(--spacing-scale-020)] lg:gap-[var(--spacing-scale-016)] relative z-10",
"flex flex-col gap-[var(--space-500)] lg:gap-[var(--space-400)] relative z-10",
textContainer:
"flex flex-col gap-[var(--spacing-scale-008)] lg:gap-[var(--spacing-scale-004)]",
"flex flex-col gap-[var(--space-200)] lg:gap-[var(--space-100)]",
titleGroup:
"flex flex-col gap-[var(--spacing-scale-008)] lg:gap-[var(--spacing-scale-004)]",
"flex flex-col gap-[var(--space-200)] lg:gap-[var(--space-100)]",
titleContainer:
"flex flex-wrap items-center gap-[var(--spacing-scale-010)] xl:gap-[var(--spacing-scale-012)]",
"flex flex-wrap items-center gap-[var(--space-250)] xl:gap-[var(--space-300)]",
title:
"font-bricolage-grotesque font-medium text-[32px] leading-[1.1] md:text-large-display xl:text-x-large-display text-[var(--color-content-default-primary,white)]",
subtitle:
@@ -78,15 +78,15 @@ const ContentLockupContainer = memo<ContentLockupProps>(
},
book: {
container:
"flex flex-col gap-[var(--spacing-scale-016)] lg:gap-[var(--spacing-scale-020)] relative z-10",
"flex flex-col gap-[var(--space-400)] lg:gap-[var(--space-500)] relative z-10",
textContainer:
"flex flex-col gap-[var(--spacing-scale-004)] lg:gap-[var(--spacing-scale-008)]",
"flex flex-col gap-[var(--space-100)] lg:gap-[var(--space-200)]",
titleGroup: "flex flex-col gap-0",
titleContainer: "flex flex-wrap items-center gap-[var(--spacing-scale-008)]",
titleContainer: "flex flex-wrap items-center gap-[var(--space-200)]",
title:
"font-bricolage-grotesque font-medium text-[18px] leading-[22px] lg:text-[length:var(--spacing-scale-020)] lg:leading-[24px] xl:text-[length:var(--spacing-scale-032)] xl:leading-[1.1] text-[var(--color-content-default-primary)]",
"font-bricolage-grotesque font-medium text-[18px] leading-[22px] lg:text-[length:var(--space-500)] lg:leading-[24px] xl:text-[length:var(--space-800)] xl:leading-[1.1] text-[var(--color-content-default-primary)]",
subtitle:
"font-bricolage-grotesque font-medium text-[18px] leading-[22px] lg:text-[length:var(--spacing-scale-020)] lg:leading-[24px] xl:text-[length:var(--spacing-scale-032)] xl:leading-[1.1] text-[var(--color-content-default-primary)]",
"font-bricolage-grotesque font-medium text-[18px] leading-[22px] lg:text-[length:var(--space-500)] lg:leading-[24px] xl:text-[length:var(--space-800)] xl:leading-[1.1] text-[var(--color-content-default-primary)]",
description:
"text-small-paragraph text-[var(--color-content-default-secondary)] whitespace-pre-line lg:text-medium-paragraph xl:text-x-large-paragraph",
shape:
@@ -94,26 +94,26 @@ const ContentLockupContainer = memo<ContentLockupProps>(
},
learn: {
container:
"flex flex-col gap-[var(--spacing-scale-012)] relative z-10 pt-[var(--spacing-scale-016)] pb-[var(--spacing-scale-016)] px-[var(--spacing-scale-020)] sm:pt-[var(--spacing-scale-040)] sm:pb-0 md:pt-[var(--spacing-scale-056)] md:px-[var(--spacing-scale-032)] lg:pt-[var(--spacing-scale-056)] lg:px-[var(--spacing-scale-064)]",
"flex flex-col gap-[var(--space-300)] relative z-10 pt-[var(--space-400)] pb-[var(--space-400)] px-[var(--space-500)] sm:pt-[var(--space-1000)] sm:pb-0 md:pt-[var(--space-1400)] md:px-[var(--space-800)] lg:pt-[var(--space-1400)] lg:px-[var(--space-1800)]",
textContainer:
"flex flex-col gap-[var(--spacing-scale-012)] md:gap-[var(--spacing-scale-016)]",
"flex flex-col gap-[var(--space-300)] md:gap-[var(--space-400)]",
titleGroup:
"flex flex-col gap-[var(--spacing-scale-012)] md:gap-[var(--spacing-scale-016)] lg:gap-[var(--spacing-scale-008)]",
titleContainer: "flex gap-[var(--spacing-scale-008)] items-center",
"flex flex-col gap-[var(--space-300)] md:gap-[var(--space-400)] lg:gap-[var(--space-200)]",
titleContainer: "flex gap-[var(--space-200)] items-center",
title:
"font-bricolage-grotesque font-medium max-md:text-[28px] max-md:leading-[36px] tracking-[0] md:text-medium-display lg:text-large-display text-[var(--color-content-default-primary)]",
subtitle:
"font-space-grotesk text-medium-paragraph tracking-[0] lg:text-x-large-label text-[var(--color-content-default-primary)]",
"font-sans text-medium-paragraph tracking-[0] lg:text-x-large-label text-[var(--color-content-default-primary)]",
description:
"font-normal text-[16px] leading-[140%] lg:text-[18px] lg:leading-[150%] xl:text-[20px] xl:leading-[160%] text-[var(--color-content-default-secondary)]",
shape:
"w-[20px] h-[20px] md:w-[24px] md:h-[24px] lg:w-[28px] lg:h-[28px]",
},
ask: {
container: "flex flex-col gap-[var(--spacing-scale-008)] relative z-10",
textContainer: "flex flex-col gap-[var(--spacing-scale-008)]",
titleGroup: "flex flex-col gap-[var(--spacing-scale-008)]",
titleContainer: "flex gap-[var(--spacing-scale-008)] items-center",
container: "flex flex-col gap-[var(--space-200)] relative z-10",
textContainer: "flex flex-col gap-[var(--space-200)]",
titleGroup: "flex flex-col gap-[var(--space-200)]",
titleContainer: "flex gap-[var(--space-200)] items-center",
title:
"font-bricolage-grotesque font-medium text-[32px] leading-[1.1] tracking-[0] md:text-medium-display text-[var(--color-content-default-brand-primary)]",
subtitle:
@@ -122,12 +122,12 @@ const ContentLockupContainer = memo<ContentLockupProps>(
"w-[16px] h-[16px] md:w-[20px] md:h-[20px] lg:w-[24px] lg:h-[24px]",
},
"ask-inverse": {
container: "flex flex-col gap-[var(--spacing-scale-008)] relative z-10 w-full",
textContainer: "flex flex-col gap-[var(--spacing-scale-008)]",
titleGroup: "flex flex-col gap-[var(--spacing-scale-008)] w-full",
titleContainer: "flex gap-[var(--spacing-scale-008)] items-center",
container: "flex flex-col gap-[var(--space-200)] relative z-10 w-full",
textContainer: "flex flex-col gap-[var(--space-200)]",
titleGroup: "flex flex-col gap-[var(--space-200)] w-full",
titleContainer: "flex gap-[var(--space-200)] items-center",
title:
"font-bricolage-grotesque font-medium text-[32px] leading-[1.1] tracking-[0] md:text-medium-display text-[var(--color-content-inverse-primary)]",
"font-bricolage-grotesque font-medium text-[32px] leading-[1.1] tracking-[0] md:text-medium-display text-[var(--color-content-invert-primary)]",
subtitle:
"text-large-paragraph tracking-[0] md:text-x-large-paragraph text-[var(--color-content-invert-secondary)]",
shape:
@@ -135,9 +135,9 @@ const ContentLockupContainer = memo<ContentLockupProps>(
},
modal: {
container:
"flex flex-col gap-[var(--spacing-scale-008)] items-start justify-center py-[12px] relative w-full",
textContainer: "flex flex-col gap-[var(--spacing-scale-008)] w-full",
titleGroup: "flex flex-col gap-[var(--spacing-scale-008)] w-full",
"flex flex-col gap-[var(--space-200)] items-start justify-center py-[12px] relative w-full",
textContainer: "flex flex-col gap-[var(--space-200)] w-full",
titleGroup: "flex flex-col gap-[var(--space-200)] w-full",
titleContainer: "flex items-center justify-start w-full",
title:
"font-bricolage-grotesque text-medium-heading tracking-[0] text-[var(--color-content-default-primary)] text-left",
@@ -149,9 +149,9 @@ const ContentLockupContainer = memo<ContentLockupProps>(
},
login: {
container:
"flex flex-col gap-[var(--spacing-scale-012)] items-start justify-center relative w-full",
textContainer: "flex flex-col gap-[var(--spacing-scale-012)] w-full",
titleGroup: "flex flex-col gap-[var(--spacing-scale-012)] w-full",
"flex flex-col gap-[var(--space-300)] items-start justify-center relative w-full",
textContainer: "flex flex-col gap-[var(--space-300)] w-full",
titleGroup: "flex flex-col gap-[var(--space-300)] w-full",
titleContainer: "flex items-center justify-start w-full",
title:
"font-bricolage-grotesque text-x-large-heading tracking-[0] text-[var(--color-content-default-primary)] text-left",
@@ -63,7 +63,7 @@ function ContentLockupView({
{titleContent ? (
<h1
id={titleId}
className={`${styles.title} flex flex-wrap items-center gap-[var(--spacing-scale-010)] xl:gap-[var(--spacing-scale-012)]`}
className={`${styles.title} flex flex-wrap items-center gap-[var(--space-250)] xl:gap-[var(--space-300)]`}
>
{titleContent}
</h1>
@@ -24,7 +24,7 @@ function HeaderLockupView({
return (
<div
className={`flex flex-col gap-[var(--measures-spacing-200,8px)] py-[12px] relative ${
className={`flex flex-col gap-[var(--space-200)] py-[12px] relative ${
isLeft ? "items-start" : "items-center"
}`}
>
@@ -29,11 +29,11 @@ function InputLabelView({
const asteriskSize = isSmall
? "text-xx-small-label"
: "font-medium text-[length:var(--measures-spacing-300,12px)] leading-[var(--measures-spacing-300,12px)]";
: "font-medium text-[length:var(--space-300)] leading-[var(--space-300)]";
// Palette-based colors
const labelColor = isInverse
? "text-[color:var(--color-content-inverse-secondary,#1f1f1f)]"
? "text-[color:var(--color-content-invert-secondary,#1f1f1f)]"
: "text-[color:var(--color-content-default-secondary,#d2d2d2)]";
const helperTextColor =
@@ -41,12 +41,12 @@ function InputLabelView({
// Layout: S uses flex-wrap with baseline, M uses flex with center
const containerClass = isSmall
? "flex flex-wrap gap-[var(--measures-spacing-200,4px_8px)] items-baseline pr-[var(--measures-spacing-100,4px)] relative w-full"
? "flex flex-wrap gap-[var(--space-100)_var(--space-200)] items-baseline pr-[var(--space-100)] relative w-full"
: "flex gap-[4px] items-center relative w-full";
const labelContainerClass = isSmall
? "flex gap-[var(--measures-spacing-050,2px)] items-center relative shrink-0"
: "flex gap-[var(--measures-spacing-100,4px)] items-center relative shrink-0";
? "flex gap-[var(--space-050)] items-center relative shrink-0"
: "flex gap-[var(--space-100)] items-center relative shrink-0";
const helpIconSize = isSmall ? "size-[12px]" : "size-[16px]";
@@ -7,7 +7,7 @@ function NumberedListView({ items, size }: NumberedListViewProps) {
const isM = size === "M";
return (
<ol className="flex flex-col gap-[var(--measures-spacing-600,24px)] items-start relative w-full list-none">
<ol className="flex flex-col gap-[var(--space-600)] items-start relative w-full list-none">
{items.map((item, index) => (
<li
key={index}
@@ -15,12 +15,12 @@ function NumberedListView({ items, size }: NumberedListViewProps) {
>
{/* Number Indicator */}
<div
className={`bg-[var(--color-surface-inverse-primary,white)] flex flex-col items-center justify-center px-[11.2px] py-[4px] relative rounded-full shrink-0 ${
className={`bg-[var(--color-surface-invert-primary,white)] flex flex-col items-center justify-center px-[11.2px] py-[4px] relative rounded-full shrink-0 ${
isM ? "size-[32px]" : "size-[24px]"
}`}
>
<div
className={`flex flex-col justify-center leading-[0] overflow-hidden relative shrink-0 text-[var(--color-content-inverse-primary,black)] text-ellipsis whitespace-nowrap ${
className={`flex flex-col justify-center leading-[0] overflow-hidden relative shrink-0 text-[var(--color-content-invert-primary,black)] text-ellipsis whitespace-nowrap ${
isM
? "text-x-small-heading"
: "font-bricolage-grotesque text-xx-small-heading"
@@ -31,7 +31,7 @@ function NumberedListView({ items, size }: NumberedListViewProps) {
</div>
{/* Content */}
<div className="flex flex-[1_0_0] flex-col gap-[var(--measures-spacing-100,4px)] items-start justify-center min-h-px min-w-px">
<div className="flex flex-[1_0_0] flex-col gap-[var(--space-100)] items-start justify-center min-h-px min-w-px">
{/* Title */}
<div className="flex items-center relative shrink-0 w-full">
<h3
@@ -28,8 +28,8 @@ function PageHeaderView({
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)]";
? "py-[var(--space-800)] md:py-[var(--space-1400)]"
: "py-[var(--space-800)] md:py-[var(--space-800)]";
const titleTypeClasses = sectionMinimal
? "font-bricolage-grotesque text-[32px] font-medium leading-[1.1] text-[var(--color-content-default-primary)] md:text-large-display xl:text-x-large-display"
@@ -45,13 +45,13 @@ function PageHeaderView({
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()}
className={`bg-[var(--color-surface-default-primary)] px-[var(--space-500)] md:px-[var(--space-1800)] ${sectionPadding} ${className}`.trim()}
>
<div
className={`mx-auto flex w-full max-w-[1440px] flex-col gap-[var(--spacing-scale-024)] ${isCenter ? "items-center" : ""}`}
className={`mx-auto flex w-full max-w-[1440px] flex-col gap-[var(--space-600)] ${isCenter ? "items-center" : ""}`}
>
<div
className={`flex w-full flex-col gap-[var(--spacing-scale-020)] ${lockupAlign}`}
className={`flex w-full flex-col gap-[var(--space-500)] ${lockupAlign}`}
>
<h1
id={titleId}
@@ -44,23 +44,23 @@ const SectionHeader = memo<SectionHeaderProps>(
ruleStackDesktopTypeScale &&
variant === "multi-line";
const rowAlignClasses = splitFromMd
? "md:flex-row md:justify-between md:items-center xl:gap-[var(--spacing-scale-024)]"
? "md:flex-row md:justify-between md:items-center xl:gap-[var(--space-600)]"
: variant === "multi-line"
? "lg:flex-row lg:justify-between lg:items-center xl:gap-[var(--spacing-scale-024)]"
: "lg:flex-row lg:justify-between lg:items-start xl:gap-[var(--spacing-scale-024)]";
? "lg:flex-row lg:justify-between lg:items-center xl:gap-[var(--space-600)]"
: "lg:flex-row lg:justify-between lg:items-start xl:gap-[var(--space-600)]";
return (
<div
className={`flex flex-col gap-[var(--spacing-scale-004)] w-full ${rowAlignClasses}`}
className={`flex flex-col gap-[var(--space-100)] w-full ${rowAlignClasses}`}
>
{/* Title — left column at md+ (use cases) or lg+ */}
<div
className={
variant === "multi-line"
? splitFromMd
? "md:w-[50%] md:h-[var(--spacing-scale-120)] md:flex md:items-center xl:w-[50%] xl:h-[156px] xl:flex xl:items-center"
: "lg:w-[50%] lg:h-[var(--spacing-scale-120)] lg:flex lg:items-center xl:w-[50%] xl:h-[156px] xl:flex xl:items-center"
: "lg:w-[369px] lg:h-[var(--spacing-scale-120)] lg:flex lg:items-center xl:w-[452px] xl:h-[156px] xl:flex xl:items-center"
? "md:w-[50%] md:h-[var(--space-3000)] md:flex md:items-center xl:w-[50%] xl:h-[156px] xl:flex xl:items-center"
: "lg:w-[50%] lg:h-[var(--space-3000)] lg:flex lg:items-center xl:w-[50%] xl:h-[156px] xl:flex xl:items-center"
: "lg:w-[369px] lg:h-[var(--space-3000)] lg:flex lg:items-center xl:w-[452px] xl:h-[156px] xl:flex xl:items-center"
}
>
<h2
@@ -71,7 +71,7 @@ const SectionHeader = memo<SectionHeaderProps>(
? "font-bricolage-grotesque text-medium-heading text-[var(--color-content-default-primary)] md:w-full md:max-w-[571px] md:text-left md:text-large-heading xl:text-xx-large-heading"
: "font-bricolage-grotesque text-medium-heading md:text-large-heading lg:w-full lg:max-w-[571px] lg:text-left lg:text-large-heading xl:text-xx-large-heading text-[var(--color-content-default-primary)]"
: "font-bricolage-grotesque text-medium-heading md:text-large-heading lg:w-[410px] lg:text-left xl:text-xx-large-heading text-[var(--color-content-default-primary)]"
: "font-bricolage-grotesque text-medium-heading sm:text-large-heading lg:text-large-heading lg:w-[369px] lg:pr-[var(--spacing-scale-096)] xl:text-xx-large-heading xl:w-[452px] xl:pr-[var(--spacing-scale-096)] text-[var(--color-content-default-primary)]"
: "font-bricolage-grotesque text-medium-heading sm:text-large-heading lg:text-large-heading lg:w-[369px] lg:pr-[var(--space-2400)] xl:text-xx-large-heading xl:w-[452px] xl:pr-[var(--space-2400)] text-[var(--color-content-default-primary)]"
}
>
<span className={splitFromMd ? "block md:hidden" : "block lg:hidden"}>
@@ -97,10 +97,10 @@ const SectionHeader = memo<SectionHeaderProps>(
variant === "multi-line"
? ruleStackDesktopTypeScale
? splitFromMd
? "md:w-[50%] md:h-[var(--spacing-scale-120)] md:flex md:items-center md:justify-start md: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-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"
? "md:w-[50%] md:h-[var(--space-3000)] md:flex md:items-center md:justify-start md:ml-[var(--space-400)] xl:ml-0 xl:w-[50%] xl:h-[156px] xl:flex xl:items-center xl:justify-start"
: "lg:w-[50%] lg:h-[var(--space-3000)] lg:flex lg:items-center lg:justify-start lg:ml-[var(--space-400)] xl:ml-0 xl:w-[50%] xl:h-[156px] xl:flex xl:items-center xl:justify-start"
: "lg:w-[50%] lg:h-[var(--space-3000)] lg:flex lg:items-center lg:justify-end lg:ml-[var(--space-400)] xl:ml-0 xl:w-[50%] xl:h-[156px] xl:flex xl:items-center xl:justify-end"
: "lg:w-[928px] lg:h-[var(--space-3000)] lg:flex lg:items-center lg:justify-end xl:h-[156px] xl:flex xl:items-center xl:justify-end"
}
>
<p
@@ -57,7 +57,7 @@ function LabeledRowView({ row }: { row: TextRow }) {
<img
src={imageSrc}
alt={alt}
className="max-h-[240px] max-w-full rounded-[var(--measures-radius-200,8px)] object-contain"
className="max-h-[240px] max-w-full rounded-[var(--radius-200)] object-contain"
/>
{hasCaption ? <ParagraphGroup text={row.body} /> : null}
</>
@@ -28,10 +28,10 @@ function TripleStepView({
<section
data-figma-node="22084-859405"
aria-labelledby={headingId}
className={`bg-transparent px-[var(--spacing-scale-032)] py-[var(--spacing-scale-032)] md:px-0 md:py-[var(--spacing-scale-048)] ${className}`.trim()}
className={`bg-transparent px-[var(--space-800)] py-[var(--space-800)] md:px-0 md:py-[var(--space-1200)] ${className}`.trim()}
>
<div className="mx-auto grid w-full min-w-0 max-w-[560px] grid-cols-1 items-center gap-[var(--spacing-scale-032)] md:max-w-none md:grid-cols-2 md:gap-0">
<div className="flex w-full min-w-0 flex-col gap-[var(--spacing-scale-040)] break-words md:pl-[var(--spacing-scale-032)] lg:min-w-[358px] lg:pl-[var(--spacing-scale-064)]">
<div className="mx-auto grid w-full min-w-0 max-w-[560px] grid-cols-1 items-center gap-[var(--space-800)] md:max-w-none md:grid-cols-2 md:gap-0">
<div className="flex w-full min-w-0 flex-col gap-[var(--space-1000)] break-words md:pl-[var(--space-800)] lg:min-w-[358px] lg:pl-[var(--space-1800)]">
<h2
id={headingId}
className="font-bricolage-grotesque text-medium-heading text-[var(--color-content-default-primary)] md:text-large-heading"
@@ -41,7 +41,7 @@ function TripleStepView({
{steps.map((step, index) => (
<div
key={step.title}
className="flex flex-col items-start gap-[var(--spacing-scale-016)]"
className="flex flex-col items-start gap-[var(--space-400)]"
>
<AssetIcon
name={
@@ -66,7 +66,7 @@ function TripleStepView({
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-medium-label md:!gap-[var(--spacing-scale-006)]"
className="max-md:!px-[var(--space-300)] max-md:!py-[var(--space-250)] max-md:!text-[14px] max-md:!leading-[18px] md:!p-[var(--space-300)] md:!text-medium-label md:!gap-[var(--space-150)]"
>
{ctaText}
</Button>
@@ -29,14 +29,14 @@ function splitDescriptionParagraphs(description: string): {
function TripleTextUseCasesColumn({ column }: { column: TripleTextBlockColumn }) {
return (
<article className="flex w-full flex-col gap-[var(--spacing-scale-006)] md: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]">
<article className="flex w-full flex-col gap-[var(--space-150)] md:gap-[var(--space-200)] lg:gap-[var(--space-100)] xl:gap-[var(--space-200)]">
<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(--scale-022)] xl:text-[32px] xl:leading-[1.1]">
{column.title}
</h3>
<div className="flex flex-col text-medium-paragraph text-[var(--color-content-default-secondary)] md:text-x-large-paragraph lg:text-small-paragraph xl:text-x-large-paragraph">
<p>{column.description}</p>
{column.descriptionSecondary ? (
<p className="mt-[var(--spacing-scale-024)] md:mt-[var(--spacing-scale-032)] lg:mt-0 lg:pt-[var(--spacing-scale-020)] xl:mt-[var(--spacing-scale-032)]">
<p className="mt-[var(--space-600)] md:mt-[var(--space-800)] lg:mt-0 lg:pt-[var(--space-500)] xl:mt-[var(--space-800)]">
{column.descriptionSecondary}
</p>
) : null}
@@ -136,13 +136,13 @@ function TripleTextBlockView({
<section
{...(isUseCases ? { "data-figma-node": "22085-860414" } : {})}
aria-labelledby={hasSectionTitle ? headingId : undefined}
className={`bg-black py-[var(--spacing-scale-064)] px-[var(--spacing-scale-032)] md:px-[var(--spacing-scale-096)] lg:px-[var(--spacing-scale-096)] xl:px-[var(--spacing-scale-160)] ${className}`.trim()}
className={`bg-black py-[var(--space-1800)] px-[var(--space-800)] md:px-[var(--space-2400)] lg:px-[var(--space-2400)] xl:px-[var(--space-4000)] ${className}`.trim()}
>
<div
className={
isUseCases
? "mx-auto flex w-full 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 flex-col items-start gap-[var(--spacing-scale-032)]"
? "mx-auto flex w-full flex-col items-start gap-[var(--space-800)] md:gap-[var(--space-1200)] lg:items-center lg:gap-[var(--space-1800)]"
: "mx-auto flex w-full flex-col items-start gap-[var(--space-800)]"
}
>
{hasSectionTitle ? (
@@ -160,8 +160,8 @@ function TripleTextBlockView({
<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-048)] lg:flex-row lg:items-start lg:gap-[var(--spacing-scale-032)]"
? "flex w-full flex-col gap-[var(--space-1200)] lg:flex-row lg:items-start lg:gap-[var(--space-800)]"
: "flex w-full flex-col gap-[var(--space-1200)] lg:flex-row lg:items-start lg:gap-[var(--space-800)]"
}
>
{columns.map((column, index) => (
+2 -2
View File
@@ -11,12 +11,12 @@ export function TagView({ variant, children, className }: TagViewProps) {
const bgClass = isTemplateRecommended
? "bg-[var(--color-surface-default-tertiary)]"
: isRecommended
? "bg-[var(--color-surface-inverse-brand-accent)]"
? "bg-[var(--color-surface-invert-brand-accent)]"
: "bg-[var(--color-gray-1000)]";
const textClass = isTemplateRecommended
? "text-[var(--color-gray-000)]"
: isRecommended
? "text-[var(--color-content-inverse-brand-primary)]"
? "text-[var(--color-content-invert-brand-primary)]"
: "text-[var(--color-gray-000)]";
return (