# WCO-K04: Widget CSS custom property system
**Area:** Widget Customization Docs
**Model:** moonshotai/kimi-k2.5
**Tokens:** 8,359
**Cost:** $0.0089
**Time:** 2604ms
**Timestamp:** 2026-02-16T13:53:24.338904

---

 I'll deliver a comprehensive CSS custom property system for the Sunaiva Talking Widget. This includes the CSS architecture, TypeScript type definitions, runtime style injection, and complete documentation.

## 1. Core CSS Custom Properties (`widget-variables.css`)

```css
/**
 * Sunaiva Talking Widget - CSS Custom Property System
 * Version: 1.0.0
 * Scope: Shadow DOM with host inheritance
 * 
 * Customization Strategy:
 * - All properties use --sw-* prefix (Sunaiva Widget)
 * - Properties cascade from :host to all shadow children
 * - Fallback chain: inline style > host attribute > default value
 * - Supports dark mode via prefers-color-scheme and data-theme attribute
 */

:host {
  /* ============================================
     COLOR SYSTEM
     ============================================ */
  
  /* Primary Brand Colors */
  --sw-primary: #0066CC;
  --sw-primary-hover: #0052A3;
  --sw-primary-active: #003D7A;
  --sw-primary-subtle: rgba(0, 102, 204, 0.1);
  --sw-primary-contrast: #FFFFFF;
  
  /* Secondary/Accent Colors */
  --sw-secondary: #FF6B35;
  --sw-secondary-hover: #E55A2B;
  --sw-secondary-active: #CC4A22;
  --sw-secondary-subtle: rgba(255, 107, 53, 0.1);
  --sw-secondary-contrast: #FFFFFF;
  
  /* Semantic Status Colors (Critical for Telnyx WebRTC states) */
  --sw-success: #10B981;
  --sw-success-subtle: rgba(16, 185, 129, 0.1);
  --sw-success-contrast: #FFFFFF;
  
  --sw-warning: #F59E0B;
  --sw-warning-subtle: rgba(245, 158, 11, 0.1);
  --sw-warning-contrast: #1F2937;
  
  --sw-error: #EF4444;
  --sw-error-subtle: rgba(239, 68, 68, 0.1);
  --sw-error-contrast: #FFFFFF;
  
  --sw-info: #3B82F6;
  --sw-info-subtle: rgba(59, 130, 246, 0.1);
  --sw-info-contrast: #FFFFFF;
  
  /* Call State Specific (Telnyx WebRTC integration) */
  --sw-call-idle: #6B7280;
  --sw-call-ringing: #F59E0B;
  --sw-call-connected: #10B981;
  --sw-call-muted: #EF4444;
  --sw-call-hold: #8B5CF6;
  --sw-call-ended: #6B7280;
  
  /* Neutral Scale (Australian tradie aesthetic - high contrast for outdoor use) */
  --sw-neutral-50: #F9FAFB;
  --sw-neutral-100: #F3F4F6;
  --sw-neutral-200: #E5E7EB;
  --sw-neutral-300: #D1D5DB;
  --sw-neutral-400: #9CA3AF;
  --sw-neutral-500: #6B7280;
  --sw-neutral-600: #4B5563;
  --sw-neutral-700: #374151;
  --sw-neutral-800: #1F2937;
  --sw-neutral-900: #111827;
  
  /* Background Layers */
  --sw-bg-primary: #FFFFFF;
  --sw-bg-secondary: #F9FAFB;
  --sw-bg-tertiary: #F3F4F6;
  --sw-bg-overlay: rgba(0, 0, 0, 0.5);
  --sw-bg-backdrop: rgba(255, 255, 255, 0.8);
  
  /* Text Colors (WCAG AA compliant) */
  --sw-text-primary: #111827;
  --sw-text-secondary: #4B5563;
  --sw-text-tertiary: #9CA3AF;
  --sw-text-disabled: #D1D5DB;
  --sw-text-inverse: #FFFFFF;
  --sw-text-link: #0066CC;
  --sw-text-link-hover: #0052A3;
  
  /* Border Colors */
  --sw-border-light: #E5E7EB;
  --sw-border-default: #D1D5DB;
  --sw-border-strong: #9CA3AF;
  --sw-border-focus: #0066CC;
  
  /* ============================================
     TYPOGRAPHY SYSTEM
     ============================================ */
  
  /* Font Families (System font stack for performance) */
  --sw-font-family-base: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, sans-serif;
  --sw-font-family-mono: "SF Mono", Monaco, "Cascadia Code", "Roboto Mono", Consolas, "Courier New", monospace;
  
  /* Font Sizes (16px base for accessibility) */
  --sw-font-size-xs: 0.75rem;    /* 12px */
  --sw-font-size-sm: 0.875rem;   /* 14px */
  --sw-font-size-base: 1rem;     /* 16px */
  --sw-font-size-md: 1.125rem;   /* 18px */
  --sw-font-size-lg: 1.25rem;    /* 20px */
  --sw-font-size-xl: 1.5rem;     /* 24px */
  --sw-font-size-2xl: 1.875rem;  /* 30px */
  --sw-font-size-3xl: 2.25rem;   /* 36px */
  
  /* Font Weights */
  --sw-font-weight-normal: 400;
  --sw-font-weight-medium: 500;
  --sw-font-weight-semibold: 600;
  --sw-font-weight-bold: 700;
  
  /* Line Heights */
  --sw-line-height-tight: 1.25;
  --sw-line-height-normal: 1.5;
  --sw-line-height-relaxed: 1.625;
  
  /* Letter Spacing */
  --sw-letter-spacing-tight: -0.025em;
  --sw-letter-spacing-normal: 0;
  --sw-letter-spacing-wide: 0.025em;
  
  /* ============================================
     SPACING SYSTEM (8px base unit)
     ============================================ */
  
  --sw-space-0: 0;
  --sw-space-px: 1px;
  --sw-space-0-5: 0.125rem;  /* 2px */
  --sw-space-1: 0.25rem;     /* 4px */
  --sw-space-2: 0.5rem;      /* 8px */
  --sw-space-3: 0.75rem;     /* 12px */
  --sw-space-4: 1rem;        /* 16px */
  --sw-space-5: 1.25rem;     /* 20px */
  --sw-space-6: 1.5rem;      /* 24px */
  --sw-space-8: 2rem;        /* 32px */
  --sw-space-10: 2.5rem;     /* 40px */
  --sw-space-12: 3rem;       /* 48px */
  --sw-space-16: 4rem;       /* 64px */
  --sw-space-20: 5rem;       /* 80px */
  --sw-space-24: 6rem;       /* 96px */
  
  /* ============================================
     LAYOUT & SIZING
     ============================================ */
  
  /* Widget Container Dimensions */
  --sw-widget-width: 380px;
  --sw-widget-width-mobile: 100vw;
  --sw-widget-height: 600px;
  --sw-widget-height-mobile: 100vh;
  --sw-widget-max-height: 90vh;
  
  /* Border Radius Scale */
  --sw-radius-none: 0;
  --sw-radius-sm: 0.25rem;   /* 4px */
  --sw-radius-md: 0.375rem;  /* 6px */
  --sw-radius-lg: 0.5rem;    /* 8px */
  --sw-radius-xl: 0.75rem;   /* 12px */
  --sw-radius-2xl: 1rem;     /* 16px */
  --sw-radius-3xl: 1.5rem;   /* 24px */
  --sw-radius-full: 9999px;
  
  /* Touch Targets (Minimum 44px for accessibility, 48px for gloves) */
  --sw-touch-target-sm: 36px;
  --sw-touch-target-md: 44px;
  --sw-touch-target-lg: 48px;
  --sw-touch-target-xl: 56px;
  
  /* ============================================
     EFFECTS & SHADOWS
     ============================================ */
  
  /* Box Shadows (Layered for depth) */
  --sw-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.05);
  --sw-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.1), 0 2px 4px -1px rgba(0, 0, 0, 0.06);
  --sw-shadow-lg: 0 10px 15px -3px rgba(0, 0, 0, 0.1), 0 4px 6px -2px rgba(0, 0, 0, 0.05);
  --sw-shadow-xl: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04);
  --sw-shadow-2xl: 0 25px 50px -12px rgba(0, 0, 0, 0.25);
  --sw-shadow-inner: inset 0 2px 4px 0 rgba(0, 0, 0, 0.06);
  --sw-shadow-focus: 0 0 0 3px rgba(0, 102, 204, 0.3);
  
  /* Backdrop Blur */
  --sw-blur-sm: 4px;
  --sw-blur-md: 8px;
  --sw-blur-lg: 16px;
  
  /* Opacity Scale */
  --sw-opacity-0: 0;
  --sw-opacity-25: 0.25;
  --sw-opacity-50: 0.5;
  --sw-opacity-75: 0.75;
  --sw-opacity-100: 1;
  
  /* ============================================
     ANIMATION & TRANSITIONS
     ============================================ */
  
  /* Duration Scale */
  --sw-duration-instant: 0ms;
  --sw-duration-fast: 150ms;
  --sw-duration-normal: 250ms;
  --sw-duration-slow: 350ms;
  --sw-duration-slower: 500ms;
  
  /* Easing Functions */
  --sw-ease-linear: linear;
  --sw-ease-in: cubic-bezier(0.4, 0, 1, 1);
  --sw-ease-out: cubic-bezier(0, 0, 0.2, 1);
  --sw-ease-in-out: cubic-bezier(0.4, 0, 0.2, 1);
  --sw-ease-spring: cubic-bezier(0.34, 1.56, 0.64, 1);
  --sw-ease-bounce: cubic-bezier(0.68, -0.55, 0.265, 1.55);
  
  /* Default Transitions */
  --sw-transition-colors: color var(--sw-duration-fast) var(--sw-ease-in-out), background-color var(--sw-duration-fast) var(--sw-ease-in-out), border-color var(--sw-duration-fast) var(--sw-ease-in-out);
  --sw-transition-transform: transform var(--sw-duration-normal) var(--sw-ease-spring);
  --sw-transition-opacity: opacity var(--sw-duration-fast) var(--sw-ease-in-out);
  --sw-transition-shadow: box-shadow var(--sw-duration-fast) var(--sw-ease-in-out);
  --sw-transition-all: all var(--sw-duration-fast) var(--sw-ease-in-out);
  
  /* Animation Keyframes (defined in widget-animations.css) */
  --sw-animation-pulse: sw-pulse 2s cubic-bezier(0.4, 0, 0.6, 1) infinite;
  --sw-animation-bounce: sw-bounce 1s infinite;
  --sw-animation-spin: sw-spin 1s linear infinite;
  --sw-animation-ping: sw-ping 1s cubic-bezier(0, 0, 0.2, 1) infinite;
  --sw-animation-fade-in: sw-fade-in var(--sw-duration-normal) var(--sw-ease-out);
  --sw-animation-slide-up: sw-slide-up var(--sw-duration-normal) var(--sw-ease-out);
  --sw-animation-slide-down: sw-slide-down var(--sw-duration-normal) var(--sw-ease-out);
  --sw-animation-scale-in: sw-scale-in var(--sw-duration-fast) var(--sw-ease-spring);
  
  /* ============================================
     Z-INDEX SCALE
     ============================================ */
  
  --sw-z-base: 0;
  --sw-z-dropdown: 100;
  --sw-z-sticky: 200;
  --sw-z-fixed: 300;
  --sw-z-modal-backdrop: 400;
  --sw-z-modal: 500;
  --sw-z-popover: 600;
  --sw-z-tooltip: 700;
  --sw-z-toast: 800;
  --sw-z-max: 9999;
  
  /* ============================================
     COMPONENT-SPECIFIC VARIABLES
     ============================================ */
  
  /* Header */
  --sw-header-height: 64px;
  --sw-header-bg: var(--sw-primary);
  --sw-header-text: var(--sw-primary-contrast);
  
  /* Message Bubbles */
  --sw-message-max-width: 80%;
  --sw-message-user-bg: var(--sw-primary);
  --sw-message-user-text: var(--sw-primary-contrast);
  --sw-message-ai-bg: var(--sw-neutral-100);
  --sw-message-ai-text: var(--sw-text-primary);
  --sw-message-border-radius: var(--sw-radius-lg);
  
  /* Input Area */
  --sw-input-height: 56px;
  --sw-input-bg: var(--sw-bg-primary);
  --sw-input-border: var(--sw-border-default);
  --sw-input-focus-border: var(--sw-primary);
  --sw-input-placeholder: var(--sw-text-tertiary);
  
  /* Buttons */
  --sw-button-height-sm: 36px;
  --sw-button-height-md: 44px;
  --sw-button-height-lg: 48px;
  --sw-button-border-radius: var(--sw-radius-lg);
  --sw-button-font-weight: var(--sw-font-weight-semibold);
  
  /* Call Controls (Telnyx specific) */
  --sw-call-button-size: 64px;
  --sw-call-button-bg: var(--sw-success);
  --sw-call-button-icon: var(--sw-success-contrast);
  --sw-call-end-button-bg: var(--sw-error);
  
  /* Scrollbar (Webkit) */
  --sw-scrollbar-width: 8px;
  --sw-scrollbar-track: transparent;
  --sw-scrollbar-thumb: var(--sw-neutral-300);
  --sw-scrollbar-thumb-hover: var(--sw-neutral-400);
  
  /* ============================================
     BREAKPOINT REFERENCE (for JS logic)
     ============================================ */
  
  --sw-breakpoint-sm: 640px;
  --sw-breakpoint-md: 768px;
  --sw-breakpoint-lg: 1024px;
  --sw-breakpoint-xl: 1280px;
}

/* ============================================
   DARK MODE SUPPORT
   ============================================ */

@media (prefers-color-scheme: dark) {
  :host {
    /* Only apply if widget doesn't have explicit light theme */
    color-scheme: dark;
    
    --sw-bg-primary: #111827;
    --sw-bg-secondary: #1F2937;
    --sw-bg-tertiary: #374151;
    
    --sw-text-primary: #F9FAFB;
    --sw-text-secondary: #D1D5DB;
    --sw-text-tertiary: #9CA3AF;
    
    --sw-border-light: #374151;
    --sw-border-default: #4B5563;
    --sw-border-strong: #6B7280;
    
    --sw-message-ai-bg: #1F2937;
    --sw-message-ai-text: #F9FAFB;
    
    --sw-shadow-sm: 0 1px 2px 0 rgba(0, 0, 0, 0.3);
    --sw-shadow-md: 0 4px 6px -1px rgba(0, 0, 0, 0.4), 0 2px 4px -1px rgba(0, 0, 0, 0.2);
  }
}

/* Manual theme override */
:host([data-theme="dark"]) {
  color-scheme: dark;
  
  --sw-bg-primary: #111827;
  --sw-bg-secondary: #1F2937;
  --sw-bg-tertiary: #374151;
  
  --sw-text-primary: #F9FAFB;
  --sw-text-secondary: #D1D5DB;
  --sw-text-tertiary: #9CA3AF;
  
  --sw-border-light: #374151;
  --sw-border-default: #4B5563;
  --sw-border-strong: #6B5563;
  
  --sw-message-ai-bg: #1F2937;
  --sw-message-ai-text: #F9FAFB;
}

/* High Contrast Mode (Accessibility) */
@media (prefers-contrast: high) {
  :host {
    --sw-border-default: #000000;
    --sw-border-strong: #000000;
    --sw-text-secondary: #000000;
    --sw-primary: #0000EE;
    --sw-text-link: #0000EE;
  }
}

/* Reduced Motion (Accessibility) */
@media (prefers-reduced-motion: reduce) {
  :host {
    --sw-duration-fast: 0ms;
    --sw-duration-normal: 0ms;
    --sw-duration-slow: 0ms;
    --sw-animation-pulse: none;
    --sw-animation-bounce: none;
    --sw-animation-spin: none;
  }
}

/* Glove-friendly mode (Australian tradie specific) */
:host([data-input-mode="gloves"]) {
  --sw-touch-target-sm: 48px;
  --sw-touch-target-md: 56px;
  --sw-touch-target-lg: 64px;
  --sw-space-2: 0.75rem;
  --sw-space-3: 1rem;
  --sw-font-size-base: 1.125rem;
}
```

