# CalloutMediaBanner Component

A full-width banner component featuring a heading, subheading, and optional action buttons. Designed for prominent page sections and hero areas with support for 5 color variants or custom background images.

## Features

- **5 Color Variants**: Default (white), Light Gray, Lilac, Green, and Gray
- **Background Image Support**: Optional image with gradient overlay for text readability
- **Mode-Aware Background Images**: Optional separate image per color scheme (light vs dark)
- **Responsive Design**: Adapts across mobile, tablet, and desktop breakpoints
- **Flexible Buttons**: Pass 0, 1, or 2 button configs; variants are assigned by count
- **Automatic Button Styling**: Intelligently selects button colors based on variant
- **Dark Mode Support**: Full light and dark mode compatibility
- **Grid Integration**: Built-in PageGrid wrapper with wide container support
- **Vertical Centering**: Automatically centers text when no buttons are present


## Responsive Behavior

The component automatically adapts its spacing and typography based on viewport width:

| Breakpoint | Padding | Content Gap | Heading Size | Subheading Size | Min Height |
|  --- | --- | --- | --- | --- | --- |
| Mobile (< 768px) | 24px | 48px | 32px | 24px | 280px |
| Tablet (768px - 1023px) | 32px | 64px | 36px | 28px | 280px |
| Desktop (≥ 1024px) | 40px | 80px | 40px | 32px | 360px |


## Color Variants

### Light Mode

