diff --git a/docs/memory/component-registry.md b/docs/memory/component-registry.md index 16d133f..9b30e0f 100644 --- a/docs/memory/component-registry.md +++ b/docs/memory/component-registry.md @@ -37,7 +37,7 @@ duplicates) and MUST update it after completing one. | Component | Status | Composed of | Notes | |-----------|--------|-------------|-------| | FormField | planned | Input + Typography (label) + Typography (helper) | Standard form field with label and validation | -| ProviderCard | review | Card + Typography + Badge | Provider listing card. Verified: image + logo + "Trusted Partner" badge. Unverified: text-only. Capability badges (arbitrary label + colour). Footer with "Packages from $X >". 7 component tokens. | +| ProviderCard | review | Card + Typography + Badge + Tooltip | Provider listing card. Verified: image + logo (64px rounded rect) + "Verified" badge. Unverified: text-only with top accent bar. Capability badges with info icon + tooltip. Price split typography. No footer. 4 component tokens. | | VenueCard | planned | Card + Typography + Badge | Venue listing card. Always has photo, location, capacity, price. Simpler than ProviderCard. | | MapCard | planned | Card + Typography + Badge | Compact horizontal map popup card. Deferred until map integration. | | ServiceOption | planned | Card + Typography + Chip + Icon | Selectable service item | diff --git a/docs/memory/session-log.md b/docs/memory/session-log.md index 806eeb8..ecad461 100644 --- a/docs/memory/session-log.md +++ b/docs/memory/session-log.md @@ -537,7 +537,46 @@ Each entry follows this structure: - **Planned (5 organisms):** ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer **Next steps:** -- User to review ProviderCard in Storybook — especially ListLayout story for verified/unverified alignment +- ~~User to review ProviderCard in Storybook~~ ✓ Feedback received, iterated in session 25m + +### Session 2026-03-25m — ProviderCard v2 refinements from user feedback + +**Agent(s):** Claude Opus (via conversation) + +**Work completed:** +- Iterated on ProviderCard based on 5 feedback items from user review +- **Logo**: circle → 64px rounded rectangle (8px radius, `borderRadius.md`). Positioned fully inside image area (absolute, bottom-left) with white border + shadow. Eliminates dead space — name sits directly below image. +- **Footer removed**: "View packages >" bar was redundant (whole card is clickable, price already in content). Removed 3 footer tokens (`footer.background`, `.paddingX`, `.paddingY`). +- **Price typography**: Split into "Packages from" (body2, 14px, secondary) + price (h6, 16px, weight 500, primary). Lighter, streamlined ecommerce feel vs old blocky labelLg/700. +- **Verified badge**: Bumped from `size="small"` to `size="medium"` for visibility. +- **Capability badge**: Bumped to `size="medium"`. Added trailing `InfoOutlinedIcon` and new `capabilityDescription` prop — wraps badge in MUI Tooltip on hover/focus for plain-language definitions of industry jargon. +- **Unverified card differentiation**: 3px `borderTop` (neutral.200) as visual anchor. ListLayout story now on neutral.50 background. +- **Caption weight fix (system-wide)**: Caption and CaptionSm bumped from fontWeight 400 (Regular) → 500 (Medium) in semantic typography tokens. Aligns with D019 — user found Regular too light for Montserrat. +- **Meta row**: Location/reviews dropped from body2 (14px) → caption (12px) with 14px icons for clearer tertiary hierarchy. +- Updated all stories with `capabilityDescription` tooltips for 3 capability types +- Preflight passed all 5 checks + +**Decisions made:** +- Logo positioned fully inside image (no overlap into content) — tried flex-row overlap approach first but it "dug into" the photo and pushed the name sideways +- Footer removal: card's interactive hover + price in content are sufficient affordance +- Caption weight 500: extends D019 (body weight = Medium) to all Montserrat text variants. Only display (Noto Serif SC) stays at 400 per D018. +- Info icon for capability badges: trailing position (after label), `cursor: help` when tooltip active + +**Token changes:** +- `providerCard.logo.size`: 56px → 64px +- `providerCard.logo.borderRadius`: new, → `{borderRadius.md}` (8px) +- `providerCard.footer.*`: 3 tokens removed (footer eliminated) +- `typography.caption.fontWeight`: `{fontWeight.regular}` → `{fontWeight.medium}` +- `typography.captionSm.fontWeight`: `{fontWeight.regular}` → `{fontWeight.medium}` + +**Component status at end of session:** +- **Done (8):** Button, Typography, Input, Card, Badge, Chip, Switch, Radio +- **Review (1 molecule):** ProviderCard (v2, user approved direction) +- **Planned (6 atoms):** IconButton, Icon, Avatar, Divider, ColourToggle, Slider, Link +- **Planned (5 molecules):** VenueCard, MapCard, ServiceOption, SearchBar, StepIndicator, FormField +- **Planned (5 organisms):** ServiceSelector, PricingTable, ArrangementForm, Navigation, Footer + +**Next steps:** - Build VenueCard molecule (simpler — always has photo, location, capacity, price) - Consider MapCard as a deferred item until map integration - Address P2 audit issues in a future cleanup pass diff --git a/docs/memory/token-registry.md b/docs/memory/token-registry.md index 9765532..1e64dbb 100644 --- a/docs/memory/token-registry.md +++ b/docs/memory/token-registry.md @@ -272,9 +272,7 @@ the correct token for any design property. | Token path | Value / Reference | Used by | Description | |-----------|-----------|---------|-------------| | providerCard.image.height | 180px | ProviderCard | Hero image fixed height | -| providerCard.logo.size | 48px | ProviderCard | Logo circle diameter | -| providerCard.footer.background | → color.brand.100 (#F7ECDF) | ProviderCard | Warm beige footer bar | -| providerCard.footer.paddingX | → spacing.4 (16px) | ProviderCard | Footer horizontal padding | -| providerCard.footer.paddingY | → spacing.3 (12px) | ProviderCard | Footer vertical padding | -| providerCard.content.padding | → spacing.4 (16px) | ProviderCard | Content area padding | -| providerCard.content.gap | → spacing.2 (8px) | ProviderCard | Gap between content rows | +| providerCard.logo.size | 64px | ProviderCard | Logo width/height — rounded rectangle inside image area | +| providerCard.logo.borderRadius | → borderRadius.md (8px) | ProviderCard | Rounded rectangle corners | +| providerCard.content.padding | → spacing.3 (12px) | ProviderCard | Content area padding | +| providerCard.content.gap | → spacing.1 (4px) | ProviderCard | Gap between content rows | diff --git a/src/components/molecules/ProviderCard/ProviderCard.stories.tsx b/src/components/molecules/ProviderCard/ProviderCard.stories.tsx index 57745f7..c419b6d 100644 --- a/src/components/molecules/ProviderCard/ProviderCard.stories.tsx +++ b/src/components/molecules/ProviderCard/ProviderCard.stories.tsx @@ -2,18 +2,18 @@ import type { Meta, StoryObj } from '@storybook/react'; import { ProviderCard } from './ProviderCard'; import Box from '@mui/material/Box'; -// Placeholder images for stories (grey boxes via data URIs) +// Placeholder images for stories const HERO_PLACEHOLDER = 'https://images.unsplash.com/photo-1600585154340-be6161a56a0c?w=600&h=300&fit=crop&auto=format'; const HERO_PLACEHOLDER_2 = 'https://images.unsplash.com/photo-1497366216548-37526070297c?w=600&h=300&fit=crop&auto=format'; const HERO_PLACEHOLDER_3 = 'https://images.unsplash.com/photo-1486406146926-c627a92ad1ab?w=600&h=300&fit=crop&auto=format'; -// Simple grey circle for logo placeholder +// Rounded-rect logo placeholder (matches new logo shape) const LOGO_PLACEHOLDER = 'data:image/svg+xml,' + encodeURIComponent( - 'Logo', + 'Logo', ); const meta: Meta = { @@ -38,6 +38,7 @@ const meta: Meta = { control: 'select', options: ['default', 'success', 'warning', 'error', 'info'], }, + capabilityDescription: { control: 'text' }, startingPrice: { control: 'number' }, onClick: { action: 'clicked' }, }, @@ -67,6 +68,7 @@ export const Default: Story = { reviewCount: 127, capabilityLabel: 'Online Arrangement', capabilityColor: 'success', + capabilityDescription: 'Complete your arrangement entirely online — no in-person visit required.', startingPrice: 900, }, }; @@ -87,6 +89,7 @@ export const VerifiedProvider: Story = { reviewCount={127} capabilityLabel="Online Arrangement" capabilityColor="success" + capabilityDescription="Complete your arrangement entirely online — no in-person visit required." startingPrice={900} onClick={() => {}} /> @@ -95,7 +98,7 @@ export const VerifiedProvider: Story = { // ─── Unverified Provider ──────────────────────────────────────────────────── -/** Unverified provider — text only, no image/logo/trusted badge */ +/** Unverified provider — text only with top accent bar, no image/logo/trusted badge */ export const UnverifiedProvider: Story = { name: 'Unverified Provider', render: () => ( @@ -106,6 +109,7 @@ export const UnverifiedProvider: Story = { reviewCount={43} capabilityLabel="Outsourced" capabilityColor="default" + capabilityDescription="This provider uses a third-party service to manage arrangements." startingPrice={1200} onClick={() => {}} /> @@ -115,15 +119,25 @@ export const UnverifiedProvider: Story = { // ─── List Layout ──────────────────────────────────────────────────────────── /** - * Mixed verified and unverified providers in a scrollable list. - * This is the primary use case — text alignment should be consistent - * across both card types for scan readability. + * Mixed verified and unverified providers in a scrollable list on + * neutral.50 background. This is the primary use case — text alignment + * should be consistent across both card types for scan readability. + * Unverified cards have a top accent bar for visibility. */ export const ListLayout: Story = { name: 'List Layout — Mixed', decorators: [ (Story) => ( - + ), @@ -140,6 +154,7 @@ export const ListLayout: Story = { reviewCount={127} capabilityLabel="Online Arrangement" capabilityColor="success" + capabilityDescription="Complete your arrangement entirely online — no in-person visit required." startingPrice={900} onClick={() => {}} /> @@ -153,6 +168,7 @@ export const ListLayout: Story = { reviewCount={89} capabilityLabel="Online Arrangement" capabilityColor="success" + capabilityDescription="Complete your arrangement entirely online — no in-person visit required." startingPrice={1100} onClick={() => {}} /> @@ -163,6 +179,7 @@ export const ListLayout: Story = { reviewCount={43} capabilityLabel="Outsourced" capabilityColor="default" + capabilityDescription="This provider uses a third-party service to manage arrangements." startingPrice={1200} onClick={() => {}} /> @@ -173,6 +190,7 @@ export const ListLayout: Story = { reviewCount={18} capabilityLabel="Partial Arrangement" capabilityColor="warning" + capabilityDescription="Some steps can be completed online, but an in-person visit is required to finalise." startingPrice={950} onClick={() => {}} /> @@ -186,6 +204,7 @@ export const ListLayout: Story = { reviewCount={203} capabilityLabel="Online Arrangement" capabilityColor="success" + capabilityDescription="Complete your arrangement entirely online — no in-person visit required." startingPrice={1500} onClick={() => {}} /> @@ -195,7 +214,7 @@ export const ListLayout: Story = { // ─── Capability Variants ──────────────────────────────────────────────────── -/** Three capability badge colours */ +/** Three capability badge colours with hover tooltips */ export const CapabilityVariants: Story = { name: 'Capability Variants', decorators: [ @@ -212,6 +231,7 @@ export const CapabilityVariants: Story = { location="Sydney" capabilityLabel="Online Arrangement" capabilityColor="success" + capabilityDescription="Complete your arrangement entirely online — no in-person visit required." startingPrice={900} onClick={() => {}} /> @@ -220,6 +240,7 @@ export const CapabilityVariants: Story = { location="Melbourne" capabilityLabel="Partial Arrangement" capabilityColor="warning" + capabilityDescription="Some steps can be completed online, but an in-person visit is required to finalise." startingPrice={1100} onClick={() => {}} /> @@ -228,6 +249,7 @@ export const CapabilityVariants: Story = { location="Brisbane" capabilityLabel="Outsourced" capabilityColor="default" + capabilityDescription="This provider uses a third-party service to manage arrangements." startingPrice={800} onClick={() => {}} /> @@ -278,7 +300,7 @@ export const EdgeCases: Story = { startingPrice={600} onClick={() => {}} /> - {/* No price (footer hidden) */} + {/* No price */} void; @@ -43,13 +46,10 @@ export interface ProviderCardProps { // ─── Constants ─────────────────────────────────────────────────────────────── const LOGO_SIZE = 'var(--fa-provider-card-logo-size)'; -const LOGO_OVERLAP = 28; // half of 56px logo, in px +const LOGO_BORDER_RADIUS = 'var(--fa-provider-card-logo-border-radius)'; const IMAGE_HEIGHT = 'var(--fa-provider-card-image-height)'; const CONTENT_PADDING = 'var(--fa-provider-card-content-padding)'; const CONTENT_GAP = 'var(--fa-provider-card-content-gap)'; -const FOOTER_BG = 'var(--fa-provider-card-footer-background)'; -const FOOTER_PX = 'var(--fa-provider-card-footer-padding-x)'; -const FOOTER_PY = 'var(--fa-provider-card-footer-padding-y)'; // ─── Component ─────────────────────────────────────────────────────────────── @@ -60,9 +60,9 @@ const FOOTER_PY = 'var(--fa-provider-card-footer-padding-y)'; * list. Supports verified (paid partner) and unverified (scraped listing) * providers with consistent text alignment for scan readability. * - * **Verified providers** get a hero image, logo overlay, and "Verified" - * badge. **Unverified providers** show text content only — no image, logo, - * or verification badge. + * **Verified providers** get a hero image, logo (rounded rectangle inside + * image area), and "Verified" badge. **Unverified providers** show text + * content only with a subtle top accent bar for visibility in mixed lists. * * Composes: Card (interactive, padding="none"), Badge, Typography. * @@ -95,6 +95,7 @@ export const ProviderCard = React.forwardRef( reviewCount, capabilityLabel, capabilityColor = 'default', + capabilityDescription, startingPrice, onClick, sx, @@ -118,6 +119,11 @@ export const ProviderCard = React.forwardRef( '&:hover': { backgroundColor: 'background.paper', }, + // Unverified cards: subtle top accent so they don't get lost + // in a mixed list. Verified cards have the hero image as anchor. + ...(!showImage && { + borderTop: '3px solid var(--fa-color-border-default)', + }), }, ...(Array.isArray(sx) ? sx : [sx]), ]} @@ -139,14 +145,14 @@ export const ProviderCard = React.forwardRef( } > Verified - {/* Logo overlay */} + {/* Logo — fully inside image area, bottom-left */} {showLogo && ( ( alt={`${name} logo`} sx={{ position: 'absolute', - bottom: -LOGO_OVERLAP, + bottom: 12, left: CONTENT_PADDING, width: LOGO_SIZE, height: LOGO_SIZE, - borderRadius: '50%', + borderRadius: LOGO_BORDER_RADIUS, objectFit: 'cover', backgroundColor: 'background.paper', - boxShadow: '0 2px 8px rgba(0,0,0,0.12)', + boxShadow: '0 2px 8px rgba(0,0,0,0.15)', + border: '2px solid white', }} /> )} @@ -175,20 +182,28 @@ export const ProviderCard = React.forwardRef( flexDirection: 'column', gap: CONTENT_GAP, p: CONTENT_PADDING, - // Extra top padding when logo overlaps into content - ...(showLogo && { pt: `calc(${CONTENT_PADDING} + ${LOGO_OVERLAP}px)` }), }} > - {/* Provider name */} + {/* Provider name — full width, no logo competition */} {name} - {/* Price — primary comparison data, prominent position */} + {/* Price — "Packages from $X" with subtle size differentiation */} {startingPrice != null && ( - - From ${startingPrice.toLocaleString('en-AU')} - + + + Packages from + + + ${startingPrice.toLocaleString('en-AU')} + + )} {/* Meta row: location + reviews */} @@ -203,9 +218,9 @@ export const ProviderCard = React.forwardRef( {/* Location */} - + {location} @@ -217,10 +232,10 @@ export const ProviderCard = React.forwardRef( aria-label={`Rated ${rating} out of 5${reviewCount != null ? `, ${reviewCount} reviews` : ''}`} > - + {rating} {reviewCount != null && ` (${reviewCount.toLocaleString('en-AU')})`} @@ -228,35 +243,34 @@ export const ProviderCard = React.forwardRef( )} - {/* Capability badge */} + {/* Capability badge — trailing info icon signals hover-for-definition */} {capabilityLabel && ( - - {capabilityLabel} - + {capabilityDescription ? ( + + + {capabilityLabel} + + + + ) : ( + + {capabilityLabel} + + + )} )} - - {/* ── Footer bar ── */} - - - View packages - - - ); }, diff --git a/src/theme/generated/tokens.css b/src/theme/generated/tokens.css index 1a084d6..1257372 100644 --- a/src/theme/generated/tokens.css +++ b/src/theme/generated/tokens.css @@ -27,7 +27,7 @@ --fa-input-height-md: 48px; /** Medium (default) — standard forms, matches Button large for alignment */ --fa-input-icon-size-default: 20px; /** 20px — icon size inside input field, matches Figma trailing icon */ --fa-provider-card-image-height: 180px; /** Fixed image height for consistent card sizing in list layouts */ - --fa-provider-card-logo-size: 56px; /** Logo circle diameter — positioned bottom-left of image, overlapping content area */ + --fa-provider-card-logo-size: 64px; /** Logo width/height — rounded rectangle, overlapping image bottom into content row */ --fa-radio-size-default: 20px; /** Default radio size — matches Figma 16px + padding for 44px touch target area */ --fa-radio-dot-size-default: 10px; /** Selected indicator dot — 50% of outer size */ --fa-switch-track-width: 44px; /** Track width — slightly narrower than Figma 52px for better proportion with 44px touch target */ @@ -267,9 +267,7 @@ --fa-input-font-size-default: var(--fa-font-size-base); /** 16px — prevents iOS auto-zoom on focus, matches Figma */ --fa-input-border-radius-default: var(--fa-border-radius-sm); /** 4px — subtle rounding, consistent with Figma design */ --fa-input-gap-default: var(--fa-spacing-2); /** 8px — vertical rhythm between label/input/helper, slightly more generous than Figma's 6px for readability */ - --fa-provider-card-footer-background: var(--fa-color-brand-100); /** Warm beige footer — brand.100 provides subtle brand warmth */ - --fa-provider-card-footer-padding-x: var(--fa-spacing-4); /** 16px horizontal padding — matches compact card padding */ - --fa-provider-card-footer-padding-y: var(--fa-spacing-2); /** 8px vertical padding — compact footer bar */ + --fa-provider-card-logo-border-radius: var(--fa-border-radius-md); /** 8px rounded rectangle — softer than circle, matches card border radius */ --fa-provider-card-content-padding: var(--fa-spacing-3); /** 12px content padding — tight to keep card compact in listing layout */ --fa-provider-card-content-gap: var(--fa-spacing-1); /** 4px vertical gap between content rows — tight for compact listing cards */ --fa-switch-track-border-radius: var(--fa-border-radius-full); /** Pill shape */ @@ -385,10 +383,10 @@ --fa-typography-label-sm-font-weight: var(--fa-font-weight-medium); --fa-typography-caption-font-family: var(--fa-font-family-body); --fa-typography-caption-font-size: var(--fa-font-size-xs); /** 12px */ - --fa-typography-caption-font-weight: var(--fa-font-weight-regular); + --fa-typography-caption-font-weight: var(--fa-font-weight-medium); --fa-typography-caption-sm-font-family: var(--fa-font-family-body); --fa-typography-caption-sm-font-size: var(--fa-font-size-2xs); /** 11px — accessibility floor */ - --fa-typography-caption-sm-font-weight: var(--fa-font-weight-regular); + --fa-typography-caption-sm-font-weight: var(--fa-font-weight-medium); --fa-typography-overline-font-family: var(--fa-font-family-body); --fa-typography-overline-font-size: var(--fa-font-size-xs); /** 12px */ --fa-typography-overline-font-weight: var(--fa-font-weight-semibold); diff --git a/src/theme/generated/tokens.js b/src/theme/generated/tokens.js index af089aa..0c3dfd1 100644 --- a/src/theme/generated/tokens.js +++ b/src/theme/generated/tokens.js @@ -73,10 +73,8 @@ export const InputBorderRadiusDefault = "4px"; // 4px — subtle rounding, consi export const InputGapDefault = "8px"; // 8px — vertical rhythm between label/input/helper, slightly more generous than Figma's 6px for readability export const InputIconSizeDefault = "20px"; // 20px — icon size inside input field, matches Figma trailing icon export const ProviderCardImageHeight = "180px"; // Fixed image height for consistent card sizing in list layouts -export const ProviderCardLogoSize = "56px"; // Logo circle diameter — positioned bottom-left of image, overlapping content area -export const ProviderCardFooterBackground = "#f7ecdf"; // Warm beige footer — brand.100 provides subtle brand warmth -export const ProviderCardFooterPaddingX = "16px"; // 16px horizontal padding — matches compact card padding -export const ProviderCardFooterPaddingY = "8px"; // 8px vertical padding — compact footer bar +export const ProviderCardLogoSize = "64px"; // Logo width/height — rounded rectangle, overlapping image bottom into content row +export const ProviderCardLogoBorderRadius = "8px"; // 8px rounded rectangle — softer than circle, matches card border radius export const ProviderCardContentPadding = "12px"; // 12px content padding — tight to keep card compact in listing layout export const ProviderCardContentGap = "4px"; // 4px vertical gap between content rows — tight for compact listing cards export const RadioSizeDefault = "20px"; // Default radio size — matches Figma 16px + padding for 44px touch target area @@ -403,13 +401,13 @@ export const TypographyLabelSmLetterSpacing = "0.2px"; export const TypographyCaptionFontFamily = "'Montserrat', 'Helvetica Neue', Arial, sans-serif"; export const TypographyCaptionFontSize = "0.75rem"; // 12px -export const TypographyCaptionFontWeight = 400; +export const TypographyCaptionFontWeight = 500; export const TypographyCaptionLineHeight = 1.417; export const TypographyCaptionLetterSpacing = "0.2px"; export const TypographyCaptionSmFontFamily = "'Montserrat', 'Helvetica Neue', Arial, sans-serif"; export const TypographyCaptionSmFontSize = "0.6875rem"; // 11px — accessibility floor -export const TypographyCaptionSmFontWeight = 400; +export const TypographyCaptionSmFontWeight = 500; export const TypographyCaptionSmLineHeight = 1.364; export const TypographyCaptionSmLetterSpacing = "0.2px"; export const TypographyOverlineFontFamily = diff --git a/tokens/component/providerCard.json b/tokens/component/providerCard.json index 97ee69a..babe624 100644 --- a/tokens/component/providerCard.json +++ b/tokens/component/providerCard.json @@ -7,26 +7,16 @@ "height": { "$value": "180px", "$description": "Fixed image height for consistent card sizing in list layouts" } }, "logo": { - "$type": "dimension", "$description": "Provider logo overlay dimensions.", - "size": { "$value": "56px", "$description": "Logo circle diameter — positioned bottom-left of image, overlapping content area" } - }, - "footer": { - "$description": "Footer bar styling — warm beige bar with package pricing.", - "background": { - "$type": "color", - "$value": "{color.brand.100}", - "$description": "Warm beige footer — brand.100 provides subtle brand warmth" - }, - "paddingX": { + "size": { "$type": "dimension", - "$value": "{spacing.4}", - "$description": "16px horizontal padding — matches compact card padding" + "$value": "64px", + "$description": "Logo width/height — rounded rectangle, overlapping image bottom into content row" }, - "paddingY": { + "borderRadius": { "$type": "dimension", - "$value": "{spacing.2}", - "$description": "8px vertical padding — compact footer bar" + "$value": "{borderRadius.md}", + "$description": "8px rounded rectangle — softer than circle, matches card border radius" } }, "content": { diff --git a/tokens/semantic/typography.json b/tokens/semantic/typography.json index 90a3629..1d84e87 100644 --- a/tokens/semantic/typography.json +++ b/tokens/semantic/typography.json @@ -162,18 +162,18 @@ }, "caption": { - "$description": "Caption default — fine print, timestamps, metadata. Montserrat Regular.", + "$description": "Caption default — fine print, timestamps, metadata. Montserrat Medium.", "fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" }, "fontSize": { "$value": "{fontSize.xs}", "$type": "dimension", "$description": "12px" }, - "fontWeight": { "$value": "{fontWeight.regular}", "$type": "fontWeight" }, + "fontWeight": { "$value": "{fontWeight.medium}", "$type": "fontWeight" }, "lineHeight": { "$value": 1.417, "$type": "number" }, "letterSpacing": { "$value": "0.2px", "$type": "dimension" } }, "captionSm": { - "$description": "Caption small — compact metadata, footnotes. Montserrat Regular. Min 11px for accessibility.", + "$description": "Caption small — compact metadata, footnotes. Montserrat Medium. Min 11px for accessibility.", "fontFamily": { "$value": "{fontFamily.body}", "$type": "fontFamily" }, "fontSize": { "$value": "{fontSize.2xs}", "$type": "dimension", "$description": "11px — accessibility floor" }, - "fontWeight": { "$value": "{fontWeight.regular}", "$type": "fontWeight" }, + "fontWeight": { "$value": "{fontWeight.medium}", "$type": "fontWeight" }, "lineHeight": { "$value": 1.364, "$type": "number" }, "letterSpacing": { "$value": "0.2px", "$type": "dimension" } },