## 2. TypeScript Type Definitions (`widget-styles.types.ts`)

```typescript
/**
 * Sunaiva Widget Style Configuration Types
 * Defines the contract for CSS custom property customization
 */

export type CSSUnit = 'px' | 'rem' | 'em' | '%' | 'vh' | 'vw' | 'ch' | 'ex';
export type CSSColor = string;
export type CSSLength = string | number;
export type CSSTime = string;
export type CSSEasing = string;

/**
 * Color palette configuration
 */
export interface WidgetColorScheme {
  primary: CSSColor;
  primaryHover?: CSSColor;
  primaryActive?: CSSColor;
  primarySubtle?: CSSColor;
  primaryContrast?: CSSColor;
  
  secondary: CSSColor;
  secondaryHover?: CSSColor;
  secondaryActive?: CSSColor;
  secondarySubtle?: CSSColor;
  secondaryContrast?: CSSColor;
  
  success: CSSColor;
  successSubtle?: CSSColor;
  successContrast?: CSSColor;
  
  warning: CSSColor;
  warningSubtle?: CSSColor;
  warningContrast?: CSSColor;
  
  error: CSSColor;
  errorSubtle?: CSSColor;
  errorContrast?: CSSColor;
  
  info: CSSColor;
  infoSubtle?: CSSColor;
  infoContrast?: CSSColor;
  
  // Call states (Telnyx WebRTC)
  callIdle: CSSColor;
  callRinging: CSSColor;
  callConnected: CSSColor;
  callMuted: CSSColor;
  callHold: CSSColor;
  callEnded: CSSColor;
  
  // Neutrals
  neutral50: CSSColor;
  neutral100: CSSColor;
  neutral200: CSSColor;
  neutral300: CSSColor;
  neutral400: CSSColor;
  neutral500: CSSColor;
  neutral600: CSSColor;
  neutral700: CSSColor;
  neutral800: CSSColor;
  neutral900: CSSColor;
  
  // Backgrounds
  bgPrimary: CSSColor;
  bgSecondary: CSSColor;
  bgTertiary: CSSColor;
  bgOverlay: CSSColor;
  bgBackdrop: CSSColor;
  
  // Text
  textPrimary: CSSColor;
  textSecondary: CSSColor;
  textTertiary: CSSColor;
  textDisabled: CSSColor;
  textInverse: CSSColor;
  textLink: CSSColor;
  textLinkHover?: CSSColor;
  
  // Borders
  borderLight: CSSColor;
  borderDefault: CSSColor;
  borderStrong: CSSColor;
  borderFocus: CSSColor;
}

/**
 * Typography configuration
 */
export interface WidgetTypography {
  fontFamilyBase: string;
  fontFamilyMono?: string;
  
  fontSizeXs: CSSLength;
  fontSizeSm: CSSLength;
  fontSizeBase: CSSLength;
  fontSizeMd: CSSLength;
  fontSizeLg: CSSLength;
  fontSizeXl: CSSLength;
  fontSize2xl: CSSLength;
  fontSize3xl: CSSLength;
  
  fontWeightNormal: number;
  fontWeightMedium: number;
  fontWeightSemibold: number;
  fontWeightBold: number;
  
  lineHeightTight: number;
  lineHeightNormal: number;
  lineHeightRelaxed: number;
  
  letterSpacingTight: CSSLength;
  letterSpacingNormal: CSSLength;
  letterSpacingWide: CSSLength;
}

/**
 * Spacing scale configuration
 */
export interface WidgetSpacing {
  space0: CSSLength;
  spacePx: CSSLength;
  space0_5: CSSLength;
  space1: CSSLength;
  space2: CSSLength;
  space3: CSSLength;
  space4: CSSLength;
  space5: CSSLength;
  space6: CSSLength;
  space8: CSSLength;
  space10: CSSLength;
  space12: CSSLength;
  space16: CSSLength;
  space20: CSSLength;
  space24: CSSLength;
}

/**
 * Layout configuration
 */
export interface WidgetLayout {
  widgetWidth: CSSLength;
  widgetWidthMobile: CSSLength;
  widgetHeight: CSSLength;
  widgetHeightMobile: CSSLength;
  widgetMaxHeight: CSSLength;
  
  radiusNone: CSSLength;
  radiusSm: CSSLength;
  radiusMd: CSSLength;
  radiusLg: CSSLength;
  radiusXl: CSSLength;
  radius2xl: CSSLength;
  radius3xl: CSSLength;
  radiusFull: CSSLength;
  
  touchTargetSm: CSSLength;
  touchTargetMd: CSSLength;
  touchTargetLg: CSSLength;
  touchTargetXl: CSSLength;
  
  headerHeight: CSSLength;
}

/**
 * Effects and shadows
 */
export interface WidgetEffects {
  shadowSm: string;
  shadowMd: string;
  shadowLg: string;
  shadowXl: string;
  shadow2xl: string;
  shadowInner: string;
  shadowFocus: string;
  
  blurSm: CSSLength;
  blurMd: CSSLength;
  blurLg: CSSLength;
}

/**
 * Animation configuration
 */
export interface WidgetAnimation {
  durationInstant: CSSTime;
  durationFast: CSSTime;
  durationNormal: CSSTime;
  durationSlow: CSSTime;
  durationSlower: CSSTime;
  
  easeLinear: CSSEasing;
  easeIn: CSSEasing;
  easeOut: CSSEasing;
  easeInOut: CSSEasing;
  easeSpring: CSSEasing;
  easeBounce: CSSEasing;
  
  // Reduced motion preference respected automatically
  respectPrefersReducedMotion: boolean;
}

/**
 * Complete widget style configuration
 */
export interface WidgetStyleConfig {
  colors?: Partial<WidgetColorScheme>;
  typography?: Partial<WidgetTypography>;
  spacing?: Partial<WidgetSpacing>;
  layout?: Partial<WidgetLayout>;
  effects?: Partial<WidgetEffects>;
  animation?: Partial<WidgetAnimation>;
  
  // Theme mode
  theme?: 'light' | 'dark' | 'auto';
  
  // Accessibility
  highContrast?: boolean;
  gloveMode?: boolean; // Larger touch targets for tradie use
}

/**
 * CSS Custom Property mapping
 * Maps JS property names to CSS variable names
 */
export const CSS_PROPERTY_MAP: Record<string, string> = {
  // Colors
  primary: '--sw-primary',
  primaryHover: '--sw-primary-hover',
  primaryActive: '--sw-primary-active',
  primarySubtle: '--sw-primary-subtle',
  primaryContrast: '--sw-primary-contrast',
  
  secondary: '--sw-secondary',
  secondaryHover: '--sw-secondary-hover',
  secondaryActive: '--sw-secondary-active',
  secondarySubtle: '--sw-secondary-subtle',
  secondaryContrast: '--sw-secondary-contrast',
  
  success: '--sw-success',
  successSubtle: '--sw-success-subtle',
  successContrast: '--sw-success-contrast',
  
  warning: '--sw-warning',
  warningSubtle: '--sw-warning-subtle',
  warningContrast: '--sw-warning-contrast',
  
  error: '--sw-error',
  errorSubtle: '--sw-error-subtle',
  errorContrast: '--sw-error-contrast',
  
  info: '--sw-info',
  infoSubtle: '--sw-info-subtle',
  infoContrast: '--sw-info-contrast',
  
  callIdle: '--sw-call-idle',
  callRinging: '--sw-call-ringing',
  callConnected: '--sw-call-connected',
  callMuted: '--sw-call-muted',
  callHold: '--sw-call-hold',
  callEnded: '--sw-call-ended',
  
  // Layout shortcuts
  borderRadius: '--sw-border-radius',
  fontFamily: '--sw-font-family-base',
};
```