| Variant | Background | Text Color | Button Color |
|  --- | --- | --- | --- |
| `default` | Inherits from parent | Black (#141414) | Green |
| `light-gray` | Gray 200 (#E6EAF0) | Black (#141414) | Black |
| `lilac` | Lilac 300 (#C0A7FF) | Black (#141414) | Black |
| `green` | Green 200 (#70EE97) | Black (#141414) | Black |
| `gray` | Gray 300 (#CAD4DF) | Black (#141414) | Black |
| `image` (textColor='white') | Background Image | White (#FFFFFF) | Green |
| `image` (textColor='black') | Background Image | Black (#141414) | Green |


### Dark Mode

| Variant | Background | Text Color | Button Color |
|  --- | --- | --- | --- |
| `default` | Inherits from parent | White (#FFFFFF) | Green |
| `light-gray` | Gray 700 (#343437) | White (#FFFFFF) | Black |
| `lilac` | Lilac 400 (#7649E3) | White (#FFFFFF) | Black |
| `green` | Green 300 (#21E46B) | Black (#141414) | Black |
| `gray` | Gray 600 (#454549) | White (#FFFFFF) | Black |
| `image` (textColor='white') | Background Image | White (#FFFFFF) | Green |
| `image` (textColor='black') | Background Image | Black (#141414) | Green |


## Props API

```typescript
interface CalloutMediaBannerProps {
  /** Color variant - determines background color (ignored if backgroundImage is provided) */
  variant?: 'default' | 'light-gray' | 'lilac' | 'green' | 'gray';
  /**
   * Background image URL. Overrides `variant` when provided.
   * Used in light mode, and also in dark mode unless `backgroundImageDark` is provided.
   */
  backgroundImage?: string;
  /**
   * Optional background image URL used when the site is in dark mode
   * (i.e. `<html class="dark">`). Falls back to `backgroundImage` if omitted.
   */
  backgroundImageDark?: string;
  /** Text color for image variant - fixes text color across light/dark modes (only applicable when backgroundImage is provided) */
  textColor?: 'white' | 'black';
  /** Main heading text */
  heading?: string;
  /** Heading element type - h1 through h6 (defaults to h6) */
  headingAs?: 'h1' | 'h2' | 'h3' | 'h4' | 'h5' | 'h6';
  /** Subheading/description text */
  subheading: string;
  /** Button configurations (1-2 buttons supported) */
  buttons?: ButtonConfig[];
  /** Additional CSS classes */
  className?: string;
}
```

### Default Values

- `variant`: `'default'`
- `backgroundImage`: `undefined`
- `textColor`: `'white'` (only used when `backgroundImage` is provided)
- `headingAs`: `'h6'`
- `buttons`: `undefined`
- `className`: `''`


### ButtonConfig

Imported from the [ButtonGroup pattern](/shared/patterns/buttongroup/readme).

```tsx
interface ButtonConfig {
  label: string;        // Button text
  href?: string;        // Link destination
  onClick?: () => void; // Click handler
}
```

A maximum of 2 buttons is supported; the array is validated by `validateButtonGroup`.

## Usage Examples

### Basic Usage with Color Variant

```tsx
import { CalloutMediaBanner } from 'shared/sections/CalloutMediaBanner';

<CalloutMediaBanner
  variant="green"
  heading="The Compliant Ledger Protocol"
  subheading="A decentralized public Layer 1 blockchain for creating, transferring, and exchanging digital assets with a focus on compliance."
  buttons={[
    { label: "Get Started", href: "/docs" },
    { label: "Learn More", href: "/about" }
  ]}
/>
```

### With Background Image (White Text - Default)

```tsx
<CalloutMediaBanner
  backgroundImage="/images/hero-bg.jpg"
  heading="Build on XRPL"
  subheading="Start building your next project on the XRP Ledger."
  buttons={[{ label: "Start Building", onClick: handleClick }]}
/>
```

### With Background Image (Black Text)

```tsx
<CalloutMediaBanner
  backgroundImage="/images/light-hero-bg.jpg"
  textColor="black"
  heading="Build on XRPL"
  subheading="Start building your next project on the XRP Ledger with black text that remains consistent across light and dark modes."
  buttons={[{ label: "Start Building", onClick: handleClick }]}
/>
```

### With Mode-Aware Background Images

Pass a separate image for each color scheme. The component swaps them purely
in CSS (no JS re-render), so the change is instant when the user toggles
between light and dark mode.

```tsx
<CalloutMediaBanner
  backgroundImage="/img/backgrounds/callout-light.jpg"
  backgroundImageDark="/img/backgrounds/callout-dark.jpg"
  heading="Build on XRPL"
  subheading="Start building your next project on the XRP Ledger."
  buttons={[{ label: "Start Building", href: "/docs" }]}
/>
```

If you provide only `backgroundImage`, that single image is used in both
modes (backward-compatible default).

### Single Button

```tsx
<CalloutMediaBanner
  variant="light-gray"
  heading="Developer Resources"
  subheading="Access comprehensive documentation and tutorials."
  buttons={[{ label: "View Docs", href: "/docs" }]}
/>
```

### No Buttons (Informational)

```tsx
<CalloutMediaBanner
  variant="lilac"
  heading="System Announcement"
  subheading="Important information or announcement without requiring user action."
/>
```

### With Click Handler

```tsx
<CalloutMediaBanner
  variant="default"
  heading="Join the Community"
  subheading="Connect with developers, validators, and enthusiasts."
  buttons={[
    {
      label: "Join Discord",
      onClick: () => window.open('https://discord.gg/xrpl', '_blank')
    },
    { label: "View Events", href: "/events" }
  ]}
/>
```

## Important Implementation Details

### Image Priority Logic

When `backgroundImage` is provided, it **overrides** the `variant` prop:

- ✅ Image is used as background
- ✅ No solid color background is applied
- ✅ Text color defaults to white (can be set to black via `textColor` prop)
- ✅ Text color remains fixed across both light and dark modes
- ✅ Gradient overlay is automatically added (dark overlay for white text, light overlay for black text)


### Button Color Logic

Buttons automatically use the appropriate color based on the variant:

- **Default variant**: Green buttons
- **Image variant**: Green buttons
- **All other variants** (light-gray, lilac, green, gray): Black buttons


### Vertical Alignment

- **With buttons**: Text stays at top, buttons stick to bottom (`justify-content: space-between`)
- **Without buttons**: Text is vertically centered (`justify-content: center`)


### Grid Integration

The component **already wraps content in PageGrid structure**. Do not nest it inside another PageGrid:

❌ **Don't do this:**

```tsx
<PageGrid>
  <PageGridRow>
    <PageGridCol span={12}>
      <CalloutMediaBanner ... />  {/* Double-wrapped! */}
    </PageGridCol>
  </PageGridRow>
</PageGrid>
```

✅ **Do this:**

```tsx
<CalloutMediaBanner ... />  {/* Already includes PageGrid internally */}
```

## Styling

### BEM Class Structure

```scss
.bds-callout-media-banner                    // Base banner
.bds-callout-media-banner--default           // Inherits parent background; only text color is themed
.bds-callout-media-banner--light-gray        // Light gray variant
.bds-callout-media-banner--lilac             // Lilac variant
.bds-callout-media-banner--green             // Green variant
.bds-callout-media-banner--gray              // Gray variant
.bds-callout-media-banner--image             // Background image variant (white text)
.bds-callout-media-banner--image-text-black  // Background image with black text (fixed across modes)
.bds-callout-media-banner--centered          // Centered content modifier
.bds-callout-media-banner__content           // Content wrapper
.bds-callout-media-banner__text              // Text container
.bds-callout-media-banner__heading           // Heading element
.bds-callout-media-banner__subheading        // Subheading element
.bds-callout-media-banner__actions           // Button container
```

### Typography Tokens

- **Heading**: Uses `heading-md` type token (Tobias Light font)
  - Desktop: 40px / 46px line-height / -1px letter-spacing
  - Tablet: 36px / 45px line-height / -0.5px letter-spacing
  - Mobile: 32px / 40px line-height / 0px letter-spacing
- **Subheading**: Uses `subhead-lg-r` type token (Booton Regular font)
  - Desktop: 32px / 40px line-height / -0.5px letter-spacing
  - Tablet: 28px / 35px line-height / -0.75px letter-spacing
  - Mobile: 24px / 30px line-height / -1px letter-spacing


### Color Tokens

All colors are sourced from `styles/_colors.scss`:

```scss
// Backgrounds
inherit       // Default variant (transparent — picks up parent's background)
$gray-200     // Light Gray variant
$lilac-300    // Lilac variant
$green-200    // Green variant
$gray-300     // Gray variant

// Dark mode backgrounds
inherit       // Default (dark) — also inherits from parent
$gray-700     // Light Gray (dark)
$lilac-400    // Lilac (dark)
$green-300    // Green (dark)
$gray-600     // Gray (dark)
```

## Accessibility

- Semantic HTML structure with proper heading hierarchy
- Button components include ARIA labels
- Keyboard navigation support through Button component
- Focus states with visible outlines
- Sufficient color contrast in all variants


## Best Practices

### When to Use Each Variant

- **Default**: Transparent banner that inherits its background from the surrounding section — use when you want the banner to blend into the page rather than introduce its own surface
- **Light Gray**: Subtle emphasis, softer than default
- **Lilac**: Special announcements, feature highlights
- **Green**: Primary brand messaging, featured content
- **Gray**: Secondary content, less prominent sections
- **Image**: Hero sections, high-impact visuals


### Content Guidelines

- **Heading**: Keep concise (1-2 short lines), use sentence case
- **Subheading**: Provide context (2-3 lines max), complete sentences
- **Buttons**: Use action-oriented labels ("Get Started" not "Click Here")
- **Button Count**: `ButtonGroup` assigns variants by count — a single button renders as primary, and with two buttons the first is primary and the second tertiary


### Image Guidelines

- Minimum recommended resolution: 1920x600px for sharp display
- Use images with clear focal points on the left/center
- **Text Color Selection**:
  - Use `textColor="white"` (default) for dark or colorful images
  - Use `textColor="black"` for light or bright images
  - Text color remains fixed across both light and dark modes
- Ensure sufficient contrast between image and text
- Test with the automatic gradient overlay (dark for white text, light for black text)


## Files

- `CalloutMediaBanner.tsx` - Component implementation
- `CalloutMediaBanner.scss` - Styles with color variants and responsive breakpoints
- `index.ts` - Barrel exports
- `README.md` - This documentation


## Related Components

- **ButtonGroup**: Renders the `buttons` array and assigns each button's variant by count
- **PageGrid**: Used internally for grid structure and wide container support


## Design References

- **Figma Design**: [Callout - Media Banner](https://www.figma.com/design/i4OuOX6QSBauMaJE4iY4kV/Callout---Media-Banner?node-id=1-2&m=dev)
- **Showcase Page**: `/about/callout-media-banner-showcase.page.tsx`
- **Component Location**: `shared/sections/CalloutMediaBanner/`


## Version History

- Initial implementation: January 2026
- Figma design alignment with 5 color variants + image support
- Responsive typography and spacing
- Automatic button color selection
- Vertical centering for text-only banners