/**
 * TableCrafter - A lightweight, mobile-responsive data table library
 * @version 1.4.3
 * @author Fahad Murtaza
 * @license MIT
 */

/**
 * Debug utility - only logs when debug mode is enabled
 * Enable via: window.TABLECRAFTER_DEBUG = true or data-debug="true" on container
 */
const TC_DEBUG = {
  enabled: typeof window !== 'undefined' && window.TABLECRAFTER_DEBUG === true,
  log: function(...args) {
    if (this.enabled) {
      console.log('[TableCrafter]', ...args);
    }
  },
  warn: function(...args) {
    if (this.enabled) {
      console.warn('[TableCrafter]', ...args);
    }
  },
  error: function(...args) {
    // Always log errors
    console.error('[TableCrafter]', ...args);
  }
};

/**
 * Internationalization utility
 * Gets translated strings from WordPress localization or falls back to defaults
 */
const TC_I18N = {
  strings: (typeof window !== 'undefined' && window.tablecrafterData && window.tablecrafterData.i18n)
    ? window.tablecrafterData.i18n
    : {},

  /**
   * Get a translated string with optional placeholder replacement
   * @param {string} key - The translation key
   * @param {Object} replacements - Object of placeholder replacements
   * @param {string} fallback - Fallback string if key not found
   * @returns {string} The translated string
   */
  get: function(key, replacements = {}, fallback = null) {
    let str = this.strings[key] || fallback || key;

    // Replace placeholders like {column}, {count}, {time}
    Object.keys(replacements).forEach(placeholder => {
      str = str.replace(new RegExp(`\\{${placeholder}\\}`, 'g'), replacements[placeholder]);
    });

    return str;
  },

  /**
   * Check if i18n strings are available
   * @returns {boolean}
   */
  isAvailable: function() {
    return Object.keys(this.strings).length > 0;
  }
};

class TableCrafter {
  constructor(container, config = {}) {
    TC_DEBUG.log('Initializing for', container);
    // Handle container parameter
    this.container = this.resolveContainer(container);
    if (!this.container) {
      throw new Error('Container element not found');
    }

    // Set up default configuration
    this.config = {
      data: [],
      columns: [],
      editable: false,
      pageSize: 25,
      pagination: true,
      sortable: true,
      filterable: true,
      globalSearch: true,
      globalSearchPlaceholder: TC_I18N.get('search', {}, 'Search...'),
      exportable: false,
      exportFiltered: true,
      exportFilename: 'table-export',
      // Advanced export configuration
      advancedExport: {
        enabled: true,
        formats: ['csv', 'excel', 'pdf'],
        excel: {
          includeFormatting: true,
          sheetName: 'Data Export',
          author: 'TableCrafter',
          autoWidth: true
        },
        pdf: {
          orientation: 'landscape',
          title: 'Data Export Report',
          subtitle: '',
          logo: '',
          footer: 'Generated by TableCrafter'
        }
      },
      currentPage: 1,
      // Advanced filtering configuration
      filters: {
        advanced: false,
        autoDetect: true,
        types: {}, // Custom filter types per column
        showClearAll: true
      },
      // Bulk operations configuration
      bulk: {
        enabled: false,
        operations: ['delete', 'export'],
        showProgress: true
      },
      // Large dataset handling configuration
      largeDataset: {
        enabled: true,
        threshold: 1000, // Enable server-side pagination for datasets > 1000 rows
        serverSide: false, // Will be auto-enabled for large datasets
        chunkSize: 100, // Load data in chunks for progressive loading
        virtualScrolling: false, // Enable virtual scrolling for datasets > 5000 rows
        virtualThreshold: 5000
      },
      // Add new entries configuration
      addNew: {
        enabled: false,
        modal: true,
        fields: [],
        validation: {}
      },
      // Data validation configuration
      validation: {
        enabled: true,
        showErrors: true,
        validateOnEdit: true,
        validateOnSubmit: true,
        rules: {}, // Column-specific validation rules
        messages: {
          required: 'This field is required',
          email: 'Please enter a valid email address',
          minLength: 'Minimum length is {min} characters',
          maxLength: 'Maximum length is {max} characters',
          min: 'Minimum value is {min}',
          max: 'Maximum value is {max}',
          pattern: 'Please enter a valid format',
          custom: 'Validation failed'
        }
      },
      // Rich cell types configuration
      cellTypes: {
        text: { multiline: false },
        textarea: { rows: 3 },
        number: { step: 1, precision: 2 },
        email: { validation: true },
        date: { format: 'YYYY-MM-DD', showCalendar: true },
        datetime: { format: 'YYYY-MM-DDTHH:mm', showTime: true },
        select: { multiple: false, searchable: false },
        multiselect: { multiple: true, searchable: true },
        checkbox: { label: '' },
        radio: { orientation: 'horizontal' },
        file: { accept: '*/*', multiple: false, preview: true },
        url: { openInNewTab: true },
        color: { format: 'hex' },
        range: { min: 0, max: 100, step: 1 }
      },
      // Enhanced mobile-first responsive configuration
      responsive: {
        enabled: true,
        breakpoints: {
          mobile: { width: 768, layout: 'cards' },
          tablet: { width: 900, layout: 'compact' },
          desktop: { width: 1200, layout: 'table' }
        },
        fieldVisibility: {}
      },
      // API integration configuration
      api: {
        baseUrl: '',
        endpoints: {
          data: '/data',
          create: '/create',
          update: '/update',
          delete: '/delete',
          lookup: '/lookup'
        },
        headers: {},
        authentication: null
      },
      // Permission system configuration
      permissions: {
        enabled: false,
        view: ['*'],
        edit: ['*'],
        delete: ['*'],
        create: ['*'],
        ownOnly: false
      },
      // State persistence configuration
      state: {
        persist: false,
        storage: 'localStorage',
        key: 'tablecrafter_state'
      },
      // Accessibility configuration for WCAG 2.1 compliance
      accessibility: {
        enabled: true,
        announcements: true,
        keyboardNavigation: true,
        focusManagement: true,
        highContrast: false,
        reducedMotion: false,
        announcer: {
          politeness: 'polite', // 'polite' or 'assertive'
          delay: 150 // ms delay before announcements
        },
        keyboard: {
          navigation: true,
          shortcuts: true,
          tabIndex: true,
          focusVisible: true
        },
        labels: {
          table: TC_I18N.get('table', {}, 'Data table'),
          search: TC_I18N.get('searchPlaceholder', {}, 'Search table data'),
          pagination: TC_I18N.get('pagination', {}, 'Table pagination'),
          sort: TC_I18N.get('sortBy', {}, 'Sort by {column}'),
          filter: TC_I18N.get('filterBy', {}, 'Filter {column}'),
          edit: TC_I18N.get('edit', {}, 'Edit cell'),
          export: TC_I18N.get('export', {}, 'Export table data'),
          noResults: TC_I18N.get('noResults', {}, 'No results found'),
          loading: TC_I18N.get('loading', {}, 'Loading data...'),
          error: TC_I18N.get('error', {}, 'Error loading data')
        }
      },
      // Smart Auto-Refresh configuration
      autoRefresh: {
        enabled: false,
        interval: 300000, // 5 minutes default
        pauseOnInteraction: true,
        pauseOnVisibilityChange: true,
        showIndicator: true,
        showCountdown: false,
        showLastUpdated: true,
        retryOnFailure: true,
        maxRetries: 3
      },
      ...config
    };

    // Parse data attributes from container and merge with config
    this.parseDataAttributes();

    // Internal state
    this.data = [];
    this.currentPage = this.config.currentPage || 1;
    this.sortField = null;
    this.sortOrder = 'asc';
    this.filters = {};
    this.searchTerm = '';
    this.isLoading = false;
    this.editingCell = null;
    this.selectedRows = new Set();
    this.filterTypes = {};
    this.uniqueValues = {};
    this.lookupCache = new Map();
    this.currentUser = null;
    this.userPermissions = [];
    this.validationErrors = new Map(); // Track validation errors by cell
    this.validationRules = new Map(); // Compiled validation rules
    this.cellTypeRegistry = new Map(); // Rich cell type handlers
    this.activeEditors = new Map(); // Track active rich editors
    
    // Auto-refresh state
    this.refreshInterval = null;
    this.countdownInterval = null;
    this.isPaused = false;
    this.lastRefresh = null;
    this.nextRefresh = null;
    this.refreshAttempts = 0;
    this.refreshIndicator = null;
    this.userIsInteracting = false;
    this.interactionTimeout = null;

    // Load state if persistence enabled
    this.loadState();

    // Initialize validation system
    this.initializeValidation();

    // Initialize rich cell types system
    this.initializeCellTypes();

    // Initialize accessibility system
    this.initializeAccessibility();

    // Initialize if data provided or embedded in HTML
    const initialDataScript = this.container.querySelector('.tc-initial-data');
    if (initialDataScript) {
      try {
        this.data = JSON.parse(initialDataScript.textContent);
      TC_DEBUG.log(' Initialized from embedded data payload');
      
      // If hydrating from SSR with embedded data, we must initialize state and listeners
      if (this.container.dataset.ssr === "true") {
        this.data = this.processData(this.data);
        this.autoDiscoverColumns();
        this.detectFilterTypes();
        this.container.dataset.ssr = "false";
        this.hydrateListeners();
      } else {
        // Normal initialization from embedded data (no SSR/Hydration context)
        this.autoDiscoverColumns();
      }
      } catch (e) {
        console.error('TableCrafter: Failed to parse embedded data', e);
      }
    }

    if (this.data.length === 0 && this.config.data) {
      if (Array.isArray(this.config.data)) {
        this.data = [...this.config.data];
        this.autoDiscoverColumns();
        this.render();
      } else if (typeof this.config.data === 'string') {
        // URL provided, will load asynchronously
        this.dataUrl = this.config.data;
        this.loadData().catch(err => {
            console.error('TableCrafter: Initial load failed', err);
            this.renderError('Unable to load data. Please check your connection.');
        });
      }
    } else if (this.data.length > 0 && typeof this.config.data === 'string') {
      // Data was embedded, but we still store the URL for potential refreshes
      this.dataUrl = this.config.data;
      this.render();
    } else if (this.data.length > 0) {
      // Data present but no URL
      this.render();
    }

    // Bind resize handler if responsive
    if (this.config.responsive) {
      this.handleResize = this.handleResize.bind(this);
      window.addEventListener('resize', this.handleResize);
    }

    // Initialize auto-refresh if enabled and data URL available
    if (this.config.autoRefresh.enabled && this.dataUrl) {
      this.initializeAutoRefresh();
    }
  }

  /**
   * Escape HTML to prevent XSS attacks
   * @param {string} str - String to escape
   * @returns {string} - Escaped string safe for HTML insertion
   */
  escapeHtml(str) {
    if (str === null || str === undefined) return '';
    const div = document.createElement('div');
    div.textContent = String(str);
    return div.innerHTML;
  }

  /**
   * Escape URL for safe use in href attributes
   * @param {string} url - URL to sanitize
   * @returns {string} - Safe URL or empty string if dangerous
   */
  sanitizeUrl(url) {
    if (!url || typeof url !== 'string') return '';
    const trimmed = url.trim().toLowerCase();
    // Block javascript:, data:, vbscript: and other dangerous protocols
    if (/^(javascript|data|vbscript|file):/i.test(trimmed)) {
      return '';
    }
    // Encode special characters
    return encodeURI(url);
  }