## 3. Style Injection Utility (`style-injector.ts`)

```typescript
/**
 * Sunaiva Widget Style Injector
 * Handles runtime customization of CSS custom properties
 */

import { WidgetStyleConfig, CSS_PROPERTY_MAP } from './widget-styles.types';

export class WidgetStyleInjector {
  private hostElement: HTMLElement;
  private styleCache: Map<string, string> = new Map();
  private observer: MutationObserver | null = null;

  constructor(hostElement: HTMLElement) {
    if (!hostElement) {
      throw new Error('WidgetStyleInjector requires a valid host element');
    }
    this.hostElement = hostElement;
  }

  /**
   * Apply complete style configuration to the widget
   * @param config - Style configuration object
   */
  public applyStyles(config: WidgetStyleConfig): void {
    try {
      // Apply theme attribute
      if (config.theme) {
        this.hostElement.setAttribute('data-theme', config.theme);
      }

      // Apply glove mode
      if (config.gloveMode) {
        this.hostElement.setAttribute('data-input-mode', 'gloves');
      }

      // Apply high contrast if requested (though this is usually OS-level)
      if (config.highContrast) {
        this.hostElement.style.setProperty('--sw-contrast-mode', 'high');
      }

      // Process colors
      if (config.colors) {
        this.applyColorStyles(config.colors);
      }

      // Process typography
      if (config.typography) {
        this.applyTypographyStyles(config.typography);
      }

      // Process spacing
      if (config.spacing) {
        this.applySpacingStyles(config.spacing);
      }

      // Process layout
      if (config.layout) {
        this.applyLayoutStyles(config.layout);
      }

      // Process effects
      if (config.effects) {
        this.applyEffectStyles(config.effects);
      }

      // Process animation
      if (config.animation) {
        this.applyAnimationStyles(config.animation);
      }

      // Setup mutation observer for dynamic updates
      this.setupStyleObserver();

    } catch (error) {
      console.error('[Sunaiva Widget] Failed to apply styles:', error);
      // Fail gracefully - widget still works with defaults
    }
  }

  /**
   * Apply individual CSS custom property
   */
  public setProperty(property: string, value: string | null): void {
    const cssVar = CSS_PROPERTY_MAP[property] || `--sw-${this.camelToKebab(property)}`;
    
    if (value === null || value === undefined) {
      this.hostElement.style.removeProperty(cssVar);
      this.styleCache.delete(cssVar);
    } else {
      this.hostElement.style.setProperty(cssVar, value);
      this.styleCache.set(cssVar, value);
    }
  }

  /**
   * Get current computed value of a custom property
   */
  public getProperty(property: string): string {
    const cssVar = CSS_PROPERTY_MAP[property] || `--sw-${this.camelToKebab(property)}`;
    return getComputedStyle(this.hostElement).getPropertyValue(cssVar).trim();
  }

  /**
   * Reset all custom styles to defaults
   */
  public resetStyles(): void {
    this.styleCache.forEach((_, property) => {
      this.hostElement.style.removeProperty(property);
    });
    this.styleCache.clear();
    this.hostElement.removeAttribute('data-theme');
    this.hostElement.removeAttribute('data-input-mode');
  }

  /**
   * Generate CSS text from configuration (for external stylesheets)
   */
  public generateCSS(config: WidgetStyleConfig): string {
    const lines: string[] = [':host {'];
    
    const processObject = (obj: Record<string, any>, prefix: string = '') => {
      Object.entries(obj).forEach(([key, value]) => {
        if (value !== undefined && value !== null) {
          const cssVar = CSS_PROPERTY_MAP[key] || `--sw-${prefix}${this.camelToKebab(key)}`;
          lines.push(`  ${cssVar}: ${value};`);
        }
      });
    };

    if (config.colors) processObject(config.colors, '');
    if (config.typography) processObject(config.typography, '');
    if (config.spacing) processObject(config.spacing, '');
    if (config.layout) processObject(config.layout, '');
    if (config.effects) processObject(config.effects, '');
    if (config.animation) processObject(config.animation, '');

    lines.push('}');
    return lines.join('\n');
  }

  private applyColorStyles(colors: Record<string, string>): void {
    Object.entries(colors).forEach(([key, value]) => {
      if (this.isValidColor(value)) {
        this.setProperty(key, value);
      } else {
        console.warn(`[Sunaiva Widget] Invalid color value for ${key}: ${value}`);
      }
    });
  }

  private applyTypographyStyles(typography: Record<string, string | number>): void {
    Object.entries(typography).forEach(([key, value]) => {
      this.setProperty(key, value.toString());
    });
  }

  private applySpacingStyles(spacing: Record<string, string | number>): void {
    Object.entries(spacing).forEach(([key, value]) => {
      const formatted = typeof value === 'number' ? `${value}px` : value;
      this.setProperty(key, formatted);
    });
  }

  private applyLayoutStyles(layout: Record<string, string | number>): void {
    Object.entries(layout).forEach(([key, value]) => {
      const formatted = typeof value === 'number' ? `${value}px` : value;
      this.setProperty(key, formatted);
    });
  }

  private applyEffectStyles(effects: Record<string, string>): void {
    Object.entries(effects).forEach(([key, value]) => {
      this.setProperty(key, value);
    });
  }

  private applyAnimationStyles(animation: Record<string, string | boolean>): void {
    Object.entries(animation).forEach(([key, value]) => {
      if (typeof value === 'boolean') {
        // Handle boolean flags
        if (key === 'respectPrefersReducedMotion' && value === false) {
          this.setProperty('respect-reduced-motion', 'false');
        }
      } else {
        this.setProperty(key, value);
      }
    });
  }

  private setupStyleObserver(): void {
    // Watch for external style changes (e.g., from parent page)
    this.observer = new MutationObserver((mutations) => {
      mutations.forEach((mutation) => {
        if (mutation.attributeName === 'style') {
          // Re-apply cached styles if they were overridden
          this.styleCache.forEach((value, property) => {
            const current = this.hostElement.style.getPropertyValue(property);
            if (current !== value) {
              this.hostElement.style.setProperty(property, value);
            }
          });
        }
      });
    });

    this.observer.observe(this.hostElement, {
      attributes: true,
      attributeFilter: ['style']
    });
  }

  private camelToKebab(str: string): string {
    return str.replace(/([a-z0-9]|(?=[A-Z]))([A-Z])/g, '$1-$2').toLowerCase();
  }

  private isValidColor(color: string): boolean {
    // Basic color validation
    if (typeof color !== 'string') return false;
    
    // Check for valid CSS color formats
    const validPatterns = [
      /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/, // Hex
      /^rgb\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*\)$/i, // RGB
      /^rgba\(\s*\d+\s*,\s*\d+\s*,\s*\d+\s*,\s*[\d.]+\s*\)$/i, // RGBA
      /^hsl\(\s*\d+\s*,\s*\d+%\s*,\s*\d+%\s*\)$/i, // HSL
      /^hsla\(\s*\d+\s*,\s*\d+%\s*,\s*\d+%\s*,\s*[\d.]+\s*\)$/i, // HSLA
      /^(transparent|inherit|currentColor)$/, // Keywords
    ];
    
    return validPatterns.some(pattern => pattern.test(color)) || 
           CSS.supports('color', color);
 