Dashboard - Widget Configuration Form

Response:
```javascript
/**
 * Widget Configuration Component
 * File: Sunaiva/talking-widget/dashboard/js/widget-config.js
 *
 * A vanilla JavaScript form component for configuring talking widget settings
 * with real-time preview capabilities.
 */

class WidgetConfig {
  constructor(containerSelector) {
    this.container = document.querySelector(containerSelector);
    if (!this.container) {
      throw new Error(`WidgetConfig: Container ${containerSelector} not found`);
    }

    // Initialize state with defaults
    this.state = {
      greeting: 'Hello! How can I help you today?',
      voice: 'en-US-Neural2-F',
      themeColor: '#3B82F6',
      position: 'bottom-right',
      businessHours: this.getDefaultBusinessHours(),
      industry: 'custom',
      isOpen: true
    };

    // Available voices for speech synthesis
    this.voices = [];
    this.speechSynthesis = window.speechSynthesis;

    // Debounce timer for preview updates
    this.debounceTimer = null;

    this.init();
  }

  /**
   * Initialize component
   */
  init() {
    this.cacheDOM();
    this.bindEvents();
    this.loadVoices();
    this.renderPreview();
    this.updateAccessibility();
  }

  /**
   * Cache DOM elements
   */
  cacheDOM() {
    // Form elements
    this.elements = {
      greeting: this.container.querySelector('[data-config="greeting"]'),
      voiceSelect: this.container.querySelector('[data-config="voice"]'),
      voicePreview: this.container.querySelector('[data-action="preview-voice"]'),
      colorPicker: this.container.querySelector('[data-config="color"]'),
      colorHex: this.container.querySelector('[data-config="color-hex"]'),
      positionGrid: this.container.querySelector('[data-config="position-grid"]'),
      businessHours: this.container.querySelector('[data-config="business-hours"]'),
      industrySelect: this.container.querySelector('[data-config="industry"]'),
      previewPanel: this.container.querySelector('[data-preview="widget"]'),
      saveButton: this.container.querySelector('[data-action="save"]'),
      resetButton: this.container.querySelector('[data-action="reset"]')
    };

    // Validate critical elements exist
    const required = ['greeting', 'voiceSelect', 'colorPicker', 'positionGrid', 'previewPanel'];
    required.forEach(key => {
      if (!this.elements[key]) {
        console.warn(`WidgetConfig: Required element [data-config="${key}"] not found`);
      }
    });
  }

  /**
   * Bind event listeners
   */
  bindEvents() {
    // Greeting input with debounce
    if (this.elements.greeting) {
      this.elements.greeting.addEventListener('input', (e) => {
        this.updateState('greeting', e.target.value);
      });
    }

    // Voice selection and preview
    if (this.elements.voiceSelect) {
      this.elements.voiceSelect.addEventListener('change', (e) => {
        this.updateState('voice', e.target.value);
      });
    }

    if (this.elements.voicePreview) {
      this.elements.voicePreview.addEventListener('click', () => this.previewVoice());
      this.elements.voicePreview.addEventListener('keydown', (e) => {
        if (e.key === 'Enter' || e.key === ' ') {
          e.preventDefault();
          this.previewVoice();
        }
      });
    }

    // Color picker synchronization
    if (this.elements.colorPicker) {
      this.elements.colorPicker.addEventListener('input', (e) => {
        this.updateColor(e.target.value);
      });
    }

    if (this.elements.colorHex) {
      this.elements.colorHex.addEventListener('change', (e) => {
        const hex = e.target.value;
        if (this.isValidHex(hex)) {
          this.updateColor(hex);
        }
      });
    }

    // Position selector
    if (this.elements.positionGrid) {
      this.elements.positionGrid.addEventListener('click', (e) => {
        const positionBtn = e.target.closest('[data-position]');
        if (positionBtn) {
          this.updatePosition(positionBtn.dataset.position);
        }
      });

      // Keyboard navigation for position grid
      this.elements.positionGrid.addEventListener('keydown', (e) => {
        this.handlePositionKeyboard(e);
      });
    }

    // Business hours
    if (this.elements.businessHours) {
      this.elements.businessHours.addEventListener('change', (e) => {
        this.handleBusinessHoursChange(e);
      });
    }

    // Industry templates
    if (this.elements.industrySelect) {
      this.elements.industrySelect.addEventListener('click', (e) => {
        const btn = e.target.closest('[data-industry]');
        if (btn) {
          this.loadIndustryTemplate(btn.dataset.industry);
        }
      });
    }

    // Global actions
    if (this.elements.saveButton) {
      this.elements.saveButton.addEventListener('click', () => this.saveConfiguration());
    }

    if (this.elements.resetButton) {
      this.elements.resetButton.addEventListener('click', () => this.resetConfiguration());
    }

    // Speech synthesis voices loaded callback
    if (this.speechSynthesis) {
      this.speechSynthesis.addEventListener('voiceschanged', () => this.loadVoices());
    }
  }

  /**
   * Update state and trigger preview refresh
   */
  updateState(key, value) {
    this.state[key] = value;

    // Debounce preview updates for performance
    clearTimeout(this.debounceTimer);
    this.debounceTimer = setTimeout(() => {
      this.renderPreview();
      this.dispatchChangeEvent();
    }, 100);
  }

  /**
   * Update color across inputs and state
   */
  updateColor(hex) {
    this.state.themeColor = hex;

    if (this.elements.colorPicker) this.elements.colorPicker.value = hex;
    if (this.elements.colorHex) this.elements.colorHex.value = hex;

    // Update CSS custom property for live theming
    document.documentElement.style.setProperty('--widget-accent-color', hex);

    this.renderPreview();
    this.dispatchChangeEvent();
  }

  /**
   * Update widget position
   */
  updatePosition(position) {
    this.state.position = position;

    // Update visual selection
    if (this.elements.positionGrid) {
      const buttons = this.elements.positionGrid.querySelectorAll('[data-position]');
      buttons.forEach(btn => {
        const isSelected = btn.dataset.position === position;
        btn.setAttribute('aria-pressed', isSelected);
        btn.classList.toggle('active', isSelected);
      });
    }

    this.renderPreview();
    this.dispatchChangeEvent();
  }

  /**
   * Handle keyboard navigation for position grid
   */
  handlePositionKeyboard(e) {
    const positions = ['top-left', 'top-center', 'top-right', 'middle-left', 'middle-center', 'middle-right', 'bottom-left', 'bottom-center', 'bottom-right'];
    const currentIndex = positions.indexOf(this.state.position);
    let newIndex = currentIndex;

    switch(e.key) {
      case 'ArrowUp':
        newIndex = Math.max(0, currentIndex - 3);
        break;
      case 'ArrowDown':
        newIndex = Math.min(positions.length - 1, currentIndex + 3);
        break;
      case 'ArrowLeft':
        newIndex = Math.max(0, currentIndex - 1);
        break;
      case 'ArrowRight':
        newIndex = Math.min(positions.length - 1, currentIndex + 1);
        break;
      default:
        return;
    }

    e.preventDefault();
    this.updatePosition(positions[newIndex]);

    // Focus the new button
    const newBtn = this.elements.positionGrid.querySelector(`[data-position="${positions[newIndex]}"]`);
    if (newBtn) newBtn.focus();
  }

  /**
   * Handle business hours changes
   */
  handleBusinessHoursChange(e) {
    const target = e.target;
    const dayIndex = parseInt(target.dataset.dayIndex);

    if (isNaN(dayIndex)) return;

    const day = this.state.businessHours[dayIndex];

    if (target.dataset.field === 'enabled') {
      day.enabled = target.checked;
    } else if (target.dataset.field === 'open') {
      day.open = target.value;
    } else if (target.dataset.field === 'close') {
      day.close = target.value;
    }

    this.validateBusinessHours(day);
    this.renderPreview();
    this.dispatchChangeEvent();
  }

  /**
   * Validate business hours logic
   */
  validateBusinessHours(day) {
    if (day.open && day.close) {
      const open = this.timeToMinutes(day.open);
      const close = this.timeToMinutes(day.close);

      if (close <= open) {
        day.error = 'Close time must be after open time';
      } else {
        delete day.error;
      }
    }
  }

  /**
   * Convert time string to minutes
   */
  timeToMinutes(time) {
    const [hours, minutes] = time.split(':').map(Number);
    return hours * 60 + minutes;
  }

  /**
   * Load industry template
   */
  loadIndustryTemplate(industry) {
    const templates = {
      healthcare: {
        greeting: 'Welcome to our practice. How may we assist you with your healthcare needs today?',
        voice: 'en-US-Neural2-F',
        themeColor: '#10B981',
        businessHours: this.generateBusinessHours('09:00', '17:00', [false, true, true, true, true, true, false])
      },
      ecommerce: {
        greeting: 'Hi there! Looking for something specific? I can help you find products and track orders.',
        voice: 'en-US-Neural2-D',
        themeColor: '#F59E0B',
        businessHours: this.generateBusinessHours('00:00', '23:59', [true, true, true, true, true, true, true])
      },
      saas: {
        greeting: 'Welcome! Need help with integration or have technical questions? I\'m here to help.',
        voice: 'en-US-Neural2-A',
        themeColor: '#3B82F6',
        businessHours: this.generateBusinessHours('08:00', '18:00', [true, true, true, true, true, false, false])
      },
      hospitality: {
        greeting: 'Hello! Ready to make a reservation or have questions about our amenities?',
        voice: 'en-US-Neural2-C',
        themeColor: '#EC4899',
        businessHours: this.generateBusinessHours('07:00', '22:00', [true, true, true, true, true, true, true])
      }
    };

    const template = templates[industry];
    if (!template) return;

    this.state.industry = industry;
    this.state.greeting = template.greeting;
    this.state.voice = template.voice;
    this.state.themeColor = template.themeColor;
    this.state.businessHours = template.businessHours;

    this.syncFormWithState();
    this.renderPreview();
    this.dispatchChangeEvent();
  }

  /**
   * Generate business hours array
   */
  generateBusinessHours(open, close, enabledDays) {
    const days = ['Monday', 'Tuesday', 'Wednesday', 'Thursday', 'Friday', 'Saturday', 'Sunday'];
    return days.map((day, index) => ({
      day,
      enabled: enabledDays[index],
      open,
      close
    }));
  }

  /**
   * Sync form inputs with current state
   */
  syncFormWithState() {
    if (this.elements.greeting) this.elements.greeting.value = this.state.greeting;
    if (this.elements.voiceSelect) this.elements.voiceSelect.value = this.state.voice;
    this.updateColor(this.state.themeColor);
    this.updatePosition(this.state.position);

    // Sync business hours
    if (this.elements.businessHours) {
      this.state.businessHours.forEach((day, index) => {
        const enabledInput = this.elements.businessHours.querySelector(`[data-day-index="${index}"][data-field="enabled"]`);
        const openInput = this.elements.businessHours.querySelector(`[data-day-index="${index}"][data-field="open"]`);
        const closeInput = this.elements.businessHours.querySelector(`[data-day-index="${index}"][data-field="close"]`);

        if (enabledInput) enabledInput.checked = day.enabled;
        if (openInput) openInput.value = day.open;
        if (closeInput) closeInput.value = day.close;
      });
    }
  }

  /**
   * Render live preview
   */
  renderPreview() {
    if (!this.elements.previewPanel) return;

    const preview = this.elements.previewPanel;

    // Apply theme color
    preview.style.setProperty('--widget-primary', this.state.themeColor);

    // Apply position
    preview.className = `widget-preview widget-position-${this.state.position}`;

    // Update content
    const greetingEl = preview.querySelector('.widget-greeting');
    if (greetingEl) greetingEl.textContent = this.state.greeting;

    // Update status based on business hours
    this.updateWidgetStatus(preview);

    // Announce change to screen readers
    this.announceChange('Widget preview updated');
  }

  /**
   * Update widget online/offline status based on business hours
   */
  updateWidgetStatus(preview) {
    const now = new Date();
    const dayIndex = (now.getDay() + 6) % 7; // Convert to Monday-start
    const currentDay = this.state.businessHours[dayIndex];

    let isOpen = false;

    if (currentDay && currentDay.enabled) {
      const currentMinutes = now.getHours() * 60 + now.getMinutes();
      const openMinutes = this.timeToMinutes(currentDay.open);
      const closeMinutes = this.timeToMinutes(currentDay.close);

      isOpen = currentMinutes >= openMinutes && currentMinutes < closeMinutes;
    }

    const statusIndicator = preview.querySelector('.widget-status');
    if (statusIndicator) {
      statusIndicator.className = `widget-status ${isOpen ? 'online' : 'offline'}`;
      statusIndicator.setAttribute('aria-label', isOpen ? 'Online' : 'Offline');
    }
  }

  /**
   * Preview voice using Web Speech API
   */
  previewVoice() {
    if (!this.speechSynthesis) {
      console.warn('Speech synthesis not supported');
      return;
    }

    // Cancel any ongoing speech
    this.speechSynthesis.cancel();

    const utterance = new SpeechSynthesisUtterance(this.state.greeting);
    const voice = this.voices.find(v => v.name === this.state.voice);

    if (voice) utterance.voice = voice;
    utterance.rate = 1;
    utterance.pitch = 1;

    this.speechSynthesis.speak(utterance);

    // Update button state
    if (this.elements.voicePreview) {
      this.elements.voicePreview.classList.add('playing');
      this.elements.voicePreview.setAttribute('aria-label', 'Stop voice preview');

      utterance.onend = () => {
        this.elements.voicePreview.classList.remove('playing');
        this.elements.voicePreview.setAttribute('aria-label', 'Preview voice');
      };
    }
  }

  /**
   * Load available voices
   */
  loadVoices() {
    if (!this.speechSynthesis) return;

    this.voices = this.speechSynthesis.getVoices().filter(v => v.lang.startsWith('en'));

    // Populate voice select if empty
    if (this.elements.voiceSelect && this.elements.voiceSelect.options.length === 0) {
      this.voices.forEach(voice => {
        const option = document.createElement('option');
        option.value = voice.name;
        option.textContent = `${voice.name} (${voice.lang})`;
        this.elements.voiceSelect.appendChild(option);
      });

      // Set current selection
      this.elements.voiceSelect.value = this.state.voice;
    }
  }

  /**
   * Save configuration
   */
  saveConfiguration() {
    const config = {
      ...this.state,
      timestamp: new Date().toISOString()
    };

    // Dispatch save event for parent application
    const event = new CustomEvent('widgetConfig:save', {
      detail: config,
      bubbles: true
    });
    this.container.dispatchEvent(event);

    // Visual feedback
    this.showNotification('Configuration saved successfully', 'success');
  }

  /**
   * Reset to defaults
   */
  resetConfiguration() {
    if (confirm('Reset all settings to default?')) {
      this.state = {
        greeting: 'Hello! How can I help you today?',
        voice: 'en-US-Neural2-F',
        themeColor: '#3B82F6',
        position: 'bottom-right',
        businessHours: this.getDefaultBusinessHours(),
        industry: 'custom',
        isOpen: true
      };

      this.syncFormWithState();
      this.renderPreview();
      this.showNotification('Configuration reset to defaults', 'info');
    }
  }

  /**
   * Get default business hours
   */
  getDefaultBusinessHours() {
    return [
      { day: 'Monday', enabled: true, open: '09:00', close: '17:00' },
      { day: 'Tuesday', enabled: true, open: '09:00', close: '17:00' },
      { day: 'Wednesday', enabled: true, open: '09:00', close: '17:00' },
      { day: 'Thursday', enabled: true, open: '09:00', close: '17:00' },
      { day: 'Friday', enabled: true, open: '09:00', close: '17:00' },
      { day: 'Saturday', enabled: false, open: '10:00', close: '16:00' },
      { day: 'Sunday', enabled: false, open: '10:00', close: '16:00' }
    ];
  }

  /**
   * Dispatch change event for external listeners
   */
  dispatchChangeEvent() {
    const event = new CustomEvent('widgetConfig:change', {
      detail: { ...this.state },
      bubbles: true
    });
    this.container.dispatchEvent(event);
  }

  /**
   * Utility: Validate hex color
   */
  isValidHex(hex) {
    return /^#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{3})$/.test(hex);
  }

  /**
   * Utility: Show notification
   */
  showNotification(message, type = 'info') {
    const notification = document.createElement('div');
    notification.className = `notification notification-${type}`;
    notification.textContent = message;
    notification.setAttribute('role', 'alert');
    notification.setAttribute('aria-live', 'polite');

    document.body.appendChild(notification);

    setTimeout(() => {
      notification.remove();
    }, 3000);
  }

  /**
   * Accessibility: Announce changes to screen readers
   */
  announceChange(message) {
    const announcer = document.createElement('div');
    announcer.setAttribute('aria-live', 'polite');
    announcer.setAttribute('aria-atomic', 'true');
    announcer.className = 'sr-only';
    announcer.textContent = message;

    document.body.appendChild(announcer);
    setTimeout(() => announcer.remove(), 1000);
  }

  /**
   * Update ARIA attributes for accessibility
   */
  updateAccessibility() {
    // Ensure position grid has correct roles
    if (this.elements.positionGrid) {
      this.elements.positionGrid.setAttribute('role', 'radiogroup');
      this.elements.positionGrid.setAttribute('aria-label', 'Widget position');

      const buttons = this.elements.positionGrid.querySelectorAll('[data-position]');
      buttons.forEach(btn => {
        btn.setAttribute('role', 'radio');
        btn.setAttribute('aria-checked', btn.dataset.position === this.state.position);
      });
    }
  }

  /**
   * Get current configuration
   */
  getConfig() {
    return { ...this.state };
  }

  /**
   * Set configuration programmatically
   */
  setConfig(config) {
    this.state = { ...this.state, ...config };
    this.syncFormWithState();
    this.renderPreview();
  }
}

// CSS Custom Properties for theming
const injectStyles = () => {
  if (document.getElementById('widget-config-styles')) return;

  const styles = document.createElement('style');
  styles.id = 'widget-config-styles';
  styles.textContent = `
    :root {
      --widget-bg-dark: #0B0C0E;
      --widget-accent: #3B82F6;
      --widget-text: #F9FAFB;
      --widget-border: #374151;
      --widget-surface: #1F2937;
    }

    .widget-config-container {
      background: var(--widget-bg-dark);
      color: var(--widget-text);
      font-family: system-ui, -apple-system, sans-serif;
    }

    .position-grid {
      display: grid;
      grid-template-columns: repeat(3, 1fr);
      gap: 0.5rem;
      max-width: 200px;
    }

    .position-btn {
      aspect-ratio: 1;
      background: var(--widget-surface);
      border: 2px solid var(--widget-border);
      border-radius: 0.375rem;
      cursor: pointer;
      transition: all 0.2s;
    }

    .position-btn:hover {
      border-color: var(--widget-accent);
    }

    .position-btn.active {
      background: var(--widget-accent);
      border-color: var(--widget-accent);
    }

    .position-btn:focus-visible {
      outline: 2px solid var(--widget-accent);
      outline-offset: 2px;
    }

    .business-hours-row {
      display: grid;
      grid-template-columns: auto 1fr 1fr;
      gap: 1rem;
      align-items: center;
      padding: 0.5rem 0;
      border-bottom: 1px solid var(--widget-border);
    }

    .widget-preview {
      position: fixed;
      width: 320px;
      background: white;
      border-radius: 1rem;
      box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1);
      transition: all 0.3s ease;
    }

    .widget-position-top-left { top: 1rem; left: 1rem; }
    .widget-position-top-center { top: 1rem; left: 50%; transform: translateX(-50%); }
    .widget-position-top-right { top: 1rem; right: 1rem; }
    .widget-position-middle-left { top: 50%; left: 1rem; transform: translateY(-50%); }
    .widget-position-middle-center { top: 50%; left: 50%; transform: translate(-50%, -50%); }
    .widget-position-middle-right { top: 50%; right: 1rem; transform: translateY(-50%); }
    .widget-position-bottom-left { bottom: 1rem; left: 1rem; }
    .widget-position-bottom-center { bottom: 1rem; left: 50%; transform: translateX(-50%); }
    .widget-position-bottom-right { bottom: 1rem; right: 1rem; }

    .sr-only {
      position: absolute;
      width: 1px;
      height: 1px;
      padding: 0;
      margin: -1px;
      overflow: hidden;
      clip: rect(0, 0, 0, 0);
      white-space: nowrap;
      border-width: 0;
    }

    .notification {
      position: fixed;
      bottom: 2rem;
      right: 2rem;
      padding: 1rem 1.5rem;
      background: var(--widget-surface);
      border: 1px solid var(--widget-border);
      border-radius: 0.5rem;
      color: var(--widget-text);
      z-index: 50;
      animation: slideIn 0.3s ease;
    }

    .notification-success { border-left: 4px solid #10B981; }
    .notification-info { border-left: 4px solid var(--widget-accent); }

    @keyframes slideIn {
      from { transform: translateX(100%); opacity: 0; }
      to { transform: translateX(0); opacity: 1; }
    }
  `;

  document.head.appendChild(styles);
};

// Auto-initialize if DOM is ready
if (document.readyState === 'loading') {
  document.addEventListener('DOMContentLoaded', injectStyles);
} else {
  injectStyles();
}

// Export for module systems
if (typeof module !== 'undefined' && module.exports) {
  module.exports = WidgetConfig;
}

// Global export
window.WidgetConfig = WidgetConfig;
```

**HTML Structure Expected:**

```html
<div class="widget-config-container">
  <!-- Greeting Editor -->
  <div class="form-group">
    <label for="greeting">Greeting Message</label>
    <textarea data-config="greeting" id="greeting" rows="3" maxlength="200"></textarea>
  </div>

  <!-- Voice Selector -->
  <div class="form-group">
    <label for="voice">Voice</label>
    <select data-config="voice" id="voice"></select>
    <button data-action="preview-voice" aria-label="Preview voice">🔊 Preview</button>
  </div>

  <!-- Color Picker -->
  <div class="form-group">
    <label for="color">Theme Color</label>
    <input type="color" data-config="color" id="color" value="#3B82F6">
    <input type="text" data-config="color-hex" value="#3B82F6" pattern="^#[A-Fa-f0-9]{6}$">
  </div>

  <!-- Position Selector -->
  <div class="form-group">
    <label>Widget Position</label>
    <div data-config="position-grid" class="position-grid">
      <button data-position="top-left" aria-label="Top left"></button>
      <button data-position="top-center" aria-label="Top center"></button>
      <button data-position="top-right" aria-label="Top right"></button>
      <button data-position="middle-left" aria-label="Middle left"></button>
      <button data-position="middle-center" aria-label="Middle center"></button>
      <button data-position="middle-right" aria-label="Middle right"></button>
      <button data-position="bottom-left" aria-label="Bottom left"></button>
      <button data-position="bottom-center" aria-label="Bottom center"></button>
      <button data-position="bottom-right" aria-label="Bottom right"></button>
    </div>
  </div>

  <!-- Business Hours -->
  <div data-config="business-hours">
    <!-- Generated rows for each day -->
  </div>

  <!-- Industry Templates -->
  <div data-config="industry">
    <button data-industry="healthcare">Healthcare</button>
    <button data-industry="ecommerce">E-Commerce</button>
    <button data-industry="saas">SaaS</button>
    <button data-industry="hospitality">Hospitality</button>
  </div>

  <!-- Preview Panel -->
  <div data-preview="widget" class="widget-preview">
    <div class="widget-status"></div>
    <div class="widget-greeting"></div>
  </div>

  <!-- Actions -->
  <button data-action="save">Save Configuration</button>
  <button data-action="reset">Reset</button>
</div>
```

**Key Features:**
- **ES6+ Class Architecture**: Clean, modular code with private methods and state management
- **Accessibility**: ARIA labels, keyboard navigation (arrow keys for position grid), focus management, and screen reader announcements
- **Debounced Updates**: Performance optimization for rapid input changes (color picker, typing)
- **Web Speech API**: Voice preview functionality with voice selection
- **Real-time Validation**: Business hours logic ensures close time is after open time
- **CSS Custom Properties**: Dynamic theming with automatic CSS variable updates
- **Industry Templates**: One-click configuration presets for common use cases
- **Event System**: Custom events (`widgetConfig:change`, `widgetConfig:save`) for parent application integration


Dashboard - Billing and Subscription Page

Response:
```javascript
/**
 * Sunaiva Billing Dashboard
 * File: Sunaiva/talking-widget/dashboard/js/billing.js
 *
 * Vanilla JS billing dashboard with Stripe integration
 * Features: Plan management, usage tracking, billing history, payment methods
 */

(function() {
  'use strict';

  // Configuration
  const CONFIG = {
    apiBase: '/api/billing',
    refreshInterval: 300000, // 5 minutes
    currency: 'USD',
    dateLocale: 'en-US'
  };

  // State management
  const state = {
    currentPlan: null,
    usage: null,
    history: [],
    paymentMethod: null,
    overages: [],
    isLoading: false,
    error: null
  };

  // CSS Custom Properties for theming
  const injectStyles = () => {
    if (document.getElementById('billing-dashboard-styles')) return;

    const styles = document.createElement('style');
    styles.id = 'billing-dashboard-styles';
    styles.textContent = `
      :root {
        --bg-primary: #0B0C0E;
        --bg-secondary: #15171A;
        --bg-tertiary: #1F2125;
        --text-primary: #F9FAFB;
        --text-secondary: #9CA3AF;
        --text-muted: #6B7280;
        --accent: #3B82F6;
        --accent-hover: #2563EB;
        --accent-light: rgba(59, 130, 246, 0.1);
        --success: #10B981;
        --warning: #F59E0B;
        --danger: #EF4444;
        --border: #2D3139;
        --radius: 8px;
        --shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
      }

      .billing-dashboard {
        max-width: 1200px;
        margin: 0 auto;
        padding: 2rem;
        background: var(--bg-primary);
        color: var(--text-primary);
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        min-height: 100vh;
      }

      .billing-header {
        margin-bottom: 2rem;
      }

      .billing-header h1 {
        font-size: 1.875rem;
        font-weight: 700;
        margin: 0 0 0.5rem 0;
        color: var(--text-primary);
      }

      .billing-grid {
        display: grid;
        grid-template-columns: 1fr;
        gap: 1.5rem;
        margin-bottom: 2rem;
      }

      @media (min-width: 768px) {
        .billing-grid {
          grid-template-columns: repeat(2, 1fr);
        }
      }

      @media (min-width: 1024px) {
        .billing-grid {
          grid-template-columns: 2fr 1fr;
        }
      }

      .card {
        background: var(--bg-secondary);
        border: 1px solid var(--border);
        border-radius: var(--radius);
        padding: 1.5rem;
        box-shadow: var(--shadow);
      }

      .card-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 1.5rem;
      }

      .card-title {
        font-size: 1.125rem;
        font-weight: 600;
        margin: 0;
        color: var(--text-primary);
      }

      .plan-badge {
        display: inline-flex;
        align-items: center;
        padding: 0.25rem 0.75rem;
        background: var(--accent-light);
        color: var(--accent);
        border-radius: 9999px;
        font-size: 0.875rem;
        font-weight: 600;
        text-transform: uppercase;
        letter-spacing: 0.05em;
      }

      .usage-meter {
        margin: 1.5rem 0;
      }

      .usage-header {
        display: flex;
        justify-content: space-between;
        margin-bottom: 0.5rem;
        font-size: 0.875rem;
        color: var(--text-secondary);
      }

      .usage-bar {
        width: 100%;
        height: 8px;
        background: var(--bg-tertiary);
        border-radius: 9999px;
        overflow: hidden;
        position: relative;
      }

      .usage-fill {
        height: 100%;
        background: linear-gradient(90deg, var(--accent), #60A5FA);
        border-radius: 9999px;
        transition: width 0.5s ease;
        position: relative;
      }

      .usage-fill.warning {
        background: linear-gradient(90deg, var(--warning), #FBBF24);
      }

      .usage-fill.danger {
        background: linear-gradient(90deg, var(--danger), #F87171);
      }

      .btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        padding: 0.625rem 1.25rem;
        border-radius: var(--radius);
        font-weight: 500;
        font-size: 0.875rem;
        cursor: pointer;
        transition: all 0.2s;
        border: none;
        text-decoration: none;
        gap: 0.5rem;
      }

      .btn:focus-visible {
        outline: 2px solid var(--accent);
        outline-offset: 2px;
      }

      .btn-primary {
        background: var(--accent);
        color: white;
      }

      .btn-primary:hover {
        background: var(--accent-hover);
      }

      .btn-secondary {
        background: var(--bg-tertiary);
        color: var(--text-primary);
        border: 1px solid var(--border);
      }

      .btn-secondary:hover {
        background: var(--border);
      }

      .btn-danger {
        background: rgba(239, 68, 68, 0.1);
        color: var(--danger);
        border: 1px solid rgba(239, 68, 68, 0.2);
      }

      .btn-danger:hover {
        background: rgba(239, 68, 68, 0.2);
      }

      .action-group {
        display: flex;
        gap: 0.75rem;
        flex-wrap: wrap;
        margin-top: 1.5rem;
      }

      .payment-method {
        display: flex;
        align-items: center;
        gap: 1rem;
        padding: 1rem;
        background: var(--bg-tertiary);
        border-radius: var(--radius);
        border: 1px solid var(--border);
      }

      .card-icon {
        width: 48px;
        height: 32px;
        background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
        border-radius: 4px;
        display: flex;
        align-items: center;
        justify-content: center;
        color: white;
        font-weight: bold;
        font-size: 0.75rem;
      }

      .card-details {
        flex: 1;
      }

      .card-number {
        font-family: monospace;
        font-size: 0.875rem;
        color: var(--text-primary);
        letter-spacing: 0.05em;
      }

      .card-expiry {
        font-size: 0.75rem;
        color: var(--text-secondary);
        margin-top: 0.25rem;
      }

      .billing-table-container {
        overflow-x: auto;
        margin: 0 -1.5rem;
        padding: 0 1.5rem;
      }

      .billing-table {
        width: 100%;
        border-collapse: collapse;
        font-size: 0.875rem;
      }

      .billing-table th {
        text-align: left;
        padding: 0.75rem 1rem;
        color: var(--text-secondary);
        font-weight: 500;
        border-bottom: 1px solid var(--border);
        white-space: nowrap;
      }

      .billing-table td {
        padding: 1rem;
        border-bottom: 1px solid var(--border);
        color: var(--text-primary);
        vertical-align: middle;
      }

      .billing-table tr:hover td {
        background: var(--bg-tertiary);
      }

      .status-badge {
        display: inline-flex;
        align-items: center;
        padding: 0.25rem 0.5rem;
        border-radius: 4px;
        font-size: 0.75rem;
        font-weight: 600;
        text-transform: capitalize;
      }

      .status-paid {
        background: rgba(16, 185, 129, 0.1);
        color: var(--success);
      }

      .status-pending {
        background: rgba(245, 158, 11, 0.1);
        color: var(--warning);
      }

      .status-failed {
        background: rgba(239, 68, 68, 0.1);
        color: var(--danger);
      }

      .amount {
        font-family: 'SF Mono', Monaco, monospace;
        font-weight: 600;
      }

      .overage-item {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 0.75rem;
        background: rgba(245, 158, 11, 0.05);
        border: 1px solid rgba(245, 158, 11, 0.1);
        border-radius: var(--radius);
        margin-bottom: 0.5rem;
      }

      .overage-label {
        font-size: 0.875rem;
        color: var(--text-secondary);
      }

      .overage-amount {
        font-weight: 600;
        color: var(--warning);
      }

      .skeleton {
        background: linear-gradient(90deg, var(--bg-tertiary) 25%, var(--border) 50%, var(--bg-tertiary) 75%);
        background-size: 200% 100%;
        animation: loading 1.5s infinite;
        border-radius: 4px;
      }

      @keyframes loading {
        0% { background-position: 200% 0; }
        100% { background-position: -200% 0; }
      }

      .empty-state {
        text-align: center;
        padding: 3rem 1rem;
        color: var(--text-secondary);
      }

      .error-toast {
        position: fixed;
        bottom: 2rem;
        right: 2rem;
        background: var(--danger);
        color: white;
        padding: 1rem 1.5rem;
        border-radius: var(--radius);
        box-shadow: var(--shadow);
        z-index: 1000;
        transform: translateY(100px);
        opacity: 0;
        transition: all 0.3s ease;
      }

      .error-toast.show {
        transform: translateY(0);
        opacity: 1;
      }

      .sr-only {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border-width: 0;
      }

      .next-payment {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        color: var(--text-secondary);
        font-size: 0.875rem;
        margin-top: 1rem;
      }

      .next-payment strong {
        color: var(--text-primary);
      }
    `;
    document.head.appendChild(styles);
  };

  // Utility functions
  const formatCurrency = (amount, currency = CONFIG.currency) => {
    return new Intl.NumberFormat(CONFIG.dateLocale, {
      style: 'currency',
      currency: currency
    }).format(amount);
  };

  const formatDate = (dateString) => {
    const date = new Date(dateString);
    return new Intl.DateTimeFormat(CONFIG.dateLocale, {
      year: 'numeric',
      month: 'short',
      day: 'numeric'
    }).format(date);
  };

  const formatDateTime = (dateString) => {
    const date = new Date(dateString);
    return new Intl.DateTimeFormat(CONFIG.dateLocale, {
      year: 'numeric',
      month: 'short',
      day: 'numeric',
      hour: '2-digit',
      minute: '2-digit'
    }).format(date);
  };

  // API Service
  const api = {
    async fetch(endpoint, options = {}) {
      try {
        const response = await fetch(`${CONFIG.apiBase}${endpoint}`, {
          headers: {
            'Content-Type': 'application/json',
            'Accept': 'application/json'
          },
          ...options
        });

        if (!response.ok) {
          throw new Error(`HTTP ${response.status}: ${response.statusText}`);
        }

        return await response.json();
      } catch (error) {
        console.error('API Error:', error);
        throw error;
      }
    },

    getCurrentPlan() {
      return this.fetch('/current');
    },

    getHistory() {
      return this.fetch('/history');
    },

    getPaymentMethod() {
      return this.fetch('/payment-method');
    },

    getOverages() {
      return this.fetch('/overages');
    },

    async redirectToStripe(action) {
      // action: 'upgrade' | 'downgrade' | 'portal'
      const response = await this.fetch(`/stripe-session`, {
        method: 'POST',
        body: JSON.stringify({ action })
      });

      if (response.url) {
        window.location.href = response.url;
      } else {
        throw new Error('No redirect URL received');
      }
    }
  };

  // UI Components
  const components = {
    skeleton(type) {
      const div = document.createElement('div');
      div.className = 'skeleton';
      if (type === 'text') {
        div.style.height = '1rem';
        div.style.width = '100%';
        div.style.marginBottom = '0.5rem';
      } else if (type === 'title') {
        div.style.height = '1.5rem';
        div.style.width = '60%';
        div.style.marginBottom = '1rem';
      } else if (type === 'button') {
        div.style.height = '2.5rem';
        div.style.width = '120px';
      }
      return div;
    },

    usageMeter(used, limit, unit = 'credits') {
      const percentage = Math.min((used / limit) * 100, 100);
      const isWarning = percentage >= 80 && percentage < 90;
      const isDanger = percentage >= 90;

      const container = document.createElement('div');
      container.className = 'usage-meter';
      container.setAttribute('role', 'progressbar');
      container.setAttribute('aria-valuenow', used);
      container.setAttribute('aria-valuemin', 0);
      container.setAttribute('aria-valuemax', limit);
      container.setAttribute('aria-label', `Usage: ${used} of ${limit} ${unit}`);

      container.innerHTML = `

          ${used.toLocaleString()} / ${limit.toLocaleString()} ${unit}
          ${percentage.toFixed(1)}%

        ${isDanger ? '
⚠ Approaching limit
' : ''}
      `;

      return container;
    },

    paymentMethodCard(method) {
      if (!method) {
        return `<div class="empty-state">No payment method on file</div>`;
      }

      const { brand, last4, expiryMonth, expiryYear, isDefault } = method;
      const brandColors = {
        visa: '#1A1F71',
        mastercard: '#EB001B',
        amex: '#006FCF',
        discover: '#FF6000'
      };

      return `

            ${brand ? brand.charAt(0).toUpperCase() : '💳'}

•••• •••• •••• ${last4}

Expires ${expiryMonth}/${expiryYear} ${isDefault ? '• Default' : ''}

          <button class="btn btn-secondary" onclick="billingDashboard.updatePaymentMethod()" aria-label="Update payment method">
            Update
          </button>

      `;
    },

    billingRow(invoice) {
      const tr = document.createElement('tr');
      tr.innerHTML = `
        ${formatDate(invoice.date)}
        ${invoice.description || 'Subscription'}
        ${formatCurrency(invoice.amount)}

            ${invoice.status}

          ${invoice.pdfUrl ? `

              PDF

          ` : '-'}

      `;
      return tr;
    },

    overageList(overages) {
      if (!overages || overages.length === 0) {
        return `<p style="color: var(--text-secondary); font-size: 0.875rem;">No overage charges</p>`;
      }

      return overages.map(overage => `

${overage.description}

              ${formatDate(overage.date)} • ${overage.usage.toLocaleString()} units

+${formatCurrency(overage.amount)}

      `).join('');
    }
  };

  // Main Dashboard Logic
  class BillingDashboard {
    constructor(containerId) {
      this.container = document.getElementById(containerId);
      if (!this.container) {
        throw new Error(`Container #${containerId} not found`);
      }

      injectStyles();
      this.init();
    }

    async init() {
      this.renderSkeleton();
      await this.loadData();
      this.startRefreshInterval();
    }

    renderSkeleton() {
      this.container.innerHTML = `

            ${components.skeleton('title').outerHTML}

              ${components.skeleton('title').outerHTML}
              ${components.skeleton('text').outerHTML}
              ${components.skeleton('text').outerHTML}

                ${components.skeleton('button').outerHTML}

              ${components.skeleton('title').outerHTML}
              ${components.skeleton('text').outerHTML}

      `;
    }

    async loadData() {
      try {
        state.isLoading = true;

        // Parallel data fetching
        const [planData, historyData, paymentData, overageData] = await Promise.all([
          api.getCurrentPlan().catch(() => null),
          api.getHistory().catch(() => []),
          api.getPaymentMethod().catch(() => null),
          api.getOverages().catch(() => [])
        ]);

        state.currentPlan = planData;
        state.history = historyData;
        state.paymentMethod = paymentData;
        state.overages = overageData;
        state.error = null;

        this.render();
      } catch (error) {
        state.error = error.message;
        this.showError('Failed to load billing data. Please try again.');
      } finally {
        state.isLoading = false;
      }
    }

    render() {
      if (!state.currentPlan) {
        this.container.innerHTML = `

Unable to load billing information

              <button class="btn btn-primary" onclick="billingDashboard.loadData()" style="margin-top: 1rem;">
                Retry
              </button>

        `;
        return;
      }

      const { plan, usage, nextBillingDate, amountDue } = state.currentPlan;

      this.container.innerHTML = `

Billing & Usage

Manage your subscription and view billing history

                  ${plan.name}

${formatCurrency(plan.price)}/month

                    ${plan.limits.credits.toLocaleString()}

credits/mo

              ${components.usageMeter(usage.used, usage.limit, 'credits').outerHTML}

                <svg width="16" height="16" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
                  <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M8 7V3m8 4V3m-9 8h10M5 21h14a2 2 0 002-2V7a2 2 0 00-2-2H5a2 2 0 00-2 2v12a2 2 0 002 2z"></path>
                </svg>
                Next payment: ${formatDate(nextBillingDate)}
                ${amountDue > 0 ? `<span style="margin-left: auto; color: var(--accent); font-weight: 600;">${formatCurrency(amountDue)} due</span>` : ''}

                <button class="btn btn-primary" onclick="billingDashboard.upgradePlan()" aria-label="Upgrade subscription plan">
                  Upgrade Plan
                </button>
                ${plan.name !== 'Free' ? `
                  <button class="btn btn-secondary" onclick="billingDashboard.downgradePlan()" aria-label="Downgrade subscription plan">
                    Downgrade
                  </button>
                ` : ''}
                <button class="btn btn-secondary" onclick="billingDashboard.openPortal()" aria-label="Manage subscription in Stripe portal">
                  Manage Subscription
                </button>

Payment Method

                ${components.paymentMethodCard(state.paymentMethod)}

Overage Charges

                  ${state.overages.reduce((sum, o) => sum + o.amount, 0) > 0 ?
                    `<span class="amount" style="color: var(--warning);">${formatCurrency(state.overages.reduce((sum, o) => sum + o.amount, 0))}</span>`
                    : ''}

                ${components.overageList(state.overages)}

Billing History

              <button class="btn btn-secondary" onclick="billingDashboard.exportHistory()" aria-label="Export billing history">
                Export CSV
              </button>

                    Date
                    Description
                    Amount
                    Status
                    Actions

                  ${state.history.length === 0 ? `

                      No billing history available

                  ` : state.history.map(invoice => components.billingRow(invoice).outerHTML).join('')}

      `;
    }

    // Action handlers
    async upgradePlan() {
      try {
        this.setLoading(true);
        await api.redirectToStripe('upgrade');
      } catch (error) {
        this.showError('Unable to initiate upgrade. Please try again.');
      } finally {
        this.setLoading(false);
      }
    }

    async downgradePlan() {
      if (!confirm('Are you sure you want to downgrade your plan? This may result in feature restrictions.')) {
        return;
      }

      try {
        this.setLoading(true);
        await api.redirectToStripe('downgrade');
      } catch (error) {
        this.showError('Unable to initiate downgrade. Please try again.');
      } finally {
        this.setLoading(false);
      }
    }

    async openPortal() {
      try {
        this.setLoading(true);
        await api.redirectToStripe('portal');
      } catch (error) {
        this.showError('Unable to open billing portal. Please try again.');
      } finally {
        this.setLoading(false);
      }
    }

    async updatePaymentMethod() {
      try {
        this.setLoading(true);
        await api.redirectToStripe('portal');
      } catch (error) {
        this.showError('Unable to update payment method. Please try again.');
      } finally {
        this.setLoading(false);
      }
    }

    exportHistory() {
      if (state.history.length === 0) {
        this.showError('No history to export');
        return;
      }

      const csv = [
        ['Date', 'Description', 'Amount', 'Status', 'Invoice ID'].join(','),
        ...state.history.map(inv => [
          formatDate(inv.date),
          `"${inv.description || 'Subscription'}"`,
          inv.amount,
          inv.status,
          inv.id
        ].join(','))
      ].join('\n');

      const blob = new Blob([csv], { type: 'text/csv' });
      const url = window.URL.createObjectURL(blob);
      const a = document.createElement('a');
      a.href = url;
      a.download = `billing-history-${new Date().toISOString().split('T')[0]}.csv`;
      a.click();
      window.URL.revokeObjectURL(url);
    }

    setLoading(loading) {
      const buttons = this.container.querySelectorAll('.btn');
      buttons.forEach(btn => {
        btn.disabled = loading;
        btn.style.opacity = loading ? '0.7' : '1';
        btn.style.cursor = loading ? 'not-allowed' : 'pointer';
      });
    }

    showError(message) {
      // Remove existing toast
      const existing = document.querySelector('.error-toast');
      if (existing) existing.remove();

      const toast = document.createElement('div');
      toast.className = 'error-toast';
      toast.setAttribute('role', 'alert');
      toast.setAttribute('aria-live', 'polite');
      toast.textContent = message;
      document.body.appendChild(toast);

      // Trigger animation
      requestAnimationFrame(() => {
        toast.classList.add('show');
      });

      setTimeout(() => {
        toast.classList.remove('show');
        setTimeout(() => toast.remove(), 300);
      }, 5000);
    }

    startRefreshInterval() {
      setInterval(() => {
        this.loadData();
      }, CONFIG.refreshInterval);
    }

    destroy() {
      // Cleanup if needed
      const styles = document.getElementById('billing-dashboard-styles');
      if (styles) styles.remove();
    }
  }

  // Initialize
  let billingDashboard;

  document.addEventListener('DOMContentLoaded', () => {
    // Look for container or create one
    let container = document.getElementById('billing-dashboard');
    if (!container) {
      container = document.createElement('div');
      container.id = 'billing-dashboard';
      document.body.appendChild(container);
    }

    billingDashboard = new BillingDashboard('billing-dashboard');
  });

  // Expose to global scope for onclick handlers
  window.billingDashboard = billingDashboard;
})();
```

This vanilla JavaScript billing dashboard includes:

1. **Current Plan Display**: Shows plan name, price, and usage meter with visual warnings at 80% and 90% thresholds
2. **Usage Meter**: Animated progress bar with ARIA accessibility attributes
3. **Stripe Integration**: Upgrade/downgrade buttons redirect to Stripe Checkout/Customer Portal
4. **Billing History**: Sortable table with status badges, PDF download links, and CSV export
5. **Payment Method**: Secure display (last 4 digits only) with card brand icons
6. **Overage Tracking**: Detailed breakdown of extra charges beyond plan limits
7. **Next Payment**: Prominent display of upcoming billing date and amount due
8. **Accessibility**: Full keyboard navigation, ARIA labels, screen reader support, and focus management
9. **Dark Theme**: Uses specified #0B0C0E background and #3B82F6 accent colors
10. **Error Handling**: Toast notifications, retry mechanisms, and loading states
11. **Responsive**: CSS Grid layout that adapts from mobile to desktop

The code expects these API endpoints:
- `GET /api/billing/current` - Returns plan, usage, next billing date
- `GET /api/billing/history` - Array of invoice objects
- `GET /api/billing/payment-method` - Card details (last4, brand, expiry)
- `GET /api/billing/overages` - Array of overage charges
- `POST /api/billing/stripe-session` - Returns Stripe redirect URL


Agency Partner Portal Page


Widget Installation Guide Component

Response:
```javascript
/**
 * Sunaiva Talking Widget - Interactive Installation Guide
 * A self-contained, accessible installation guide component
 *
 * @class InstallGuide
 * @version 1.0.0
 * @author Frontend Expert
 */