  /**
   * Format value for display
   */
  formatValue(value, type) {
    if (value === null || value === undefined) return '';

    // Auto-detect if not specified
    if (!type) {
      type = this.detectDataType(value);
    }

    switch (type) {
      case 'date':
        // Try to parse date
        const date = new Date(value);
        if (isNaN(date.getTime())) return this.escapeHtml(value);

        return this.escapeHtml(date.toLocaleDateString(undefined, {
          year: 'numeric',
          month: 'short',
          day: 'numeric'
        }));

      case 'datetime':
        const dt = new Date(value);
        if (isNaN(dt.getTime())) return this.escapeHtml(value);

        return this.escapeHtml(dt.toLocaleString(undefined, {
          year: 'numeric',
          month: 'short',
          day: 'numeric',
          hour: '2-digit',
          minute: '2-digit'
        }));

      case 'boolean':
        const isTrue = value === true || value === 'true' || value === 1 || value === '1';
        const yesLabel = TC_I18N.get('yes', {}, 'Yes');
        const noLabel = TC_I18N.get('no', {}, 'No');
        return isTrue
          ? `<span class="tc-badge tc-badge-success">${this.escapeHtml(yesLabel)}</span>`
          : `<span class="tc-badge tc-badge-error">${this.escapeHtml(noLabel)}</span>`;

      case 'email':
        // Validate email format before rendering
        const emailStr = String(value);
        if (!/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(emailStr) || emailStr.length > 254) {
          return this.escapeHtml(value);
        }
        const safeEmail = this.escapeHtml(emailStr);
        return `<a href="mailto:${safeEmail}" class="tc-link">${safeEmail}</a>`;

      case 'url':
        let url = String(value);
        // Ensure protocol
        if (!/^https?:\/\//i.test(url)) url = 'https://' + url;
        // Sanitize URL
        const sanitizedUrl = this.sanitizeUrl(url);
        if (!sanitizedUrl) return this.escapeHtml(value);
        // Truncate for display
        const displayUrl = value.length > 30 ? value.substring(0, 27) + '...' : value;
        return `<a href="${sanitizedUrl}" target="_blank" rel="noopener noreferrer" class="tc-link">${this.escapeHtml(displayUrl)}</a>`;

      case 'image':
        const imgUrl = String(value);
        // Only allow http/https URLs for images
        if (!/^https?:\/\//i.test(imgUrl)) {
          return this.escapeHtml(value);
        }
        const safeImgUrl = this.sanitizeUrl(imgUrl);
        if (!safeImgUrl) return this.escapeHtml(value);
        return `<img src="${safeImgUrl}" alt="Image" class="tc-cell-image" style="max-height: 50px; border-radius: 4px;" loading="lazy">`;

      default:
        // Always escape HTML for unknown types
        return this.escapeHtml(value);
    }
  }

  /**
   * Detect data type from value
   */
  detectDataType(value) {
    if (value === null || value === undefined) return 'text';
    
    // Check Boolean
    if (typeof value === 'boolean' || value === 'true' || value === 'false') return 'boolean';

    // Check String formats
    if (typeof value === 'string') {
      if (/^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value)) return 'email';
      if (/^https?:\/\/[^\s]+$/i.test(value)) {
         return /\.(jpg|jpeg|png|gif|webp)$/i.test(value) ? 'image' : 'url';
      }
      // ISO Date Check (YYYY-MM-DD or YYYY-MM-DDTHH:mm:ss)
      if (/^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d{3})?Z?)?$/.test(value)) {
          const d = new Date(value);
          return !isNaN(d.getTime()) ? 'date' : 'text';
      }
    }

    return 'text';
  }

  /**
   * Debounce Utility.
   * Prevents rapid firing of expensive operations.
   * 
   * @param {Function} func The function to debounce.
   * @param {number} wait Delay in milliseconds.
   */
  debounce(func, wait) {
    let timeout;
    return function (...args) {
      const context = this;
      clearTimeout(timeout);
      timeout = setTimeout(() => func.apply(context, args), wait);
    };
  }

  /**
   * Resolve container from selector or element
   */
  resolveContainer(container) {
    if (typeof container === 'string') {
      return document.querySelector(container);
    } else if (container && container.nodeType === 1) { // Check for Element nodeType instead of instanceof
      return container;
    }
    return null;
  }

  /**
   * Load data from URL
   */
  async loadData() {
    this.isLoading = true;
    this.renderLoading();

    // If SSR mode is enabled and content exists, handle hydration logic
    if (this.container.dataset.ssr === "true") {
      // this.render(); // <-- REMOVED: Do not wipe server content yet!
      if (this.data && this.data.length > 0) {
      // Vital: Initialize internal state so future renders (sorting/filtering) work!
      this.data = this.processData(this.data);
      this.autoDiscoverColumns();
      this.detectFilterTypes();
      
      this.container.dataset.ssr = "false";
      this.hydrateListeners(); // Attach listeners to existing DOM
      this.isLoading = false;
      return Promise.resolve(this.data);
    }
      if (this.dataUrl) {
         try {
           const response = await fetch(this.dataUrl);
           if (!response.ok) throw new Error(`HTTP ${response.status}`);
           const data = await response.json();
           this.data = this.processData(data);
           this.autoDiscoverColumns();
           this.detectFilterTypes();
           this.container.dataset.ssr = "false";
           this.render();
         } catch (e) {
           console.error('TableCrafter: Hydration failed', e);
           // Silent fail for hydration is okay, user sees SSR content
         }
      }
      this.isLoading = false;
      return this.data;
    }

    // Standard Client-Side Load
    try {
      let data;
      
      // Check for Proxy Configuration
      if (this.config.api && this.config.api.proxy && this.config.api.proxy.url) {
        TC_DEBUG.log(' Using Proxy', this.config.api.proxy);
        
        const formData = new FormData();
        formData.append('action', 'tc_proxy_fetch');
        formData.append('nonce', this.config.api.proxy.nonce);
        formData.append('url', this.dataUrl);

        const response = await fetch(this.config.api.proxy.url, {
            method: 'POST',
            body: formData
        });

        if (!response.ok) throw new Error(`Proxy HTTP error! status: ${response.status}`);
        
        const jsonResponse = await response.json();
        
        if (!jsonResponse.success) {
            throw new Error(jsonResponse.data || 'Proxy Error');
        }
        
        data = jsonResponse.data;

      } else {
        // Direct Fetch (Fallback / Legacy)
        const response = await fetch(this.dataUrl);
        if (!response.ok) {
          throw new Error(`HTTP error! status: ${response.status}`);
        }
        const text = await response.text();
        // Debug: Log raw response to find HTML errors
        TC_DEBUG.log('Raw Response:', text.substring(0, 500)); 
        
        data = JSON.parse(text);
      }

      this.data = this.processData(data); // Using processData for consistency
      
      this.autoDiscoverColumns();
      this.render();
    } catch (error) {
      console.error('TableCrafter: Load failed', error);
      this.renderError(`Unable to load data. ${error.message}`);
      throw error;
    } finally {
      this.isLoading = false;
    }
  }

  renderLoading() {
      if (!this.container) return;
      // Do not show skeleton if we have SSR content that hasn't been hydrated yet
      if (this.container.dataset.ssr === "true" && this.container.children.length > 0) {
          return;
      }
      
      // improved skeleton loading
      const skeletonRows = Array(5).fill(0).map(() => `
          <div class="tc-skeleton-row">
              <div class="tc-skeleton-cell tc-skeleton"></div>
              <div class="tc-skeleton-cell tc-skeleton"></div>
              <div class="tc-skeleton-cell tc-skeleton"></div>
              <div class="tc-skeleton-cell tc-skeleton"></div>
              <div class="tc-skeleton-cell tc-skeleton"></div>
          </div>
      `).join('');

      this.container.innerHTML = `
          <div class="tc-wrapper">
              <div class="tc-loading-container">
                  ${skeletonRows}
              </div>
          </div>
      `;
  }

  renderError(message) {
      this.container.innerHTML = `
        <div class="tc-error-container">
          <div class="tc-error-message">${message}</div>
          <button class="tc-retry-button">Retry</button>
        </div>
      `;
      
      const retryBtn = this.container.querySelector('.tc-retry-button');
      if (retryBtn) {
        retryBtn.addEventListener('click', () => {
          this.renderLoading();
          this.loadData().catch(err => {
               console.error('TableCrafter: Retry failed', err);
               this.renderError('Retry failed. Please try again later.');
          });
        });
      }
        }



  /**
   * Process and normalize data based on configuration (root path, etc.)
   */
  processData(data) {
    if (!data) return [];

    // Handle nested data path (root)
    const root = this.config.root || this.config.dataRoot;
    if (root) {
      const path = root.split('.');
      for (const segment of path) {
        if (data && typeof data === 'object' && segment in data) {
          data = data[segment];
        } else {
          console.warn(`TableCrafter: Path segment "${segment}" not found in data`, data);
          return [];
        }
      }
    }

    return Array.isArray(data) ? data : (data ? [data] : []);
  }

  /**
   * Get current data
   */
  getData() {
    return this.data;
  }

  /**
   * Set data with intelligent optimization for large datasets
   */
  setData(data) {
    this.data = data;
    
    // Intelligent large dataset optimization
    this.optimizeForDatasetSize();
    
    if (this.container.querySelector('.tc-wrapper')) {
      this.render();
    }
  }

  /**
   * Automatically optimize configuration based on dataset size
   */
  optimizeForDatasetSize() {
    const dataSize = this.data.length;
    
    // Auto-enable pagination for datasets > threshold
    if (dataSize > this.config.largeDataset.threshold) {
      this.config.pagination = true;
      this.config.largeDataset.serverSide = true;
      
      // Adjust page size for better performance
      if (dataSize > 5000) {
        this.config.pageSize = 50; // Larger pages for very large datasets
      } else if (dataSize > 2000) {
        this.config.pageSize = 25; // Medium pages for large datasets  
      }
      
      TC_DEBUG.log(`Large dataset detected (${dataSize} rows). Enabling optimizations.`);
    }
    
    // Auto-enable virtual scrolling for massive datasets
    if (dataSize > this.config.largeDataset.virtualThreshold) {
      this.config.largeDataset.virtualScrolling = true;
      this.config.pageSize = 100; // Larger virtual pages
      TC_DEBUG.log(`Massive dataset detected (${dataSize} rows). Enabling virtual scrolling.`);
    }
    
    // Performance warning for extremely large datasets
    if (dataSize > 10000) {
      console.warn(`TableCrafter: Very large dataset (${dataSize} rows) detected. Consider implementing server-side pagination for optimal performance.`);
    }
  }


  /**
   * Toggle row selection for bulk operations
   */
  toggleRowSelection(rowIndex, selected) {
    if (selected) {
      this.selectedRows.add(rowIndex);
    } else {
      this.selectedRows.delete(rowIndex);
    }

    // Update bulk controls visibility
    this.updateBulkControls();

    // Call callback if provided
    if (this.config.onSelectionChange) {
      this.config.onSelectionChange({
        selectedRows: Array.from(this.selectedRows),
        totalSelected: this.selectedRows.size
      });
    }
  }

  /**
   * Select all visible rows
   */
  selectAllRows() {
    const displayData = this.getPaginatedData();
    displayData.forEach((row, index) => {
      const actualRowIndex = this.config.pagination ?
        (this.currentPage - 1) * this.config.pageSize + index :
        index;
      this.selectedRows.add(actualRowIndex);
    });

    this.updateBulkControls();
    this.render();
  }

  /**
   * Deselect all rows
   */
  deselectAllRows() {
    this.selectedRows.clear();
    this.updateBulkControls();
    this.render();
  }

  /**
   * Update bulk controls visibility and state
   */
  updateBulkControls() {
    const bulkControls = this.container.querySelector('.tc-bulk-controls');
    if (!bulkControls) return;

    const selectedCount = this.selectedRows.size;
    const bulkInfo = bulkControls.querySelector('.tc-bulk-info');

    if (selectedCount === 0) {
      bulkControls.style.display = 'none';
    } else {
      bulkControls.style.display = 'flex';
      if (bulkInfo) {
        bulkInfo.textContent = `${selectedCount} item${selectedCount === 1 ? '' : 's'} selected`;
      }
    }
  }

  /**
   * Auto-discover columns from data
   */
  autoDiscoverColumns() {
    if (this.data.length > 0 && this.config.columns.length === 0) {
      const firstItem = this.data[0];
      let keys = Object.keys(firstItem);

      // Apply include/exclude rules
      const include = this.config.include ?
        (Array.isArray(this.config.include) ? this.config.include : this.config.include.split(',').map(s => s.trim())) :
        null;
      const exclude = this.config.exclude ?
        (Array.isArray(this.config.exclude) ? this.config.exclude : this.config.exclude.split(',').map(s => s.trim())) :
        [];

      if (include) {
        keys = keys.filter(key => include.includes(key));
        // Sort keys to match include order
        keys.sort((a, b) => include.indexOf(a) - include.indexOf(b));
      }

      if (exclude.length > 0) {
        keys = keys.filter(key => !exclude.includes(key));
      }

      this.config.columns = keys.map(key => ({
        field: key,
        label: key.charAt(0).toUpperCase() + key.slice(1).replace(/_/g, ' '),
        sortable: true
      }));
    }
  }

  render() {
    // Check if we are hydrating (SSR content already present)
    const isHydrating = this.container.dataset.ssr === "true" &&
      (this.container.querySelector('table') || this.container.querySelector('.tc-cards-container') || this.container.querySelector('.tc-loading') || this.container.querySelector('.tc-wrapper'));

    let wrapper;
    if (isHydrating) {
      // If hydrating, we don't clear the container. 
      // Instead, we ensure the .tc-wrapper exists and wraps the content.
      wrapper = this.container.querySelector('.tc-wrapper');
      if (!wrapper) {
        wrapper = document.createElement('div');
        wrapper.className = 'tc-wrapper';

        // Move all existing children into the wrapper
        while (this.container.firstChild) {
          wrapper.appendChild(this.container.firstChild);
        }
        this.container.appendChild(wrapper);
      }

      // Remove any existing tools to avoid duplicates
      const tools = wrapper.querySelectorAll('.tc-global-search-container, .tc-filters, .tc-bulk-controls, .tc-export-controls, .tc-pagination');
      tools.forEach(tool => tool.remove());
    } else {
      // Standard render: clear and rebuild
      this.container.innerHTML = '';
      wrapper = document.createElement('div');
      wrapper.className = 'tc-wrapper';
      this.container.appendChild(wrapper);
    }

    // Add global search if enabled
    if (this.config.globalSearch) {
      const searchContainer = this.renderGlobalSearch();
      if (isHydrating) {
        wrapper.insertBefore(searchContainer, wrapper.firstChild);
      } else {
        wrapper.appendChild(searchContainer);
      }
    }

    // Add filters if enabled
    if (this.config.filterable) {
      const filters = this.renderFilters();
      if (filters) {
        if (isHydrating) {
          // If search was added, insert filters after it. Otherwise insert at beginning.
          const search = wrapper.querySelector('.tc-global-search-container');
          if (search && search.nextSibling) {
            wrapper.insertBefore(filters, search.nextSibling);
          } else {
            wrapper.insertBefore(filters, wrapper.firstChild);
          }
        } else {
          wrapper.appendChild(filters);
        }
      }
    }

    // Add bulk controls if enabled
    if (this.config.bulk.enabled) {
      wrapper.appendChild(this.renderBulkControls());
    }

    // Add export controls if enabled
    if (this.config.exportable) {
      const exportTools = this.renderExportControls();
      if (isHydrating) {
        // Find existing tools area or insert after table/cards
        const target = wrapper.querySelector('.tc-table-container, .tc-cards-container') || wrapper.firstChild;
        wrapper.insertBefore(exportTools, target);
      } else {
        wrapper.appendChild(exportTools);
      }
    }

    // Render data view if not hydrating
    if (!isHydrating) {
      if (this.config.responsive && this.isMobile()) {
        wrapper.appendChild(this.renderCards());
      } else {
        wrapper.appendChild(this.renderTable());
      }
    }

    // Add pagination if enabled and needed
    if (this.config.pagination && this.shouldShowPagination()) {
      wrapper.appendChild(this.renderPagination());
    }
  }

  /**
   * Hydrate listeners for server-rendered content
   */
  hydrateListeners() {
    const table = this.container.querySelector('table.tc-table');
    if (!table) return;

    // Hydrate Sort Headers
    if (this.config.sortable) {
        const headers = table.querySelectorAll('th.tc-sortable');
        headers.forEach((th, index) => {
            // Get field from data attribute or fallback to config
            const field = th.dataset.field || (this.config.columns[index] ? this.config.columns[index].field : null);
            
            if (field) {
                // Remove old listeners if any (cloning to be safe or just add new ones)
                // Note: In hydration we assume fresh DOM
                th.addEventListener('click', () => this.sort(field));
                th.addEventListener('keydown', (e) => {
                    if (e.key === 'Enter' || e.key === ' ') {
                        e.preventDefault();
                        this.sort(field);
                    }
                });
            }
        });
    }

    // Hydrate Filters (if they exist in DOM)
    // For now, PHP only renders the table, filters are usually JS-only or need separate hydration logic.
    // If we wanted to hydrate filters, we'd do it here. 
  }

  /**
   * Render table view
   */
  renderTable() {
    const tableContainer = document.createElement('div');
    tableContainer.className = 'tc-table-container';

    const table = document.createElement('table');
    table.className = 'tc-table';

    // Render header
    const thead = document.createElement('thead');
    const headerRow = document.createElement('tr');

    this.config.columns.forEach(column => {
      const th = document.createElement('th');
      th.setAttribute('scope', 'col');
      th.textContent = column.label;
      th.dataset.field = column.field;

      if (this.config.sortable && column.sortable !== false) {
        th.className = 'tc-sortable';
        th.tabIndex = 0; // Make focusable
        
        // helper to get aria-sort state
        let sortState = 'none';
        if (this.sortField === column.field) {
            sortState = this.sortOrder === 'asc' ? 'ascending' : 'descending';
        }
        th.setAttribute('aria-sort', sortState);

        // Click handler
        th.addEventListener('click', () => this.sort(column.field));
        
        // Keyboard handler (Enter/Space)
        th.addEventListener('keydown', (e) => {
            if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                this.sort(column.field);
            }
        });
      }

      headerRow.appendChild(th);
    });

    thead.appendChild(headerRow);
    table.appendChild(thead);

    // Render body
    const tbody = document.createElement('tbody');

    const displayData = this.getPaginatedData();

    if (displayData.length === 0) {
      // Show no results message
      const tr = document.createElement('tr');
      const td = document.createElement('td');
      td.colSpan = this.config.columns.length;
      td.className = 'tc-no-results';
      td.textContent = 'No results found';
      td.style.textAlign = 'center';
      td.style.padding = '20px';
      tr.appendChild(td);
      tbody.appendChild(tr);
    } else {
      displayData.forEach((row, rowIndex) => {
        const actualRowIndex = this.config.pagination ?
          (this.currentPage - 1) * this.config.pageSize + rowIndex :
          rowIndex;
        const tr = document.createElement('tr');
        tr.dataset.rowIndex = actualRowIndex;

        const columnPromises = this.config.columns.map(async (column) => {
          const td = document.createElement('td');

          // Format lookup values
          let displayValue = row[column.field];
          
          if (displayValue === null || displayValue === undefined) {
             displayValue = '';
          }

          if (column.lookup && displayValue) {
            displayValue = await this.formatLookupValue(column, displayValue);
            td.textContent = displayValue;
          } else {
             // Auto-format value
             const formatted = this.formatValue(displayValue, column.type);
             
             // SECURITY: Use safe HTML rendering to prevent XSS
             if (typeof formatted === 'string' && /<[a-z][\s\S]*>/i.test(formatted)) {
                // Only allow HTML from trusted server-side formatting
                if (this.isTrustedHTML(formatted)) {
                   td.innerHTML = formatted;
                } else {
                   // Escape potentially dangerous HTML
                   td.textContent = formatted;
                }
             } else {
                td.textContent = formatted;
             }
          }
          td.dataset.field = column.field;

          // Make cell editable if configured and user has permission
          if (this.config.editable && column.editable && this.hasPermission('edit', row)) {
            td.className = 'tc-editable';
            td.addEventListener('click', (e) => this.startEdit(e, actualRowIndex, column.field));
          }

          tr.appendChild(td);
        });

        // We don't necessarily need to await them all here since they append to tr
        // but it's cleaner to handle them.
        tbody.appendChild(tr);
      });
    }

    table.appendChild(tbody);
    tableContainer.appendChild(table);

    // Enhance table with accessibility features
    if (this.config.accessibility.enabled) {
      this.enhanceTableAccessibility(table);
    }

    return tableContainer;
  }

  /**
   * Get current breakpoint with enhanced mobile-first detection
   */
  getCurrentBreakpoint() {
    const width = window.innerWidth;
    const defaults = {
      mobile: { width: 768, layout: 'cards' },
      tablet: { width: 900, layout: 'compact' },
      desktop: { width: 1200, layout: 'table' }
    };
    const breakpoints = { ...defaults, ...(this.config.responsive.breakpoints || {}) };

    if (width <= breakpoints.mobile.width) return 'mobile';
    if (width <= breakpoints.tablet.width) return 'tablet';
    return 'desktop';
  }

  /**
   * Enhanced mobile detection with touch capability
   */
  isMobile() {
    const breakpoint = this.getCurrentBreakpoint();
    const isTouchDevice = 'ontouchstart' in window || navigator.maxTouchPoints > 0;
    
    // Consider device mobile if either small screen OR touch-only device
    return breakpoint === 'mobile' || (isTouchDevice && breakpoint === 'tablet');
  }

  /**
   * Check if device supports touch interactions
   */
  isTouchDevice() {
    return 'ontouchstart' in window || 
           navigator.maxTouchPoints > 0 || 
           (window.matchMedia && window.matchMedia('(pointer: coarse)').matches);
  }

  /**
   * Add enhanced touch gestures to mobile cards
   */
  addTouchGestures(card, rowData, rowIndex) {
    let startX = 0;
    let startY = 0;
    let startTime = 0;
    let isDragging = false;
    let hasMoved = false;
    const threshold = 50; // minimum distance for swipe
    const timeThreshold = 300; // maximum time for swipe (ms)

    // Touch start
    card.addEventListener('touchstart', (e) => {
      const touch = e.touches[0];
      startX = touch.clientX;
      startY = touch.clientY;
      startTime = Date.now();
      isDragging = false;
      hasMoved = false;
      
      // Add visual feedback
      card.style.transition = 'transform 0.1s ease';
      card.style.transform = 'scale(0.98)';
    }, { passive: true });

    // Touch move
    card.addEventListener('touchmove', (e) => {
      if (e.touches.length > 1) return; // ignore multi-touch
      
      const touch = e.touches[0];
      const deltaX = Math.abs(touch.clientX - startX);
      const deltaY = Math.abs(touch.clientY - startY);
      
      // Mark as moved if significant movement
      if (deltaX > 10 || deltaY > 10) {
        hasMoved = true;
      }
      
      // Start drag if horizontal movement exceeds threshold
      if (deltaX > 20 && deltaX > deltaY) {
        isDragging = true;
        e.preventDefault(); // prevent scrolling
        
        // Visual feedback for drag
        const translateX = (touch.clientX - startX) * 0.3; // reduced movement
        card.style.transform = `translateX(${translateX}px) scale(0.98)`;
        
        // Add visual hint based on swipe direction
        if (translateX > 20) {
          card.style.backgroundColor = '#e8f5e8'; // green hint for right swipe
        } else if (translateX < -20) {
          card.style.backgroundColor = '#ffe8e8'; // red hint for left swipe
        }
      }
    }, { passive: false });

    // Touch end
    card.addEventListener('touchend', (e) => {
      const endTime = Date.now();
      const touch = e.changedTouches[0];
      const deltaX = touch.clientX - startX;
      const deltaY = touch.clientY - startY;
      const duration = endTime - startTime;
      
      // Reset visual state
      card.style.transition = 'transform 0.3s ease, background-color 0.3s ease';
      card.style.transform = '';
      card.style.backgroundColor = '';
      
      // Handle swipe gestures
      if (Math.abs(deltaX) > threshold && Math.abs(deltaX) > Math.abs(deltaY) && duration < timeThreshold) {
        e.preventDefault();
        
        if (deltaX > 0) {
          // Right swipe - expand/collapse card if expandable
          this.handleCardSwipeRight(card, rowData, rowIndex);
        } else {
          // Left swipe - show quick actions
          this.handleCardSwipeLeft(card, rowData, rowIndex);
        }
      } else if (!hasMoved && duration < 200) {
        // Quick tap without movement - handle as click
        this.handleCardTap(card, rowData, rowIndex);
      }
    }, { passive: false });

    // Touch cancel
    card.addEventListener('touchcancel', () => {
      // Reset visual state
      card.style.transition = 'transform 0.3s ease, background-color 0.3s ease';
      card.style.transform = '';
      card.style.backgroundColor = '';
    });
  }

  /**
   * Handle right swipe on card (expand/collapse)
   */
  handleCardSwipeRight(card, rowData, rowIndex) {
    const isExpandable = card.classList.contains('tc-card-expandable');
    if (isExpandable) {
      // Toggle expanded state
      const isExpanded = card.classList.contains('tc-card-expanded');
      if (isExpanded) {
        card.classList.remove('tc-card-expanded');
        this.announceToScreenReader('Card collapsed');
      } else {
        card.classList.add('tc-card-expanded');
        this.announceToScreenReader('Card expanded to show more details');
      }
    } else {
      // Provide haptic feedback if available
      if (navigator.vibrate) {
        navigator.vibrate(50);
      }
      this.showToast('Swipe left for actions', 'info');
    }
  }

  /**
   * Handle left swipe on card (quick actions)
   */
  handleCardSwipeLeft(card, rowData, rowIndex) {
    // Show quick action menu
    this.showCardQuickActions(card, rowData, rowIndex);
    
    // Haptic feedback
    if (navigator.vibrate) {
      navigator.vibrate([50, 50, 50]);
    }
  }

  /**
   * Handle tap on card
   */
  handleCardTap(card, rowData, rowIndex) {
    // Check if card is expandable
    const expandToggle = card.querySelector('.tc-card-toggle');
    if (expandToggle) {
      // Trigger expand/collapse
      const isExpanded = card.classList.contains('tc-card-expanded');
      card.classList.toggle('tc-card-expanded');
      this.announceToScreenReader(isExpanded ? 'Card collapsed' : 'Card expanded');
    }
    
    // Fire card selection event
    this.dispatchEvent('cardTap', { 
      rowData, 
      rowIndex, 
      card 
    });
  }

  /**
   * Show quick actions for card
   */
  showCardQuickActions(card, rowData, rowIndex) {
    // Create floating action menu
    const actionMenu = document.createElement('div');
    actionMenu.className = 'tc-card-quick-actions';
    actionMenu.style.cssText = `
      position: fixed;
      background: rgba(0, 0, 0, 0.9);
      color: white;
      padding: 12px;
      border-radius: 8px;
      display: flex;
      gap: 12px;
      z-index: 1000;
      transform: scale(0);
      transition: transform 0.2s ease;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
    `;

    // Position menu near the card
    const cardRect = card.getBoundingClientRect();
    actionMenu.style.left = Math.min(cardRect.left + 20, window.innerWidth - 200) + 'px';
    actionMenu.style.top = (cardRect.top + cardRect.height / 2 - 25) + 'px';

    // Add action buttons
    const actions = [
      { label: 'View', icon: '👁️', action: () => this.viewCardDetails(rowData, rowIndex) },
      { label: 'Edit', icon: '✏️', action: () => this.editCardData(rowData, rowIndex) },
      { label: 'Share', icon: '📤', action: () => this.shareCardData(rowData, rowIndex) }
    ];

    actions.forEach(({ label, icon, action }) => {
      const button = document.createElement('button');
      button.className = 'tc-quick-action-btn';
      button.style.cssText = `
        background: transparent;
        border: 1px solid rgba(255, 255, 255, 0.3);
        color: white;
        padding: 8px 12px;
        border-radius: 4px;
        cursor: pointer;
        font-size: 12px;
        display: flex;
        align-items: center;
        gap: 4px;
        transition: background-color 0.2s;
      `;
      button.innerHTML = `<span>${icon}</span><span>${label}</span>`;
      
      button.addEventListener('click', () => {
        action();
        document.body.removeChild(actionMenu);
      });
      
      button.addEventListener('touchend', (e) => {
        e.preventDefault();
        action();
        document.body.removeChild(actionMenu);
      });

      actionMenu.appendChild(button);
    });

    // Add close button
    const closeBtn = document.createElement('button');
    closeBtn.innerHTML = '✕';
    closeBtn.style.cssText = `
      background: transparent;
      border: none;
      color: white;
      font-size: 16px;
      cursor: pointer;
      padding: 4px;
    `;
    closeBtn.addEventListener('click', () => {
      document.body.removeChild(actionMenu);
    });
    actionMenu.appendChild(closeBtn);

    document.body.appendChild(actionMenu);
    
    // Animate in
    requestAnimationFrame(() => {
      actionMenu.style.transform = 'scale(1)';
    });

    // Auto-hide after 5 seconds
    setTimeout(() => {
      if (document.body.contains(actionMenu)) {
        actionMenu.style.transform = 'scale(0)';
        setTimeout(() => {
          if (document.body.contains(actionMenu)) {
            document.body.removeChild(actionMenu);
          }
        }, 200);
      }
    }, 5000);
  }

  /**
   * Show toast notification for mobile feedback
   */
  showToast(message, type = 'info') {
    const toast = document.createElement('div');
    toast.className = `tc-toast tc-toast-${type}`;
    toast.style.cssText = `
      position: fixed;
      bottom: 20px;
      left: 50%;
      transform: translateX(-50%) translateY(100px);
      background: ${type === 'info' ? '#007bff' : type === 'success' ? '#28a745' : '#dc3545'};
      color: white;
      padding: 12px 20px;
      border-radius: 25px;
      z-index: 1001;
      font-size: 14px;
      box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3);
      transition: transform 0.3s ease;
      max-width: calc(100vw - 40px);
      text-align: center;
    `;
    toast.textContent = message;

    document.body.appendChild(toast);

    // Animate in
    requestAnimationFrame(() => {
      toast.style.transform = 'translateX(-50%) translateY(0)';
    });

    // Auto-hide
    setTimeout(() => {
      toast.style.transform = 'translateX(-50%) translateY(100px)';
      setTimeout(() => {
        if (document.body.contains(toast)) {
          document.body.removeChild(toast);
        }
      }, 300);
    }, 3000);
  }

  /**
   * Placeholder methods for card actions (can be customized)
   */
  viewCardDetails(rowData, rowIndex) {
    this.showToast('View details functionality can be customized', 'info');
    this.dispatchEvent('cardView', { rowData, rowIndex });
  }

  editCardData(rowData, rowIndex) {
    this.showToast('Edit functionality can be customized', 'info');
    this.dispatchEvent('cardEdit', { rowData, rowIndex });
  }

  shareCardData(rowData, rowIndex) {
    if (navigator.share) {
      navigator.share({
        title: 'Table Data',
        text: JSON.stringify(rowData, null, 2)
      });
    } else {
      // Fallback: copy to clipboard
      navigator.clipboard?.writeText(JSON.stringify(rowData, null, 2));
      this.showToast('Data copied to clipboard', 'success');
    }
  }

  /**
   * Dispatch custom events for mobile interactions
   */
  dispatchEvent(eventName, detail) {
    const event = new CustomEvent(`tablecrafter:${eventName}`, {
      detail,
      bubbles: true
    });
    this.container.dispatchEvent(event);
  }

  /**
   * Get visible fields for current breakpoint
   */
  getVisibleFields(breakpoint) {
    const visibility = this.config.responsive.fieldVisibility || {};
    const breakpointConfig = visibility[breakpoint];

    if (!breakpointConfig) {
      return this.config.columns;
    }

    if (breakpointConfig.showFields) {
      return this.config.columns.filter(col => breakpointConfig.showFields.includes(col.field));
    }

    if (breakpointConfig.hideFields) {
      return this.config.columns.filter(col => !breakpointConfig.hideFields.includes(col.field));
    }

    return this.config.columns;
  }

  /**
   * Get hidden fields for current breakpoint
   */
  getHiddenFields(breakpoint) {
    const visibility = this.config.responsive.fieldVisibility || {};
    const breakpointConfig = visibility[breakpoint];

    if (!breakpointConfig) {
      return [];
    }

    if (breakpointConfig.hideFields) {
      return this.config.columns.filter(col => breakpointConfig.hideFields.includes(col.field));
    }

    if (breakpointConfig.showFields) {
      return this.config.columns.filter(col => !breakpointConfig.showFields.includes(col.field));
    }

    return [];
  }

  /**
   * Render cards view for mobile with expandable details
   */
  renderCards() {
    const cardsContainer = document.createElement('div');
    cardsContainer.className = 'tc-cards-container';
    cardsContainer.setAttribute('role', 'list');

    const displayData = this.getPaginatedData();
    const breakpoint = this.getCurrentBreakpoint();
    const visibleFields = this.getVisibleFields(breakpoint);
    const hiddenFields = this.getHiddenFields(breakpoint);
    const hasHiddenFields = hiddenFields.length > 0;

    if (displayData.length === 0) {
      // Show no results message
      const noResults = document.createElement('div');
      noResults.className = 'tc-no-results';
      noResults.textContent = 'No results found';
      noResults.style.textAlign = 'center';
      noResults.style.padding = '20px';
      cardsContainer.appendChild(noResults);
    } else {
      displayData.forEach((row, rowIndex) => {
        const actualRowIndex = this.config.pagination ?
          (this.currentPage - 1) * this.config.pageSize + rowIndex :
          rowIndex;
        const card = document.createElement('div');
        card.className = 'tc-card';
        card.setAttribute('role', 'listitem');
        if (hasHiddenFields) {
          card.className += ' tc-card-expandable';
        }
        card.dataset.rowIndex = actualRowIndex;

        // Bulk selection checkbox if enabled
        if (this.config.bulk.enabled) {
          const checkboxContainer = document.createElement('div');
          checkboxContainer.className = 'tc-card-checkbox';

          const checkbox = document.createElement('input');
          checkbox.type = 'checkbox';
          checkbox.className = 'tc-row-checkbox';
          checkbox.dataset.rowIndex = actualRowIndex;
          checkbox.checked = this.selectedRows.has(actualRowIndex);
          checkbox.addEventListener('change', (e) => {
            this.toggleRowSelection(actualRowIndex, e.target.checked);
          });

          checkboxContainer.appendChild(checkbox);
          card.appendChild(checkboxContainer);
        }

        // Card header with expand toggle
        const cardHeader = document.createElement('div');
        cardHeader.className = 'tc-card-header';

        // Use first column as title
        const firstColumn = this.config.columns[0];
        if (firstColumn) {
          const title = document.createElement('span');
          title.textContent = row[firstColumn.field] || `Item ${actualRowIndex + 1}`;
          cardHeader.appendChild(title);
        }

        // Add expand toggle if there are hidden fields
        if (hasHiddenFields) {
          const toggle = document.createElement('span');
          toggle.className = 'tc-card-toggle';
          toggle.textContent = '▼';
          cardHeader.appendChild(toggle);

          cardHeader.addEventListener('click', () => {
            this.toggleCard(card);
          });
          cardHeader.style.cursor = 'pointer';
        }

        card.appendChild(cardHeader);

        // Card body with visible fields
        const cardBody = document.createElement('div');
        cardBody.className = 'tc-card-body';

        visibleFields.forEach(column => {
          if (column === firstColumn) return; // Skip first column as it's in header

          const field = document.createElement('div');
          field.className = 'tc-card-field';

          const label = document.createElement('span');
          label.className = 'tc-card-label';
          label.textContent = column.label + ':';

          const value = document.createElement('span');
          value.className = 'tc-card-value';

          // Format lookup values
          let displayValue = row[column.field] || '';
          if (column.lookup && displayValue) {
            this.formatLookupValue(column, displayValue).then(formatted => {
              value.textContent = formatted;
            });
          } else {
            value.textContent = displayValue;
          }

          value.dataset.field = column.field;

          // Make field editable if configured and user has permission
          if (this.config.editable && column.editable && this.hasPermission('edit', row)) {
            value.className += ' tc-editable';
            value.addEventListener('click', (e) => this.startEdit(e, actualRowIndex, column.field));
          }

          field.appendChild(label);
          field.appendChild(value);
          cardBody.appendChild(field);
        });

        card.appendChild(cardBody);

        // Hidden fields section (initially hidden)
        if (hasHiddenFields) {
          const hiddenSection = document.createElement('div');
          hiddenSection.className = 'tc-card-hidden-fields';

          hiddenFields.forEach(column => {
            const field = document.createElement('div');
            field.className = 'tc-card-field';

            const label = document.createElement('span');
            label.className = 'tc-card-label';
            label.textContent = column.label + ':';

            const value = document.createElement('span');
            value.className = 'tc-card-value';

            // Format lookup values
            let displayValue = row[column.field] || '';
            if (column.lookup && displayValue) {
              this.formatLookupValue(column, displayValue).then(formatted => {
                value.textContent = formatted;
              });
            } else {
              value.textContent = displayValue;
            }

            value.dataset.field = column.field;

            // Make field editable if configured and user has permission
            if (this.config.editable && column.editable && this.hasPermission('edit', row)) {
              value.className += ' tc-editable';
              value.addEventListener('click', (e) => this.startEdit(e, actualRowIndex, column.field));
            }

            field.appendChild(label);
            field.appendChild(value);
            hiddenSection.appendChild(field);
          });

          card.appendChild(hiddenSection);
        }

        // Enhanced mobile touch interaction
        if (this.isTouchDevice()) {
          this.addTouchGestures(card, row, actualRowIndex);
        }

        cardsContainer.appendChild(card);
      });
    }

    return cardsContainer;
  }

  /**
   * Toggle card expansion
   */
  toggleCard(card) {
    const isExpanded = card.classList.contains('tc-card-expanded');

    if (isExpanded) {
      card.classList.remove('tc-card-expanded');
    } else {
      card.classList.add('tc-card-expanded');
    }
  }

  /**
   * Start editing a cell
   */
  async startEdit(event, rowIndex, field) {
    const target = event.currentTarget;

    // Check permissions
    if (!this.hasPermission('edit', this.data[rowIndex])) {
      return;
    }

    // Don't start edit if already editing
    if (this.editingCell === target) {
      return;
    }

    // Cancel any existing edit
    if (this.editingCell) {
      this.cancelEdit();
    }

    const currentValue = this.data[rowIndex][field];
    const column = this.config.columns.find(col => col.field === field);

    let editElement;

    // Create appropriate edit control based on field type
    if (column && column.lookup) {
      // Create lookup dropdown
      editElement = await this.createLookupDropdown(column, currentValue);
      editElement.className = 'tc-edit-select';
    } else if (column && column.type && this.cellTypeRegistry.has(column.type)) {
      // Create rich cell type editor
      editElement = await this.createRichCellEditor(column, currentValue, rowIndex);
    } else {
      // Create regular input
      editElement = document.createElement('input');
      editElement.type = column?.type || 'text';
      editElement.value = currentValue || '';
      editElement.className = 'tc-edit-input';
    }

    // Store original value and metadata
    editElement.dataset.originalValue = currentValue || '';
    editElement.dataset.rowIndex = rowIndex;
    editElement.dataset.field = field;

    // Replace content with edit element
    target.innerHTML = '';
    target.appendChild(editElement);

    // Focus the element
    editElement.focus();
    if (editElement.select) {
      editElement.select();
    }

    // Set current editing cell
    this.editingCell = target;

    // Handle blur/change events
    if (editElement.tagName === 'SELECT') {
      editElement.addEventListener('change', () => this.saveEdit(editElement));
      editElement.addEventListener('blur', () => this.saveEdit(editElement));
    } else {
      editElement.addEventListener('blur', () => this.saveEdit(editElement));
    }

    // Handle Enter/Escape keys
    editElement.addEventListener('keydown', (e) => {
      if (e.key === 'Enter') {
        this.saveEdit(editElement);
      } else if (e.key === 'Escape') {
        this.cancelEdit();
      }
    });
  }

  /**
   * Save edited value
   */
  async saveEdit(element) {
    const rowIndex = parseInt(element.dataset.rowIndex);
    const field = element.dataset.field;
    const oldValue = element.dataset.originalValue;

    // Get new value based on element type
    let newValue;
    if (element.getValue && typeof element.getValue === 'function') {
      // Rich cell type with custom getValue method
      newValue = element.getValue();
    } else if (element.type === 'checkbox') {
      newValue = element.checked;
    } else if (element.type === 'file') {
      newValue = element.files.length > 0 ? element.files[0].name : oldValue;
    } else {
      newValue = element.value;
    }

    // Validate the new value
    if (this.config.validation.enabled && this.config.validation.validateOnEdit) {
      const validation = this.validateField(field, newValue, this.data[rowIndex]);

      if (!validation.isValid) {
        // Show validation errors
        this.showValidationError(element, validation.errors);
        this.setValidationError(rowIndex, field, validation.errors);

        // Don't save invalid data
        element.value = oldValue; // Revert to original value
        element.focus();
        return;
      } else {
        // Clear any existing validation errors
        this.clearValidationError(element);
        this.setValidationError(rowIndex, field, []);
      }
    }

    // Update data
    this.data[rowIndex][field] = newValue;

    // Update via API if configured
    if (this.config.api.baseUrl) {
      try {
        await this.updateEntry(rowIndex, { [field]: newValue });
      } catch (error) {
        // Revert on error
        this.data[rowIndex][field] = oldValue;
        alert('Failed to save changes: ' + error.message);
        this.cancelEdit();
        return;
      }
    }

    // Call onEdit callback if provided
    if (this.config.onEdit) {
      this.config.onEdit({
        row: rowIndex,
        field: field,
        oldValue: oldValue,
        newValue: newValue
      });
    }

    // Update display with formatted value
    const parent = element.parentElement;
    const column = this.config.columns.find(col => col.field === field);

    if (column && column.lookup) {
      // Format lookup value for display
      const displayValue = await this.formatLookupValue(column, newValue);
      parent.textContent = displayValue;
    } else {
      parent.textContent = newValue;
    }

    // Clear editing state
    this.editingCell = null;
  }

  /**
   * Cancel editing
   */
  cancelEdit() {
    if (!this.editingCell) return;

    const element = this.editingCell.querySelector('input, select');
    if (element) {
      this.editingCell.textContent = element.dataset.originalValue;
    }

    this.editingCell = null;
  }

  /**
   * Get filtered data with advanced filtering support
   */
  getFilteredData() {
    // Apply permission filtering first
    let data = this.getPermissionFilteredData();

    if (!this.config.filterable && !this.config.globalSearch) {
      return data;
    }

    // Apply global search filter
    if (this.config.globalSearch && this.searchTerm) {
      const searchLower = this.searchTerm.toLowerCase();
      data = data.filter(row => {
        return Object.values(row).some(val => {
          if (val === null || val === undefined) return false;
          return val.toString().toLowerCase().includes(searchLower);
        });
      });
    }

    // Apply column filters
    if (Object.keys(this.filters).length === 0) {
      return data;
    }

    return data.filter(row => {
      return Object.entries(this.filters).every(([field, filterValue]) => {
        if (!filterValue || (Array.isArray(filterValue) && filterValue.length === 0)) {
          return true;
        }

        const cellValue = row[field];
        const filterType = this.filterTypes[field] || 'text';

        switch (filterType) {
          case 'multiselect':
            return Array.isArray(filterValue) && filterValue.includes(cellValue);

          case 'daterange':
            if (!cellValue) return false;
            const cellDate = new Date(cellValue);
            const fromDate = filterValue.from ? new Date(filterValue.from) : null;
            const toDate = filterValue.to ? new Date(filterValue.to) : null;

            if (fromDate && cellDate < fromDate) return false;
            if (toDate && cellDate > toDate) return false;
            return true;

          case 'numberrange':
            if (!cellValue && cellValue !== 0) return false;
            const numValue = parseFloat(cellValue);
            if (isNaN(numValue)) return false;

            if (filterValue.min !== undefined && numValue < filterValue.min) return false;
            if (filterValue.max !== undefined && numValue > filterValue.max) return false;
            return true;

          default: // text
            const cellString = (cellValue || '').toString().toLowerCase();
            const filterString = filterValue.toString().toLowerCase();
            return cellString.includes(filterString);
        }
      });
    });
  }

  /**
   * Get paginated data for current page
   */
  getPaginatedData() {
    const filteredData = this.getFilteredData();

    if (!this.config.pagination) {
      return filteredData;
    }

    const startIndex = (this.currentPage - 1) * this.config.pageSize;
    const endIndex = startIndex + this.config.pageSize;
    return filteredData.slice(startIndex, endIndex);
  }

  /**
   * Get total number of pages
   */
  getTotalPages() {
    if (!this.config.pagination) {
      return 1;
    }
    const filteredData = this.getFilteredData();
    return Math.ceil(filteredData.length / this.config.pageSize);
  }

  /**
   * Check if pagination should be shown
   */
  shouldShowPagination() {
    const filteredData = this.getFilteredData();
    return filteredData.length > this.config.pageSize;
  }

  /**
   * Go to specific page
   */
  goToPage(page) {
    const totalPages = this.getTotalPages();
    if (page >= 1 && page <= totalPages) {
      this.currentPage = page;
      this.saveState();
      this.render();
    }
  }

  /**
   * Go to next page
   */
  nextPage() {
    this.goToPage(this.currentPage + 1);
  }

  /**
   * Go to previous page
   */
  prevPage() {
    this.goToPage(this.currentPage - 1);
  }

  /**
   * Render enhanced pagination controls for large datasets
   */
  renderPagination() {
    const pagination = document.createElement('div');
    pagination.className = 'tc-pagination';

    const totalPages = this.getTotalPages();
    const filteredData = this.getFilteredData();
    const startIndex = (this.currentPage - 1) * this.config.pageSize + 1;
    const endIndex = Math.min(this.currentPage * this.config.pageSize, filteredData.length);

    // Enhanced pagination info with performance indicator
    const paginationInfo = document.createElement('div');
    paginationInfo.className = 'tc-pagination-info';
    
    let infoText = `${startIndex.toLocaleString()}-${endIndex.toLocaleString()} of ${filteredData.length.toLocaleString()}`;
    
    // Add performance indicator for large datasets
    if (filteredData.length > this.config.largeDataset.threshold) {
      infoText += ' (Optimized)';
      paginationInfo.title = 'Large dataset optimization enabled for better performance';
    }
    
    paginationInfo.textContent = infoText;

    // Enhanced pagination controls
    const paginationControls = document.createElement('div');
    paginationControls.className = 'tc-pagination-controls';

    // First page button (for large datasets)
    if (totalPages > 10) {
      const firstBtn = document.createElement('button');
      firstBtn.className = 'tc-first-btn';
      firstBtn.textContent = '≪';
      firstBtn.title = 'First page';
      firstBtn.disabled = this.currentPage === 1;
      firstBtn.addEventListener('click', () => this.goToPage(1));
      paginationControls.appendChild(firstBtn);
    }

    // Previous button
    const prevBtn = document.createElement('button');
    prevBtn.className = 'tc-prev-btn';
    prevBtn.textContent = '‹ Previous';
    prevBtn.disabled = this.currentPage === 1;
    prevBtn.addEventListener('click', () => this.prevPage());
    paginationControls.appendChild(prevBtn);

    // Page jump input for large datasets
    if (totalPages > 5) {
      const pageJump = document.createElement('div');
      pageJump.className = 'tc-page-jump';
      
      const pageInput = document.createElement('input');
      pageInput.type = 'number';
      pageInput.min = '1';
      pageInput.max = totalPages.toString();
      pageInput.value = this.currentPage.toString();
      pageInput.className = 'tc-page-input';
      pageInput.style.width = '60px';
      
      pageInput.addEventListener('change', (e) => {
        const page = parseInt(e.target.value);
        if (page >= 1 && page <= totalPages) {
          this.goToPage(page);
        } else {
          e.target.value = this.currentPage.toString();
        }
      });
      
      pageInput.addEventListener('keypress', (e) => {
        if (e.key === 'Enter') {
          pageInput.blur();
        }
      });
      
      const ofSpan = document.createElement('span');
      ofSpan.textContent = ` of ${totalPages.toLocaleString()}`;
      
      pageJump.appendChild(pageInput);
      pageJump.appendChild(ofSpan);
      paginationControls.appendChild(pageJump);
    } else {
      // Simple page display for small datasets
      const currentPage = document.createElement('span');
      currentPage.className = 'tc-current-page';
      currentPage.textContent = this.currentPage.toString();

      const separator = document.createElement('span');
      separator.textContent = ' of ';

      const totalPagesSpan = document.createElement('span');
      totalPagesSpan.className = 'tc-total-pages';
      totalPagesSpan.textContent = totalPages.toString();
      
      paginationControls.appendChild(currentPage);
      paginationControls.appendChild(separator);
      paginationControls.appendChild(totalPagesSpan);
    }

    // Next button
    const nextBtn = document.createElement('button');
    nextBtn.className = 'tc-next-btn';
    nextBtn.textContent = 'Next ›';
    nextBtn.disabled = this.currentPage === totalPages;
    nextBtn.addEventListener('click', () => this.nextPage());
    paginationControls.appendChild(nextBtn);

    // Last page button (for large datasets)
    if (totalPages > 10) {
      const lastBtn = document.createElement('button');
      lastBtn.className = 'tc-last-btn';
      lastBtn.textContent = '≫';
      lastBtn.title = 'Last page';
      lastBtn.disabled = this.currentPage === totalPages;
      lastBtn.addEventListener('click', () => this.goToPage(totalPages));
      paginationControls.appendChild(lastBtn);
    }

    // Page size selector for large datasets
    if (filteredData.length > this.config.largeDataset.threshold) {
      const pageSizeControls = document.createElement('div');
      pageSizeControls.className = 'tc-page-size-controls';
      
      const pageSizeLabel = document.createElement('label');
      pageSizeLabel.textContent = 'Rows per page: ';
      pageSizeLabel.className = 'tc-page-size-label';
      
      const pageSizeSelect = document.createElement('select');
      pageSizeSelect.className = 'tc-page-size-select';
      
      const pageSizeOptions = [10, 25, 50, 100, 250];
      pageSizeOptions.forEach(size => {
        const option = document.createElement('option');
        option.value = size.toString();
        option.textContent = size.toString();
        option.selected = this.config.pageSize === size;
        pageSizeSelect.appendChild(option);
      });
      
      pageSizeSelect.addEventListener('change', (e) => {
        this.config.pageSize = parseInt(e.target.value);
        this.currentPage = 1; // Reset to first page
        this.render();
      });
      
      pageSizeControls.appendChild(pageSizeLabel);
      pageSizeControls.appendChild(pageSizeSelect);
      pagination.appendChild(pageSizeControls);
    }

    // Assemble pagination
    pagination.appendChild(paginationInfo);
    pagination.appendChild(paginationControls);

    // Enhance pagination with accessibility features
    if (this.config.accessibility.enabled) {
      this.enhancePaginationAccessibility(pagination);
    }

    return pagination;
  }

  /**
   * Analyze data to detect filter types
   */
  detectFilterTypes() {
    if (!this.config.filters.autoDetect || this.data.length === 0) {
      return;
    }

    this.config.columns.forEach(column => {
      const field = column.field;
      const values = this.data.map(row => row[field]).filter(val => val != null);

      if (values.length === 0) return;

      // Store unique values for dropdowns
      this.uniqueValues[field] = [...new Set(values)];

      // Auto-detect filter type if not specified
      if (!this.config.filters.types[field]) {
        const sampleValue = values[0];

        // Check if it's a date
        if (this.isDateField(values) && !/sku|id|ref|code|serial|part/i.test(field)) {
          this.filterTypes[field] = 'daterange';
        }
        // Check if it's numeric
        else if (this.isNumericField(values)) {
          this.filterTypes[field] = 'numberrange';
        }
        // Check if it should be a multiselect (limited unique values)
        // Skip common text fields (name, email, etc)
        else if (this.uniqueValues[field].length <= 20 &&
          this.uniqueValues[field].length > 1 &&
          !/name|email|title|desc|phone|address|subject/i.test(field)) {
          this.filterTypes[field] = 'multiselect';
        }
        // Default to text
        else {
          this.filterTypes[field] = 'text';
        }
      } else {
        this.filterTypes[field] = this.config.filters.types[field].type || 'text';
      }
    });
  }

  /**
   * Check if field contains date values
   */
  isDateField(values) {
    const datePatterns = [
      /^\d{4}-\d{2}-\d{2}$/, // YYYY-MM-DD
      /^\d{2}\/\d{2}\/\d{4}$/, // MM/DD/YYYY
      /^\d{2}-\d{2}-\d{4}$/, // MM-DD-YYYY
      /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}:\d{2}/ // ISO
    ];

    return values.length > 0 && values.slice(0, 5).every(val => {
      if (!val) return false;
      const str = val.toString();
      // Must match strict pattern OR be a valid date parse that is NOT a number
      // Also ensure it's not too short (Date.parse is very aggressive)
      return datePatterns.some(pattern => pattern.test(str)) ||
        (str.length > 6 && !isNaN(Date.parse(str)) && isNaN(Number(str)));
    });
  }

  /**
   * Check if field contains numeric values
   */
  isNumericField(values) {
    return values.slice(0, 10).every(val => !isNaN(parseFloat(val)) && isFinite(val));
  }

  /**
   * Render filter controls
   */
  renderFilters() {
    if (!this.config.filterable) return null;

    const filtersContainer = document.createElement('div');
    filtersContainer.className = 'tc-filters';

    // 1. Clear All Button
    if (this.config.filters.showClearAll) {
      const clearAllBtn = document.createElement('button');
      clearAllBtn.className = 'tc-clear-filters';
      clearAllBtn.textContent = 'Clear All Filters';
      clearAllBtn.addEventListener('click', () => this.clearFilters());
      
      // Styling enhancements
      clearAllBtn.style.padding = '6px 12px';
      clearAllBtn.style.marginBottom = '10px';
      clearAllBtn.style.backgroundColor = '#d63638';
      clearAllBtn.style.color = '#fff';
      clearAllBtn.style.border = '1px solid #d63638';
      clearAllBtn.style.borderRadius = '4px';
      clearAllBtn.style.cursor = 'pointer';
      clearAllBtn.style.fontSize = '12px';

      filtersContainer.appendChild(clearAllBtn);
    }

    // 2. Specific Column Filters
    this.detectFilterTypes();
    const filterRow = document.createElement('div');
    filterRow.className = 'tc-filters-row';

    this.config.columns.forEach(column => {
      // In advanced mode, we show all columns that aren't explicitly excluded
      if (column.filterable !== false) {
        const filterType = this.filterTypes[column.field] || 'text';
        const filterDiv = this.createFilterControl(column, filterType);
        filterRow.appendChild(filterDiv);
      }
    });
    filtersContainer.appendChild(filterRow);

    return filtersContainer;
  }

  /**
   * Render global search bar
   */
  renderGlobalSearch() {
    const searchContainer = document.createElement('div');
    searchContainer.className = 'tc-global-search-container';

    const searchInput = document.createElement('input');
    searchInput.type = 'text';
    searchInput.className = 'tc-global-search';
    searchInput.setAttribute('aria-label', 'Search table');
    searchInput.placeholder = this.config.globalSearchPlaceholder || 'Search table...';
    searchInput.value = this.searchTerm;

    const debouncedSearch = this.debounce((value) => {
      this.searchTerm = value;
      this.currentPage = 1;
      this.render();
    }, 300);

    searchInput.addEventListener('input', (e) => debouncedSearch(e.target.value));

    // Styling enhancements
    searchInput.style.padding = '8px 12px';
    searchInput.style.marginBottom = '15px';
    searchInput.style.width = '100%';
    searchInput.style.maxWidth = '400px';
    searchInput.style.border = '1px solid #ddd';
    searchInput.style.borderRadius = '4px';

    searchContainer.appendChild(searchInput);

    // Enhance search with accessibility features
    if (this.config.accessibility.enabled) {
      this.enhanceSearchAccessibility(searchContainer);
    }

    return searchContainer;
  }

  /**
   * Create individual filter control
   */
  createFilterControl(column, filterType) {
    const filterDiv = document.createElement('div');
    filterDiv.className = 'tc-filter';

    const label = document.createElement('label');
    label.textContent = column.label;
    label.className = 'tc-filter-label';
    filterDiv.appendChild(label);

    switch (filterType) {
      case 'multiselect':
        filterDiv.appendChild(this.createMultiselectFilter(column));
        break;
      case 'daterange':
        filterDiv.appendChild(this.createDateRangeFilter(column));
        break;
      case 'numberrange':
        filterDiv.appendChild(this.createNumberRangeFilter(column));
        break;
      default:
        filterDiv.appendChild(this.createTextFilter(column));
    }

    return filterDiv;
  }

  /**
   * Create text filter input
   */
  createTextFilter(column) {
    const input = document.createElement('input');
    input.type = 'text';
    input.className = 'tc-filter-input';
    input.placeholder = `Filter ${column.label}...`;
    input.dataset.field = column.field;
    input.value = this.filters[column.field] || '';

    input.addEventListener('input', this.debounce((e) => {
      this.setFilter(column.field, e.target.value);
    }, 300));

    return input;
  }

  /**
   * Create multiselect filter dropdown
   */
  createMultiselectFilter(column) {
    const button = document.createElement('button');
    button.className = 'tc-multiselect-button';
    button.textContent = 'Select values...';
    button.type = 'button';

    const dropdown = document.createElement('div');
    dropdown.className = 'tc-multiselect-dropdown';
    dropdown.style.display = 'none';

    const uniqueValues = this.uniqueValues[column.field] || [];
    const currentFilter = this.filters[column.field] || [];

    uniqueValues.forEach(value => {
      const option = document.createElement('label');
      option.className = 'tc-multiselect-option';

      const checkbox = document.createElement('input');
      checkbox.type = 'checkbox';
      checkbox.value = value;
      checkbox.checked = currentFilter.includes(value);
      checkbox.addEventListener('change', () => {
        this.updateMultiselectFilter(column.field, dropdown, button);
      });

      option.appendChild(checkbox);
      option.appendChild(document.createTextNode(value));
      dropdown.appendChild(option);
    });

    // Toggle logic with Fixed Positioning (Popover)
    const toggleDropdown = (e) => {
      e.stopPropagation();
      const isHidden = dropdown.style.display === 'none';

      // Close all other dropdowns
      document.querySelectorAll('.tc-multiselect-dropdown').forEach(d => d.style.display = 'none');

      if (isHidden) {
        dropdown.style.display = 'block';
        dropdown.style.position = 'fixed';
        dropdown.style.zIndex = '10000'; // High z-index

        const rect = button.getBoundingClientRect();
        dropdown.style.top = (rect.bottom) + 'px';
        dropdown.style.left = rect.left + 'px';
        dropdown.style.width = rect.width + 'px';
        dropdown.style.maxHeight = '300px'; // Ensure visibility

        // Add global listeners
        document.addEventListener('click', closeDropdown);
        window.addEventListener('scroll', closeDropdown, { capture: true });
      } else {
        closeDropdown();
      }
    };

    const closeDropdown = (e) => {
      if (e && (dropdown.contains(e.target) || e.target === button)) return;
      dropdown.style.display = 'none';
      document.removeEventListener('click', closeDropdown);
      window.removeEventListener('scroll', closeDropdown, { capture: true });
    };

    button.addEventListener('click', toggleDropdown);

    // Initial setup
    this.updateMultiselectButton(button, currentFilter);

    // Append to body and track
    document.body.appendChild(dropdown);
    if (!this.dropdowns) this.dropdowns = [];
    this.dropdowns.push(dropdown);

    return button;
  }

  /**
   * Update multiselect filter based on checkbox changes
   */
  updateMultiselectFilter(field, dropdown, button) {
    const checkboxes = dropdown.querySelectorAll('input[type="checkbox"]');
    const selectedValues = Array.from(checkboxes)
      .filter(cb => cb.checked)
      .map(cb => cb.value);

    this.setFilter(field, selectedValues);

    // Update button text
    if (button) {
      this.updateMultiselectButton(button, selectedValues);
    }
  }

  /**
   * Update multiselect button text
   */
  updateMultiselectButton(button, selectedValues) {
    if (selectedValues.length === 0) {
      button.textContent = 'Select values...';
    } else if (selectedValues.length === 1) {
      button.textContent = selectedValues[0];
    } else {
      button.textContent = `${selectedValues.length} selected`;
    }
  }

  /**
   * Create date range filter
   */
  createDateRangeFilter(column) {
    const container = document.createElement('div');
    container.className = 'tc-daterange-container';

    const fromInput = document.createElement('input');
    fromInput.type = 'date';
    fromInput.className = 'tc-date-from';
    fromInput.placeholder = 'From';

    const toInput = document.createElement('input');
    toInput.type = 'date';
    toInput.className = 'tc-date-to';
    toInput.placeholder = 'To';

    const currentFilter = this.filters[column.field] || {};
    fromInput.value = currentFilter.from || '';
    toInput.value = currentFilter.to || '';

    const updateDateFilter = () => {
      const filter = {};
      if (fromInput.value) filter.from = fromInput.value;
      if (toInput.value) filter.to = toInput.value;

      this.setFilter(column.field, Object.keys(filter).length > 0 ? filter : null);
    };

    fromInput.addEventListener('change', updateDateFilter);
    toInput.addEventListener('change', updateDateFilter);

    container.appendChild(fromInput);
    container.appendChild(toInput);
    return container;
  }

  /**
   * Create number range filter
   */
  createNumberRangeFilter(column) {
    const container = document.createElement('div');
    container.className = 'tc-numberrange-container';

    const minInput = document.createElement('input');
    minInput.type = 'number';
    minInput.className = 'tc-number-min';
    minInput.placeholder = 'Min';

    const maxInput = document.createElement('input');
    maxInput.type = 'number';
    maxInput.className = 'tc-number-max';
    maxInput.placeholder = 'Max';

    const currentFilter = this.filters[column.field] || {};
    minInput.value = currentFilter.min || '';
    maxInput.value = currentFilter.max || '';

    const updateNumberFilter = () => {
      const filter = {};
      if (minInput.value) filter.min = parseFloat(minInput.value);
      if (maxInput.value) filter.max = parseFloat(maxInput.value);

      this.setFilter(column.field, Object.keys(filter).length > 0 ? filter : null);
    };

    const debouncedUpdate = this.debounce(updateNumberFilter, 300);
    minInput.addEventListener('input', debouncedUpdate);
    maxInput.addEventListener('input', debouncedUpdate);

    container.appendChild(minInput);
    container.appendChild(maxInput);
    return container;
  }

  /**
   * Set filter for a field
   */
  setFilter(field, value) {
    if (!value || (typeof value === 'string' && value.trim() === '') || (Array.isArray(value) && value.length === 0)) {
      delete this.filters[field];
    } else {
      this.filters[field] = typeof value === 'string' ? value.trim() : value;
    }

    // Reset to first page when filtering
    this.currentPage = 1;

    // Save state if persistence enabled
    this.saveState();

    // Call onFilter callback if provided
    if (this.config.onFilter) {
      const filteredData = this.getFilteredData();
      this.config.onFilter({
        filters: { ...this.filters },
        filteredData: filteredData
      });
    }

    this.render();
  }

  /**
   * Clear all filters
   */
  clearFilters() {
    this.filters = {};
    this.currentPage = 1;
    this.saveState();
    this.render();
  }

  /**
   * Render export controls
   */
  renderExportControls() {
    const exportContainer = document.createElement('div');
    exportContainer.className = 'tc-export-controls';

    // Advanced export dropdown if enabled
    if (this.config.advancedExport.enabled && this.config.advancedExport.formats.length > 1) {
      const exportDropdown = this.createExportDropdown();
      exportContainer.appendChild(exportDropdown);
    } else {
      // Fallback to simple CSV button
      const exportCsvBtn = document.createElement('button');
      exportCsvBtn.className = 'tc-export-csv';
      exportCsvBtn.textContent = 'Export CSV';
      exportCsvBtn.addEventListener('click', () => this.downloadEnhanced('csv'));
      exportContainer.appendChild(exportCsvBtn);
    }

    const copyBtn = document.createElement('button');
    copyBtn.className = 'tc-copy-clipboard';
    copyBtn.textContent = 'Copy to Clipboard';
    copyBtn.style.marginLeft = '8px';
    copyBtn.addEventListener('click', () => this.copyToClipboard());
    exportContainer.appendChild(copyBtn);

    return exportContainer;
  }

  /**
   * Copy table data to clipboard
   */
  copyToClipboard() {
    const exportableData = this.getExportableData();
    const exportableColumns = this.getExportableColumns();

    if (exportableData.length === 0) return;

    // Create tab-separated text for spreadsheets
    const header = exportableColumns.map(col => col.label).join('\t');
    const rows = exportableData.map(row => {
      return exportableColumns.map(col => row[col.field]).join('\t');
    }).join('\n');

    const text = header + '\n' + rows;

    const onSuccess = () => {
      const btn = this.container.querySelector('.tc-copy-clipboard');
      if (btn) {
        const originalText = btn.textContent;
        btn.textContent = 'Copied!';
        btn.classList.add('tc-copy-success');
        setTimeout(() => {
          btn.textContent = originalText;
          btn.classList.remove('tc-copy-success');
        }, 2000);
      }
    };

    const onError = (err) => {
      console.error('Failed to copy: ', err);
      // Fallback method
      const textArea = document.createElement('textarea');
      textArea.value = text;
      textArea.style.position = 'fixed';
      textArea.style.left = '-9999px';
      textArea.style.top = '0';
      document.body.appendChild(textArea);
      textArea.focus();
      textArea.select();
      try {
        const successful = document.execCommand('copy');
        if (successful) onSuccess();
      } catch (err) {
        console.error('Fallback copy failed: ', err);
      }
      document.body.removeChild(textArea);
    };

    if (navigator.clipboard && navigator.clipboard.writeText) {
      navigator.clipboard.writeText(text).then(onSuccess).catch(onError);
    } else {
      onError('Clipboard API unavailable');
    }
  }

  /**
   * Get exportable data (respects filtering if enabled)
   */
  getExportableData() {
    if (this.config.exportFiltered) {
      return this.getFilteredData();
    }
    return this.data;
  }

  /**
   * Get exportable columns (excludes non-exportable columns)
   */
  getExportableColumns() {
    return this.config.columns.filter(column => column.exportable !== false);
  }

  /**
   * Escape CSV field value
   */
  escapeCSVField(value) {
    if (value === null || value === undefined) {
      return '""';
    }

    const stringValue = value.toString();

    // If the value contains comma, newline, or quote, wrap in quotes and escape quotes
    if (stringValue.includes(',') || stringValue.includes('\n') || stringValue.includes('"')) {
      return '"' + stringValue.replace(/"/g, '""') + '"';
    }

    // For simple values without special characters, don't quote numbers
    if (!isNaN(stringValue) && !isNaN(parseFloat(stringValue))) {
      return stringValue;
    }

    // Quote text values
    return '"' + stringValue + '"';
  }

  /**
   * Export data to CSV format
   */
  exportToCSV() {
    const exportableColumns = this.getExportableColumns();
    const exportableData = this.getExportableData();

    // Create header row
    const headerRow = exportableColumns.map(column => column.label).join(',');

    // Create data rows
    const dataRows = exportableData.map(row => {
      return exportableColumns.map(column => {
        const value = row[column.field];
        return this.escapeCSVField(value);
      }).join(',');
    });

    const csvContent = [headerRow, ...dataRows].join('\n');

    // Call onExport callback if provided
    if (this.config.onExport) {
      this.config.onExport({
        format: 'csv',
        data: exportableData,
        csvData: csvContent
      });
    }

    return csvContent;
  }

  /**
   * Download CSV file
   */
  downloadCSV() {
    const csvContent = this.exportToCSV();
    const blob = new Blob([csvContent], { type: 'text/csv;charset=utf-8;' });
    const url = URL.createObjectURL(blob);

    const link = document.createElement('a');
    link.href = url;
    link.download = this.config.exportFilename + '.csv';
    link.click();

    // Clean up
    URL.revokeObjectURL(url);
  }

  /**
   * Create export format dropdown
   */
  createExportDropdown() {
    const dropdownWrapper = document.createElement('div');
    dropdownWrapper.className = 'tc-export-dropdown-wrapper';

    const exportBtn = document.createElement('button');
    exportBtn.className = 'tc-export-main-btn';
    // SECURITY: Use safe DOM creation instead of innerHTML
    exportBtn.textContent = 'Export Data ';
    const dropdownArrow = document.createElement('span');
    dropdownArrow.className = 'tc-dropdown-arrow';
    dropdownArrow.textContent = '▼';
    exportBtn.appendChild(dropdownArrow);
    
    const dropdown = document.createElement('div');
    dropdown.className = 'tc-export-dropdown';
    dropdown.style.display = 'none';

    // Add export format options
    this.config.advancedExport.formats.forEach(format => {
      const option = document.createElement('button');
      option.className = `tc-export-option tc-export-${format}`;
      // SECURITY: Use safe DOM creation instead of innerHTML
      const formatInfo = this.getExportOptionInfo(format);
      
      // Create icon span
      const iconSpan = document.createElement('span');
      iconSpan.className = 'tc-export-icon';
      iconSpan.textContent = formatInfo.icon;
      
      // Create details div
      const detailsDiv = document.createElement('div');
      detailsDiv.className = 'tc-export-details';
      
      // Create title div
      const titleDiv = document.createElement('div');
      titleDiv.className = 'tc-export-title';
      titleDiv.textContent = formatInfo.title;
      
      // Create description div
      const descDiv = document.createElement('div');
      descDiv.className = 'tc-export-desc';
      descDiv.textContent = formatInfo.description;
      
      // Assemble structure
      detailsDiv.appendChild(titleDiv);
      detailsDiv.appendChild(descDiv);
      option.appendChild(iconSpan);
      option.appendChild(detailsDiv);
      option.addEventListener('click', (e) => {
        e.stopPropagation();
        this.handleExportFormat(format);
        dropdown.style.display = 'none';
      });
      dropdown.appendChild(option);
    });

    // Toggle dropdown
    exportBtn.addEventListener('click', (e) => {
      e.stopPropagation();
      dropdown.style.display = dropdown.style.display === 'none' ? 'block' : 'none';
    });

    // Close dropdown when clicking outside
    document.addEventListener('click', () => {
      dropdown.style.display = 'none';
    });

    dropdownWrapper.appendChild(exportBtn);
    dropdownWrapper.appendChild(dropdown);

    return dropdownWrapper;
  }

  /**
   * SECURITY: Get safe export option info (replaces getExportOptionHTML)
   */
  getExportOptionInfo(format) {
    const icons = {
      csv: '📄',
      excel: '📊', 
      pdf: '📑'
    };
    
    const descriptions = {
      csv: 'CSV - Basic spreadsheet format',
      excel: 'Excel - Advanced spreadsheet with formatting',
      pdf: 'PDF - Professional report format'
    };
    
    return {
      icon: icons[format] || '📄',
      title: format.toUpperCase(),
      description: descriptions[format] || format.toUpperCase()
    };
  }

  /**
   * Handle export format selection
   */
  handleExportFormat(format) {
    switch(format) {
      case 'csv':
        this.downloadCSV();
        break;
      case 'excel':
        this.downloadEnhanced('excel');
        break;
      case 'pdf':
        this.downloadEnhanced('pdf');
        break;
      default:
        console.warn(`Unknown export format: ${format}`);
    }
  }

  /**
   * Enhanced download using server-side processing
   * Replaces broken client-side Excel/PDF generation
   */
  downloadEnhanced(format) {
    const exportableData = this.getExportableData();
    const exportableColumns = this.getExportableColumns();

    if (exportableData.length === 0) {
      alert('No data to export');
      return;
    }

    // Show loading indicator
    const loadingEl = this.showExportLoading(format);
    
    // Prepare options based on format
    let options = {};
    if (format === 'excel') {
      options = {
        sheet_name: this.config.advancedExport.excel.sheetName || 'Data Export',
        auto_width: this.config.advancedExport.excel.autoWidth || false
      };
    } else if (format === 'pdf') {
      options = {
        title: this.config.advancedExport.pdf.title || 'Data Export Report',
        subtitle: this.config.advancedExport.pdf.subtitle || '',
        orientation: this.config.advancedExport.pdf.orientation || 'portrait',
        footer: this.config.advancedExport.pdf.footer || 'Generated by TableCrafter'
      };
    }

    // Prepare AJAX request
    const formData = new FormData();
    formData.append('action', 'tc_export_data');
    formData.append('format', format);
    formData.append('data', JSON.stringify(exportableData));
    formData.append('columns', JSON.stringify(exportableColumns));
    formData.append('filename', this.config.exportFilename || 'table-export');
    formData.append('options', JSON.stringify(options));
    formData.append('nonce', this.getExportNonce());

    // Send request to server-side export handler
    fetch(this.config.api.ajaxUrl || '/wp-admin/admin-ajax.php', {
      method: 'POST',
      body: formData
    })
    .then(response => response.json())
    .then(result => {
      this.hideExportLoading(loadingEl);
      
      if (result.success) {
        // Trigger download
        this.triggerDownload(result.data.download_url, result.data.filename);
        
        // Fire export event
        if (this.config.onExport) {
          this.config.onExport({
            format: format,
            data: exportableData,
            columns: exportableColumns,
            filename: result.data.filename,
            size: result.data.size
          });
        }
        
        this.showExportSuccess(format, result.data.size);
      } else {
        this.showExportError(result.data.message || 'Export failed');
      }
    })
    .catch(error => {
      this.hideExportLoading(loadingEl);
      console.error('Export failed:', error);
      this.showExportError('Network error during export');
    });
  }

  /**
   * Show export loading indicator
   */
  showExportLoading(format) {
    const loadingEl = document.createElement('div');
    loadingEl.className = 'tc-export-loading';
    loadingEl.innerHTML = `
      <div style="position: fixed; top: 50%; left: 50%; transform: translate(-50%, -50%); 
                  background: white; padding: 20px; border-radius: 8px; box-shadow: 0 4px 20px rgba(0,0,0,0.15); 
                  z-index: 9999; text-align: center;">
        <div style="font-size: 16px; margin-bottom: 10px;">Generating ${format.toUpperCase()} export...</div>
        <div style="width: 200px; height: 4px; background: #f0f0f0; border-radius: 2px; overflow: hidden;">
          <div style="height: 100%; background: #4472C4; width: 0%; animation: tcProgress 2s infinite ease-in-out;"></div>
        </div>
      </div>
      <style>
        @keyframes tcProgress {
          0% { width: 0%; }
          50% { width: 70%; }
          100% { width: 100%; }
        }
      </style>
    `;
    document.body.appendChild(loadingEl);
    return loadingEl;
  }

  /**
   * Hide export loading indicator
   */
  hideExportLoading(loadingEl) {
    if (loadingEl && loadingEl.parentNode) {
      loadingEl.parentNode.removeChild(loadingEl);
    }
  }

  /**
   * Trigger file download
   */
  triggerDownload(url, filename) {
    const link = document.createElement('a');
    link.href = url;
    link.download = filename;
    link.style.display = 'none';
    document.body.appendChild(link);
    link.click();
    document.body.removeChild(link);
  }

  /**
   * Show export success message
   */
  showExportSuccess(format, size) {
    const message = `${format.toUpperCase()} export completed successfully! File size: ${this.formatBytes(size)}`;
    this.showNotification(message, 'success');
  }

  /**
   * Show export error message
   */
  showExportError(message) {
    this.showNotification('Export failed: ' + message, 'error');
  }

  /**
   * Show notification
   */
  showNotification(message, type = 'info') {
    const notification = document.createElement('div');
    notification.className = `tc-notification tc-notification-${type}`;
    notification.style.cssText = `
      position: fixed; top: 20px; right: 20px; z-index: 10000;
      padding: 12px 20px; border-radius: 6px; color: white;
      font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
      font-size: 14px; max-width: 400px;
      background: ${type === 'success' ? '#28a745' : type === 'error' ? '#dc3545' : '#007bff'};
      box-shadow: 0 4px 12px rgba(0,0,0,0.15);
      transform: translateX(100%); transition: transform 0.3s ease;
    `;
    notification.textContent = message;
    
    document.body.appendChild(notification);
    
    // Animate in
    setTimeout(() => {
      notification.style.transform = 'translateX(0)';
    }, 100);
    
    // Remove after delay
    setTimeout(() => {
      notification.style.transform = 'translateX(100%)';
      setTimeout(() => {
        if (notification.parentNode) {
          notification.parentNode.removeChild(notification);
        }
      }, 300);
    }, type === 'error' ? 6000 : 3000);
  }

  /**
   * Format bytes for display
   */
  formatBytes(bytes) {
    if (bytes === 0) return '0 B';
    const k = 1024;
    const sizes = ['B', 'KB', 'MB', 'GB'];
    const i = Math.floor(Math.log(bytes) / Math.log(k));
    return parseFloat((bytes / Math.pow(k, i)).toFixed(2)) + ' ' + sizes[i];
  }

  /**
   * Get export nonce for security
   */
  getExportNonce() {
    // Try to get from global wp object or container data
    if (typeof wp !== 'undefined' && wp.ajax && wp.ajax.settings && wp.ajax.settings.nonce) {
      return wp.ajax.settings.nonce;
    }
    
    // Try to get from container data attribute
    const nonce = this.container.dataset.exportNonce;
    if (nonce) {
      return nonce;
    }
    
    // Fallback - get from meta tag or global
    const metaNonce = document.querySelector('meta[name="tc-export-nonce"]');
    if (metaNonce) {
      return metaNonce.getAttribute('content');
    }
    
    // Last resort - check global variable
    return window.tcExportNonce || '';
  }

  /**
   * Escape HTML entities
   */
  escapeHtml(text) {
    const div = document.createElement('div');
    div.textContent = text;
    return div.innerHTML;
  }

  /**
   * SECURITY: Check if HTML content is trusted (from server-side rendering)
   * Only allow specific safe HTML patterns
   */
  isTrustedHTML(html) {
    if (typeof html !== 'string') return false;
    
    // Allow specific trusted HTML patterns from server-side rendering
    const trustedPatterns = [
      /^<span class="tc-badge tc-(yes|no)">(?:Yes|No)<\/span>$/,
      /^<img src="[^"]*" style="[^"]*" alt="[^"]*" loading="lazy">$/,
      // Enhanced email pattern to handle various formats and attribute orders
      /^<a(?=.*href="mailto:[^"]*")[^>]*>.*?<\/a>$/,
      /^<time datetime="[^"]*">[^<]*<\/time>$/,
      /^<a href="https?:\/\/[^"]*" target="_blank" rel="noopener noreferrer" title="[^"]*">[^<]*<\/a>$/,
      /^<div class="tc-tag-list">(<span class="tc-tag">[^<]*<\/span>)*(<span class="tc-tag tc-more">\+\d+ more<\/span>)?<\/div>$/,
      /^<span class="tc-tag">[^<]*<\/span>$/
    ];

    return trustedPatterns.some(pattern => pattern.test(html));
  }

  /**
   * SECURITY: Safely set innerHTML with validation
   */
  safeSetInnerHTML(element, html) {
    if (this.isTrustedHTML(html)) {
      element.innerHTML = html;
    } else {
      element.textContent = html;
    }
  }

  /**
   * SECURITY: Create safe DOM element with escaped content
   */
  createSafeElement(tagName, content, attributes = {}) {
    const element = document.createElement(tagName);
    
    // Set text content safely
    if (content) {
      element.textContent = content;
    }
    
    // Set attributes safely
    for (const [key, value] of Object.entries(attributes)) {
      element.setAttribute(key, String(value));
    }
    
    return element;
  }

  /**
   * Sort data
   */
  sort(field) {
    if (this.sortField === field) {
      this.sortOrder = this.sortOrder === 'asc' ? 'desc' : 'asc';
    } else {
      this.sortField = field;
      this.sortOrder = 'asc';
    }

    this.data.sort((a, b) => {
      const aVal = a[field];
      const bVal = b[field];

      if (aVal === bVal) return 0;

      const result = aVal < bVal ? -1 : 1;
      return this.sortOrder === 'asc' ? result : -result;
    });

    // Reset to first page after sorting
    this.currentPage = 1;
    this.saveState();
    this.render();

    // Announce sort change for accessibility
    this.announceDataChange('sorted');
  }

  /**
   * Handle window resize
   */
  handleResize() {
    // Re-render if crossing mobile breakpoint
    const isMobileNow = this.isMobile();
    const wrapper = this.container.querySelector('.tc-wrapper');

    if (!wrapper) return;

    const hasCards = wrapper.querySelector('.tc-cards-container');
    const hasTable = wrapper.querySelector('.tc-table-container');

    if ((isMobileNow && hasTable) || (!isMobileNow && hasCards)) {
      this.render();
    }
  }

  /**
   * Render bulk controls
   */
  renderBulkControls() {
    const bulkContainer = document.createElement('div');
    bulkContainer.className = 'tc-bulk-controls';
    bulkContainer.style.display = 'none'; // Initially hidden

    // Bulk info
    const bulkInfo = document.createElement('div');
    bulkInfo.className = 'tc-bulk-info';
    bulkInfo.textContent = '0 items selected';

    // Select all checkbox
    const selectAllContainer = document.createElement('label');
    selectAllContainer.className = 'tc-bulk-select-all';

    const selectAllCheckbox = document.createElement('input');
    selectAllCheckbox.type = 'checkbox';
    selectAllCheckbox.addEventListener('change', (e) => {
      if (e.target.checked) {
        this.selectAllRows();
      } else {
        this.deselectAllRows();
      }
    });

    selectAllContainer.appendChild(selectAllCheckbox);
    selectAllContainer.appendChild(document.createTextNode(' Select All'));

    // Bulk actions
    const actionsContainer = document.createElement('div');
    actionsContainer.className = 'tc-bulk-actions';

    // Create action buttons based on configuration
    this.config.bulk.operations.forEach(operation => {
      const button = document.createElement('button');
      button.className = `tc-bulk-${operation}`;
      button.textContent = operation.charAt(0).toUpperCase() + operation.slice(1);
      button.addEventListener('click', () => this.performBulkAction(operation));
      actionsContainer.appendChild(button);
    });

    bulkContainer.appendChild(bulkInfo);
    bulkContainer.appendChild(selectAllContainer);
    bulkContainer.appendChild(actionsContainer);

    return bulkContainer;
  }

  /**
   * Perform bulk action on selected rows
   */
  performBulkAction(action) {
    const selectedRows = Array.from(this.selectedRows);
    if (selectedRows.length === 0) return;

    const selectedData = selectedRows.map(index => this.data[index]).filter(Boolean);

    switch (action) {
      case 'delete':
        this.bulkDelete(selectedRows, selectedData);
        break;
      case 'export':
        this.bulkExport(selectedData);
        break;
      case 'edit':
        this.bulkEdit(selectedRows, selectedData);
        break;
      default:
        // Call custom bulk action if provided
        if (this.config.onBulkAction) {
          this.config.onBulkAction({
            action: action,
            selectedRows: selectedRows,
            selectedData: selectedData
          });
        }
    }
  }

  /**
   * Bulk delete selected rows
   */
  bulkDelete(selectedRows, selectedData) {
    if (!confirm(`Are you sure you want to delete ${selectedRows.length} item${selectedRows.length === 1 ? '' : 's'}?`)) {
      return;
    }

    // Sort indices in descending order to remove from end first
    selectedRows.sort((a, b) => b - a);

    selectedRows.forEach(index => {
      this.data.splice(index, 1);
    });

    // Clear selection
    this.selectedRows.clear();
    this.updateBulkControls();
    this.render();

    // Call callback if provided
    if (this.config.onBulkDelete) {
      this.config.onBulkDelete({
        deletedRows: selectedRows,
        deletedData: selectedData
      });
    }
  }

  /**
   * Bulk export selected rows
   */
  bulkExport(selectedData) {
    const originalData = this.data;
    this.data = selectedData;

    try {
      this.downloadCSV();
    } finally {
      this.data = originalData;
    }

    // Call callback if provided
    if (this.config.onBulkExport) {
      this.config.onBulkExport({
        exportedData: selectedData
      });
    }
  }

  /**
   * Bulk edit selected rows
   */
  bulkEdit(selectedRows, selectedData) {
    // This could open a modal for bulk editing
    // For now, just call the callback
    if (this.config.onBulkEdit) {
      this.config.onBulkEdit({
        selectedRows: selectedRows,
        selectedData: selectedData
      });
    }
  }

  /**
   * Render add new entry button
   */
  renderAddNewButton() {
    if (!this.config.addNew.enabled) return null;

    const button = document.createElement('button');
    button.className = 'tc-add-new';
    button.textContent = 'Add New Entry';
    button.addEventListener('click', () => this.showAddNewModal());

    return button;
  }

  /**
   * Show add new entry modal
   */
  showAddNewModal() {
    const modal = this.createModal('Add New Entry', this.renderAddNewForm());
    document.body.appendChild(modal);
  }

  /**
   * Create modal structure
   */
  createModal(title, content) {
    const overlay = document.createElement('div');
    overlay.className = 'tc-modal-overlay';

    const modal = document.createElement('div');
    modal.className = 'tc-modal';

    // Header
    const header = document.createElement('div');
    header.className = 'tc-modal-header';

    const titleElement = document.createElement('h3');
    titleElement.className = 'tc-modal-title';
    titleElement.textContent = title;

    const closeButton = document.createElement('button');
    closeButton.className = 'tc-modal-close';
    closeButton.textContent = '×';
    closeButton.addEventListener('click', () => {
      document.body.removeChild(overlay);
    });

    header.appendChild(titleElement);
    header.appendChild(closeButton);

    // Content
    modal.appendChild(header);
    modal.appendChild(content);

    overlay.appendChild(modal);

    // Close on overlay click
    overlay.addEventListener('click', (e) => {
      if (e.target === overlay) {
        document.body.removeChild(overlay);
      }
    });

    return overlay;
  }

  /**
   * Render add new entry form
   */
  renderAddNewForm() {
    const form = document.createElement('form');
    form.className = 'tc-modal-form';

    const fields = this.config.addNew.fields.length > 0 ?
      this.config.addNew.fields :
      this.config.columns.filter(col => col.field !== 'id');

    fields.forEach(field => {
      const fieldDiv = document.createElement('div');
      fieldDiv.className = 'tc-form-field';

      const label = document.createElement('label');
      label.className = 'tc-form-label';
      label.textContent = field.label || field.name;
      label.setAttribute('for', `tc-form-${field.field || field.name}`);

      const input = document.createElement('input');
      input.className = 'tc-form-input';
      input.type = field.type || 'text';
      input.id = `tc-form-${field.field || field.name}`;
      input.name = field.field || field.name;
      input.required = field.required || false;

      if (field.placeholder) {
        input.placeholder = field.placeholder;
      }

      fieldDiv.appendChild(label);
      fieldDiv.appendChild(input);
      form.appendChild(fieldDiv);
    });

    // Actions
    const actions = document.createElement('div');
    actions.className = 'tc-modal-actions';

    const cancelButton = document.createElement('button');
    cancelButton.type = 'button';
    cancelButton.className = 'tc-btn-cancel';
    cancelButton.textContent = 'Cancel';
    cancelButton.addEventListener('click', () => {
      const overlay = form.closest('.tc-modal-overlay');
      document.body.removeChild(overlay);
    });

    const saveButton = document.createElement('button');
    saveButton.type = 'submit';
    saveButton.className = 'tc-btn-save';
    saveButton.textContent = 'Save';

    actions.appendChild(cancelButton);
    actions.appendChild(saveButton);
    form.appendChild(actions);

    // Handle form submission
    form.addEventListener('submit', (e) => {
      e.preventDefault();
      this.handleAddNewSubmit(form);
    });

    return form;
  }

  /**
   * Handle add new entry form submission
   */
  handleAddNewSubmit(form) {
    const formData = new FormData(form);
    const newEntry = {};

    for (let [key, value] of formData.entries()) {
      newEntry[key] = value;
    }

    // Validate using the new validation system
    if (this.config.validation.enabled && this.config.validation.validateOnSubmit) {
      const validation = this.validateRow(newEntry, -1); // -1 for new entry

      if (!validation.isValid) {
        this.showFormValidationErrors(form, validation.errors);
        return;
      }
    }

    // Add to data
    this.data.push(newEntry);

    // Close modal
    const overlay = form.closest('.tc-modal-overlay');
    document.body.removeChild(overlay);

    // Re-render
    this.render();

    // Call callback if provided
    if (this.config.onAdd) {
      this.config.onAdd({
        newEntry: newEntry,
        totalEntries: this.data.length
      });
    }
  }

  /**
   * Validate entry against rules
   */
  validateEntry(entry, rules) {
    const errors = [];

    Object.entries(rules).forEach(([field, rule]) => {
      const value = entry[field];

      if (rule.required && (!value || value.trim() === '')) {
        errors.push({ field, message: rule.message || `${field} is required` });
      }

      if (value && rule.type === 'email' && !this.isValidEmail(value)) {
        errors.push({ field, message: rule.message || 'Please enter a valid email address' });
      }

      if (value && rule.minLength && value.length < rule.minLength) {
        errors.push({ field, message: rule.message || `${field} must be at least ${rule.minLength} characters` });
      }

      if (value && rule.maxLength && value.length > rule.maxLength) {
        errors.push({ field, message: rule.message || `${field} must be no more than ${rule.maxLength} characters` });
      }
    });

    return errors;
  }

  /**
   * Show validation errors in form
   */
  showValidationErrors(form, errors) {
    // Clear existing errors
    form.querySelectorAll('.tc-form-error').forEach(error => error.remove());

    errors.forEach(error => {
      const field = form.querySelector(`[name="${error.field}"]`);
      if (field) {
        field.classList.add('tc-error');

        const errorDiv = document.createElement('div');
        errorDiv.className = 'tc-form-error';
        errorDiv.textContent = error.message;

        field.parentNode.appendChild(errorDiv);
      }
    });
  }

  /**
   * Validate email format
   */
  isValidEmail(email) {
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    return emailRegex.test(email);
  }

  /**
   * API Integration Methods
   */

  /**
   * Make API request with authentication and error handling
   */
  async apiRequest(endpoint, options = {}) {
    const config = this.config.api;
    const url = config.baseUrl + endpoint;

    const requestOptions = {
      method: 'GET',
      headers: {
        'Content-Type': 'application/json',
        ...config.headers
      },
      ...options
    };

    // Add authentication if configured
    if (config.authentication) {
      if (config.authentication.type === 'bearer') {
        requestOptions.headers['Authorization'] = `Bearer ${config.authentication.token}`;
      } else if (config.authentication.type === 'api-key') {
        requestOptions.headers[config.authentication.headerName] = config.authentication.key;
      }
    }

    try {
      const response = await fetch(url, requestOptions);

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

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

  /**
   * Load data from API
   */
  async loadDataFromAPI() {
    if (!this.config.api.baseUrl) {
      throw new Error('API base URL not configured');
    }

    try {
      this.isLoading = true;
      const data = await this.apiRequest(this.config.api.endpoints.data);
      this.data = Array.isArray(data) ? data : data.data || [];
      this.isLoading = false;

      if (this.container.querySelector('.tc-wrapper')) {
        this.render();
      }

      return this.data;
    } catch (error) {
      this.isLoading = false;
      throw error;
    }
  }

  /**
   * Create new entry via API
   */
  async createEntry(entryData) {
    if (!this.config.api.baseUrl) {
      // Fall back to local creation
      this.data.push(entryData);
      return entryData;
    }

    try {
      const response = await this.apiRequest(this.config.api.endpoints.create, {
        method: 'POST',
        body: JSON.stringify(entryData)
      });

      // Add to local data
      this.data.push(response);
      return response;
    } catch (error) {
      console.error('Failed to create entry:', error);
      throw error;
    }
  }

  /**
   * Update entry via API
   */
  async updateEntry(index, entryData) {
    const originalEntry = this.data[index];

    if (!this.config.api.baseUrl) {
      // Fall back to local update
      this.data[index] = { ...originalEntry, ...entryData };
      return this.data[index];
    }

    try {
      const response = await this.apiRequest(
        `${this.config.api.endpoints.update}/${originalEntry.id || index}`,
        {
          method: 'PUT',
          body: JSON.stringify(entryData)
        }
      );

      // Update local data
      this.data[index] = response;
      return response;
    } catch (error) {
      console.error('Failed to update entry:', error);
      throw error;
    }
  }

  /**
   * Delete entry via API
   */
  async deleteEntry(index) {
    const entry = this.data[index];

    if (!this.config.api.baseUrl) {
      // Fall back to local deletion
      this.data.splice(index, 1);
      return true;
    }

    try {
      await this.apiRequest(
        `${this.config.api.endpoints.delete}/${entry.id || index}`,
        { method: 'DELETE' }
      );

      // Remove from local data
      this.data.splice(index, 1);
      return true;
    } catch (error) {
      console.error('Failed to delete entry:', error);
      throw error;
    }
  }

  /**
   * Lookup Fields System
   */

  /**
   * Load lookup data for a field
   */
  async loadLookupData(field, lookupConfig) {
    const cacheKey = `${field}_${JSON.stringify(lookupConfig)}`;

    // Check cache first
    if (this.lookupCache.has(cacheKey)) {
      return this.lookupCache.get(cacheKey);
    }

    try {
      let data;

      if (lookupConfig.url) {
        // Load from custom URL
        const response = await fetch(lookupConfig.url);
        data = await response.json();
      } else if (lookupConfig.type && this.config.api.baseUrl) {
        // Load from API endpoint
        const endpoint = `${this.config.api.endpoints.lookup}/${lookupConfig.type}`;
        data = await this.apiRequest(endpoint);
      } else if (lookupConfig.data) {
        // Use provided static data
        data = lookupConfig.data;
      } else {
        throw new Error('No lookup data source configured');
      }

      // Apply filters if specified
      if (lookupConfig.filter) {
        data = data.filter(item => {
          return Object.entries(lookupConfig.filter).every(([key, value]) => {
            return item[key] === value;
          });
        });
      }

      // Cache the result
      this.lookupCache.set(cacheKey, data);
      return data;
    } catch (error) {
      console.error('Failed to load lookup data:', error);
      return [];
    }
  }

  /**
   * Create lookup dropdown for editing
   */
  async createLookupDropdown(column, currentValue) {
    const lookupConfig = column.lookup;
    if (!lookupConfig) return null;

    const data = await this.loadLookupData(column.field, lookupConfig);

    const select = document.createElement('select');
    select.className = 'tc-lookup-select';

    // Add empty option
    const emptyOption = document.createElement('option');
    emptyOption.value = '';
    emptyOption.textContent = 'Select...';
    select.appendChild(emptyOption);

    // Add options from lookup data
    data.forEach(item => {
      const option = document.createElement('option');
      option.value = item[lookupConfig.valueField || 'id'];
      option.textContent = item[lookupConfig.displayField || 'name'];

      if (option.value == currentValue) {
        option.selected = true;
      }

      select.appendChild(option);
    });

    return select;
  }

  /**
   * Format lookup field display value
   */
  async formatLookupValue(column, value) {
    if (!value || !column.lookup) return value;

    const lookupConfig = column.lookup;
    const data = await this.loadLookupData(column.field, lookupConfig);

    const item = data.find(item =>
      item[lookupConfig.valueField || 'id'] == value
    );

    return item ? item[lookupConfig.displayField || 'name'] : value;
  }

  /**
   * Permission System
   */

  /**
   * Set current user context
   */
  setCurrentUser(user) {
    this.currentUser = user;
    this.userPermissions = user.roles || user.permissions || [];
  }

  /**
   * Check if user has permission for action
   */
  hasPermission(action, entry = null) {
    if (!this.config.permissions.enabled) {
      return true;
    }

    const permissions = this.config.permissions;
    const allowedRoles = permissions[action] || [];

    // Check if all users allowed
    if (allowedRoles.includes('*')) {
      return true;
    }

    // Check if user has required role
    const hasRole = this.userPermissions.some(role => allowedRoles.includes(role));
    if (!hasRole) {
      return false;
    }

    // Check own-only restriction
    if (permissions.ownOnly && entry && this.currentUser) {
      return entry.user_id === this.currentUser.id || entry.created_by === this.currentUser.id;
    }

    return true;
  }

  /**
   * Filter data based on permissions
   */
  getPermissionFilteredData() {
    if (!this.config.permissions.enabled || !this.config.permissions.ownOnly) {
      return this.data;
    }

    return this.data.filter(entry => this.hasPermission('view', entry));
  }

  /**
   * State Persistence System
   */

  /**
   * Save current state to storage
   */
  saveState() {
    if (!this.config.state.persist) return;

    const state = {
      filters: this.filters,
      sortField: this.sortField,
      sortOrder: this.sortOrder,
      currentPage: this.currentPage,
      selectedRows: Array.from(this.selectedRows),
      timestamp: Date.now()
    };

    try {
      const storage = this.config.state.storage === 'sessionStorage' ?
        sessionStorage : localStorage;
      storage.setItem(this.config.state.key, JSON.stringify(state));
    } catch (error) {
      console.warn('Failed to save state:', error);
    }
  }

  /**
   * Load state from storage
   */
  loadState() {
    if (!this.config.state.persist) return;

    try {
      const storage = this.config.state.storage === 'sessionStorage' ?
        sessionStorage : localStorage;
      const stateJson = storage.getItem(this.config.state.key);

      if (!stateJson) return;

      const state = JSON.parse(stateJson);

      // Restore state
      this.filters = state.filters || {};
      this.sortField = state.sortField;
      this.sortOrder = state.sortOrder || 'asc';
      this.currentPage = state.currentPage || 1;
      this.selectedRows = new Set(state.selectedRows || []);

    } catch (error) {
      console.warn('Failed to load state:', error);
    }
  }

  /**
   * Clear saved state
   */
  clearState() {
    try {
      const storage = this.config.state.storage === 'sessionStorage' ?
        sessionStorage : localStorage;
      storage.removeItem(this.config.state.key);
    } catch (error) {
      console.warn('Failed to clear state:', error);
    }
  }

  /**
   * Rich Cell Types System
   */

  /**
   * Initialize built-in cell types
   */
  initializeCellTypes() {
    // Register built-in cell types
    this.registerCellType('text', this.createTextEditor.bind(this));
    this.registerCellType('textarea', this.createTextareaEditor.bind(this));
    this.registerCellType('number', this.createNumberEditor.bind(this));
    this.registerCellType('email', this.createEmailEditor.bind(this));
    this.registerCellType('date', this.createDateEditor.bind(this));
    this.registerCellType('datetime', this.createDateTimeEditor.bind(this));
    this.registerCellType('select', this.createSelectEditor.bind(this));
    this.registerCellType('multiselect', this.createMultiSelectEditor.bind(this));
    this.registerCellType('checkbox', this.createCheckboxEditor.bind(this));
    this.registerCellType('radio', this.createRadioEditor.bind(this));
    this.registerCellType('file', this.createFileEditor.bind(this));
    this.registerCellType('url', this.createUrlEditor.bind(this));
    this.registerCellType('color', this.createColorEditor.bind(this));
    this.registerCellType('range', this.createRangeEditor.bind(this));
  }

  /**
   * Register a custom cell type
   */
  registerCellType(type, editorFactory) {
    this.cellTypeRegistry.set(type, editorFactory);
  }

  /**
   * Create rich cell editor based on column type
   */
  async createRichCellEditor(column, currentValue, rowIndex) {
    const editorFactory = this.cellTypeRegistry.get(column.type);
    if (!editorFactory) {
      throw new Error(`Unknown cell type: ${column.type}`);
    }

    return await editorFactory(column, currentValue, rowIndex);
  }

  /**
   * Built-in Cell Type Editors
   */

  createTextEditor(column, currentValue) {
    const input = document.createElement('input');
    input.type = 'text';
    input.value = currentValue || '';
    input.className = 'tc-edit-input tc-text-input';

    if (column.maxLength) input.maxLength = column.maxLength;
    if (column.placeholder) input.placeholder = column.placeholder;

    return input;
  }

  createTextareaEditor(column, currentValue) {
    const textarea = document.createElement('textarea');
    textarea.value = currentValue || '';
    textarea.className = 'tc-edit-textarea';

    const config = this.config.cellTypes.textarea;
    textarea.rows = column.rows || config.rows;

    if (column.maxLength) textarea.maxLength = column.maxLength;
    if (column.placeholder) textarea.placeholder = column.placeholder;

    return textarea;
  }

  createNumberEditor(column, currentValue) {
    const input = document.createElement('input');
    input.type = 'number';
    input.value = currentValue || '';
    input.className = 'tc-edit-input tc-number-input';

    if (column.min !== undefined) input.min = column.min;
    if (column.max !== undefined) input.max = column.max;
    if (column.step !== undefined) input.step = column.step;
    if (column.placeholder) input.placeholder = column.placeholder;

    return input;
  }

  createEmailEditor(column, currentValue) {
    const input = document.createElement('input');
    input.type = 'email';
    input.value = currentValue || '';
    input.className = 'tc-edit-input tc-email-input';

    if (column.placeholder) input.placeholder = column.placeholder;

    return input;
  }

  createDateEditor(column, currentValue) {
    const input = document.createElement('input');
    input.type = 'date';
    input.className = 'tc-edit-input tc-date-input';

    // Format date value for input
    if (currentValue) {
      const date = new Date(currentValue);
      if (!isNaN(date.getTime())) {
        input.value = date.toISOString().split('T')[0];
      }
    }

    if (column.min) input.min = column.min;
    if (column.max) input.max = column.max;

    return input;
  }

  createDateTimeEditor(column, currentValue) {
    const input = document.createElement('input');
    input.type = 'datetime-local';
    input.className = 'tc-edit-input tc-datetime-input';

    // Format datetime value for input
    if (currentValue) {
      const date = new Date(currentValue);
      if (!isNaN(date.getTime())) {
        const offset = date.getTimezoneOffset();
        const localDate = new Date(date.getTime() - (offset * 60 * 1000));
        input.value = localDate.toISOString().slice(0, 16);
      }
    }

    return input;
  }

  createSelectEditor(column, currentValue) {
    const select = document.createElement('select');
    select.className = 'tc-edit-select';

    // Add default option
    if (column.placeholder) {
      const defaultOption = document.createElement('option');
      defaultOption.value = '';
      defaultOption.textContent = column.placeholder;
      defaultOption.disabled = true;
      select.appendChild(defaultOption);
    }

    // Add options
    const options = column.options || [];
    options.forEach(option => {
      const optionElement = document.createElement('option');

      if (typeof option === 'string') {
        optionElement.value = option;
        optionElement.textContent = option;
      } else {
        optionElement.value = option.value;
        optionElement.textContent = option.label || option.value;
      }

      if (optionElement.value === currentValue) {
        optionElement.selected = true;
      }

      select.appendChild(optionElement);
    });

    return select;
  }

  createMultiSelectEditor(column, currentValue) {
    const container = document.createElement('div');
    container.className = 'tc-multiselect-container';

    const selectedValues = Array.isArray(currentValue) ? currentValue :
      (currentValue ? currentValue.split(',') : []);

    const options = column.options || [];
    options.forEach(option => {
      const label = document.createElement('label');
      label.className = 'tc-multiselect-option';

      const checkbox = document.createElement('input');
      checkbox.type = 'checkbox';
      checkbox.className = 'tc-multiselect-checkbox';

      const text = document.createElement('span');

      if (typeof option === 'string') {
        checkbox.value = option;
        text.textContent = option;
        checkbox.checked = selectedValues.includes(option);
      } else {
        checkbox.value = option.value;
        text.textContent = option.label || option.value;
        checkbox.checked = selectedValues.includes(option.value);
      }

      label.appendChild(checkbox);
      label.appendChild(text);
      container.appendChild(label);
    });

    // Add method to get selected values
    container.getValue = function () {
      const checkboxes = this.querySelectorAll('input[type="checkbox"]:checked');
      return Array.from(checkboxes).map(cb => cb.value);
    };

    return container;
  }

  createCheckboxEditor(column, currentValue) {
    const container = document.createElement('div');
    container.className = 'tc-checkbox-container';

    const checkbox = document.createElement('input');
    checkbox.type = 'checkbox';
    checkbox.className = 'tc-edit-checkbox';
    checkbox.checked = this.isTruthy(currentValue);

    if (column.label) {
      const label = document.createElement('label');
      label.className = 'tc-checkbox-label';

      const text = document.createElement('span');
      text.textContent = column.label;

      label.appendChild(checkbox);
      label.appendChild(text);
      container.appendChild(label);
    } else {
      container.appendChild(checkbox);
    }

    // Add method to get value
    container.getValue = function () {
      return this.querySelector('input[type="checkbox"]').checked;
    };

    return container;
  }

  createRadioEditor(column, currentValue) {
    const container = document.createElement('div');
    container.className = 'tc-radio-container';

    const fieldName = `radio_${Date.now()}_${Math.random()}`;
    const options = column.options || [];

    options.forEach(option => {
      const label = document.createElement('label');
      label.className = 'tc-radio-option';

      const radio = document.createElement('input');
      radio.type = 'radio';
      radio.name = fieldName;
      radio.className = 'tc-edit-radio';

      const text = document.createElement('span');

      if (typeof option === 'string') {
        radio.value = option;
        text.textContent = option;
        radio.checked = option === currentValue;
      } else {
        radio.value = option.value;
        text.textContent = option.label || option.value;
        radio.checked = option.value === currentValue;
      }

      label.appendChild(radio);
      label.appendChild(text);
      container.appendChild(label);
    });

    // Add method to get selected value
    container.getValue = function () {
      const selected = this.querySelector('input[type="radio"]:checked');
      return selected ? selected.value : '';
    };

    return container;
  }

  createFileEditor(column, currentValue) {
    const container = document.createElement('div');
    container.className = 'tc-file-container';

    const input = document.createElement('input');
    input.type = 'file';
    input.className = 'tc-edit-file';

    if (column.accept) input.accept = column.accept;
    if (column.multiple) input.multiple = column.multiple;

    // Show current file if exists
    if (currentValue) {
      const preview = document.createElement('div');
      preview.className = 'tc-file-preview';
      preview.textContent = `Current: ${currentValue}`;
      container.appendChild(preview);
    }

    container.appendChild(input);

    // Add method to get value
    container.getValue = function () {
      const fileInput = this.querySelector('input[type="file"]');
      return fileInput.files.length > 0 ? fileInput.files[0].name : currentValue;
    };

    return container;
  }

  createUrlEditor(column, currentValue) {
    const input = document.createElement('input');
    input.type = 'url';
    input.value = currentValue || '';
    input.className = 'tc-edit-input tc-url-input';
    input.placeholder = column.placeholder || 'https://example.com';

    return input;
  }

  createColorEditor(column, currentValue) {
    const container = document.createElement('div');
    container.className = 'tc-color-container';

    const input = document.createElement('input');
    input.type = 'color';
    input.value = currentValue || '#000000';
    input.className = 'tc-edit-color';

    const textInput = document.createElement('input');
    textInput.type = 'text';
    textInput.value = currentValue || '#000000';
    textInput.className = 'tc-color-text';
    textInput.placeholder = '#000000';

    // Sync color picker and text input
    input.addEventListener('change', () => {
      textInput.value = input.value;
    });

    textInput.addEventListener('change', () => {
      if (/^#[0-9A-F]{6}$/i.test(textInput.value)) {
        input.value = textInput.value;
      }
    });

    container.appendChild(input);
    container.appendChild(textInput);

    // Add method to get value
    container.getValue = function () {
      return this.querySelector('.tc-color-text').value;
    };

    return container;
  }

  createRangeEditor(column, currentValue) {
    const container = document.createElement('div');
    container.className = 'tc-range-container';

    const range = document.createElement('input');
    range.type = 'range';
    range.value = currentValue || column.min || 0;
    range.className = 'tc-edit-range';

    if (column.min !== undefined) range.min = column.min;
    if (column.max !== undefined) range.max = column.max;
    if (column.step !== undefined) range.step = column.step;

    const display = document.createElement('span');
    display.className = 'tc-range-display';
    display.textContent = range.value;

    range.addEventListener('input', () => {
      display.textContent = range.value;
    });

    container.appendChild(range);
    container.appendChild(display);

    // Add method to get value
    container.getValue = function () {
      return this.querySelector('input[type="range"]').value;
    };

    return container;
  }

  /**
   * Helper method to determine if a value is truthy for checkboxes
   */
  isTruthy(value) {
    if (typeof value === 'boolean') return value;
    if (typeof value === 'string') {
      return ['true', '1', 'yes', 'on'].includes(value.toLowerCase());
    }
    if (typeof value === 'number') return value !== 0;
    return false;
  }

  /**
   * Data Validation System
   */

  /**
   * Initialize validation rules for columns
   */
  initializeValidation() {
    if (!this.config.validation.enabled) return;

    this.config.columns.forEach(column => {
      if (column.validation) {
        this.validationRules.set(column.field, column.validation);
      }
    });
  }

  /**
   * Validate a single field value
   */
  validateField(field, value, rowData = {}) {
    if (!this.config.validation.enabled) return { isValid: true };

    const rules = this.validationRules.get(field) || this.config.validation.rules[field];
    if (!rules) return { isValid: true };

    const errors = [];

    // Required validation
    if (rules.required && (value === null || value === undefined || value === '')) {
      errors.push(this.getValidationMessage('required', rules));
    }

    // Skip other validations if empty and not required
    if (!rules.required && (value === null || value === undefined || value === '')) {
      return { isValid: true };
    }

    // Email validation
    if (rules.email || rules.type === 'email') {
      const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
      if (!emailRegex.test(value)) {
        errors.push(this.getValidationMessage('email', rules));
      }
    }

    // Min/Max length validation
    if (rules.minLength && value.length < rules.minLength) {
      errors.push(this.getValidationMessage('minLength', rules));
    }
    if (rules.maxLength && value.length > rules.maxLength) {
      errors.push(this.getValidationMessage('maxLength', rules));
    }

    // Min/Max value validation (for numbers)
    if (rules.min !== undefined) {
      const numValue = parseFloat(value);
      if (!isNaN(numValue) && numValue < rules.min) {
        errors.push(this.getValidationMessage('min', rules));
      }
    }
    if (rules.max !== undefined) {
      const numValue = parseFloat(value);
      if (!isNaN(numValue) && numValue > rules.max) {
        errors.push(this.getValidationMessage('max', rules));
      }
    }

    // Pattern validation
    if (rules.pattern) {
      const regex = new RegExp(rules.pattern);
      if (!regex.test(value)) {
        errors.push(this.getValidationMessage('pattern', rules));
      }
    }

    // Custom validation function
    if (rules.custom && typeof rules.custom === 'function') {
      try {
        const result = rules.custom(value, rowData, field);
        if (result !== true) {
          errors.push(typeof result === 'string' ? result : this.getValidationMessage('custom', rules));
        }
      } catch (error) {
        errors.push(this.getValidationMessage('custom', rules));
      }
    }

    return {
      isValid: errors.length === 0,
      errors: errors
    };
  }

  /**
   * Get validation message with parameter substitution
   */
  getValidationMessage(type, rules) {
    let message = rules.message || this.config.validation.messages[type];

    // Substitute parameters
    if (rules.minLength) message = message.replace('{min}', rules.minLength);
    if (rules.maxLength) message = message.replace('{max}', rules.maxLength);
    if (rules.min !== undefined) message = message.replace('{min}', rules.min);
    if (rules.max !== undefined) message = message.replace('{max}', rules.max);

    return message;
  }

  /**
   * Validate entire row
   */
  validateRow(rowData, rowIndex) {
    if (!this.config.validation.enabled) return { isValid: true };

    const errors = {};
    let isValid = true;

    this.config.columns.forEach(column => {
      const validation = this.validateField(column.field, rowData[column.field], rowData);
      if (!validation.isValid) {
        errors[column.field] = validation.errors;
        isValid = false;
      }
    });

    return { isValid, errors };
  }

  /**
   * Show validation error for a cell
   */
  showValidationError(element, errors) {
    if (!this.config.validation.showErrors || !errors || errors.length === 0) return;

    // Remove existing error
    this.clearValidationError(element);

    // Add error class
    element.classList.add('tc-validation-error');

    // Create error tooltip
    const errorTooltip = document.createElement('div');
    errorTooltip.className = 'tc-validation-tooltip';
    errorTooltip.textContent = errors[0]; // Show first error

    // Position tooltip
    const rect = element.getBoundingClientRect();
    errorTooltip.style.position = 'absolute';
    errorTooltip.style.top = (rect.bottom + window.scrollY + 5) + 'px';
    errorTooltip.style.left = (rect.left + window.scrollX) + 'px';
    errorTooltip.style.zIndex = '1000';

    document.body.appendChild(errorTooltip);

    // Store reference for cleanup
    element._validationTooltip = errorTooltip;

    // Auto-hide after 5 seconds
    setTimeout(() => this.clearValidationError(element), 5000);
  }

  /**
   * Clear validation error for a cell
   */
  clearValidationError(element) {
    element.classList.remove('tc-validation-error');

    if (element._validationTooltip) {
      document.body.removeChild(element._validationTooltip);
      delete element._validationTooltip;
    }
  }

  /**
   * Set validation error state for a cell
   */
  setValidationError(rowIndex, field, errors) {
    const key = `${rowIndex}_${field}`;
    if (errors && errors.length > 0) {
      this.validationErrors.set(key, errors);
    } else {
      this.validationErrors.delete(key);
    }
  }

  /**
   * Get validation errors for a cell
   */
  getValidationErrors(rowIndex, field) {
    const key = `${rowIndex}_${field}`;
    return this.validationErrors.get(key) || [];
  }

  /**
   * Clear all validation errors
   */
  clearAllValidationErrors() {
    this.validationErrors.clear();
    // Remove all error classes and tooltips
    const errorElements = this.container.querySelectorAll('.tc-validation-error');
    errorElements.forEach(element => this.clearValidationError(element));
  }

  /**
   * Show validation errors in a form (for Add New modal)
   */
  showFormValidationErrors(form, fieldErrors) {
    // Clear existing errors
    const existingErrors = form.querySelectorAll('.tc-validation-message');
    existingErrors.forEach(error => error.remove());

    const errorFields = form.querySelectorAll('.tc-field-error');
    errorFields.forEach(field => field.classList.remove('tc-field-error'));

    // Show new errors
    Object.keys(fieldErrors).forEach(fieldName => {
      const field = form.querySelector(`[name="${fieldName}"]`);
      if (field) {
        // Add error class to field
        field.classList.add('tc-field-error');

        // Create error message
        const errorMessage = document.createElement('span');
        errorMessage.className = 'tc-validation-message';
        errorMessage.textContent = fieldErrors[fieldName][0]; // Show first error

        // Insert after the field
        field.parentNode.insertBefore(errorMessage, field.nextSibling);
      }
    });
  }

  /**
   * Destroy the table instance
   */
  destroy() {
    // Save final state
    this.saveState();

    // Remove event listeners
    if (this.config.responsive) {
      window.removeEventListener('resize', this.handleResize);
    }

    // Clear container
    this.container.innerHTML = '';

    // Clear data
    this.data = [];
    this.editingCell = null;
    this.selectedRows.clear();
    this.lookupCache.clear();

    // Cleanup dropdowns appended to body
    if (this.dropdowns) {
      this.dropdowns.forEach(dropdown => dropdown.remove());
      this.dropdowns = [];
    }
  }

  // ==================== DATA ATTRIBUTE PARSING ====================

  /**
   * Parse data attributes from container and merge with config
   */
  parseDataAttributes() {
    if (!this.container) return;

    const dataset = this.container.dataset;

    // Parse basic attributes
    if (dataset.source) this.config.data = dataset.source;
    if (dataset.include) this.config.include = dataset.include;
    if (dataset.exclude) this.config.exclude = dataset.exclude;
    if (dataset.root) this.config.root = dataset.root;
    if (dataset.perPage && dataset.perPage !== '0') {
      this.config.pageSize = parseInt(dataset.perPage);
      this.config.pagination = true;
    }
    if (dataset.sort) this.config.sort = dataset.sort;

    // Parse boolean attributes
    if (dataset.search !== undefined) {
      this.config.globalSearch = dataset.search === 'true';
    }
    if (dataset.filters !== undefined) {
      this.config.filterable = dataset.filters === 'true';
    }
    if (dataset.export !== undefined) {
      this.config.exportable = dataset.export === 'true';
    }

    // Parse auto-refresh attributes
    if (dataset.autoRefresh !== undefined) {
      this.config.autoRefresh.enabled = dataset.autoRefresh === 'true';
    }
    if (dataset.refreshInterval) {
      this.config.autoRefresh.interval = parseInt(dataset.refreshInterval);
    }
    if (dataset.refreshIndicator !== undefined) {
      this.config.autoRefresh.showIndicator = dataset.refreshIndicator === 'true';
    }
    if (dataset.refreshCountdown !== undefined) {
      this.config.autoRefresh.showCountdown = dataset.refreshCountdown === 'true';
    }
    if (dataset.refreshLastUpdated !== undefined) {
      this.config.autoRefresh.showLastUpdated = dataset.refreshLastUpdated === 'true';
    }

    TC_DEBUG.log(' Parsed data attributes', {
      autoRefreshEnabled: this.config.autoRefresh.enabled,
      interval: this.config.autoRefresh.interval,
      showIndicator: this.config.autoRefresh.showIndicator
    });
  }

  // ==================== AUTO-REFRESH METHODS ====================

  /**
   * Initialize the Smart Auto-Refresh system
   */
  initializeAutoRefresh() {
    if (!this.dataUrl) {
      console.warn('TableCrafter: Auto-refresh requires a data URL');
      return;
    }

    TC_DEBUG.log(' Initializing Smart Auto-Refresh');
    
    // Create refresh indicator if configured
    if (this.config.autoRefresh.showIndicator) {
      this.createRefreshIndicator();
    }
    
    // Set up interaction detection for smart pausing
    if (this.config.autoRefresh.pauseOnInteraction) {
      this.setupInteractionDetection();
    }
    
    // Set up visibility change detection
    if (this.config.autoRefresh.pauseOnVisibilityChange) {
      this.setupVisibilityDetection();
    }
    
    // Start the refresh cycle
    this.startAutoRefresh();
  }

  /**
   * Create visual refresh indicator
   */
  createRefreshIndicator() {
    this.refreshIndicator = document.createElement('div');
    this.refreshIndicator.className = 'tc-refresh-indicator';
    this.refreshIndicator.innerHTML = `
      <div class="tc-refresh-status">
        <span class="tc-refresh-icon">🔄</span>
        <span class="tc-refresh-text">Auto-refresh active</span>
        ${this.config.autoRefresh.showCountdown ? '<span class="tc-countdown"></span>' : ''}
        ${this.config.autoRefresh.showLastUpdated ? '<span class="tc-last-updated"></span>' : ''}
      </div>
      <button class="tc-refresh-toggle" title="Toggle auto-refresh">⏸️</button>
      <button class="tc-refresh-manual" title="Refresh now">↻</button>
    `;

    // Add styling if not already present
    if (!document.querySelector('#tc-refresh-styles')) {
      const style = document.createElement('style');
      style.id = 'tc-refresh-styles';
      style.textContent = `
        .tc-refresh-indicator {
          position: relative;
          background: #f8fafc;
          border: 1px solid #e2e8f0;
          border-radius: 6px;
          padding: 8px 12px;
          margin-bottom: 16px;
          font-size: 14px;
          display: flex;
          align-items: center;
          justify-content: space-between;
          color: #475569;
        }
        .tc-refresh-status {
          display: flex;
          align-items: center;
          gap: 8px;
        }
        .tc-refresh-icon {
          display: inline-block;
          animation: tc-spin 2s linear infinite;
        }
        .tc-refresh-indicator.paused .tc-refresh-icon {
          animation: none;
          opacity: 0.5;
        }
        .tc-refresh-toggle, .tc-refresh-manual {
          background: none;
          border: none;
          padding: 4px 8px;
          border-radius: 4px;
          cursor: pointer;
          font-size: 16px;
          margin-left: 4px;
        }
        .tc-refresh-toggle:hover, .tc-refresh-manual:hover {
          background: #e2e8f0;
        }
        .tc-countdown {
          font-weight: 600;
          color: #3b82f6;
        }
        .tc-last-updated {
          color: #64748b;
          font-size: 12px;
        }
        @keyframes tc-spin {
          from { transform: rotate(0deg); }
          to { transform: rotate(360deg); }
        }
      `;
      document.head.appendChild(style);
    }

    // Insert before table
    this.container.insertBefore(this.refreshIndicator, this.container.firstChild);

    // Add event listeners
    const toggleBtn = this.refreshIndicator.querySelector('.tc-refresh-toggle');
    const manualBtn = this.refreshIndicator.querySelector('.tc-refresh-manual');
    
    toggleBtn?.addEventListener('click', () => this.toggleAutoRefresh());
    manualBtn?.addEventListener('click', () => this.refreshNow());

    this.updateRefreshIndicator();
  }

  /**
   * Update refresh indicator display
   */
  updateRefreshIndicator() {
    if (!this.refreshIndicator) return;

    const icon = this.refreshIndicator.querySelector('.tc-refresh-icon');
    const text = this.refreshIndicator.querySelector('.tc-refresh-text');
    const countdown = this.refreshIndicator.querySelector('.tc-countdown');
    const lastUpdated = this.refreshIndicator.querySelector('.tc-last-updated');
    const toggle = this.refreshIndicator.querySelector('.tc-refresh-toggle');

    // Update status
    if (this.isPaused) {
      this.refreshIndicator.classList.add('paused');
      text.textContent = 'Auto-refresh paused';
      toggle.textContent = '▶️';
      toggle.title = 'Resume auto-refresh';
    } else {
      this.refreshIndicator.classList.remove('paused');
      text.textContent = 'Auto-refresh active';
      toggle.textContent = '⏸️';
      toggle.title = 'Pause auto-refresh';
    }

    // Update last updated
    if (lastUpdated && this.lastRefresh) {
      const timeAgo = this.formatTimeAgo(this.lastRefresh);
      lastUpdated.textContent = `Updated ${timeAgo}`;
    }
  }

  /**
   * Set up interaction detection for smart pausing
   */
  setupInteractionDetection() {
    const events = ['mouseenter', 'mousemove', 'click', 'scroll', 'keydown'];
    
    const handleInteraction = () => {
      if (!this.userIsInteracting) {
        this.userIsInteracting = true;
        if (!this.isPaused) {
          this.pauseAutoRefresh(true); // Smart pause
        }
      }

      // Reset interaction timeout
      clearTimeout(this.interactionTimeout);
      this.interactionTimeout = setTimeout(() => {
        this.userIsInteracting = false;
        if (this.isPaused) {
          this.resumeAutoRefresh(true); // Smart resume
        }
      }, 5000); // Resume after 5 seconds of inactivity
    };

    events.forEach(event => {
      this.container.addEventListener(event, handleInteraction, { passive: true });
    });
  }

  /**
   * Set up visibility change detection
   */
  setupVisibilityDetection() {
    document.addEventListener('visibilitychange', () => {
      if (document.hidden) {
        this.pauseAutoRefresh(true);
      } else {
        this.resumeAutoRefresh(true);
      }
    });
  }

  /**
   * Start auto-refresh cycle
   */
  startAutoRefresh() {
    if (this.refreshInterval) {
      clearInterval(this.refreshInterval);
    }

    this.lastRefresh = new Date();
    this.nextRefresh = new Date(Date.now() + this.config.autoRefresh.interval);
    this.refreshAttempts = 0;
    
    this.refreshInterval = setInterval(() => {
      if (!this.isPaused) {
        this.performRefresh();
      }
    }, this.config.autoRefresh.interval);

    // Start countdown if enabled
    if (this.config.autoRefresh.showCountdown) {
      this.startCountdown();
    }

    this.updateRefreshIndicator();
  }

  /**
   * Stop auto-refresh
   */
  stopAutoRefresh() {
    if (this.refreshInterval) {
      clearInterval(this.refreshInterval);
      this.refreshInterval = null;
    }
    if (this.countdownInterval) {
      clearInterval(this.countdownInterval);
      this.countdownInterval = null;
    }
    this.isPaused = false;
    this.updateRefreshIndicator();
  }

  /**
   * Pause auto-refresh
   */
  pauseAutoRefresh(smart = false) {
    this.isPaused = true;
    if (this.countdownInterval) {
      clearInterval(this.countdownInterval);
      this.countdownInterval = null;
    }
    this.updateRefreshIndicator();
    
    if (!smart) {
      TC_DEBUG.log(' Auto-refresh paused manually');
    }
  }

  /**
   * Resume auto-refresh
   */
  resumeAutoRefresh(smart = false) {
    this.isPaused = false;
    if (this.config.autoRefresh.showCountdown) {
      this.startCountdown();
    }
    this.updateRefreshIndicator();
    
    if (!smart) {
      TC_DEBUG.log(' Auto-refresh resumed manually');
    }
  }

  /**
   * Toggle auto-refresh state
   */
  toggleAutoRefresh() {
    if (this.isPaused) {
      this.resumeAutoRefresh();
    } else {
      this.pauseAutoRefresh();
    }
  }

  /**
   * Manually trigger refresh
   */
  refreshNow() {
    TC_DEBUG.log(' Manual refresh triggered');
    this.performRefresh();
    
    // Reset the interval
    this.startAutoRefresh();
  }

  /**
   * Perform the actual data refresh
   */
  async performRefresh() {
    TC_DEBUG.log(' Performing auto-refresh');
    
    try {
      // Store current state before refresh
      const currentPage = this.currentPage;
      const currentFilters = {...this.filters};
      const currentSearch = this.searchTerm;
      const currentSort = { field: this.sortField, order: this.sortOrder };

      // Fetch fresh data
      await this.loadData(true); // Pass true to indicate this is a refresh

      // Restore user state
      this.currentPage = currentPage;
      this.filters = currentFilters;
      this.searchTerm = currentSearch;
      this.sortField = currentSort.field;
      this.sortOrder = currentSort.order;

      // Re-render with preserved state
      this.render();

      // Update refresh tracking
      this.lastRefresh = new Date();
      this.nextRefresh = new Date(Date.now() + this.config.autoRefresh.interval);
      this.refreshAttempts = 0;
      
      this.updateRefreshIndicator();
      TC_DEBUG.log(' Auto-refresh completed successfully');

    } catch (error) {
      console.error('TableCrafter: Auto-refresh failed', error);
      this.refreshAttempts++;

      if (this.config.autoRefresh.retryOnFailure && 
          this.refreshAttempts < this.config.autoRefresh.maxRetries) {
        TC_DEBUG.log(`Retrying refresh (${this.refreshAttempts}/${this.config.autoRefresh.maxRetries})`);
        
        // Exponential backoff: retry after 2^attempt seconds
        const retryDelay = Math.pow(2, this.refreshAttempts) * 1000;
        setTimeout(() => this.performRefresh(), retryDelay);
      } else {
        console.error('TableCrafter: Auto-refresh failed after max retries, stopping auto-refresh');
        this.stopAutoRefresh();
      }
    }
  }

  /**
   * Start countdown display
   */
  startCountdown() {
    if (this.countdownInterval) {
      clearInterval(this.countdownInterval);
    }

    this.countdownInterval = setInterval(() => {
      if (this.isPaused) return;

      const countdown = this.refreshIndicator?.querySelector('.tc-countdown');
      if (countdown && this.nextRefresh) {
        const remaining = Math.max(0, this.nextRefresh.getTime() - Date.now());
        const seconds = Math.ceil(remaining / 1000);
        
        if (seconds > 0) {
          countdown.textContent = `Next: ${this.formatDuration(seconds * 1000)}`;
        } else {
          countdown.textContent = 'Refreshing...';
        }
      }
    }, 1000);
  }

  /**
   * Format time duration for display
   */
  formatDuration(ms) {
    const seconds = Math.floor(ms / 1000);
    const minutes = Math.floor(seconds / 60);
    const hours = Math.floor(minutes / 60);

    if (hours > 0) {
      return `${hours}h ${minutes % 60}m`;
    } else if (minutes > 0) {
      return `${minutes}m ${seconds % 60}s`;
    } else {
      return `${seconds}s`;
    }
  }

  /**
   * Format time ago for display
   */
  formatTimeAgo(date) {
    const now = new Date();
    const diff = now - date;
    const seconds = Math.floor(diff / 1000);
    const minutes = Math.floor(seconds / 60);
    const hours = Math.floor(minutes / 60);

    if (hours > 0) {
      return `${hours}h ago`;
    } else if (minutes > 0) {
      return `${minutes}m ago`;
    } else {
      return 'just now';
    }
  }

  /**
   * Clean up auto-refresh when instance is destroyed
   */
  destroyAutoRefresh() {
    this.stopAutoRefresh();
    
    if (this.refreshIndicator) {
      this.refreshIndicator.remove();
      this.refreshIndicator = null;
    }
    
    if (this.interactionTimeout) {
      clearTimeout(this.interactionTimeout);
    }
    
    TC_DEBUG.log(' Auto-refresh destroyed');
  }

  /**
   * ===== ACCESSIBILITY SYSTEM =====
   * Comprehensive WCAG 2.1 compliance implementation
   */

  /**
   * Initialize accessibility features
   */
  initializeAccessibility() {
    if (!this.config.accessibility.enabled) return;

    // Create screen reader announcer
    this.createAccessibilityAnnouncer();

    // Detect user preferences
    this.detectAccessibilityPreferences();

    // Initialize keyboard navigation
    if (this.config.accessibility.keyboardNavigation) {
      this.initializeKeyboardNavigation();
    }

    // Set up focus management
    if (this.config.accessibility.focusManagement) {
      this.setupFocusManagement();
    }

    TC_DEBUG.log(' Accessibility features initialized');
  }

  /**
   * Create invisible ARIA live region for screen reader announcements
   */
  createAccessibilityAnnouncer() {
    const announcer = document.createElement('div');
    announcer.id = `tc-announcer-${Date.now()}`;
    announcer.className = 'tc-sr-only';
    announcer.setAttribute('aria-live', this.config.accessibility.announcer.politeness);
    announcer.setAttribute('aria-atomic', 'true');
    announcer.style.cssText = `
      position: absolute !important;
      width: 1px !important;
      height: 1px !important;
      padding: 0 !important;
      margin: -1px !important;
      overflow: hidden !important;
      clip: rect(0, 0, 0, 0) !important;
      white-space: nowrap !important;
      border: 0 !important;
    `;
    
    document.body.appendChild(announcer);
    this.announcer = announcer;
  }

  /**
   * Announce text to screen readers
   */
  announce(message, priority = 'polite') {
    if (!this.config.accessibility.announcements || !this.announcer) return;

    // Clear previous announcement
    this.announcer.textContent = '';
    
    // Set priority
    this.announcer.setAttribute('aria-live', priority);
    
    // Announce with slight delay to ensure it's heard
    setTimeout(() => {
      this.announcer.textContent = message;
    }, this.config.accessibility.announcer.delay);
  }

  /**
   * Detect user accessibility preferences
   */
  detectAccessibilityPreferences() {
    // Detect reduced motion preference
    if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) {
      this.config.accessibility.reducedMotion = true;
      this.container.classList.add('tc-reduced-motion');
    }

    // Detect high contrast preference
    if (window.matchMedia('(prefers-contrast: high)').matches) {
      this.config.accessibility.highContrast = true;
      this.container.classList.add('tc-high-contrast');
    }

    // Listen for changes
    window.matchMedia('(prefers-reduced-motion: reduce)').addEventListener('change', (e) => {
      this.config.accessibility.reducedMotion = e.matches;
      this.container.classList.toggle('tc-reduced-motion', e.matches);
    });

    window.matchMedia('(prefers-contrast: high)').addEventListener('change', (e) => {
      this.config.accessibility.highContrast = e.matches;
      this.container.classList.toggle('tc-high-contrast', e.matches);
    });
  }

  /**
   * Initialize comprehensive keyboard navigation
   */
  initializeKeyboardNavigation() {
    this.container.addEventListener('keydown', (e) => {
      this.handleKeyboardNavigation(e);
    });

    // Make container focusable for keyboard entry
    if (this.config.accessibility.keyboard.tabIndex) {
      this.container.setAttribute('tabindex', '0');
    }
  }

  /**
   * Handle keyboard navigation events
   */
  handleKeyboardNavigation(e) {
    if (!this.config.accessibility.keyboard.navigation) return;

    const focusableElements = this.getFocusableElements();
    const currentIndex = Array.from(focusableElements).indexOf(document.activeElement);

    switch (e.key) {
      case 'Tab':
        // Let default tab behavior handle most cases
        this.handleTabNavigation(e, focusableElements, currentIndex);
        break;
      
      case 'ArrowDown':
      case 'ArrowUp':
        if (this.isInTable(e.target)) {
          this.handleArrowNavigation(e, 'vertical');
        }
        break;
      
      case 'ArrowLeft':
      case 'ArrowRight':
        if (this.isInTable(e.target)) {
          this.handleArrowNavigation(e, 'horizontal');
        }
        break;
      
      case 'Home':
        if (this.isInTable(e.target)) {
          e.preventDefault();
          this.focusFirstCellInRow();
        }
        break;
      
      case 'End':
        if (this.isInTable(e.target)) {
          e.preventDefault();
          this.focusLastCellInRow();
        }
        break;
      
      case 'PageUp':
        if (e.target.closest('.tc-pagination')) {
          e.preventDefault();
          this.goToPreviousPage();
        }
        break;
      
      case 'PageDown':
        if (e.target.closest('.tc-pagination')) {
          e.preventDefault();
          this.goToNextPage();
        }
        break;
      
      case 'Escape':
        this.handleEscapeKey(e);
        break;
      
      case 'Enter':
      case ' ':
        this.handleActivationKey(e);
        break;
      
      case 'f':
        if (e.ctrlKey || e.metaKey) {
          e.preventDefault();
          this.focusSearchInput();
        }
        break;
    }
  }

  /**
   * Get all focusable elements in the table
   */
  getFocusableElements() {
    const selector = `
      input:not([disabled]),
      button:not([disabled]),
      select:not([disabled]),
      textarea:not([disabled]),
      a[href],
      [tabindex]:not([tabindex="-1"]),
      .tc-sortable,
      .tc-editable
    `;
    return this.container.querySelectorAll(selector);
  }

  /**
   * Check if element is within the table
   */
  isInTable(element) {
    return element.closest('.tc-table') !== null;
  }

  /**
   * Handle arrow key navigation within table cells
   */
  handleArrowNavigation(e, direction) {
    e.preventDefault();
    
    const currentCell = e.target.closest('td, th');
    if (!currentCell) return;

    let targetCell = null;

    if (direction === 'vertical') {
      const row = currentCell.closest('tr');
      const cellIndex = Array.from(row.children).indexOf(currentCell);
      
      if (e.key === 'ArrowDown') {
        const nextRow = row.nextElementSibling;
        if (nextRow) {
          targetCell = nextRow.children[cellIndex];
        }
      } else { // ArrowUp
        const prevRow = row.previousElementSibling;
        if (prevRow) {
          targetCell = prevRow.children[cellIndex];
        }
      }
    } else { // horizontal
      if (e.key === 'ArrowRight') {
        targetCell = currentCell.nextElementSibling;
      } else { // ArrowLeft
        targetCell = currentCell.previousElementSibling;
      }
    }

    if (targetCell) {
      this.focusCell(targetCell);
    }
  }

  /**
   * Focus a table cell properly
   */
  focusCell(cell) {
    // If cell is editable, focus it directly
    if (cell.classList.contains('tc-editable') || cell.hasAttribute('tabindex')) {
      cell.focus();
    } else {
      // Find focusable element within cell
      const focusable = cell.querySelector('input, button, select, textarea, a[href], [tabindex]:not([tabindex="-1"])');
      if (focusable) {
        focusable.focus();
      } else {
        // Make cell temporarily focusable
        cell.setAttribute('tabindex', '0');
        cell.focus();
        cell.addEventListener('blur', () => {
          cell.removeAttribute('tabindex');
        }, { once: true });
      }
    }
  }

  /**
   * Focus first cell in current row
   */
  focusFirstCellInRow() {
    const currentCell = document.activeElement.closest('td, th');
    if (!currentCell) return;
    
    const row = currentCell.closest('tr');
    const firstCell = row.querySelector('td, th');
    if (firstCell) {
      this.focusCell(firstCell);
    }
  }

  /**
   * Focus last cell in current row
   */
  focusLastCellInRow() {
    const currentCell = document.activeElement.closest('td, th');
    if (!currentCell) return;
    
    const row = currentCell.closest('tr');
    const cells = row.querySelectorAll('td, th');
    const lastCell = cells[cells.length - 1];
    if (lastCell) {
      this.focusCell(lastCell);
    }
  }

  /**
   * Handle escape key for canceling operations
   */
  handleEscapeKey(e) {
    // Cancel editing
    if (this.editingCell) {
      this.cancelEdit();
      e.preventDefault();
    }
    
    // Close modals
    const modal = this.container.querySelector('.tc-modal.open');
    if (modal) {
      this.closeModal();
      e.preventDefault();
    }
    
    // Clear search
    if (e.target.matches('.tc-search-input')) {
      e.target.value = '';
      this.handleSearch();
      e.preventDefault();
    }
  }

  /**
   * Handle Enter/Space activation keys
   */
  handleActivationKey(e) {
    const target = e.target;
    
    // Sort headers
    if (target.classList.contains('tc-sortable')) {
      e.preventDefault();
      this.sort(target.dataset.field);
      return;
    }
    
    // Edit cells
    if (target.classList.contains('tc-editable')) {
      e.preventDefault();
      this.startEdit(target);
      return;
    }
    
    // Pagination buttons
    if (target.closest('.tc-pagination-btn')) {
      e.preventDefault();
      target.click();
      return;
    }
  }

  /**
   * Focus the search input
   */
  focusSearchInput() {
    const searchInput = this.container.querySelector('.tc-search-input');
    if (searchInput) {
      searchInput.focus();
      this.announce('Search focused');
    }
  }

  /**
   * Set up focus management
   */
  setupFocusManagement() {
    // Track focus for better accessibility
    this.container.addEventListener('focusin', (e) => {
      this.handleFocusIn(e);
    });
    
    this.container.addEventListener('focusout', (e) => {
      this.handleFocusOut(e);
    });
  }

  /**
   * Handle focus entering elements
   */
  handleFocusIn(e) {
    const target = e.target;
    
    // Add visual focus indicator
    target.classList.add('tc-focused');
    
    // Announce context for screen readers
    if (target.classList.contains('tc-sortable')) {
      const column = target.textContent;
      const sortState = target.getAttribute('aria-sort');
      const message = `${column} column header, ${sortState === 'none' ? 'not sorted' : sortState}. Press Enter or Space to sort.`;
      this.announce(message);
    }
    
    if (target.classList.contains('tc-editable')) {
      this.announce('Editable cell. Press Enter or Space to edit.');
    }
  }

  /**
   * Handle focus leaving elements
   */
  handleFocusOut(e) {
    const target = e.target;
    target.classList.remove('tc-focused');
  }

  /**
   * Enhance table with accessibility attributes
   */
  enhanceTableAccessibility(table) {
    // Add table role and description
    table.setAttribute('role', 'table');
    table.setAttribute('aria-label', this.config.accessibility.labels.table);
    
    // Add table summary if we have data
    if (this.data.length > 0) {
      const summary = `Table with ${this.data.length} rows and ${this.config.columns.length} columns. ${this.config.sortable ? 'Sortable columns available.' : ''} ${this.config.globalSearch ? 'Search available.' : ''}`;
      table.setAttribute('aria-describedby', this.createTableDescription(summary));
    }
    
    // Enhance headers
    const headers = table.querySelectorAll('th');
    headers.forEach((th, index) => {
      th.setAttribute('scope', 'col');
      th.setAttribute('role', 'columnheader');
      
      if (th.classList.contains('tc-sortable')) {
        const column = this.config.columns[index];
        const sortLabel = this.config.accessibility.labels.sort.replace('{column}', column.label);
        th.setAttribute('aria-label', sortLabel);
        th.setAttribute('title', sortLabel);
      }
    });
    
    // Enhance data cells
    const cells = table.querySelectorAll('td');
    cells.forEach(cell => {
      cell.setAttribute('role', 'gridcell');
      
      if (cell.classList.contains('tc-editable')) {
        cell.setAttribute('aria-label', this.config.accessibility.labels.edit);
        cell.setAttribute('tabindex', '0');
      }
    });
  }

  /**
   * Create table description element
   */
  createTableDescription(text) {
    const id = `tc-table-desc-${Date.now()}`;
    const desc = document.createElement('div');
    desc.id = id;
    desc.className = 'tc-sr-only';
    desc.textContent = text;
    desc.style.cssText = `
      position: absolute !important;
      width: 1px !important;
      height: 1px !important;
      padding: 0 !important;
      margin: -1px !important;
      overflow: hidden !important;
      clip: rect(0, 0, 0, 0) !important;
      white-space: nowrap !important;
      border: 0 !important;
    `;
    
    this.container.appendChild(desc);
    return id;
  }

  /**
   * Enhance pagination with accessibility
   */
  enhancePaginationAccessibility(pagination) {
    pagination.setAttribute('role', 'navigation');
    pagination.setAttribute('aria-label', this.config.accessibility.labels.pagination);
    
    const buttons = pagination.querySelectorAll('button, a');
    buttons.forEach(button => {
      const page = button.dataset.page;
      if (page) {
        button.setAttribute('aria-label', `Go to page ${page}`);
      }
      
      if (button.classList.contains('tc-pagination-current')) {
        button.setAttribute('aria-current', 'page');
      }
    });
  }

  /**
   * Enhance search with accessibility
   */
  enhanceSearchAccessibility(searchContainer) {
    const input = searchContainer.querySelector('input');
    if (input) {
      input.setAttribute('aria-label', this.config.accessibility.labels.search);
      input.setAttribute('role', 'searchbox');
      
      // Add search results announcement
      input.addEventListener('input', () => {
        clearTimeout(this.searchAnnounceTimeout);
        this.searchAnnounceTimeout = setTimeout(() => {
          const resultCount = this.getFilteredData().length;
          this.announce(`${resultCount} results found`);
        }, 500);
      });
    }
  }

  /**
   * Announce data changes
   */
  announceDataChange(type, count = null) {
    if (!this.config.accessibility.announcements) return;

    let message = '';
    switch (type) {
      case 'loaded':
        message = `Table data loaded. ${count || this.data.length} rows available.`;
        break;
      case 'sorted':
        message = `Table sorted by ${this.sortField}, ${this.sortOrder}ending order.`;
        break;
      case 'filtered':
        message = `Table filtered. ${count} rows shown.`;
        break;
      case 'page-changed':
        message = `Page ${this.currentPage} of ${this.getTotalPages()} loaded.`;
        break;
      case 'editing':
        message = 'Editing mode activated.';
        break;
      case 'edit-cancelled':
        message = 'Edit cancelled.';
        break;
      case 'edit-saved':
        message = 'Changes saved.';
        break;
      case 'error':
        message = 'An error occurred. Please try again.';
        break;
    }

    if (message) {
      this.announce(message);
    }
  }

  /**
   * Clean up accessibility features
   */
  destroyAccessibility() {
    if (this.announcer) {
      this.announcer.remove();
      this.announcer = null;
    }
    
    if (this.searchAnnounceTimeout) {
      clearTimeout(this.searchAnnounceTimeout);
    }
    
    // Remove accessibility event listeners
    this.container.removeEventListener('keydown', this.handleKeyboardNavigation);
    this.container.removeEventListener('focusin', this.handleFocusIn);
    this.container.removeEventListener('focusout', this.handleFocusOut);
  }
}

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

if (typeof define === 'function' && define.amd) {
  define([], function () {
    return TableCrafter;
  });
}

if (typeof window !== 'undefined') {
  window.TableCrafter = TableCrafter;
}