class InstallGuide {
  /**
   * @param {HTMLElement|string} container - Container element or selector
   * @param {Object} config - Configuration options
   * @param {string} config.widgetId - Unique widget identifier
   * @param {string} config.apiEndpoint - Verification API endpoint
   * @param {string} config.initialPlatform - Pre-selected platform
   */
  constructor(container, config = {}) {
    this.container = typeof container === 'string'
      ? document.querySelector(container)
      : container;

    if (!this.container) {
      throw new Error('InstallGuide: Container not found');
    }

    this.config = {
      widgetId: config.widgetId || 'sun-widget-default',
      apiEndpoint: config.apiEndpoint || '/api/widget/verify',
      initialPlatform: config.initialPlatform || this.detectPlatform(),
      ...config
    };

    this.state = {
      currentPlatform: this.config.initialPlatform,
      verificationStatus: 'idle', // idle, loading, success, error
      copiedSection: null
    };

    this.platforms = {
      wordpress: {
        name: 'WordPress',
        icon: '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.486 2 2 6.486 2 12s4.486 10 10 10 10-4.486 10-10S17.514 2 12 2zm-1.5 17.5c-3.5-1-6-4.5-6-8.5 0-2.5 1-4.5 2.5-6l6 14zm3 0l6-14c1.5 1.5 2.5 3.5 2.5 6 0 4-2.5 7.5-6 8.5h-2.5z"/></svg>',
        steps: [
          {
            title: 'Install via Plugin (Recommended)',
            content: 'Download the Sunaiva plugin from your dashboard and upload it to Plugins > Add New > Upload Plugin.',
            code: null
          },
          {
            title: 'Or Add Code Manually',
            content: 'Add this code to your theme\'s header.php file before the closing </head> tag, or use a plugin like "Insert Headers and Footers".',
            code: `<script src="https://cdn.sunaiva.ai/widget/${this.config.widgetId}.js" async></script>`
          }
        ]
      },
      shopify: {
        name: 'Shopify',
        icon: '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M15.337 2.415c-.042-.025-.084-.042-.126-.042s-.084 0-.126.017c-.042.017-2.066 1.536-2.066 1.536s-1.536-.5-1.62-.517c-.084-.017-.168 0-.252.042-.084.042-1.45 1.03-1.62 1.13-.168.1-.252.217-.235.334.017.117.42 2.283.42 2.283s-.92 2.15-.938 2.184c-.017.033-.084.15-.05.267.034.117.118.184.202.218l1.116.384s-.235.584-.268.651c-.034.067-.05.117-.034.184.017.067 1.252 3.804 1.252 3.804s.084.267.318.35c.235.084.42-.017.42-.017l1.737-.667s.62.452.77.568c.15.117.235.1.336.067.1-.033 2.082-1.018 2.082-1.018s.084-.033.1-.084c.017-.05.034-1.018.034-1.018s.235-.067.368-.1c.134-.033.235-.117.268-.234.034-.117-.084-2.15-.084-2.15s.353-.084.486-.117c.134-.033.235-.117.252-.217.017-.1-.05-1.887-.05-1.887s1.15-3.42 1.184-3.487c.033-.067.05-.134.033-.2-.017-.067-.084-.117-.168-.134-.084-.017-1.15-.334-1.15-.334s-.067-.084-.15-.1c-.084-.017-.168 0-.252.05z"/></svg>',
        steps: [
          {
            title: 'Online Store > Themes > Edit Code',
            content: 'Navigate to your Shopify admin, go to Online Store > Themes > Actions > Edit Code.',
            code: null
          },
          {
            title: 'Edit theme.liquid',
            content: 'Find theme.liquid in the Layout folder and paste this code before the closing </head> tag.',
            code: `
`
          }
        ]
      },
      wix: {
        name: 'Wix',
        icon: '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2L2 7l10 5 10-5-10-5zM2 17l10 5 10-5M2 12l10 5 10-5"/></svg>',
        steps: [
          {
            title: 'Settings > Custom Code',
            content: 'In your Wix dashboard, go to Settings > Advanced > Custom Code.',
            code: null
          },
          {
            title: 'Add Custom Code',
            content: 'Click "Add Custom Code" and paste the snippet below. Set it to load on all pages and place in the Head section.',
            code: `<script src="https://cdn.sunaiva.ai/widget/${this.config.widgetId}.js" async></script>`
          }
        ]
      },
      squarespace: {
        name: 'Squarespace',
        icon: '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M12 2C6.48 2 2 6.48 2 12s4.48 10 10 10 10-4.48 10-10S17.52 2 12 2zm-2 15l-5-5 1.41-1.41L10 14.17l7.59-7.59L19 8l-9 9z"/></svg>',
        steps: [
          {
            title: 'Settings > Advanced > Code Injection',
            content: 'Navigate to Settings > Advanced > Code Injection in your Squarespace admin.',
            code: null
          },
          {
            title: 'Header Injection',
            content: 'Paste this code into the HEADER section:',
            code: `<script src="https://cdn.sunaiva.ai/widget/${this.config.widgetId}.js" async></script>`
          }
        ]
      },
      custom: {
        name: 'Custom HTML',
        icon: '<svg viewBox="0 0 24 24" fill="currentColor" aria-hidden="true"><path d="M9.4 16.6L4.8 12l4.6-4.6L8 6l-6 6 6 6 1.4-1.4zm5.2 0l4.6-4.6-4.6-4.6L16 6l6 6-6 6-1.4-1.4z"/></svg>',
        steps: [
          {
            title: 'Copy the Embed Code',
            content: 'Add this script tag to your HTML file, preferably in the <head> section or just before the closing </body> tag.',
            code: `
`
          }
        ]
      }
    };

    this.faqData = [
      {
        question: 'Widget not appearing on my site?',
        answer: 'Ensure the script is placed before the closing  tag. Check browser console for errors (F12 > Console). If using a caching plugin (WP Rocket, etc.), clear your cache after installation.'
      },
      {
        question: 'Can I install on multiple domains?',
        answer: 'Yes, your widget ID works across unlimited domains. However, for security, you can whitelist specific domains in your dashboard settings.'
      },
      {
        question: 'Does this slow down my site?',
        answer: 'No. Our script loads asynchronously (async) and is hosted on a global CDN. It typically loads in under 50ms and defers heavy assets until after page load.'
      },
      {
        question: 'How do I uninstall?',
        answer: 'Simply remove the script tag from your site. For WordPress, deactivate the plugin. The widget will stop loading immediately.'
      }
    ];

    this.init();
  }

  /**
   * Detect platform from URL parameters or user agent
   */
  detectPlatform() {
    const urlParams = new URLSearchParams(window.location.search);
    const platform = urlParams.get('platform');

    if (platform && this.platforms[platform]) {
      return platform;
    }

    // Basic user agent detection
    const ua = navigator.userAgent.toLowerCase();
    const referrer = document.referrer.toLowerCase();

    if (referrer.includes('wordpress') || referrer.includes('wp-admin')) return 'wordpress';
    if (referrer.includes('shopify')) return 'shopify';
    if (referrer.includes('wix')) return 'wix';
    if (referrer.includes('squarespace')) return 'squarespace';

    return 'custom';
  }

  init() {
    this.injectStyles();
    this.render();
    this.attachEvents();
    this.announceToScreenReader('Installation guide loaded. Use tab navigation to select your platform.');
  }

  injectStyles() {
    if (document.getElementById('install-guide-styles')) return;

    const styles = document.createElement('style');
    styles.id = 'install-guide-styles';
    styles.textContent = `
      :root {
        --sun-bg-primary: #0B0C0E;
        --sun-bg-secondary: #15171A;
        --sun-bg-tertiary: #1F2937;
        --sun-accent: #3B82F6;
        --sun-accent-hover: #2563EB;
        --sun-text-primary: #F9FAFB;
        --sun-text-secondary: #9CA3AF;
        --sun-border: #2D3748;
        --sun-success: #10B981;
        --sun-error: #EF4444;
        --sun-radius: 8px;
        --sun-spacing: 1.5rem;
      }

      .install-guide {
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        background: var(--sun-bg-primary);
        color: var(--sun-text-primary);
        max-width: 800px;
        margin: 0 auto;
        padding: var(--sun-spacing);
        border-radius: var(--sun-radius);
      }

      .install-guide__header {
        margin-bottom: 2rem;
      }

      .install-guide__title {
        font-size: 1.5rem;
        font-weight: 700;
        margin: 0 0 0.5rem;
        color: var(--sun-text-primary);
      }

      .install-guide__subtitle {
        color: var(--sun-text-secondary);
        margin: 0;
        font-size: 0.95rem;
      }

      /* Platform Tabs */
      .install-guide__tabs {
        display: flex;
        gap: 0.5rem;
        margin-bottom: 2rem;
        overflow-x: auto;
        padding-bottom: 0.5rem;
        scrollbar-width: thin;
        scrollbar-color: var(--sun-border) var(--sun-bg-primary);
      }

      .install-guide__tabs::-webkit-scrollbar {
        height: 6px;
      }

      .install-guide__tabs::-webkit-scrollbar-track {
        background: var(--sun-bg-primary);
      }

      .install-guide__tabs::-webkit-scrollbar-thumb {
        background: var(--sun-border);
        border-radius: 3px;
      }

      .install-guide__tab {
        display: flex;
        align-items: center;
        gap: 0.5rem;
        padding: 0.75rem 1rem;
        background: var(--sun-bg-secondary);
        border: 1px solid var(--sun-border);
        border-radius: var(--sun-radius);
        color: var(--sun-text-secondary);
        cursor: pointer;
        transition: all 0.2s ease;
        white-space: nowrap;
        font-size: 0.9rem;
        font-weight: 500;
      }

      .install-guide__tab:hover {
        border-color: var(--sun-accent);
        color: var(--sun-text-primary);
      }

      .install-guide__tab[aria-selected="true"] {
        background: var(--sun-accent);
        border-color: var(--sun-accent);
        color: white;
      }

      .install-guide__tab svg {
        width: 18px;
        height: 18px;
      }

      /* Content Panels */
      .install-guide__panel {
        display: none;
        animation: fadeIn 0.3s ease;
      }

      .install-guide__panel[aria-hidden="false"] {
        display: block;
      }

      @keyframes fadeIn {
        from { opacity: 0; transform: translateY(10px); }
        to { opacity: 1; transform: translateY(0); }
      }

      .install-guide__step {
        background: var(--sun-bg-secondary);
        border: 1px solid var(--sun-border);
        border-radius: var(--sun-radius);
        padding: 1.5rem;
        margin-bottom: 1rem;
      }

      .install-guide__step-title {
        font-size: 1.1rem;
        font-weight: 600;
        margin: 0 0 0.75rem;
        color: var(--sun-text-primary);
      }

      .install-guide__step-content {
        color: var(--sun-text-secondary);
        line-height: 1.6;
        margin-bottom: 1rem;
      }

      .install-guide__step-content code {
        background: var(--sun-bg-tertiary);
        padding: 0.2rem 0.4rem;
        border-radius: 4px;
        font-family: 'Monaco', 'Menlo', monospace;
        font-size: 0.9em;
        color: var(--sun-accent);
      }

      /* Code Block */
      .install-guide__code-wrapper {
        position: relative;
        background: #0d1117;
        border: 1px solid var(--sun-border);
        border-radius: var(--sun-radius);
        overflow: hidden;
      }

      .install-guide__code {
        display: block;
        padding: 1rem;
        font-family: 'Monaco', 'Menlo', 'Consolas', monospace;
        font-size: 0.85rem;
        line-height: 1.5;
        color: #e6edf3;
        overflow-x: auto;
        white-space: pre;
      }

      .install-guide__copy-btn {
        position: absolute;
        top: 0.5rem;
        right: 0.5rem;
        padding: 0.5rem 1rem;
        background: var(--sun-bg-tertiary);
        border: 1px solid var(--sun-border);
        border-radius: 6px;
        color: var(--sun-text-secondary);
        cursor: pointer;
        font-size: 0.85rem;
        display: flex;
        align-items: center;
        gap: 0.5rem;
        transition: all 0.2s;
      }

      .install-guide__copy-btn:hover {
        background: var(--sun-accent);
        border-color: var(--sun-accent);
        color: white;
      }

      .install-guide__copy-btn[aria-pressed="true"] {
        background: var(--sun-success);
        border-color: var(--sun-success);
        color: white;
      }

      /* Verification Section */
      .install-guide__verify {
        background: var(--sun-bg-secondary);
        border: 1px solid var(--sun-border);
        border-radius: var(--sun-radius);
        padding: 1.5rem;
        margin-top: 2rem;
      }

      .install-guide__verify-title {
        font-size: 1.1rem;
        font-weight: 600;
        margin: 0 0 1rem;
        display: flex;
        align-items: center;
        gap: 0.5rem;
      }

      .install-guide__input-group {
        display: flex;
        gap: 0.5rem;
        margin-bottom: 1rem;
      }

      .install-guide__input {
        flex: 1;
        padding: 0.75rem 1rem;
        background: var(--sun-bg-primary);
        border: 1px solid var(--sun-border);
        border-radius: var(--sun-radius);
        color: var(--sun-text-primary);
        font-size: 0.95rem;
      }

      .install-guide__input:focus {
        outline: 2px solid var(--sun-accent);
        outline-offset: -1px;
      }

      .install-guide__btn {
        padding: 0.75rem 1.5rem;
        background: var(--sun-accent);
        border: none;
        border-radius: var(--sun-radius);
        color: white;
        font-weight: 600;
        cursor: pointer;
        transition: background 0.2s;
        white-space: nowrap;
      }

      .install-guide__btn:hover:not(:disabled) {
        background: var(--sun-accent-hover);
      }

      .install-guide__btn:disabled {
        opacity: 0.6;
        cursor: not-allowed;
      }

      .install-guide__status {
        display: none;
        padding: 1rem;
        border-radius: var(--sun-radius);
        margin-top: 1rem;
        font-size: 0.95rem;
      }

      .install-guide__status[data-status="success"] {
        display: block;
        background: rgba(16, 185, 129, 0.1);
        border: 1px solid var(--sun-success);
        color: var(--sun-success);
      }

      .install-guide__status[data-status="error"] {
        display: block;
        background: rgba(239, 68, 68, 0.1);
        border: 1px solid var(--sun-error);
        color: var(--sun-error);
      }

      .install-guide__status[data-status="loading"] {
        display: block;
        background: rgba(59, 130, 246, 0.1);
        border: 1px solid var(--sun-accent);
        color: var(--sun-accent);
      }

      /* FAQ Section */
      .install-guide__faq {
        margin-top: 2rem;
        border-top: 1px solid var(--sun-border);
        padding-top: 2rem;
      }

      .install-guide__faq-title {
        font-size: 1.25rem;
        font-weight: 700;
        margin: 0 0 1.5rem;
      }

      .install-guide__faq-item {
        border: 1px solid var(--sun-border);
        border-radius: var(--sun-radius);
        margin-bottom: 0.75rem;
        overflow: hidden;
      }

      .install-guide__faq-question {
        width: 100%;
        padding: 1rem 1.25rem;
        background: var(--sun-bg-secondary);
        border: none;
        color: var(--sun-text-primary);
        text-align: left;
        font-size: 0.95rem;
        font-weight: 600;
        cursor: pointer;
        display: flex;
        justify-content: space-between;
        align-items: center;
        transition: background 0.2s;
      }

      .install-guide__faq-question:hover {
        background: var(--sun-bg-tertiary);
      }

      .install-guide__faq-question[aria-expanded="true"] {
        background: var(--sun-bg-tertiary);
        border-bottom: 1px solid var(--sun-border);
      }

      .install-guide__faq-icon {
        width: 20px;
        height: 20px;
        transition: transform 0.2s;
        color: var(--sun-text-secondary);
      }

      .install-guide__faq-question[aria-expanded="true"] .install-guide__faq-icon {
        transform: rotate(180deg);
      }

      .install-guide__faq-answer {
        display: none;
        padding: 1rem 1.25rem;
        background: var(--sun-bg-primary);
        color: var(--sun-text-secondary);
        line-height: 1.6;
        font-size: 0.95rem;
      }

      .install-guide__faq-answer[aria-hidden="false"] {
        display: block;
        animation: slideDown 0.2s ease;
      }

      @keyframes slideDown {
        from { opacity: 0; max-height: 0; }
        to { opacity: 1; max-height: 500px; }
      }

      /* Accessibility */
      .sr-only {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border-width: 0;
      }

      /* Responsive */
      @media (max-width: 640px) {
        .install-guide__tabs {
          gap: 0.4rem;
        }

        .install-guide__tab {
          padding: 0.6rem 0.8rem;
          font-size: 0.85rem;
        }

        .install-guide__input-group {
          flex-direction: column;
        }
      }
    `;

    document.head.appendChild(styles);
  }

  render() {
    this.container.className = 'install-guide';
    this.container.innerHTML = `

Install Your Widget

Select your platform for specific instructions or verify your installation.

        ${Object.entries(this.platforms).map(([key, platform]) => `
          <button
            class="install-guide__tab"
            role="tab"
            id="tab-${key}"
            aria-selected="${key === this.state.currentPlatform}"
            aria-controls="panel-${key}"
            data-platform="${key}"
            tabindex="${key === this.state.currentPlatform ? '0' : '-1'}"
          >
            ${platform.icon}
            ${platform.name}
          </button>
        `).join('')}

      ${Object.entries(this.platforms).map(([key, platform]) => `

          ${platform.steps.map((step, index) => `

Step ${index + 1}: ${step.title}

${step.content}

              ${step.code ? `

${this.escapeHtml(step.code)}

                  <button
                    class="install-guide__copy-btn"
                    data-clipboard="${this.escapeHtml(step.code)}"
                    aria-label="Copy code to clipboard"
                    aria-pressed="false"
                  >
                    <svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
                      <rect x="9" y="9" width="13" height="13" rx="2" ry="2"></rect>
                      <path d="M5 15H4a2 2 0 0 1-2-2V4a2 2 0 0 1 2-2h9a2 2 0 0 1 2 2v1"></path>
                    </svg>
                    Copy
                  </button>

              ` : ''}

          `).join('')}

      `).join('')}

          <svg width="20" height="20" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
            <path d="M9 11l3 3L22 4"></path>
            <path d="M21 12v7a2 2 0 0 1-2 2H5a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h11"></path>
          </svg>
          Verify Installation

          Enter your website URL to check if the widget is properly installed.

          <input
            type="url"
            class="install-guide__input"
            id="verify-url"
            placeholder="https://yoursite.com"
            aria-label="Website URL"
          >
          <button class="install-guide__btn" id="verify-btn">Check Installation</button>

Troubleshooting

          ${this.faqData.map((item, index) => `

              <button
                class="install-guide__faq-question"
                aria-expanded="false"
                aria-controls="faq-answer-${index}"
                id="faq-question-${index}"
              >
                ${item.question}
                <svg class="install-guide__faq-icon" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" aria-hidden="true">
                  <polyline points="6 9 12 15 18 9"></polyline>
                </svg>
              </button>

                ${item.answer}

          `).join('')}

    `;

    // Cache DOM elements
    this.elements = {
      tabs: this.container.querySelectorAll('[role="tab"]'),
      panels: this.container.querySelectorAll('[role="tabpanel"]'),
      copyButtons: this.container.querySelectorAll('.install-guide__copy-btn'),
      verifyBtn: this.container.getElementById('verify-btn'),
      verifyInput: this.container.getElementById('verify-url'),
      verifyStatus: this.container.getElementById('verify-status'),
      faqButtons: this.container.querySelectorAll('.install-guide__faq-question'),
      announceRegion: this.container.getElementById('announce-region')
    };
  }

  attachEvents() {
    // Tab navigation
    this.elements.tabs.forEach(tab => {
      tab.addEventListener('click', () => this.switchPlatform(tab.dataset.platform));
      tab.addEventListener('keydown', (e) => this.handleTabKeydown(e));
    });

    // Copy to clipboard
    this.elements.copyButtons.forEach(btn => {
      btn.addEventListener('click', () => this.copyToClipboard(btn));
    });

    // Verification
    this.elements.verifyBtn.addEventListener('click', () => this.verifyInstallation());
    this.elements.verifyInput.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') this.verifyInstallation();
    });

    // FAQ Accordion
    this.elements.faqButtons.forEach(btn => {
      btn.addEventListener('click', () => this.toggleFAQ(btn));
    });
  }

  /**
   * Handle keyboard navigation for tabs (Arrow keys, Home, End)
   */
  handleTabKeydown(e) {
    const tabs = Array.from(this.elements.tabs);
    const currentIndex = tabs.indexOf(e.target);
    let nextIndex;

    switch(e.key) {
      case 'ArrowRight':
        nextIndex = (currentIndex + 1) % tabs.length;
        break;
      case 'ArrowLeft':
        nextIndex = (currentIndex - 1 + tabs.length) % tabs.length;
        break;
      case 'Home':
        nextIndex = 0;
        break;
      case 'End':
        nextIndex = tabs.length - 1;
        break;
      default:
        return;
    }

    e.preventDefault();
    tabs[nextIndex].focus();
    tabs[nextIndex].click();
  }

  switchPlatform(platform) {
    if (platform === this.state.currentPlatform) return;

    this.state.currentPlatform = platform;

    // Update tabs
    this.elements.tabs.forEach(tab => {
      const isSelected = tab.dataset.platform === platform;
      tab.setAttribute('aria-selected', isSelected);
      tab.setAttribute('tabindex', isSelected ? '0' : '-1');
    });

    // Update panels
    this.elements.panels.forEach(panel => {
      const isCurrent = panel.id === `panel-${platform}`;
      panel.setAttribute('aria-hidden', !isCurrent);
    });

    this.announceToScreenReader(`Showing installation steps for ${this.platforms[platform].name}`);
  }

  async copyToClipboard(button) {
    const text = button.dataset.clipboard;

    try {
      await navigator.clipboard.writeText(text);

      // Visual feedback
      const originalContent = button.innerHTML;
      button.setAttribute('aria-pressed', 'true');
      button.innerHTML = `
        <svg width="16" height="16" viewBox="0 0 24 24" fill="none"


Real-time Call Activity Feed


Admin Panel - User Management

Response:
Here's a complete, production-ready admin user management module. The code includes the JavaScript class, expected HTML structure, and CSS custom properties.

```javascript
/**
 * Sunaiva Admin User Manager
 * Path: Sunaiva/talking-widget/dashboard/js/admin-users.js
 *
 * A vanilla JavaScript admin panel for user management with impersonation,
 * tier overrides, and usage analytics.
 */

class AdminUserManager {
  constructor(containerId = 'admin-users-container') {
    this.container = document.getElementById(containerId);
    if (!this.container) {
      throw new Error(`Container #${containerId} not found`);
    }

    // State
    this.users = [];
    this.filteredUsers = [];
    this.currentUser = null;
    this.currentPage = 1;
    this.itemsPerPage = 25;
    this.filters = {
      search: '',
      status: 'all',
      tier: 'all',
      dateRange: 'all'
    };
    this.sortConfig = {
      key: 'lastActive',
      direction: 'desc'
    };

    // Bind methods
    this.handleSearch = this.debounce(this.handleSearch.bind(this), 300);
    this.handleKeydown = this.handleKeydown.bind(this);

    // Initialize
    this.init();
  }

  init() {
    this.injectStyles();
    this.renderLayout();
    this.attachEventListeners();
    this.loadUsers();
    this.setupImpersonationBanner();
  }

  /**
   * CSS Custom Properties & Component Styles
   */
  injectStyles() {
    if (document.getElementById('admin-users-styles')) return;

    const styles = document.createElement('style');
    styles.id = 'admin-users-styles';
    styles.textContent = `
      :root {
        --adm-bg-primary: #0B0C0E;
        --adm-bg-secondary: #15171A;
        --adm-bg-tertiary: #1F2125;
        --adm-bg-elevated: #252830;
        --adm-accent: #3B82F6;
        --adm-accent-hover: #2563EB;
        --adm-accent-muted: rgba(59, 130, 246, 0.1);
        --adm-text-primary: #F3F4F6;
        --adm-text-secondary: #9CA3AF;
        --adm-text-muted: #6B7280;
        --adm-border: #2D3139;
        --adm-success: #10B981;
        --adm-warning: #F59E0B;
        --adm-danger: #EF4444;
        --adm-radius: 8px;
        --adm-shadow: 0 4px 6px -1px rgba(0, 0, 0, 0.3);
      }

      .admin-users-container {
        background: var(--adm-bg-primary);
        color: var(--adm-text-primary);
        font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
        min-height: 100vh;
        padding: 2rem;
      }

      /* Header & Controls */
      .adm-header {
        display: flex;
        justify-content: space-between;
        align-items: center;
        margin-bottom: 2rem;
        flex-wrap: wrap;
        gap: 1rem;
      }

      .adm-title {
        font-size: 1.875rem;
        font-weight: 700;
        margin: 0;
      }

      .adm-controls {
        display: flex;
        gap: 1rem;
        flex-wrap: wrap;
        align-items: center;
      }

      .adm-search-wrapper {
        position: relative;
      }

      .adm-search-input {
        background: var(--adm-bg-secondary);
        border: 1px solid var(--adm-border);
        color: var(--adm-text-primary);
        padding: 0.625rem 1rem 0.625rem 2.5rem;
        border-radius: var(--adm-radius);
        width: 300px;
        font-size: 0.875rem;
        transition: border-color 0.2s;
      }

      .adm-search-input:focus {
        outline: none;
        border-color: var(--adm-accent);
        box-shadow: 0 0 0 3px rgba(59, 130, 246, 0.1);
      }

      .adm-search-icon {
        position: absolute;
        left: 0.75rem;
        top: 50%;
        transform: translateY(-50%);
        color: var(--adm-text-muted);
        width: 1rem;
        height: 1rem;
      }

      .adm-select {
        background: var(--adm-bg-secondary);
        border: 1px solid var(--adm-border);
        color: var(--adm-text-primary);
        padding: 0.625rem 2rem 0.625rem 1rem;
        border-radius: var(--adm-radius);
        font-size: 0.875rem;
        cursor: pointer;
        appearance: none;
        background-image: url("data:image/svg+xml,%3Csvg xmlns='http://www.w3.org/2000/svg' fill='none' viewBox='0 0 20 20'%3E%3Cpath stroke='%236B7280' stroke-linecap='round' stroke-linejoin='round' stroke-width='1.5' d='M6 8l4 4 4-4'/%3E%3C/svg%3E");
        background-position: right 0.5rem center;
        background-repeat: no-repeat;
        background-size: 1.5em 1.5em;
      }

      .adm-select:focus {
        outline: none;
        border-color: var(--adm-accent);
      }

      /* Data Table */
      .adm-table-container {
        background: var(--adm-bg-secondary);
        border: 1px solid var(--adm-border);
        border-radius: var(--adm-radius);
        overflow: hidden;
        overflow-x: auto;
      }

      .adm-table {
        width: 100%;
        border-collapse: collapse;
        font-size: 0.875rem;
      }

      .adm-table th {
        background: var(--adm-bg-tertiary);
        color: var(--adm-text-secondary);
        font-weight: 600;
        text-align: left;
        padding: 0.875rem 1rem;
        text-transform: uppercase;
        font-size: 0.75rem;
        letter-spacing: 0.05em;
        cursor: pointer;
        user-select: none;
        white-space: nowrap;
      }

      .adm-table th:hover {
        color: var(--adm-text-primary);
      }

      .adm-table th[aria-sort="ascending"]::after {
        content: " ↑";
        color: var(--adm-accent);
      }

      .adm-table th[aria-sort="descending"]::after {
        content: " ↓";
        color: var(--adm-accent);
      }

      .adm-table td {
        padding: 1rem;
        border-bottom: 1px solid var(--adm-border);
        color: var(--adm-text-primary);
      }

      .adm-table tr:hover td {
        background: var(--adm-bg-tertiary);
      }

      .adm-table tr:focus-within {
        outline: 2px solid var(--adm-accent);
        outline-offset: -2px;
      }

      .adm-user-cell {
        display: flex;
        align-items: center;
        gap: 0.75rem;
      }

      .adm-avatar {
        width: 2.5rem;
        height: 2.5rem;
        border-radius: 50%;
        background: var(--adm-accent-muted);
        display: flex;
        align-items: center;
        justify-content: center;
        font-weight: 600;
        color: var(--adm-accent);
        flex-shrink: 0;
      }

      .adm-user-info {
        display: flex;
        flex-direction: column;
      }

      .adm-user-name {
        font-weight: 600;
        color: var(--adm-text-primary);
      }

      .adm-user-email {
        color: var(--adm-text-secondary);
        font-size: 0.75rem;
      }

      /* Status Badges */
      .adm-badge {
        display: inline-flex;
        align-items: center;
        padding: 0.25rem 0.75rem;
        border-radius: 9999px;
        font-size: 0.75rem;
        font-weight: 600;
        text-transform: capitalize;
      }

      .adm-badge--active {
        background: rgba(16, 185, 129, 0.1);
        color: var(--adm-success);
      }

      .adm-badge--suspended {
        background: rgba(239, 68, 68, 0.1);
        color: var(--adm-danger);
      }

      .adm-badge--pending {
        background: rgba(245, 158, 11, 0.1);
        color: var(--adm-warning);
      }

      .adm-badge--enterprise { color: #8B5CF6; background: rgba(139, 92, 246, 0.1); }
      .adm-badge--pro { color: var(--adm-accent); background: var(--adm-accent-muted); }
      .adm-badge--basic { color: var(--adm-text-secondary); background: var(--adm-bg-elevated); }

      /* Action Buttons */
      .adm-actions {
        display: flex;
        gap: 0.5rem;
      }

      .adm-btn {
        display: inline-flex;
        align-items: center;
        justify-content: center;
        gap: 0.5rem;
        padding: 0.5rem 1rem;
        border-radius: var(--adm-radius);
        font-size: 0.875rem;
        font-weight: 500;
        cursor: pointer;
        border: none;
        transition: all 0.2s;
        background: transparent;
        color: var(--adm-text-secondary);
      }

      .adm-btn:hover {
        background: var(--adm-bg-elevated);
        color: var(--adm-text-primary);
      }

      .adm-btn--primary {
        background: var(--adm-accent);
        color: white;
      }

      .adm-btn--primary:hover {
        background: var(--adm-accent-hover);
      }

      .adm-btn--danger {
        color: var(--adm-danger);
      }

      .adm-btn--danger:hover {
        background: rgba(239, 68, 68, 0.1);
      }

      .adm-btn--icon {
        padding: 0.5rem;
        width: 2rem;
        height: 2rem;
      }

      /* Modal / Detail View */
      .adm-modal-overlay {
        position: fixed;
        inset: 0;
        background: rgba(0, 0, 0, 0.8);
        backdrop-filter: blur(4px);
        display: flex;
        align-items: center;
        justify-content: center;
        z-index: 50;
        opacity: 0;
        visibility: hidden;
        transition: all 0.3s;
      }

      .adm-modal-overlay.active {
        opacity: 1;
        visibility: visible;
      }

      .adm-modal {
        background: var(--adm-bg-secondary);
        border: 1px solid var(--adm-border);
        border-radius: var(--adm-radius);
        width: 90%;
        max-width: 900px;
        max-height: 90vh;
        overflow: hidden;
        display: flex;
        flex-direction: column;
        transform: scale(0.95);
        transition: transform 0.3s;
      }

      .adm-modal-overlay.active .adm-modal {
        transform: scale(1);
      }

      .adm-modal-header {
        padding: 1.5rem;
        border-bottom: 1px solid var(--adm-border);
        display: flex;
        justify-content: space-between;
        align-items: center;
      }

      .adm-modal-title {
        font-size: 1.25rem;
        font-weight: 700;
        margin: 0;
      }

      .adm-modal-close {
        background: none;
        border: none;
        color: var(--adm-text-secondary);
        cursor: pointer;
        padding: 0.5rem;
        border-radius: var(--adm-radius);
        display: flex;
        align-items: center;
        justify-content: center;
      }

      .adm-modal-close:hover {
        background: var(--adm-bg-elevated);
        color: var(--adm-text-primary);
      }

      .adm-modal-body {
        padding: 1.5rem;
        overflow-y: auto;
        flex: 1;
      }

      /* User Detail Layout */
      .adm-detail-grid {
        display: grid;
        grid-template-columns: 1fr 1fr;
        gap: 1.5rem;
        margin-bottom: 1.5rem;
      }

      @media (max-width: 768px) {
        .adm-detail-grid {
          grid-template-columns: 1fr;
        }
      }

      .adm-card {
        background: var(--adm-bg-tertiary);
        border: 1px solid var(--adm-border);
        border-radius: var(--adm-radius);
        padding: 1.25rem;
      }

      .adm-card-title {
        font-size: 0.875rem;
        font-weight: 600;
        color: var(--adm-text-secondary);
        text-transform: uppercase;
        letter-spacing: 0.05em;
        margin: 0 0 1rem 0;
      }

      .adm-stat {
        display: flex;
        justify-content: space-between;
        align-items: center;
        padding: 0.75rem 0;
        border-bottom: 1px solid var(--adm-border);
      }

      .adm-stat:last-child {
        border-bottom: none;
      }

      .adm-stat-label {
        color: var(--adm-text-secondary);
        font-size: 0.875rem;
      }

      .adm-stat-value {
        font-weight: 600;
        color: var(--adm-text-primary);
      }

      .adm-progress-bar {
        width: 100%;
        height: 0.5rem;
        background: var(--adm-bg-elevated);
        border-radius: 9999px;
        overflow: hidden;
        margin-top: 0.5rem;
      }

      .adm-progress-fill {
        height: 100%;
        background: var(--adm-accent);
        border-radius: 9999px;
        transition: width 0.3s;
      }

      .adm-progress-fill--warning { background: var(--adm-warning); }
      .adm-progress-fill--danger { background: var(--adm-danger); }

      /* Widget List */
      .adm-widget-list {
        display: flex;
        flex-direction: column;
        gap: 0.75rem;
      }

      .adm-widget-item {
        display: flex;
        align-items: center;
        justify-content: space-between;
        padding: 0.75rem;
        background: var(--adm-bg-elevated);
        border-radius: var(--adm-radius);
        border: 1px solid var(--adm-border);
      }

      .adm-widget-name {
        font-weight: 500;
        font-size: 0.875rem;
      }

      .adm-widget-id {
        font-size: 0.75rem;
        color: var(--adm-text-muted);
        font-family: monospace;
      }

      /* Form Elements in Modal */
      .adm-form-group {
        margin-bottom: 1rem;
      }

      .adm-label {
        display: block;
        font-size: 0.875rem;
        font-weight: 500;
        color: var(--adm-text-secondary);
        margin-bottom: 0.5rem;
      }

      .adm-input, .adm-textarea {
        width: 100%;
        background: var(--adm-bg-primary);
        border: 1px solid var(--adm-border);
        color: var(--adm-text-primary);
        padding: 0.625rem;
        border-radius: var(--adm-radius);
        font-size: 0.875rem;
        font-family: inherit;
      }

      .adm-input:focus, .adm-textarea:focus {
        outline: none;
        border-color: var(--adm-accent);
      }

      /* Impersonation Banner */
      .adm-impersonation-banner {
        position: fixed;
        top: 0;
        left: 0;
        right: 0;
        background: var(--adm-warning);
        color: #000;
        padding: 0.75rem;
        text-align: center;
        font-weight: 600;
        z-index: 100;
        display: none;
        align-items: center;
        justify-content: center;
        gap: 1rem;
      }

      .adm-impersonation-banner.active {
        display: flex;
      }

      .adm-impersonation-banner button {
        background: rgba(0,0,0,0.2);
        border: none;
        padding: 0.25rem 0.75rem;
        border-radius: var(--adm-radius);
        cursor: pointer;
        font-weight: 600;
      }

      /* Toast Notifications */
      .adm-toast-container {
        position: fixed;
        bottom: 1.5rem;
        right: 1.5rem;
        z-index: 100;
        display: flex;
        flex-direction: column;
        gap: 0.75rem;
      }

      .adm-toast {
        background: var(--adm-bg-elevated);
        border: 1px solid var(--adm-border);
        color: var(--adm-text-primary);
        padding: 1rem 1.5rem;
        border-radius: var(--adm-radius);
        box-shadow: var(--adm-shadow);
        display: flex;
        align-items: center;
        gap: 0.75rem;
        min-width: 300px;
        animation: slideIn 0.3s ease-out;
      }

      @keyframes slideIn {
        from {
          transform: translateX(100%);
          opacity: 0;
        }
        to {
          transform: translateX(0);
          opacity: 1;
        }
      }

      .adm-toast--success { border-left: 4px solid var(--adm-success); }
      .adm-toast--error { border-left: 4px solid var(--adm-danger); }
      .adm-toast--warning { border-left: 4px solid var(--adm-warning); }

      /* Pagination */
      .adm-pagination {
        display: flex;
        justify-content: center;
        align-items: center;
        gap: 0.5rem;
        margin-top: 1.5rem;
        padding: 1rem;
      }

      .adm-page-btn {
        min-width: 2.5rem;
        height: 2.5rem;
        display: flex;
        align-items: center;
        justify-content: center;
        background: var(--adm-bg-secondary);
        border: 1px solid var(--adm-border);
        color: var(--adm-text-primary);
        border-radius: var(--adm-radius);
        cursor: pointer;
        font-weight: 500;
        transition: all 0.2s;
      }

      .adm-page-btn:hover:not(:disabled) {
        border-color: var(--adm-accent);
        color: var(--adm-accent);
      }

      .adm-page-btn.active {
        background: var(--adm-accent);
        border-color: var(--adm-accent);
        color: white;
      }

      .adm-page-btn:disabled {
        opacity: 0.5;
        cursor: not-allowed;
      }

      /* Loading State */
      .adm-skeleton {
        background: linear-gradient(90deg, var(--adm-bg-tertiary) 25%, var(--adm-bg-elevated) 50%, var(--adm-bg-tertiary) 75%);
        background-size: 200% 100%;
        animation: loading 1.5s infinite;
        border-radius: var(--adm-radius);
        height: 1rem;
      }

      @keyframes loading {
        0% { background-position: 200% 0; }
        100% { background-position: -200% 0; }
      }

      /* Confirmation Dialog */
      .adm-confirm-dialog {
        background: var(--adm-bg-secondary);
        border: 1px solid var(--adm-border);
        border-radius: var(--adm-radius);
        padding: 1.5rem;
        max-width: 400px;
        text-align: center;
      }

      .adm-confirm-title {
        font-size: 1.125rem;
        font-weight: 700;
        margin-bottom: 0.5rem;
      }

      .adm-confirm-text {
        color: var(--adm-text-secondary);
        margin-bottom: 1.5rem;
        font-size: 0.875rem;
      }

      .adm-confirm-actions {
        display: flex;
        gap: 0.75rem;
        justify-content: center;
      }

      /* Screen reader only */
      .sr-only {
        position: absolute;
        width: 1px;
        height: 1px;
        padding: 0;
        margin: -1px;
        overflow: hidden;
        clip: rect(0, 0, 0, 0);
        white-space: nowrap;
        border-width: 0;
      }

      /* Focus visible for keyboard navigation */
      *:focus-visible {
        outline: 2px solid var(--adm-accent);
        outline-offset: 2px;
      }

      button:focus-visible,
      input:focus-visible,
      select:focus-visible {
        outline-offset: 0;
      }
    `;
    document.head.appendChild(styles);
  }

  renderLayout() {
    this.container.innerHTML = `

User Management

              <svg class="adm-search-icon" fill="none" stroke="currentColor" viewBox="0 0 24 24" aria-hidden="true">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M21 21l-6-6m2-5a7 7 0 11-14 0 7 7 0 0114 0z"></path>
              </svg>
              <input
                type="search"
                class="adm-search-input"
                id="user-search"
                placeholder="Search users by name, email, or ID..."
                aria-label="Search users"
                autocomplete="off"
              >

            <select class="adm-select" id="filter-status" aria-label="Filter by status">
              <option value="all">All Status</option>
              <option value="active">Active</option>
              <option value="suspended">Suspended</option>
              <option value="pending">Pending</option>
            </select>

            <select class="adm-select" id="filter-tier" aria-label="Filter by tier">
              <option value="all">All Tiers</option>
              <option value="enterprise">Enterprise</option>
              <option value="pro">Pro</option>
              <option value="basic">Basic</option>
            </select>

                User
                Tier
                Status
                Widgets
                Usage
                Last Active
                Actions

User Details

            <button class="adm-modal-close" aria-label="Close modal" id="modal-close">
              <svg width="24" height="24" fill="none" stroke="currentColor" viewBox="0 0 24 24">
                <path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
              </svg>
            </button>

Confirm Action

Are you sure you want to proceed?

            <button class="adm-btn" id="confirm-cancel">Cancel</button>
            <button class="adm-btn adm-btn--primary" id="confirm-ok">Confirm</button>

        🔮 You are currently viewing as User
        <button onclick="adminUserManager.endImpersonation()">Return to Admin</button>

    `;
  }

  attachEventListeners() {
    // Search
    const searchInput = document.getElementById('user-search');
    searchInput.addEventListener('input', (e) => this.handleSearch(e.target.value));

    // Filters
    document.getElementById('filter-status').addEventListener('change', (e) => {
      this.filters.status = e.target.value;
      this.applyFilters();
    });

    document.getElementById('filter-tier').addEventListener('change', (e) => {
      this.filters.tier = e.target.value;
      this.applyFilters();
    });

    // Sorting
    document.querySelectorAll('.adm-table th[data-sort]').forEach(th => {
      th.addEventListener('click', () => this.handleSort(th.dataset.sort));
      th.style.cursor = 'pointer';
    });

    // Modal close
    document.getElementById('modal-close').addEventListener('click', () => this.closeModal());
    document.getElementById('user-modal').addEventListener('click', (e) => {
      if (e.target.id === 'user-modal') this.closeModal();
    });

    // Keyboard navigation
    document.addEventListener('keydown', this.handleKeydown);
  }

  handleKeydown(e) {
    // Close modal on Escape
    if (e.key === 'Escape') {
      this.closeModal();
      this.closeConfirmModal();
    }
  }

  debounce(func, wait) {
    let timeout;
    return function executedFunction(...args) {
      const later = () => {
        clearTimeout(timeout);
        func(...args);
      };
      clearTimeout(timeout);
      timeout = setTimeout(later, wait);
    };
  }

  handleSearch(query) {
    this.filters.search = query.toLowerCase();
    this.currentPage = 1;
    this.applyFilters();
  }

  handleSort(key) {
    // Toggle direction if same key
    if (this.sortConfig.key === key) {
      this.sortConfig.direction = this.sortConfig.direction === 'asc' ? 'desc' : 'asc';
    } else {
      this.sortConfig.key = key;
      this.sortConfig.direction = 'asc';
    }

    // Update aria-sort
    document.querySelectorAll('.adm-table th[data-sort]').forEach(th => {
      if (th.dataset.sort === key) {
        th.setAttribute('aria-sort', this.sortConfig.direction === 'asc' ? 'ascending' : 'descending');
      } else {
        th.setAttribute('aria-sort', 'none');
      }
    });

    this.applyFilters();
  }

  /**
   *


Admin Panel - System Metrics Dashboard


Landing Page Pricing Calculator


Widget Demo - Interactive Preview


Dashboard - Settings Page