/**
 * RSL JSON Layout Engine v2.0 - Enhanced Edition
 *
 * A massively powerful, developer-friendly JSON-driven layout system that makes
 * building complex responsive layouts incredibly easy while maintaining full
 * backward compatibility with v1.
 *
 * @fileoverview Enhanced JSON Layout Engine with advanced features
 * @version 2.0.0
 * @license MIT
 *
 * NEW FEATURES IN V2:
 * ==================
 *
 * 🎨 Enhanced Content Types:
 *    - card: Beautiful card layouts with image, title, body, footer
 *    - image: Responsive images with lazy loading, srcset support
 *    - button: Styled buttons with variants and icons
 *    - link: Styled links and CTA elements
 *    - heading: Semantic headings (h1-h6)
 *    - paragraph: Text paragraphs with styling
 *    - list: Ordered/unordered lists
 *    - table: Data tables from JSON
 *    - icon: FontAwesome/icon font support
 *    - badge: Inline badges and tags
 *    - alert: Alert/notification boxes
 *    - divider: Visual separators
 *    - spacer: Flexible spacing control
 *
 * 🎮 Interactive Component Wrappers (v1 components with v2 syntax):
 *    - select: Custom select dropdowns with search and multi-select
 *    - modal: Dialog windows and overlays
 *    - tooltip: Contextual tooltips and popovers
 *
 * 🔄 Template System:
 *    - Render arrays of data with templates
 *    - Loop through items with automatic ID generation
 *    - Data binding and interpolation
 *
 * 🎭 Conditional Rendering:
 *    - Show/hide content based on conditions
 *    - Expression evaluation
 *    - Dynamic visibility
 *
 * 🏗️ Component Presets:
 *    - hero: Hero/banner sections
 *    - features: Feature grid layouts
 *    - pricing: Pricing tables
 *    - testimonials: Testimonial cards
 *    - gallery: Image galleries
 *    - stats: Statistic displays
 *    - cta: Call-to-action sections
 *    - team: Team member cards
 *
 * 🎨 Enhanced Styling:
 *    - Inline styles support
 *    - Utility classes
 *    - Spacing utilities (margin, padding)
 *    - Alignment options
 *    - Responsive visibility
 *    - Background/border options
 *
 * 📦 Nested Layouts:
 *    - Nest grids within items
 *    - Infinite nesting support
 *    - Isolated breakpoints
 *
 * 🎨 Named Grid Areas:
 *    - Custom grid-template-areas via JSON
 *    - Responsive area definitions
 *    - Dynamic column/row sizing
 *    - Area-based item placement
 *
 * 🎯 Event Handlers:
 *    - onClick handlers
 *    - Custom events
 *    - Event delegation
 *
 * ✨ Developer Experience:
 *    - Better error messages
 *    - Helpful warnings
 *    - Auto-completion friendly
 *    - Extensive examples
 *
 * BACKWARD COMPATIBILITY:
 * ======================
 * All v1 configurations work exactly as before!
 * New features are opt-in and don't affect existing code.
 *
 * QUICK START:
 * ============
 *
 * // Simple card grid
 * RSL.JSONLayout.renderLayout('#container', {
 *   version: 2,
 *   layoutId: "products",
 *   breakpoints: { xs: 1, md: 2, lg: 3 },
 *   template: {
 *     data: products,
 *     item: {
 *       content: {
 *         type: "card",
 *         image: "{{image}}",
 *         title: "{{name}}",
 *         text: "{{description}}",
 *         price: "${{price}}",
 *         button: { text: "Buy Now", variant: "primary" }
 *       }
 *     }
 *   }
 * });
 *
 * // Component preset
 * RSL.JSONLayout.renderPreset('#hero', 'hero', {
 *   title: "Welcome to Our Site",
 *   subtitle: "The best solution for your needs",
 *   image: "hero.jpg",
 *   buttons: [
 *     { text: "Get Started", variant: "primary", href: "#" },
 *     { text: "Learn More", variant: "secondary", href: "#about" }
 *   ]
 * });
 *
 * // Custom grid areas layout
 * RSL.JSONLayout.renderLayout('#app', {
 *   version: 2,
 *   layoutId: "app-layout",
 *   gridAreas: {
 *     xs: {
 *       areas: [["header"], ["nav"], ["main"], ["footer"]],
 *       columns: "1fr",
 *       rows: "auto auto 1fr auto"
 *     },
 *     md: {
 *       areas: [["header", "header"], ["nav", "main"], ["footer", "footer"]],
 *       columns: "200px 1fr",
 *       rows: "auto 1fr auto"
 *     }
 *   },
 *   items: [
 *     { area: "header", content: { type: "heading", text: "My App" } },
 *     { area: "nav", content: { type: "html", value: "Nav..." } },
 *     { area: "main", content: { type: "html", value: "Main content" } },
 *     { area: "footer", content: { type: "text", value: "Footer" } }
 *   ]
 * });
 */

(function() {
    'use strict';

    /**
     * Schema versions supported
     */
    const SCHEMA_VERSIONS = [1, 2];
    const CURRENT_VERSION = 2;

    /**
     * Enhanced JSONLayoutEngine
     */
    class JSONLayoutEngineV2 {
        constructor() {
            // Bind methods
            this.validateSchema = this.validateSchema.bind(this);
            this.renderLayout = this.renderLayout.bind(this);
            this.renderPreset = this.renderPreset.bind(this);
            this.buildFromDOM = this.buildFromDOM.bind(this);
            this.convertHTMLtoJSON = this.convertHTMLtoJSON.bind(this);
            this.updateLayoutFromJSON = this.updateLayoutFromJSON.bind(this);

            // Counters for unique IDs
            this._iframeCounter = 0;

            // Content type renderers
            this.contentRenderers = this._initContentRenderers();

            // Component presets
            this.presets = this._initPresets();

            // Global event handlers registry
            this.eventHandlers = new Map();
        }

        /**
         * Initialize content type renderers
         * @private
         */
        _initContentRenderers() {
            return {
                // V1 types (backward compatible)
                'html': this._renderHTML.bind(this),
                'text': this._renderText.bind(this),
                'slot': this._renderSlot.bind(this),
                'component': this._renderComponent.bind(this),

                // V2 enhanced types
                'card': this._renderCard.bind(this),
                'image': this._renderImage.bind(this),
                'thumbnail': this._renderThumbnail.bind(this),
                'button': this._renderButton.bind(this),
                'link': this._renderLink.bind(this),
                'heading': this._renderHeading.bind(this),
                'paragraph': this._renderParagraph.bind(this),
                'list': this._renderList.bind(this),
                'table': this._renderTable.bind(this),
                'icon': this._renderIcon.bind(this),
                'badge': this._renderBadge.bind(this),
                'progress': this._renderProgress.bind(this),
                'alert': this._renderAlert.bind(this),
                'divider': this._renderDivider.bind(this),
                'spacer': this._renderSpacer.bind(this),
                'grid': this._renderNestedGrid.bind(this),
                'balanced': this._renderBalanced.bind(this),

                // V2 interactive component wrappers (use v1 components)
                'select': this._renderSelect.bind(this),
                'modal': this._renderModal.bind(this),
                'tooltip': this._renderTooltip.bind(this),
                'popover': this._renderPopover.bind(this),
                'accordion': this._renderAccordion.bind(this),
                'tabs': this._renderTabs.bind(this),
                'alertButton': this._renderAlertButton.bind(this),
                'confirmButton': this._renderConfirmButton.bind(this),
                'promptButton': this._renderPromptButton.bind(this),
                'navbar': this._renderNavbar.bind(this),
                'pagination': this._renderPagination.bind(this),
                'sidebar': this._renderSidebar.bind(this),
                'toast': this._renderToast.bind(this),
                'carousel': this._renderCarousel.bind(this),
                'offcanvas': this._renderOffCanvas.bind(this),
                'breadcrumb': this._renderBreadcrumb.bind(this),
                'skeleton': this._renderSkeleton.bind(this),
                'form': this._renderForm.bind(this),
                'inlayAlert': this._renderInlayAlert.bind(this),
                'iframe': this._renderIframe.bind(this),
                'image': this._renderImage.bind(this),
                'gallery': this._renderGallery.bind(this),
                'chart': this._renderChart.bind(this),
                'kpi': this._renderKPI.bind(this),
                'stat': this._renderStat.bind(this),
                'stats': this._renderStats.bind(this),
                'gantt': this._renderGantt.bind(this),
                'smart-table': this._renderSmartTable.bind(this),
                'datepicker': this._renderDatePicker.bind(this),
                'timepicker': this._renderTimePicker.bind(this),
                'filter': this._renderFilter.bind(this),
                'calendar': this._renderCalendar.bind(this),
                'hero': this._renderHero.bind(this),
                'announcements': this._renderAnnouncements.bind(this),
                'iconpicker': this._renderIconPicker.bind(this),
                'star-rating': this._renderStarRating.bind(this),
                'star-rating-filter': this._renderStarRatingFilter.bind(this),
                'testimonial': this._renderTestimonial.bind(this),
                'pricing-table': this._renderPricingTable.bind(this),
                'video-player': this._renderVideoPlayer.bind(this),
                'loader': this._renderLoader.bind(this),
                'sticky': this._renderSticky.bind(this),
                'timeline': this._renderTimeline.bind(this)
            };
        }

        /**
         * Initialize component presets
         * @private
         */
        _initPresets() {
            return {
                'hero': this._presetHero.bind(this),
                'features': this._presetFeatures.bind(this),
                'pricing': this._presetPricing.bind(this),
                'testimonials': this._presetTestimonials.bind(this),
                'gallery': this._presetGallery.bind(this),
                'stats': this._presetStats.bind(this),
                'cta': this._presetCTA.bind(this),
                'team': this._presetTeam.bind(this)
            };
        }

        /**
         * Validate JSON configuration
         * Supports both v1 and v2 schemas
         */
        validateSchema(config) {
            const errors = [];
            const warnings = [];

            if (!config || typeof config !== 'object') {
                return {
                    valid: false,
                    errors: ['Configuration must be an object'],
                    warnings: []
                };
            }

            // Version check
            const version = config.version || 1;
            if (!SCHEMA_VERSIONS.includes(version)) {
                errors.push(`Unsupported schema version: ${version}. Supported: ${SCHEMA_VERSIONS.join(', ')}`);
            }

            // Check for template (v2 feature)
            if (config.template) {
                if (!config.template.data) {
                    errors.push('Template must have a "data" array');
                }
                if (!config.template.item) {
                    errors.push('Template must have an "item" configuration');
                }
                // When using templates, items array is optional
                if (!config.items && !config.template) {
                    warnings.push('Neither "items" nor "template" provided');
                }
            } else if (config.gridAreas) {
                // Validate gridAreas configuration (v2 feature)
                const validBreakpoints = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
                const gridAreaBreakpoints = Object.keys(config.gridAreas);

                if (gridAreaBreakpoints.length === 0) {
                    errors.push('gridAreas must define at least one breakpoint');
                }

                gridAreaBreakpoints.forEach(bp => {
                    if (!validBreakpoints.includes(bp)) {
                        warnings.push(`Unknown gridAreas breakpoint: ${bp}. Valid: ${validBreakpoints.join(', ')}`);
                    }

                    const areaConfig = config.gridAreas[bp];

                    if (!areaConfig.areas || !Array.isArray(areaConfig.areas)) {
                        errors.push(`gridAreas.${bp} must have an "areas" array`);
                    } else if (areaConfig.areas.length === 0) {
                        errors.push(`gridAreas.${bp}.areas cannot be empty`);
                    }

                    // Columns and rows are optional (will use defaults)
                    if (areaConfig.columns && typeof areaConfig.columns !== 'string') {
                        warnings.push(`gridAreas.${bp}.columns should be a string (e.g., "200px 1fr 200px")`);
                    }

                    if (areaConfig.rows && typeof areaConfig.rows !== 'string') {
                        warnings.push(`gridAreas.${bp}.rows should be a string (e.g., "auto 1fr auto")`);
                    }
                });

                // When using gridAreas, items should have area properties
                if (config.items && Array.isArray(config.items)) {
                    config.items.forEach((item, index) => {
                        if (!item.area) {
                            warnings.push(`Item ${index}: missing "area" property when using gridAreas`);
                        }
                    });
                }
            } else {
                // Standard validation for non-template layouts
                if (!config.layoutId || typeof config.layoutId !== 'string') {
                    errors.push('layoutId is required and must be a string');
                }

                // Breakpoints are optional when using alternative grid modes:
                // - autoFit/autoFill (fluid grids)
                // - layoutPattern/layoutPatternBreakpoints (named grid areas)
                // - When items contain grid content type (nested grids handle their own layout)
                // - When wrapper.renderMode is 'direct' (renders items without grid wrapper)
                const usesAlternativeGridMode = config.autoFit || config.autoFill ||
                    config.layoutPattern || config.layoutPatternBreakpoints ||
                    (config.wrapper && config.wrapper.renderMode === 'direct') ||
                    (config.items && config.items.some(item => item.content && item.content.type === 'grid'));

                if (!usesAlternativeGridMode && (!config.breakpoints || typeof config.breakpoints !== 'object')) {
                    errors.push('breakpoints are required and must be an object');
                } else if (config.breakpoints && typeof config.breakpoints === 'object') {
                    const validBreakpoints = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
                    for (const bp in config.breakpoints) {
                        if (!validBreakpoints.includes(bp)) {
                            warnings.push(`Unknown breakpoint: ${bp}. Valid: ${validBreakpoints.join(', ')}`);
                        }
                        if (typeof config.breakpoints[bp] !== 'number' || config.breakpoints[bp] < 1) {
                            errors.push(`Breakpoint ${bp} must be a positive number`);
                        }
                    }
                }

                if (config.items && Array.isArray(config.items)) {
                    config.items.forEach((item, index) => {
                        // ID required for v1, optional for v2 (auto-generated)
                        if (version === 1 && (!item.id || typeof item.id !== 'string')) {
                            errors.push(`Item ${index}: id is required in v1 schema`);
                        }

                        // Enhanced content validation for v2
                        if (item.content) {
                            const type = item.content.type;
                            if (type && !this.contentRenderers[type]) {
                                warnings.push(`Item ${index}: unknown content type "${type}". Will be ignored.`);
                            }
                        }
                    });
                }
            }

            return {
                valid: errors.length === 0,
                errors,
                warnings,
                version
            };
        }

        /**
         * Render layout from JSON configuration
         * Enhanced version with v2 features
         */
        renderLayout(container, config) {
            // Auto-upgrade v1 configs
            if (!config.version) {
                config.version = 1;
            }

            // Validate
            const validation = this.validateSchema(config);

            // Log warnings if any
            if (validation.warnings && validation.warnings.length > 0) {
                console.warn('RSL JSON Layout warnings:', validation.warnings);
            }

            if (!validation.valid) {
                console.error('RSL JSON Layout validation failed:', validation.errors);
                throw new Error('Invalid layout configuration: ' + validation.errors.join('; '));
            }

            // Get container
            const containerEl = typeof container === 'string'
                ? document.querySelector(container)
                : container;

            if (!containerEl) {
                throw new Error(`Container not found: ${container}`);
            }

            // Handle template rendering (v2)
            if (config.template) {
                return this._renderTemplateLayout(containerEl, config);
            }

            // Handle gridAreas rendering (v2)
            if (config.gridAreas) {
                return this._renderGridAreasLayout(containerEl, config);
            }

            // Handle componentType (legacy)
            if (config.componentType) {
                return this._renderLegacyComponent(containerEl, config);
            }

            // Handle page mode (for full HTML page rendering without slot-layout wrapper)
            if (config.pageMode) {
                return this._renderPageLayout(containerEl, config);
            }

            // Standard layout rendering
            return this._renderStandardLayout(containerEl, config);
        }

        /**
         * Render using template (v2 feature)
         * @private
         */
        _renderTemplateLayout(containerEl, config) {
            const { template, breakpoints, gap, layoutId, wrapper } = config;

            // Generate items from template data
            const generatedItems = template.data.map((dataItem, index) => {
                // Clone the template item
                const itemConfig = JSON.parse(JSON.stringify(template.item));

                // Auto-generate ID if not provided
                if (!itemConfig.id) {
                    itemConfig.id = `${layoutId || 'layout'}-item-${index}`;
                }

                // Interpolate data into content
                if (itemConfig.content) {
                    itemConfig.content = this._interpolateData(itemConfig.content, dataItem, index);
                }

                // Apply item-level overrides from template
                if (template.itemStyles) {
                    itemConfig.style = { ...itemConfig.style, ...template.itemStyles };
                }

                return itemConfig;
            });

            // Create modified config with generated items
            const renderConfig = {
                version: config.version,
                layoutId: layoutId || `template-layout-${Date.now()}`,
                breakpoints: breakpoints || { xs: 1, md: 2, lg: 3 },
                gap,
                wrapper,
                items: generatedItems
            };

            // Render as standard layout
            return this._renderStandardLayout(containerEl, renderConfig);
        }

        /**
         * Interpolate template data
         * Replaces {{key}} with values from data object
         * @private
         */
        _interpolateData(content, data, index) {
            // Deep clone to avoid mutation
            const interpolated = JSON.parse(JSON.stringify(content));

            // Recursive interpolation function
            const interpolate = (obj) => {
                if (typeof obj === 'string') {
                    // Replace {{key}} patterns
                    return obj.replace(/\{\{([^}]+)\}\}/g, (match, key) => {
                        const trimmedKey = key.trim();

                        // Special keys
                        if (trimmedKey === 'index') return index;
                        if (trimmedKey === 'index1') return index + 1;

                        // Data property
                        return data[trimmedKey] !== undefined ? data[trimmedKey] : match;
                    });
                }

                if (Array.isArray(obj)) {
                    return obj.map(interpolate);
                }

                if (obj && typeof obj === 'object') {
                    const result = {};
                    for (const key in obj) {
                        result[key] = interpolate(obj[key]);
                    }
                    return result;
                }

                return obj;
            };

            return interpolate(interpolated);
        }

        /**
         * Render using gridAreas (v2 feature)
         * Creates responsive layouts with named grid areas
         * @private
         */
        _renderGridAreasLayout(containerEl, config) {
            const { layoutId, gridAreas, items, gap, wrapper } = config;
            const generatedId = layoutId || `grid-areas-layout-${Date.now()}`;

            // Create or get layout element
            let layoutEl = containerEl.querySelector(`#${generatedId}`);
            let wrapperEl = null;

            if (!layoutEl) {
                // Create wrapper if specified
                if (wrapper) {
                    wrapperEl = this._createWrapperElement(wrapper);
                    layoutEl = document.createElement('div');
                    layoutEl.id = generatedId;
                    layoutEl.className = 'slot-layout';
                    wrapperEl.appendChild(layoutEl);
                    containerEl.appendChild(wrapperEl);
                } else {
                    layoutEl = document.createElement('div');
                    layoutEl.id = generatedId;
                    layoutEl.className = 'slot-layout';
                    containerEl.appendChild(layoutEl);
                }
            }

            // Apply base grid styles
            layoutEl.style.display = 'grid';
            if (gap) {
                layoutEl.style.gap = gap;
            }

            // Generate responsive grid areas CSS
            const styleId = `${generatedId}-grid-areas-styles`;
            let existingStyle = document.getElementById(styleId);
            if (existingStyle) {
                existingStyle.remove();
            }

            const styleEl = document.createElement('style');
            styleEl.id = styleId;
            styleEl.textContent = this._generateGridAreasCSS(generatedId, gridAreas);
            document.head.appendChild(styleEl);

            // Clear existing content
            layoutEl.innerHTML = '';

            // Render items with area assignments
            if (items && items.length > 0) {
                items.forEach(itemConfig => {
                    const itemEl = this._createItemElement(itemConfig, false);

                    // Apply grid-area to item
                    if (itemConfig.area) {
                        itemEl.style.gridArea = itemConfig.area;
                    }

                    layoutEl.appendChild(itemEl);
                });
            }

            // Initialize components
            this._initializeComponents(containerEl);

            return layoutEl;
        }

        /**
         * Generate responsive CSS for grid areas
         * @private
         */
        _generateGridAreasCSS(layoutId, gridAreas) {
            const breakpoints = {
                xs: 0,
                sm: 577,
                md: 769,
                lg: 993,
                xl: 1201,
                xxl: 1601
            };

            const sortedBreakpoints = Object.keys(gridAreas).sort((a, b) => {
                return breakpoints[a] - breakpoints[b];
            });

            let css = '';

            sortedBreakpoints.forEach((bp, index) => {
                const areaConfig = gridAreas[bp];
                const minWidth = breakpoints[bp];
                const isFirst = index === 0;

                // Convert areas array to grid-template-areas string
                const areasString = areaConfig.areas
                    .map(row => `"${row.join(' ')}"`)
                    .join('\n        ');

                const columns = areaConfig.columns || '1fr';
                const rows = areaConfig.rows || 'auto';

                // Generate CSS for this breakpoint
                if (isFirst && minWidth === 0) {
                    // Base styles (no media query for xs)
                    css += `
#${layoutId} {
    grid-template-areas:
        ${areasString};
    grid-template-columns: ${columns};
    grid-template-rows: ${rows};
}
`;
                } else {
                    // Media query for larger breakpoints
                    css += `
@media (min-width: ${minWidth}px) {
    #${layoutId} {
        grid-template-areas:
            ${areasString};
        grid-template-columns: ${columns};
        grid-template-rows: ${rows};
    }
}
`;
                }
            });

            return css;
        }

        /**
         * Render page layout (for full HTML pages without slot-layout wrapper)
         * Renders items directly into container, handles placeholder replacement for grids
         * @private
         */
        _renderPageLayout(containerEl, config) {
            // Clear existing content
            containerEl.innerHTML = '';

            // Separate items into regular items and placeholder grid items
            const regularItems = [];
            const placeholderGrids = new Map(); // index -> grid config

            if (config.items && config.items.length > 0) {
                config.items.forEach(itemConfig => {
                    // Check if this is a placeholder grid item (ID starts with "layout-")
                    if (itemConfig.id && itemConfig.id.startsWith('layout-') && itemConfig.content && itemConfig.content.type === 'grid') {
                        const match = itemConfig.id.match(/^layout-(\d+)$/);
                        if (match) {
                            const index = parseInt(match[1], 10) - 1; // layout-1 = index 0
                            placeholderGrids.set(index, itemConfig);
                        } else {
                            regularItems.push(itemConfig);
                        }
                    } else {
                        regularItems.push(itemConfig);
                    }
                });
            }

            // Render regular items directly into container (no slot-layout wrapper)
            regularItems.forEach(itemConfig => {
                if (itemConfig.content) {
                    if (itemConfig.content.type === 'html') {
                        // For HTML content, insert directly without wrapper
                        const tempDiv = document.createElement('div');
                        tempDiv.innerHTML = itemConfig.content.value;

                        // Move all children to container
                        while (tempDiv.firstChild) {
                            containerEl.appendChild(tempDiv.firstChild);
                        }
                    } else {
                        // For other content types, create element normally but without slot-item class
                        const itemEl = document.createElement('div');
                        if (itemConfig.id) {
                            itemEl.id = itemConfig.id;
                        }
                        if (itemConfig.classes && itemConfig.classes.length > 0) {
                            itemEl.className = itemConfig.classes.join(' ');
                        }
                        this._setItemContent(itemEl, itemConfig.content);
                        containerEl.appendChild(itemEl);
                    }
                }
            });

            // Now find and replace all placeholders with their grid content
            if (placeholderGrids.size > 0) {
                const placeholders = containerEl.querySelectorAll('[data-slot-layout-placeholder]');

                placeholders.forEach(placeholder => {
                    const index = parseInt(placeholder.getAttribute('data-slot-layout-placeholder'), 10);
                    const gridConfig = placeholderGrids.get(index);

                    if (gridConfig && gridConfig.content) {
                        const gridEl = this._renderPlaceholderGrid(gridConfig.content);
                        if (gridEl) {
                            placeholder.parentNode.replaceChild(gridEl, placeholder);
                        }
                    }
                });
            }

            // Initialize components
            this._initializeComponents(containerEl);

            return containerEl;
        }

        /**
         * Render standard layout
         * @private
         */
        _renderStandardLayout(containerEl, config) {
            const isDirectRender = config.wrapper && config.wrapper.renderMode === 'direct';

            // Get or create layout element
            let layoutEl = containerEl.querySelector(`#${config.layoutId}`);
            let wrapperEl = null;

            if (!layoutEl) {
                // Create wrapper if specified
                if (config.wrapper) {
                    wrapperEl = this._createWrapperElement(config.wrapper);

                    if (isDirectRender) {
                        wrapperEl.id = config.layoutId;
                        containerEl.appendChild(wrapperEl);
                        layoutEl = wrapperEl;
                    } else {
                        layoutEl = document.createElement('div');
                        layoutEl.id = config.layoutId;
                        layoutEl.className = 'slot-layout';
                        wrapperEl.appendChild(layoutEl);
                        containerEl.appendChild(wrapperEl);
                    }
                } else {
                    layoutEl = document.createElement('div');
                    layoutEl.id = config.layoutId;
                    layoutEl.className = 'slot-layout';
                    containerEl.appendChild(layoutEl);
                }
            }

            // Set breakpoints (non-direct render only)
            if (!isDirectRender) {
                // Apply breakpoints if provided
                if (config.breakpoints && typeof config.breakpoints === 'object') {
                    Object.entries(config.breakpoints).forEach(([bp, cols]) => {
                        layoutEl.setAttribute(`data-cols-${bp}`, cols);
                    });

                    // Set initial columns to prevent flash
                    const initialCols = this._calculateInitialColumns(config.breakpoints);
                    layoutEl.style.setProperty('--dynamic-cols', initialCols);
                }

                // Apply gap
                if (config.gap) {
                    layoutEl.setAttribute('data-gap', config.gap);
                }

                // Apply auto-fit/auto-fill for fluid grids
                if (config.autoFit) {
                    layoutEl.setAttribute('data-auto-fit', config.autoFit);
                }
                if (config.autoFill) {
                    layoutEl.setAttribute('data-auto-fill', config.autoFill);
                }

                // Apply layout pattern for named grid areas
                if (config.layoutPattern) {
                    layoutEl.setAttribute('data-layout-pattern', config.layoutPattern);
                }
                if (config.layoutPatternBreakpoints) {
                    const bpNames = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
                    bpNames.forEach(bp => {
                        if (config.layoutPatternBreakpoints[bp]) {
                            layoutEl.setAttribute(`data-layout-pattern-${bp}`, config.layoutPatternBreakpoints[bp]);
                        }
                    });
                }

                layoutEl.setAttribute('data-json-layout-pending', 'true');
            }

            // Clear existing content
            layoutEl.innerHTML = '';

            // Separate items into regular items and placeholder grid items
            const regularItems = [];
            const placeholderGrids = new Map(); // index -> grid config

            if (config.items && config.items.length > 0) {
                config.items.forEach(itemConfig => {
                    // Check if this is a placeholder grid item (ID starts with "layout-")
                    if (itemConfig.id && itemConfig.id.startsWith('layout-') && itemConfig.content && itemConfig.content.type === 'grid') {
                        // Extract the index (layout-1 -> 0, layout-2 -> 1, etc.)
                        const match = itemConfig.id.match(/^layout-(\d+)$/);
                        if (match) {
                            const index = parseInt(match[1], 10) - 1; // layout-1 = index 0
                            placeholderGrids.set(index, itemConfig);
                        } else {
                            regularItems.push(itemConfig);
                        }
                    } else {
                        regularItems.push(itemConfig);
                    }
                });
            }

            // Render regular items first
            regularItems.forEach(itemConfig => {
                const itemEl = this._createItemElement(itemConfig, isDirectRender);
                layoutEl.appendChild(itemEl);
            });

            // Now find and replace all placeholders with their grid content
            if (placeholderGrids.size > 0) {
                const placeholders = layoutEl.querySelectorAll('[data-slot-layout-placeholder]');
                placeholders.forEach(placeholder => {
                    const index = parseInt(placeholder.getAttribute('data-slot-layout-placeholder'), 10);
                    const gridConfig = placeholderGrids.get(index);

                    if (gridConfig && gridConfig.content) {
                        // Create a grid element from the grid config
                        const gridEl = this._renderPlaceholderGrid(gridConfig.content);
                        if (gridEl) {
                            // Replace the placeholder with the rendered grid
                            placeholder.parentNode.replaceChild(gridEl, placeholder);
                        }
                    }
                });
            }

            // Trigger layout calculation
            if (!isDirectRender && window.RSL && window.RSL.recalculateLayout) {
                window.RSL.recalculateLayout(layoutEl);
            }

            // Remove pending marker
            if (!isDirectRender) {
                layoutEl.removeAttribute('data-json-layout-pending');
            }

            // Initialize components
            this._initializeComponents(containerEl);

            return layoutEl;
        }

        /**
         * Render a placeholder grid from grid config (for placeholder replacement in pageMode)
         * @private
         */
        _renderPlaceholderGrid(gridConfig) {
            // Create the grid container
            const gridEl = document.createElement('div');
            gridEl.className = 'slot-layout';

            // Apply breakpoints
            if (gridConfig.breakpoints && typeof gridConfig.breakpoints === 'object') {
                Object.entries(gridConfig.breakpoints).forEach(([bp, cols]) => {
                    gridEl.setAttribute(`data-cols-${bp}`, cols);
                });

                // Set initial columns
                const initialCols = this._calculateInitialColumns(gridConfig.breakpoints);
                gridEl.style.setProperty('--dynamic-cols', initialCols);
            }

            // Apply gap
            if (gridConfig.gap) {
                gridEl.setAttribute('data-gap', gridConfig.gap);
            }

            // Apply auto-fit/auto-fill
            if (gridConfig.autoFit) {
                gridEl.setAttribute('data-auto-fit', gridConfig.autoFit);
            }
            if (gridConfig.autoFill) {
                gridEl.setAttribute('data-auto-fill', gridConfig.autoFill);
            }

            // Render grid items
            if (gridConfig.items && gridConfig.items.length > 0) {
                gridConfig.items.forEach(itemConfig => {
                    const itemEl = this._createItemElement(itemConfig, false);
                    gridEl.appendChild(itemEl);
                });
            }

            // Trigger layout calculation for this nested grid
            if (window.RSL && window.RSL.recalculateLayout) {
                // Use setTimeout to ensure DOM is ready
                setTimeout(() => {
                    window.RSL.recalculateLayout(gridEl);
                }, 0);
            }

            return gridEl;
        }

        /**
         * Create wrapper element
         * @private
         */
        _createWrapperElement(wrapperConfig) {
            const el = document.createElement(wrapperConfig.tag || 'div');

            if (wrapperConfig.id) {
                el.id = wrapperConfig.id;
            }

            // Support both 'class' (string) and 'classes' (array)
            if (wrapperConfig.class) {
                el.className = wrapperConfig.class;
            } else if (wrapperConfig.classes && wrapperConfig.classes.length > 0) {
                el.className = wrapperConfig.classes.join(' ');
            }

            if (wrapperConfig.data) {
                Object.entries(wrapperConfig.data).forEach(([key, value]) => {
                    el.setAttribute(`data-${key}`, value);
                });
            }

            if (wrapperConfig.style) {
                this._applyStyles(el, wrapperConfig.style);
            }

            return el;
        }

        /**
         * Create item element (enhanced)
         * @private
         */
        _createItemElement(itemConfig, isDirectRender) {
            const itemEl = document.createElement('div');

            // Set ID (auto-generate if missing in v2)
            itemEl.id = itemConfig.id || `item-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

            // Set classes
            const classes = isDirectRender ? [] : ['slot-item'];
            if (itemConfig.classes) {
                classes.push(...itemConfig.classes);
            }
            if (classes.length > 0) {
                itemEl.className = classes.join(' ');
            }

            // Enhanced styling (v2)
            if (itemConfig.style) {
                this._applyStyles(itemEl, itemConfig.style);
            }

            // Spacing utilities (v2)
            if (itemConfig.spacing) {
                this._applySpacing(itemEl, itemConfig.spacing);
            }

            // Grid positioning
            if (itemConfig.grid) {
                this._applyGridPosition(itemEl, itemConfig.grid);
            }

            // Order
            if (itemConfig.order !== undefined) {
                itemEl.style.order = itemConfig.order;
            }

            // Visibility
            if (itemConfig.visible === false || itemConfig.hidden === true) {
                itemEl.classList.add('hidden');
            }

            // Responsive visibility (v2)
            if (itemConfig.hideOn) {
                itemConfig.hideOn.forEach(bp => {
                    itemEl.classList.add(`hide-${bp}`);
                });
            }
            if (itemConfig.showOn) {
                itemConfig.showOn.forEach(bp => {
                    itemEl.classList.add(`show-${bp}-only`);
                });
            }

            // Data attributes
            if (itemConfig.data) {
                Object.entries(itemConfig.data).forEach(([key, value]) => {
                    itemEl.setAttribute(`data-${key}`, value);
                });
            }

            // Render content
            if (itemConfig.content) {
                this._setItemContent(itemEl, itemConfig.content);
            }

            // Event handlers (v2)
            if (itemConfig.onClick) {
                this._attachClickHandler(itemEl, itemConfig.onClick, itemConfig);
            }
            if (itemConfig.events) {
                this._attachEvents(itemEl, itemConfig.events, itemConfig);
            }

            return itemEl;
        }

        /**
         * Set item content using enhanced renderers
         * @private
         */
        _setItemContent(itemEl, contentConfig) {
            const type = contentConfig.type || 'html';
            const renderer = this.contentRenderers[type];

            if (renderer) {
                renderer(itemEl, contentConfig);
            } else {
                console.warn(`Unknown content type: ${type}`);
                // Fallback to HTML
                itemEl.innerHTML = contentConfig.value || '';
            }
        }

        // ====================================================================
        // CONTENT TYPE RENDERERS (V1 - Backward Compatible)
        // ====================================================================

        _renderHTML(el, config) {
            el.innerHTML = config.value || '';
        }

        _renderText(el, config) {
            el.textContent = config.value || '';
        }

        _renderSlot(el, config) {
            const template = document.querySelector(config.selector);
            if (template) {
                const clone = template.content
                    ? template.content.cloneNode(true)
                    : template.cloneNode(true);
                el.appendChild(clone);
            } else {
                console.warn(`Template not found: ${config.selector}`);
            }
        }

        _renderComponent(el, config) {
            el.setAttribute('data-component', config.component);
            if (config.props) {
                el.setAttribute('data-props', JSON.stringify(config.props));
            }
        }

        // ====================================================================
        // CONTENT TYPE RENDERERS (V2 - Enhanced)
        // ====================================================================

        /**
         * Render card component
         */
        /**
         * Render card component
         * Creates cards with header, title, body, and footer sections
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Card configuration
         * @param {string} [config.image] - Image URL for card header
         * @param {string} [config.imageAlt] - Alt text for image
         * @param {string} [config.title] - Card title text
         * @param {string} [config.titleIcon] - Icon class for title (e.g., "fas fa-rocket")
         * @param {string} [config.body] - Card body text/HTML
         * @param {string} [config.subtitle] - Card subtitle
         * @param {string} [config.price] - Price text
         * @param {Array} [config.buttons] - Array of button configs
         * @param {boolean} [config.sameSize=false] - Apply data-same-size attribute
         * @param {boolean} [config.tabCard=false] - Make card keyboard accessible
         * @param {string} [config.role] - ARIA role attribute
         * @private
         */
        _renderCard(el, config) {
            const card = document.createElement('div');
            card.className = 'card';

            // Add data attributes for card behavior
            if (config.sameSize !== false) {
                card.setAttribute('data-same-size', 'true');
            }

            if (config.tabCard) {
                card.setAttribute('data-tab-card', 'true');
                card.setAttribute('role', config.role || 'button');
                card.setAttribute('tabindex', '0');
            }

            // Card header (for images)
            if (config.image) {
                const header = document.createElement('div');
                header.className = 'card-header';

                const imgWrapper = document.createElement('div');
                imgWrapper.className = 'img-wrapper';

                const img = document.createElement('img');
                img.className = 'card-img';
                img.src = config.image;
                img.alt = config.imageAlt || config.title || '';

                imgWrapper.appendChild(img);
                header.appendChild(imgWrapper);
                card.appendChild(header);
            }

            // Card title (can be in header or standalone)
            if (config.title) {
                // If title has icon or is in header position
                if (config.titleIcon || (config.titleInHeader && !config.image)) {
                    const header = config.image ? card.querySelector('.card-header') : document.createElement('div');
                    if (!config.image) {
                        header.className = 'card-header';
                        card.appendChild(header);
                    }

                    const titleDiv = document.createElement('div');
                    titleDiv.className = 'card-title';

                    if (config.titleIcon) {
                        const icon = document.createElement('i');
                        icon.className = config.titleIcon;
                        titleDiv.appendChild(icon);
                        titleDiv.appendChild(document.createTextNode(' ' + config.title));
                    } else {
                        titleDiv.textContent = config.title;
                    }

                    header.appendChild(titleDiv);
                } else {
                    // Standalone title
                    const titleDiv = document.createElement('div');
                    titleDiv.className = 'card-title';
                    titleDiv.style.padding = '1rem 1rem 0.5rem 1rem';
                    titleDiv.style.fontWeight = '600';
                    titleDiv.style.fontSize = '1.1rem';
                    titleDiv.textContent = config.title;
                    card.appendChild(titleDiv);
                }
            }

            // Card body
            if (config.body || config.subtitle || config.price) {
                const body = document.createElement('div');
                body.className = 'card-body';

                if (config.subtitle) {
                    const subtitleP = document.createElement('p');
                    const strong = document.createElement('strong');
                    strong.textContent = config.subtitle;
                    subtitleP.appendChild(strong);
                    body.appendChild(subtitleP);
                }

                if (config.body) {
                    if (typeof config.body === 'string') {
                        const bodyP = document.createElement('p');
                        bodyP.textContent = config.body;
                        body.appendChild(bodyP);
                    } else if (config.body.type) {
                        // Nested content type
                        const renderer = this.contentRenderers[config.body.type];
                        if (renderer) {
                            renderer(body, config.body);
                        }
                    }
                }

                if (config.price) {
                    const priceP = document.createElement('p');
                    const strong = document.createElement('strong');
                    strong.textContent = config.price;
                    priceP.appendChild(strong);
                    body.appendChild(priceP);
                }

                card.appendChild(body);
            }

            // Custom content (for nested components like gantt, charts, etc.)
            if (config.customContent && config.customContent.type) {
                const contentWrapper = document.createElement('div');
                contentWrapper.className = 'card-custom-content';
                // Adjust padding based on whether title exists
                contentWrapper.style.padding = config.title ? '0.5rem 1rem 1rem 1rem' : '1rem';

                // Clone customContent to avoid modifying original config
                const nestedConfig = Object.assign({}, config.customContent);

                // If card has a title and nested content doesn't, pass it through for accessibility
                if (config.title && !nestedConfig.title && !nestedConfig.name) {
                    nestedConfig.title = config.title;
                }

                const renderer = this.contentRenderers[nestedConfig.type];
                if (renderer) {
                    renderer(contentWrapper, nestedConfig);
                }

                card.appendChild(contentWrapper);
            }

            // Card footer (for buttons)
            if (config.buttons && config.buttons.length > 0) {
                const footer = document.createElement('div');
                footer.className = 'card-footer';

                const btnWrapper = document.createElement('div');
                btnWrapper.className = 'btn-wrapper btn-wrapper-line';

                config.buttons.forEach(btnConfig => {
                    // Use _createButton for full feature support (icons, dataAttributes, etc.)
                    const button = this._createButton(btnConfig);
                    btnWrapper.appendChild(button);
                });

                footer.appendChild(btnWrapper);
                card.appendChild(footer);
            }

            el.appendChild(card);
        }

        /**
         * Render image
         */
        _renderImage(el, config) {
            const img = document.createElement('img');
            img.src = config.src || config.value;
            img.alt = config.alt || '';

            if (config.className) {
                img.className = config.className;
            }

            if (config.lazy !== false) {
                img.loading = 'lazy';
            }

            if (config.srcset) {
                img.srcset = config.srcset;
            }

            if (config.sizes) {
                img.sizes = config.sizes;
            }

            if (config.width) {
                img.width = config.width;
            }

            if (config.height) {
                img.height = config.height;
            }

            if (config.objectFit) {
                img.style.objectFit = config.objectFit;
            }

            // Wrap in figure if caption provided
            if (config.caption) {
                const figure = document.createElement('figure');
                figure.appendChild(img);

                const figcaption = document.createElement('figcaption');
                figcaption.textContent = config.caption;
                figure.appendChild(figcaption);

                el.appendChild(figure);
            } else {
                el.appendChild(img);
            }
        }

        /**
         * Render thumbnail with overlay, buttons, and optional modal
         */
        _renderThumbnail(el, config) {
            const container = document.createElement('div');

            // Set data attributes for thumbnail.js to initialize
            container.setAttribute('data-thumbnail-image', config.image || config.src);

            if (config.imageAlt) {
                container.setAttribute('data-thumbnail-image-alt', config.imageAlt);
            }

            if (config.aspect) {
                container.setAttribute('data-thumbnail-aspect', config.aspect);
            }

            if (config.header) {
                container.setAttribute('data-thumbnail-header', config.header);
            }

            if (config.description) {
                container.setAttribute('data-thumbnail-description', config.description);
            }

            // Link configuration
            if (config.link) {
                container.setAttribute('data-thumbnail-link', config.link);
            }

            if (config.linkText) {
                container.setAttribute('data-thumbnail-link-text', config.linkText);
            }

            if (config.linkTarget) {
                container.setAttribute('data-thumbnail-link-target', config.linkTarget);
            }

            // Overlay configuration
            if (config.overlayColor) {
                container.setAttribute('data-overlay-color', config.overlayColor);
            }

            if (config.overlayOpacity) {
                container.setAttribute('data-overlay-opacity', config.overlayOpacity);
            }

            if (config.showButtons === false) {
                container.setAttribute('data-thumbnail-show-buttons', 'false');
            }

            // Button 1 configuration
            if (config.button1Text) {
                container.setAttribute('data-thumbnail-button1-text', config.button1Text);
            }

            if (config.button1Action) {
                container.setAttribute('data-thumbnail-button1-action', config.button1Action);
            }

            if (config.button1Link) {
                container.setAttribute('data-thumbnail-button1-link', config.button1Link);
            }

            if (config.button1Icon) {
                container.setAttribute('data-thumbnail-button1-icon', config.button1Icon);
            }

            if (config.button1Target) {
                container.setAttribute('data-thumbnail-button1-target', config.button1Target);
            }

            // Button 2 configuration
            if (config.button2Text) {
                container.setAttribute('data-thumbnail-button2-text', config.button2Text);
            }

            if (config.button2Action) {
                container.setAttribute('data-thumbnail-button2-action', config.button2Action);
            }

            if (config.button2Link) {
                container.setAttribute('data-thumbnail-button2-link', config.button2Link);
            }

            if (config.button2Icon) {
                container.setAttribute('data-thumbnail-button2-icon', config.button2Icon);
            }

            if (config.button2Target) {
                container.setAttribute('data-thumbnail-button2-target', config.button2Target);
            }

            // Modal configuration
            if (config.modal === true || config.enableModal === true) {
                container.setAttribute('data-thumbnail-modal', 'true');
            }

            if (config.modalHeader) {
                container.setAttribute('data-thumbnail-modal-header', config.modalHeader);
            }

            if (config.modalDescription) {
                container.setAttribute('data-thumbnail-modal-description', config.modalDescription);
            }

            // Behavior
            if (config.lazyLoad === true) {
                container.setAttribute('data-thumbnail-lazy', 'true');
            }

            if (config.disabled === true) {
                container.setAttribute('data-thumbnail-disabled', 'true');
            }

            el.appendChild(container);

            // Initialize thumbnail component
            setTimeout(() => {
                if (window.RSL && window.RSL.Thumbnail) {
                    window.RSL.Thumbnail.init();
                }
            }, 50);
        }

        /**
         * Render button
         */
        _renderButton(el, config) {
            const btn = this._createButton(config);
            el.appendChild(btn);
        }

        /**
         * Create button element helper
         * @private
         */
        _createButton(config) {
            const isLink = config.href || config.link;
            const btn = document.createElement(isLink ? 'a' : 'button');

            // Base button class
            btn.className = 'btn';

            // Variant class (primary, secondary, danger, success, warning, info, etc.)
            // Supports both formats: "primary" or "btn-primary"
            const variant = config.variant;
            if (variant) {
                // Remove 'btn-' prefix if present to normalize
                const normalizedVariant = variant.startsWith('btn-') ? variant.substring(4) : variant;
                btn.classList.add(`btn-${normalizedVariant}`);
            }

            // Additional classes from config
            if (config.classes && Array.isArray(config.classes)) {
                config.classes.forEach(cls => btn.classList.add(cls));
            }

            if (config.className) {
                btn.className += ' ' + config.className;
            }

            if (config.outline) {
                btn.classList.add('btn-outline');
            }

            if (config.block) {
                btn.classList.add('btn-block');
            }

            if (isLink) {
                btn.href = config.href || config.link;
                if (config.target) {
                    btn.target = config.target;
                }
            } else {
                btn.type = config.type || 'button';
                if (config.disabled) {
                    btn.disabled = true;
                }
            }

            // Icon + text
            if (config.icon) {
                const icon = document.createElement('i');
                icon.className = config.icon;
                btn.appendChild(icon);
                if (config.text) {
                    btn.appendChild(document.createTextNode(' ' + config.text));
                }
            } else {
                btn.textContent = config.text || config.value || 'Button';
            }

            // Custom data attributes
            if (config.dataAttributes) {
                Object.entries(config.dataAttributes).forEach(([key, value]) => {
                    btn.setAttribute(key, value);
                });
            }

            // Event handler
            if (config.onClick && typeof config.onClick === 'function') {
                btn.addEventListener('click', (e) => config.onClick(e, btn));
            }

            return btn;
        }

        /**
         * Render link
         */
        _renderLink(el, config) {
            const link = document.createElement('a');
            link.href = config.href || config.value || '#';
            link.textContent = config.text || config.href;

            if (config.target) {
                link.target = config.target;
            }

            if (config.className) {
                link.className = config.className;
            }

            if (config.icon) {
                const icon = document.createElement('i');
                icon.className = config.icon;
                link.prepend(icon);
                link.prepend(document.createTextNode(' '));
            }

            el.appendChild(link);
        }

        /**
         * Render heading
         */
        _renderHeading(el, config) {
            const level = config.level || 2;
            const heading = document.createElement(`h${level}`);
            heading.textContent = config.text || config.value || '';

            if (config.className) {
                heading.className = config.className;
            }

            if (config.id) {
                heading.id = config.id;
            }

            el.appendChild(heading);
        }

        /**
         * Render paragraph
         */
        _renderParagraph(el, config) {
            const p = document.createElement('p');
            p.textContent = config.text || config.value || '';

            if (config.className) {
                p.className = config.className;
            }

            el.appendChild(p);
        }

        /**
         * Render list
         */
        _renderList(el, config) {
            const list = document.createElement(config.ordered ? 'ol' : 'ul');

            if (config.className) {
                list.className = config.className;
            }

            const items = config.items || config.value || [];
            items.forEach(item => {
                const li = document.createElement('li');
                li.textContent = typeof item === 'string' ? item : item.text;
                if (item.className) {
                    li.className = item.className;
                }
                list.appendChild(li);
            });

            el.appendChild(list);
        }

        /**
         * Render responsive table with multiple variants
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Table configuration
         *
         * Config options:
         * - variant: "scrollable" | "responsive" | "responsive-card" | "default"
         * - headers: Array of column header strings
         * - rows: Array of row data (each row is an array of cell values or objects with {value, html})
         * - caption: Optional table caption for accessibility
         * - sortable: Boolean to add sort indicators (visual only)
         * - customClass: Additional CSS class (e.g., "rsl-table-card")
         */
        _renderTable(el, config) {
            const variant = config.variant || 'default';
            const headers = config.headers || [];
            const rows = config.rows || [];

            // For scrollable tables, wrap in scroll container
            let container = el;
            if (variant === 'scrollable') {
                const wrapper = document.createElement('div');
                wrapper.className = 'table-scroll-wrapper';
                el.appendChild(wrapper);
                container = wrapper;
            }

            // Create table element
            const table = document.createElement('table');

            // Build class list based on variant
            const classes = [];
            if (variant === 'scrollable') {
                classes.push('scrollable');
            } else if (variant === 'responsive') {
                classes.push('responsive');
            } else if (variant === 'responsive-card') {
                classes.push('responsive-card');
            }

            // Add sortable class if enabled
            if (config.sortable) {
                classes.push('sortable');
            }

            // Add custom class if provided
            if (config.customClass) {
                classes.push(config.customClass);
            }

            // Legacy support for className
            if (config.className) {
                classes.push(config.className);
            }

            table.className = classes.join(' ');

            // Add caption for accessibility
            if (config.caption) {
                const caption = document.createElement('caption');
                caption.textContent = config.caption;
                // Optionally visually hide caption but keep for screen readers
                if (config.captionHidden) {
                    caption.style.cssText = 'position: absolute; width: 1px; height: 1px; padding: 0; margin: -1px; overflow: hidden; clip: rect(0, 0, 0, 0); white-space: nowrap; border: 0;';
                }
                table.appendChild(caption);
            }

            // Create thead with headers
            if (headers.length > 0) {
                const thead = document.createElement('thead');
                const tr = document.createElement('tr');
                headers.forEach((header, index) => {
                    const th = document.createElement('th');
                    // Support header as string or object {text, scope}
                    if (typeof header === 'object') {
                        th.textContent = header.text || '';
                        if (header.scope) {
                            th.setAttribute('scope', header.scope);
                        }
                    } else {
                        th.textContent = header;
                        th.setAttribute('scope', 'col');
                    }
                    tr.appendChild(th);
                });
                thead.appendChild(tr);
                table.appendChild(thead);
            }

            // Create tbody with rows
            if (rows.length > 0) {
                const tbody = document.createElement('tbody');
                rows.forEach(row => {
                    const tr = document.createElement('tr');

                    // Handle row as array of cells
                    const cells = Array.isArray(row) ? row : (row.cells || []);

                    cells.forEach((cell, cellIndex) => {
                        const td = document.createElement('td');

                        // For responsive and responsive-card, add data-label attribute
                        if (variant === 'responsive' || variant === 'responsive-card') {
                            const headerLabel = headers[cellIndex];
                            if (headerLabel) {
                                const labelText = typeof headerLabel === 'object' ? headerLabel.text : headerLabel;
                                td.setAttribute('data-label', labelText);
                            }
                        }

                        // Handle cell as string, HTML string, or object
                        if (typeof cell === 'object' && cell !== null) {
                            if (cell.html) {
                                td.innerHTML = cell.html;
                            } else if (cell.value !== undefined) {
                                td.textContent = cell.value;
                            } else if (cell.text !== undefined) {
                                td.textContent = cell.text;
                            }
                            // Apply cell-specific classes
                            if (cell.className) {
                                td.className = cell.className;
                            }
                        } else {
                            td.textContent = cell !== null && cell !== undefined ? cell : '';
                        }

                        tr.appendChild(td);
                    });

                    // Apply row-specific classes if row is an object
                    if (!Array.isArray(row) && row.className) {
                        tr.className = row.className;
                    }

                    tbody.appendChild(tr);
                });
                table.appendChild(tbody);
            }

            container.appendChild(table);
        }

        /**
         * Render icon
         */
        _renderIcon(el, config) {
            const icon = document.createElement('i');
            icon.className = config.className || config.value || '';

            if (config.size) {
                icon.style.fontSize = config.size;
            }

            if (config.color) {
                icon.style.color = config.color;
            }

            el.appendChild(icon);
        }

        /**
         * Render badge component
         * Supports: colors, styles, sizes, shapes, icons, status, counters,
         * dismissible, animations, gradients, positioned, clickable
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Badge configuration
         */
        _renderBadge(el, config) {
            const badge = document.createElement('span');

            // Build class list
            const classes = ['rsl-badge'];

            // Color variant (primary, secondary, success, warning, danger, info, light, dark)
            if (config.color || config.variant) {
                classes.push(`rsl-badge-${config.color || config.variant}`);
            } else {
                classes.push('rsl-badge-primary');
            }

            // Style variant (outline, subtle, glass)
            if (config.style) {
                classes.push(`rsl-badge-${config.style}`);
            }

            // Size variant (xs, sm, md, lg, xl)
            if (config.size) {
                classes.push(`rsl-badge-${config.size}`);
            }

            // Shape variant (pill is default, rounded, square, circle)
            if (config.shape && config.shape !== 'pill') {
                classes.push(`rsl-badge-${config.shape}`);
            }

            // Gradient badges
            if (config.gradient) {
                classes.push(`rsl-badge-gradient-${config.gradient}`);
            }

            // Animation (pulse, bounce, shimmer, glow)
            if (config.animation) {
                classes.push(`rsl-badge-${config.animation}`);
            }

            // Status badge (adds dot)
            if (config.status) {
                classes.push('rsl-badge-status');
            }

            // Counter badge
            if (config.counter !== undefined) {
                classes.push('rsl-badge-counter');
            }

            // Dismissible badge
            if (config.dismissible) {
                classes.push('rsl-badge-dismissible');
            }

            // Positioned badge (for overlays)
            if (config.positioned) {
                classes.push('rsl-badge-positioned');
                if (config.position) {
                    classes.push(`rsl-badge-${config.position}`);
                } else {
                    classes.push('rsl-badge-top-right');
                }
            }

            // Clickable badge
            if (config.clickable || config.onClick) {
                classes.push('rsl-badge-clickable');
            }

            badge.className = classes.join(' ');

            // Add data attributes for V1 badge.js initialization
            badge.setAttribute('data-rsl-badge', '');

            // Counter data attributes
            if (config.counter !== undefined) {
                badge.setAttribute('data-counter', config.counter);
                if (config.counterMax) {
                    badge.setAttribute('data-counter-max', config.counterMax);
                }
                if (config.hideZero) {
                    badge.setAttribute('data-hide-zero', '');
                }
            }

            // Clickable data attribute
            if (config.clickable) {
                badge.setAttribute('data-clickable', '');
            }

            // Build content
            // Status dot (rendered via CSS ::before, but we can add explicit dot if needed)
            if (config.status && config.statusDot !== false) {
                const dot = document.createElement('span');
                dot.className = 'rsl-badge-dot';
                badge.appendChild(dot);
            }

            // Icon (before text)
            if (config.icon) {
                const icon = document.createElement('i');
                icon.className = config.icon;
                icon.setAttribute('aria-hidden', 'true');
                badge.appendChild(icon);

                // Add space if there's also text
                if (config.text || config.value || config.counter !== undefined) {
                    badge.appendChild(document.createTextNode(' '));
                }
            }

            // Text/value content
            if (config.counter !== undefined) {
                // Counter badge displays count
                // Don't include '+' in text - CSS ::after handles it via .rsl-badge-counter-max class
                const max = config.counterMax || 99;
                if (config.counter > max) {
                    badge.appendChild(document.createTextNode(String(max)));
                    badge.classList.add('rsl-badge-counter-max');
                } else {
                    badge.appendChild(document.createTextNode(String(config.counter)));
                }
            } else if (config.text || config.value) {
                badge.appendChild(document.createTextNode(config.text || config.value));
            }

            // Icon (after text)
            if (config.iconAfter) {
                badge.appendChild(document.createTextNode(' '));
                const iconAfter = document.createElement('i');
                iconAfter.className = config.iconAfter;
                iconAfter.setAttribute('aria-hidden', 'true');
                badge.appendChild(iconAfter);
            }

            // Dismiss button
            if (config.dismissible) {
                const dismissBtn = document.createElement('button');
                dismissBtn.className = 'rsl-badge-dismiss';
                dismissBtn.setAttribute('aria-label', 'Dismiss');
                dismissBtn.innerHTML = '&times;';
                badge.appendChild(dismissBtn);
            }

            // Click handler
            if (config.onClick && typeof config.onClick === 'function') {
                badge.style.cursor = 'pointer';
                badge.addEventListener('click', (e) => {
                    if (!e.target.classList.contains('rsl-badge-dismiss')) {
                        config.onClick(e, badge);
                    }
                });
            }

            // ID for targeting
            if (config.id) {
                badge.id = config.id;
            }

            // Additional custom classes
            if (config.class) {
                badge.classList.add(...config.class.split(' '));
            }

            el.appendChild(badge);
        }

        /**
         * Render progress bar component
         * Maps V2 config to V1 data attributes for progress-bar.js
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Progress configuration
         */
        _renderProgress(el, config) {
            // Create progress container with data attribute marker
            const progress = document.createElement('div');
            progress.setAttribute('data-rsl-progress', '');

            // Value (required) - convert to number if string from template
            const value = typeof config.value === 'string' ? parseFloat(config.value) : (config.value || 0);
            progress.setAttribute('data-value', String(value));

            // Min/Max values
            if (config.min !== undefined) {
                progress.setAttribute('data-min', String(config.min));
            }
            if (config.max !== undefined) {
                progress.setAttribute('data-max', String(config.max));
            }

            // Buffer value (for video-style progress)
            if (config.buffer !== undefined) {
                progress.setAttribute('data-buffer', String(config.buffer));
            }

            // Color variant (primary, secondary, success, warning, danger, info, dark, light)
            if (config.variant || config.color) {
                progress.setAttribute('data-variant', config.variant || config.color);
            }

            // Size (xs, sm, md, lg, xl)
            if (config.size) {
                progress.setAttribute('data-size', config.size);
            }

            // Shape (horizontal, vertical, circular, gauge, steps)
            if (config.shape) {
                progress.setAttribute('data-shape', config.shape);
            }

            // Label position (inside, outside, floating, hidden)
            if (config.label) {
                progress.setAttribute('data-label', config.label);
            }

            // Custom label format (e.g., "{value}/{max}")
            if (config.labelFormat) {
                progress.setAttribute('data-label-format', config.labelFormat);
            }

            // Striped pattern
            if (config.striped) {
                progress.setAttribute('data-striped', '');
            }

            // Animated stripes
            if (config.animated) {
                progress.setAttribute('data-animated', '');
            }

            // Indeterminate state (unknown progress)
            if (config.indeterminate) {
                progress.setAttribute('data-indeterminate', '');
            }

            // Glow effect
            if (config.glow) {
                progress.setAttribute('data-glow', '');
            }

            // Pulse animation
            if (config.pulse) {
                progress.setAttribute('data-pulse', '');
            }

            // Thresholds (JSON object for auto color change)
            if (config.thresholds) {
                const thresholdsJson = typeof config.thresholds === 'string'
                    ? config.thresholds
                    : JSON.stringify(config.thresholds);
                progress.setAttribute('data-thresholds', thresholdsJson);
            }

            // Milestones (JSON array of milestone objects)
            if (config.milestones) {
                const milestonesJson = typeof config.milestones === 'string'
                    ? config.milestones
                    : JSON.stringify(config.milestones);
                progress.setAttribute('data-milestones', milestonesJson);
            }

            // Segments (JSON array for segmented progress)
            if (config.segments) {
                const segmentsJson = typeof config.segments === 'string'
                    ? config.segments
                    : JSON.stringify(config.segments);
                progress.setAttribute('data-segments', segmentsJson);
            }

            // Animate on view (trigger animation when scrolled into view)
            if (config.animateOnView) {
                progress.setAttribute('data-animate-on-view', '');
            }

            // Animation duration (ms)
            if (config.duration) {
                progress.setAttribute('data-duration', String(config.duration));
            }

            // Steps (for step progress shape)
            if (config.steps) {
                progress.setAttribute('data-steps', String(config.steps));
            }

            // Show step value
            if (config.showValue) {
                progress.setAttribute('data-show-value', '');
            }

            // Add gradient class if specified
            if (config.gradient) {
                progress.classList.add('rsl-progress', `rsl-progress-gradient-${config.gradient}`);
            }

            // Add shimmer class for indeterminate shimmer effect
            if (config.shimmer) {
                progress.classList.add('rsl-progress', 'rsl-progress-indeterminate', 'rsl-progress-shimmer');
            }

            // Custom ID
            if (config.id) {
                progress.id = config.id;
            }

            // Custom classes
            if (config.class) {
                progress.classList.add(...config.class.split(' '));
            }
            if (config.classes && Array.isArray(config.classes)) {
                config.classes.forEach(cls => progress.classList.add(cls));
            }

            // Custom inline styles
            if (config.style && typeof config.style === 'object') {
                Object.keys(config.style).forEach(prop => {
                    progress.style[prop] = config.style[prop];
                });
            }

            el.appendChild(progress);

            // Note: Progress bar will be initialized by _initializeComponents()
            // which calls RSL.Progress.init() - no need to call create() here
        }

        /**
         * Render alert
         */
        _renderAlert(el, config) {
            const alert = document.createElement('div');
            alert.className = `rsl-alert rsl-alert-${config.variant || 'info'}`;
            alert.textContent = config.text || config.value || '';

            if (config.dismissible) {
                alert.classList.add('rsl-alert-dismissible');
                const closeBtn = document.createElement('button');
                closeBtn.className = 'rsl-alert-close';
                closeBtn.innerHTML = '&times;';
                closeBtn.onclick = () => alert.remove();
                alert.appendChild(closeBtn);
            }

            el.appendChild(alert);
        }

        /**
         * Render divider
         */
        _renderDivider(el, config) {
            const hr = document.createElement('hr');

            if (config.className) {
                hr.className = config.className;
            }

            if (config.spacing) {
                hr.style.margin = config.spacing;
            }

            el.appendChild(hr);
        }

        /**
         * Render spacer
         */
        _renderSpacer(el, config) {
            const spacer = document.createElement('div');
            spacer.className = 'rsl-spacer';
            spacer.style.height = config.height || config.value || '1rem';
            el.appendChild(spacer);
        }

        /**
         * Render RSL Grid Layout with full feature support
         * Supports all RSL grid features including:
         * - Responsive breakpoint columns (data-cols-xs/sm/md/lg/xl/xxl)
         * - Gap control (data-gap)
         * - Auto-fit/auto-fill fluid grids
         * - CSS Subgrid (data-subgrid, data-row-span, data-auto-rows)
         * - Named grid areas (data-layout-pattern, data-area)
         * - Nested grids (nested-slot-layout, nested-slot-item)
         * - Column spanning on items (data-span-*)
         * - Container types (container, container-fluid, container-full, container-flex)
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Grid configuration
         *
         * Config options:
         * - breakpoints: { xs: 1, sm: 2, md: 3, lg: 4 } - Responsive columns
         * - cols: { xs: 1, md: 2 } - Shorthand for breakpoints
         * - gap: "1rem" - Gap between items
         * - autoFit: "250px" - Auto-fit with minmax (150px|200px|250px|300px|350px|400px)
         * - autoFill: "250px" - Auto-fill with minmax
         * - nested: true - Use nested-slot-layout classes
         * - autoRows: "auto" - Enable subgrid row sizing (data-auto-rows)
         * - layoutPattern: "holy-grail" - Named grid area pattern
         * - layoutPatternBreakpoints: { xs: "stacked", md: "holy-grail" } - Responsive patterns
         * - container: "fluid" | "full" | "flex" | true - Wrapper container type
         * - items: [] - Grid items with content and optional grid positioning
         */
        _renderNestedGrid(el, config) {
            // Create the grid container
            const gridEl = document.createElement('div');
            const isNested = config.nested === true;

            // Set grid class
            gridEl.className = isNested ? 'nested-slot-layout' : 'slot-layout';

            // Ensure grid fills its container
            gridEl.style.width = '100%';

            // Add custom classes
            if (config.classes) {
                config.classes.forEach(cls => gridEl.classList.add(cls));
            }

            // Generate unique ID
            gridEl.id = config.layoutId || config.id || `grid-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

            // Apply responsive breakpoint columns
            const breakpoints = config.breakpoints || config.cols;
            if (breakpoints) {
                const bpNames = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
                bpNames.forEach(bp => {
                    if (breakpoints[bp] !== undefined) {
                        gridEl.setAttribute(`data-cols-${bp}`, breakpoints[bp]);
                    }
                });
            }

            // Apply gap
            if (config.gap) {
                gridEl.setAttribute('data-gap', config.gap);
            }

            // Apply auto-fit (fluid responsive grid)
            if (config.autoFit) {
                gridEl.setAttribute('data-auto-fit', config.autoFit);
            }

            // Apply auto-fill (fluid responsive grid with empty columns)
            if (config.autoFill) {
                gridEl.setAttribute('data-auto-fill', config.autoFill);
            }

            // Apply auto-rows for subgrid layouts
            if (config.autoRows) {
                gridEl.setAttribute('data-auto-rows', config.autoRows);
            }

            // Apply named grid area patterns
            if (config.layoutPattern) {
                gridEl.setAttribute('data-layout-pattern', config.layoutPattern);
            }

            // Apply responsive layout patterns
            if (config.layoutPatternBreakpoints) {
                const bpNames = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
                bpNames.forEach(bp => {
                    if (config.layoutPatternBreakpoints[bp]) {
                        gridEl.setAttribute(`data-layout-pattern-${bp}`, config.layoutPatternBreakpoints[bp]);
                    }
                });
            }

            // Apply inline styles
            if (config.style) {
                this._applyStyles(gridEl, config.style);
            }

            // Handle container wrapper
            let containerEl = null;
            if (config.container) {
                containerEl = document.createElement('div');
                if (config.container === 'fluid') {
                    containerEl.className = 'container-fluid';
                } else if (config.container === 'full') {
                    containerEl.className = 'container-full';
                } else if (config.container === 'flex') {
                    containerEl.className = 'container-flex';
                } else {
                    containerEl.className = 'container';
                }
            }

            // Render grid items
            if (config.items && Array.isArray(config.items)) {
                config.items.forEach(itemConfig => {
                    const itemEl = document.createElement('div');
                    itemEl.className = isNested ? 'nested-slot-item' : 'slot-item';

                    // Add custom classes to item
                    if (itemConfig.classes) {
                        itemConfig.classes.forEach(cls => itemEl.classList.add(cls));
                    }

                    // Set item ID
                    if (itemConfig.id) {
                        itemEl.id = itemConfig.id;
                    }

                    // Apply grid positioning (span, area, subgrid, rowSpan)
                    if (itemConfig.grid) {
                        this._applyGridPosition(itemEl, itemConfig.grid);
                    }

                    // Apply inline styles to item
                    if (itemConfig.style) {
                        this._applyStyles(itemEl, itemConfig.style);
                    }

                    // Apply data attributes
                    if (itemConfig.data) {
                        Object.entries(itemConfig.data).forEach(([key, value]) => {
                            itemEl.setAttribute(`data-${key}`, value);
                        });
                    }

                    // Add slotId as data attribute for targeted updates (used by Page Builder)
                    if (itemConfig.slotId) {
                        itemEl.setAttribute('data-slot-id', itemConfig.slotId);
                    }

                    // Render content
                    if (itemConfig.content) {
                        this._setItemContent(itemEl, itemConfig.content);
                    } else if (itemConfig.html) {
                        // Shorthand for HTML content
                        itemEl.innerHTML = itemConfig.html;
                    } else if (itemConfig.text) {
                        // Shorthand for text content
                        itemEl.textContent = itemConfig.text;
                    }

                    gridEl.appendChild(itemEl);
                });
            }

            // Append to container or directly to parent
            if (containerEl) {
                containerEl.appendChild(gridEl);
                el.appendChild(containerEl);
            } else {
                el.appendChild(gridEl);
            }

            // Trigger layout recalculation for dynamically added grids
            setTimeout(() => {
                this._calculateGridColumns(gridEl);

                // Add resize listener
                const resizeHandler = () => this._calculateGridColumns(gridEl);
                window.addEventListener('resize', resizeHandler);
                gridEl._resizeHandler = resizeHandler;
            }, 50);

            return gridEl;
        }

        /**
         * Render balanced (masonry-style) layout
         * Creates a responsive-slot-layout with data-layout="balanced"
         * Items are distributed across columns by placing in the shortest column
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Balanced layout configuration
         *
         * Config options:
         * - breakpoints/slots: { xs: 1, sm: 2, md: 3, lg: 4 } - Column counts per breakpoint
         * - gap: "1rem" - Gap between items
         * - items: Array of item configurations with content
         * - classes: Additional CSS classes for the container
         * - id/layoutId: Optional ID for the container
         *
         * Example:
         * {
         *   type: "balanced",
         *   breakpoints: { xs: 1, md: 2, lg: 3 },
         *   gap: "1.5rem",
         *   items: [
         *     { content: { type: "card", title: "Card 1", body: "Short" } },
         *     { content: { type: "card", title: "Card 2", body: "Tall content..." } },
         *     { content: { type: "card", title: "Card 3", body: "Medium" } }
         *   ]
         * }
         */
        _renderBalanced(el, config) {
            // Create the balanced layout container
            const balancedEl = document.createElement('div');
            balancedEl.className = 'responsive-slot-layout';

            // Set the balanced layout mode
            balancedEl.setAttribute('data-layout', 'balanced');

            // Ensure grid fills its container
            balancedEl.style.width = '100%';

            // Add custom classes
            if (config.classes) {
                config.classes.forEach(cls => balancedEl.classList.add(cls));
            }

            // Generate unique ID
            balancedEl.id = config.layoutId || config.id || `balanced-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

            // Apply responsive breakpoint columns using data-slots-* (preferred) or data-cols-*
            const breakpoints = config.breakpoints || config.slots || config.cols;
            if (breakpoints) {
                const bpNames = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
                bpNames.forEach(bp => {
                    if (breakpoints[bp] !== undefined) {
                        // Use data-slots-* as it takes precedence for balanced layouts
                        balancedEl.setAttribute(`data-slots-${bp}`, breakpoints[bp]);
                    }
                });
            } else {
                // Default: 1 column on mobile, 2 on tablet, 3 on desktop
                balancedEl.setAttribute('data-slots-xs', '1');
                balancedEl.setAttribute('data-slots-md', '2');
                balancedEl.setAttribute('data-slots-lg', '3');
            }

            // Apply gap
            if (config.gap) {
                balancedEl.setAttribute('data-gap', config.gap);
            }

            // Apply inline styles
            if (config.style) {
                this._applyStyles(balancedEl, config.style);
            }

            // Handle container wrapper
            let containerEl = null;
            if (config.container) {
                containerEl = document.createElement('div');
                if (config.container === 'fluid') {
                    containerEl.className = 'container-fluid';
                } else if (config.container === 'full') {
                    containerEl.className = 'container-full';
                } else if (config.container === 'flex') {
                    containerEl.className = 'container-flex';
                } else {
                    containerEl.className = 'container';
                }
            }

            // Render items
            if (config.items && Array.isArray(config.items)) {
                config.items.forEach(itemConfig => {
                    const itemEl = document.createElement('div');
                    itemEl.className = 'slot-item';

                    // Add custom classes to item
                    if (itemConfig.classes) {
                        itemConfig.classes.forEach(cls => itemEl.classList.add(cls));
                    }

                    // Set item ID
                    if (itemConfig.id) {
                        itemEl.id = itemConfig.id;
                    }

                    // Apply inline styles to item
                    if (itemConfig.style) {
                        this._applyStyles(itemEl, itemConfig.style);
                    }

                    // Apply data attributes
                    if (itemConfig.data) {
                        Object.entries(itemConfig.data).forEach(([key, value]) => {
                            itemEl.setAttribute(`data-${key}`, value);
                        });
                    }

                    // Add slotId as data attribute for targeted updates (used by Page Builder)
                    if (itemConfig.slotId) {
                        itemEl.setAttribute('data-slot-id', itemConfig.slotId);
                    }

                    // Render content
                    if (itemConfig.content) {
                        this._setItemContent(itemEl, itemConfig.content);
                    } else if (itemConfig.html) {
                        // Shorthand for HTML content
                        itemEl.innerHTML = itemConfig.html;
                    } else if (itemConfig.text) {
                        // Shorthand for text content
                        itemEl.textContent = itemConfig.text;
                    }

                    balancedEl.appendChild(itemEl);
                });
            }

            // Append to container or directly to parent
            if (containerEl) {
                containerEl.appendChild(balancedEl);
                el.appendChild(containerEl);
            } else {
                el.appendChild(balancedEl);
            }

            // Initialize balanced layout after DOM is ready
            setTimeout(() => {
                if (window.RSL && window.RSL.initBalancedSlots) {
                    window.RSL.initBalancedSlots();
                }
            }, 100);

            return balancedEl;
        }

        // ====================================================================
        // V2 INTERACTIVE COMPONENT WRAPPERS
        // These wrap existing v1 components with semantic v2 syntax
        // ====================================================================

        /**
         * Render select dropdown (wrapper for v1 Select component)
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Select configuration
         */
        _renderSelect(el, config) {
            // Create select element with v1 data attributes
            const select = document.createElement('select');
            select.setAttribute('data-rsl-select', '');

            // Map v2 config to v1 data attributes
            if (config.placeholder) {
                select.setAttribute('data-rsl-select-placeholder', config.placeholder);
            }

            if (config.multi) {
                select.setAttribute('data-rsl-select-multi', 'true');
            }

            if (config.searchable) {
                select.setAttribute('data-rsl-select-searchable', 'true');
            }

            if (config.clearable) {
                select.setAttribute('data-rsl-select-clearable', 'true');
            }

            // Add CSS classes if specified
            if (config.classes) {
                config.classes.forEach(cls => select.classList.add(cls));
            }

            // Add options
            (config.options || []).forEach(opt => {
                const option = document.createElement('option');
                option.value = opt.value;
                option.textContent = opt.label || opt.text || opt.value;
                if (opt.selected) option.selected = true;
                if (opt.disabled) option.disabled = true;
                select.appendChild(option);
            });

            // Add to container
            el.appendChild(select);

            // Note: Select will be initialized by _initializeComponents()
            // No need to call create() here to avoid double-initialization

            // Add change event handler if specified
            if (config.onChange) {
                select.addEventListener('change', (e) => {
                    config.onChange(e, select);
                });
            }
        }

        /**
         * Render modal dialog (wrapper for v1 Modal component)
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Modal configuration
         */
        _renderModal(el, config) {
            // Generate unique ID if not provided
            const modalId = config.id || `modal-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

            // Create modal container
            const container = document.createElement('div');
            container.className = 'modal-container';
            container.id = modalId;
            container.setAttribute('role', 'dialog');
            container.setAttribute('aria-modal', 'true');

            // Add size class
            const sizeClass = config.size === 'small' ? 'small-modal-size' :
                            config.size === 'large' ? 'large-modal-size' :
                            'default-modal-size';
            container.classList.add(sizeClass);

            // Add custom classes
            if (config.classes) {
                config.classes.forEach(cls => container.classList.add(cls));
            }

            // Create modal
            const modal = document.createElement('div');
            modal.className = 'modal';

            // Modal header
            if (config.title || config.showCloseButton !== false) {
                const header = document.createElement('div');
                header.className = 'modal-header';

                // Apply custom header styling if provided
                if (config.headerStyle) {
                    Object.entries(config.headerStyle).forEach(([key, value]) => {
                        header.style[key] = value;
                    });
                }

                if (config.title) {
                    const title = document.createElement('h2');
                    title.id = `${modalId}-title`;
                    title.textContent = config.title;

                    // Apply title styling if header has custom background
                    if (config.headerStyle && config.headerStyle.background) {
                        title.style.color = config.headerStyle.color || 'white';
                    }

                    header.appendChild(title);
                    container.setAttribute('aria-labelledby', `${modalId}-title`);
                }

                if (config.showCloseButton !== false) {
                    const closeBtn = document.createElement('button');
                    closeBtn.className = 'close-modal';
                    closeBtn.setAttribute('aria-label', 'Close Modal');
                    closeBtn.setAttribute('data-animation-out', 'fadeOut');
                    closeBtn.innerHTML = '&times;';

                    // Apply close button styling if header has custom background
                    if (config.headerStyle && config.headerStyle.background) {
                        closeBtn.style.color = config.headerStyle.color || 'white';
                        closeBtn.style.background = 'transparent';
                        closeBtn.style.border = 'none';
                    }

                    header.appendChild(closeBtn);
                }

                modal.appendChild(header);
            }

            // Modal body
            const body = document.createElement('div');
            body.className = 'modal-body';

            if (config.content) {
                if (typeof config.content === 'string') {
                    body.innerHTML = config.content;
                } else if (config.content.type) {
                    // Render nested content type
                    const renderer = this.contentRenderers[config.content.type];
                    if (renderer) {
                        renderer(body, config.content);
                    }
                }
            } else if (config.body) {
                body.innerHTML = config.body;
            }

            modal.appendChild(body);

            // Modal footer with buttons
            if (config.buttons && config.buttons.length > 0) {
                const footer = document.createElement('div');
                footer.className = 'modal-footer';

                // Button alignment
                const alignment = config.buttonAlign || 'right';
                footer.classList.add(`modal-buttons-${alignment}`);

                config.buttons.forEach((btnConfig, index) => {
                    const btn = this._createButton(btnConfig);
                    // Add spacing between buttons (except last one)
                    if (index < config.buttons.length - 1) {
                        btn.style.marginRight = '0.5rem';
                    }
                    footer.appendChild(btn);
                });

                modal.appendChild(footer);
            }

            container.appendChild(modal);
            el.appendChild(container);

            // Move modal to body for proper positioning (after a brief delay)
            setTimeout(() => {
                if (container.parentElement && container.parentElement.id !== 'body') {
                    document.body.appendChild(container);
                }

                // Initialize v1 Modal component
                if (window.RSL && window.RSL.Modal && window.RSL.Modal.init) {
                    window.RSL.Modal.init();
                }

                // Auto-show if specified
                if (config.show) {
                    if (window.RSL && window.RSL.Modal && window.RSL.Modal.showModal) {
                        window.RSL.Modal.showModal({ target: `#${modalId}` });
                    }
                }
            }, 100);
        }

        /**
         * Render tooltip (wrapper for v1 Tooltip component)
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Tooltip configuration
         */
        _renderTooltip(el, config) {
            let triggerElement;

            if (config.trigger) {
                // Use specified trigger element
                if (typeof config.trigger === 'string') {
                    triggerElement = document.createElement('span');
                    triggerElement.innerHTML = config.trigger;
                } else if (config.trigger.type) {
                    // Render nested content type directly as trigger
                    const renderer = this.contentRenderers[config.trigger.type];
                    if (renderer) {
                        // Create a temporary container to render into
                        const tempContainer = document.createElement('div');
                        renderer(tempContainer, config.trigger);
                        // Get the actual rendered element (first child)
                        triggerElement = tempContainer.firstElementChild || tempContainer.firstChild;
                        if (!triggerElement) {
                            triggerElement = tempContainer;
                        }
                    }
                }
            } else {
                // Create default trigger
                triggerElement = document.createElement('span');
                triggerElement.className = 'tooltip-trigger';
                triggerElement.innerHTML = config.triggerText || '<i class="fa fa-info-circle"></i>';
            }

            // Add tooltip data attributes directly to the trigger element (e.g., the button)
            if (triggerElement) {
                triggerElement.setAttribute('data-tooltip', config.text || config.content || '');

                if (config.position) {
                    triggerElement.setAttribute('data-tooltip-position', config.position);
                }

                if (config.variant) {
                    triggerElement.setAttribute('data-tooltip-variant', config.variant);
                }

                if (config.size) {
                    triggerElement.setAttribute('data-tooltip-size', config.size);
                }

                // Add custom classes
                if (config.classes) {
                    config.classes.forEach(cls => triggerElement.classList.add(cls));
                }

                // Add inline styles
                if (config.style) {
                    Object.keys(config.style).forEach(prop => {
                        triggerElement.style[prop] = config.style[prop];
                    });
                }

                el.appendChild(triggerElement);
            }

            // Note: Tooltip will be initialized by _initializeComponents()
            // No need to call attach() here to avoid double-initialization
        }

        /**
         * Render popover with trigger and popover elements
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Popover configuration
         */
        _renderPopover(el, config) {
            // Generate unique ID for popover
            const popoverId = config.id || `popover-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;

            // Create wrapper container
            const wrapper = document.createElement('div');
            wrapper.className = 'popover-wrapper';

            // Create trigger element
            let triggerElement;

            if (config.trigger && config.trigger.type) {
                // Render nested content type as trigger (e.g., button, link)
                const renderer = this.contentRenderers[config.trigger.type];
                if (renderer) {
                    const tempContainer = document.createElement('div');
                    renderer(tempContainer, config.trigger);
                    triggerElement = tempContainer.firstElementChild || tempContainer.firstChild;
                    if (!triggerElement) {
                        triggerElement = tempContainer;
                    }
                }
            } else if (config.triggerText || config.triggerHTML) {
                // Create default button trigger
                triggerElement = document.createElement('button');
                triggerElement.className = 'btn btn-default';
                if (config.triggerHTML) {
                    triggerElement.innerHTML = config.triggerHTML;
                } else {
                    triggerElement.textContent = config.triggerText || 'Show Popover';
                }
            } else {
                // Fallback default trigger
                triggerElement = document.createElement('button');
                triggerElement.className = 'btn btn-default';
                triggerElement.textContent = 'Show Popover';
            }

            // Add data attributes to trigger
            triggerElement.setAttribute('data-toggle', 'popover');
            triggerElement.setAttribute('data-popover', popoverId);
            triggerElement.setAttribute('aria-describedby', popoverId);

            if (config.triggerMode || config.trigger?.mode) {
                triggerElement.setAttribute('data-trigger', config.triggerMode || config.trigger.mode);
            }

            if (config.placement) {
                triggerElement.setAttribute('data-placement', config.placement);
            }

            if (config.animation) {
                triggerElement.setAttribute('data-animation', config.animation);
            }

            // Add trigger classes
            if (config.triggerClasses) {
                config.triggerClasses.forEach(cls => triggerElement.classList.add(cls));
            }

            wrapper.appendChild(triggerElement);

            // Create popover element
            const popoverElement = document.createElement('div');
            popoverElement.id = popoverId;
            popoverElement.className = 'rsl-popover';
            popoverElement.setAttribute('role', 'tooltip');
            popoverElement.style.display = 'none';

            // Add arrow if enabled (default true)
            if (config.arrow !== false) {
                const arrow = document.createElement('div');
                arrow.className = 'arrow';
                popoverElement.appendChild(arrow);
            }

            // Add popover header if provided
            if (config.header || config.title) {
                const header = document.createElement('div');
                header.className = 'rsl-popover-header';
                header.textContent = config.header || config.title;
                popoverElement.appendChild(header);
            }

            // Add popover body
            const body = document.createElement('div');
            body.className = 'rsl-popover-body';

            if (config.content) {
                if (typeof config.content === 'string') {
                    body.innerHTML = config.content;
                } else if (config.content.type) {
                    // Render nested content type
                    const renderer = this.contentRenderers[config.content.type];
                    if (renderer) {
                        renderer(body, config.content);
                    }
                }
            } else if (config.body) {
                body.innerHTML = config.body;
            }

            popoverElement.appendChild(body);

            // Add popover classes
            if (config.popoverClasses) {
                config.popoverClasses.forEach(cls => popoverElement.classList.add(cls));
            }

            wrapper.appendChild(popoverElement);
            el.appendChild(wrapper);

            // Note: Popover will be initialized by _initializeComponents()
            // No need to call init() here to avoid double-initialization
        }

        /**
         * Render accordion (wrapper for v1 Accordion component)
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Accordion configuration
         */
        _renderAccordion(el, config) {
            // Create accordion container
            const container = document.createElement('div');
            const variant = config.variant || 'default'; // default or classic

            // Classic accordion needs both slot-layout and classic-accordion classes
            if (variant === 'classic') {
                container.className = 'slot-layout classic-accordion';
            } else {
                container.className = 'accordion';
            }

            // Add single-open attribute if specified
            if (config.singleOpen !== undefined) {
                container.setAttribute('data-single-open', config.singleOpen.toString());
            }

            // Add custom classes
            if (config.classes) {
                config.classes.forEach(cls => container.classList.add(cls));
            }

            // Render accordion items
            if (config.items && Array.isArray(config.items)) {
                config.items.forEach(item => {
                    const accordionItem = document.createElement('div');
                    accordionItem.className = 'accordion-item';

                    // Create title element (button for default, div for classic)
                    const titleElement = document.createElement(variant === 'classic' ? 'div' : 'button');
                    titleElement.className = 'accordion-title';

                    // Classic accordion has different structure for icon and text
                    if (variant === 'classic') {
                        // Make div focusable for keyboard navigation
                        titleElement.setAttribute('tabindex', '0');
                        titleElement.setAttribute('role', 'button');

                        // Classic: icon and text-content div as siblings
                        if (item.icon) {
                            const icon = document.createElement('i');
                            icon.className = item.icon;
                            titleElement.appendChild(icon);
                        }
                        const textContent = document.createElement('div');
                        textContent.className = 'text-content';
                        textContent.textContent = item.title || '';
                        titleElement.appendChild(textContent);
                    } else {
                        // Default: icon and text inline in button
                        if (item.icon) {
                            const icon = document.createElement('i');
                            icon.className = item.icon;
                            titleElement.appendChild(icon);
                            titleElement.appendChild(document.createTextNode(' ' + (item.title || '')));
                        } else {
                            titleElement.textContent = item.title || '';
                        }
                    }

                    // Set initial state
                    if (item.open) {
                        titleElement.setAttribute('aria-expanded', 'true');
                    }

                    accordionItem.appendChild(titleElement);

                    // Create content div
                    const contentDiv = document.createElement('div');
                    contentDiv.className = 'accordion-content';

                    if (item.open) {
                        contentDiv.classList.add('open');
                    }

                    // Create inner body wrapper for proper padding
                    const bodyDiv = document.createElement('div');
                    bodyDiv.className = 'accordion-body';
                    bodyDiv.style.padding = '1rem 1.25rem';

                    // Add content to body wrapper
                    if (typeof item.content === 'string') {
                        bodyDiv.innerHTML = item.content;
                    } else if (item.content && item.content.type) {
                        // Render nested content type
                        const renderer = this.contentRenderers[item.content.type];
                        if (renderer) {
                            renderer(bodyDiv, item.content);
                        }
                    }

                    contentDiv.appendChild(bodyDiv);
                    accordionItem.appendChild(contentDiv);
                    container.appendChild(accordionItem);
                });
            }

            el.appendChild(container);

            // Initialize accordion component after a short delay to ensure DOM is ready
            setTimeout(() => {
                // Initialize the accordion with keyboard navigation and ARIA
                if (window.RSL && window.RSL.Accordion && window.RSL.Accordion.create) {
                    window.RSL.Accordion.create(container);
                }

                // Set up grid column calculation for dynamically added grids inside accordion
                const grids = container.querySelectorAll('.slot-layout:not(.accordion):not(.classic-accordion)');
                grids.forEach(grid => {
                    // Calculate columns initially
                    this._calculateGridColumns(grid);

                    // Add resize listener to recalculate when window resizes
                    const resizeHandler = () => {
                        this._calculateGridColumns(grid);
                    };
                    window.addEventListener('resize', resizeHandler);

                    // Store handler for potential cleanup
                    grid._resizeHandler = resizeHandler;
                });
            }, 200);
        }

        /**
         * Render tabs (wrapper for v1 Tabs component)
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Tabs configuration
         *
         * Supported config options:
         * - variant: 'default' | 'pills' | 'boxed' | 'minimal'
         * - alignment: 'left' | 'center' | 'right' | 'stretch'
         * - orientation: 'horizontal' | 'vertical'
         * - animated: boolean (default: true)
         * - defaultTab: number (0-based index)
         * - filterSubscribe: string (FilterBus subscribe key)
         * - dateFilterKey: string (date filter key)
         * - tabs[].filterValue: string (per-tab filter value)
         * - tabs[].dateValue: string (per-tab date value)
         * - tabs[].icon: string (FontAwesome class)
         * - tabs[].disabled: boolean
         */
        _renderTabs(el, config) {
            // Create tabs-display container
            const tabsDisplay = document.createElement('div');
            tabsDisplay.className = 'tabs-display';

            // Apply variant class
            const variant = config.variant || 'default';
            if (variant !== 'default') {
                tabsDisplay.classList.add(`tabs-${variant}`);
            }

            // Apply orientation
            const orientation = config.orientation || 'horizontal';
            if (orientation === 'vertical') {
                tabsDisplay.classList.add('tabs-vertical');
            }

            // Apply alignment via data attribute (CSS can use this)
            const alignment = config.alignment || 'left';
            tabsDisplay.setAttribute('data-tabs-alignment', alignment);

            // Apply animation setting
            if (config.animated === false) {
                tabsDisplay.setAttribute('data-tabs-animated', 'false');
            }

            // Add FilterBus subscription if specified
            if (config.filterSubscribe) {
                tabsDisplay.setAttribute('data-filter-subscribe', config.filterSubscribe);
            }

            // Add date filter key if specified
            if (config.dateFilterKey) {
                tabsDisplay.setAttribute('data-date-filter', config.dateFilterKey);
            }

            // Create tab links container
            const tabsContainer = document.createElement('div');
            tabsContainer.className = 'slot-layout tabs';
            tabsContainer.setAttribute('role', 'tablist');

            // Apply alignment style to tabs container
            if (alignment === 'center') {
                tabsContainer.style.justifyContent = 'center';
            } else if (alignment === 'right') {
                tabsContainer.style.justifyContent = 'flex-end';
            } else if (alignment === 'stretch') {
                tabsContainer.style.justifyContent = 'stretch';
            }

            // Default tab index
            const defaultTab = config.defaultTab || 0;

            // Render tab links
            if (config.tabs && Array.isArray(config.tabs)) {
                config.tabs.forEach((tab, index) => {
                    const tabId = tab.id || `tab-${Date.now()}-${index}`;

                    const tabLink = document.createElement('a');
                    tabLink.className = 'slot-item tab-link';
                    tabLink.setAttribute('data-tab', tabId);

                    // Mark active tab
                    if (index === defaultTab) {
                        tabLink.classList.add('active');
                    }

                    // Handle disabled state
                    if (tab.disabled) {
                        tabLink.classList.add('disabled');
                        tabLink.setAttribute('aria-disabled', 'true');
                        tabLink.setAttribute('tabindex', '-1');
                    }

                    // Add FilterBus filter value if specified
                    if (tab.filterValue) {
                        tabLink.setAttribute('data-filter-value', tab.filterValue);
                    }

                    // Add date value if specified
                    if (tab.dateValue) {
                        tabLink.setAttribute('data-date', tab.dateValue);
                    }

                    // Build tab content with optional icon
                    const labelText = tab.label || tab.title || `Tab ${index + 1}`;
                    if (tab.icon) {
                        const icon = document.createElement('i');
                        icon.className = tab.icon;
                        icon.setAttribute('aria-hidden', 'true');
                        tabLink.appendChild(icon);
                        tabLink.appendChild(document.createTextNode(' ' + labelText));
                    } else {
                        tabLink.textContent = labelText;
                    }

                    tabsContainer.appendChild(tabLink);
                });
            }

            tabsDisplay.appendChild(tabsContainer);

            // Create tab content container
            const tabContentContainer = document.createElement('div');
            tabContentContainer.className = 'slot-layout tabs-content';

            // Render tab content panels
            if (config.tabs && Array.isArray(config.tabs)) {
                config.tabs.forEach((tab, index) => {
                    const tabId = tab.id || `tab-${Date.now()}-${index}`;

                    const contentDiv = document.createElement('div');
                    contentDiv.className = 'slot-item tab-content';
                    contentDiv.setAttribute('data-tab', tabId);

                    // Set active class on default tab (CSS handles display via .active class)
                    if (index === defaultTab) {
                        contentDiv.classList.add('active');
                    }

                    // Add content
                    if (typeof tab.content === 'string') {
                        contentDiv.innerHTML = tab.content;
                    } else if (tab.content && tab.content.type) {
                        // Render nested content type
                        const renderer = this.contentRenderers[tab.content.type];
                        if (renderer) {
                            renderer(contentDiv, tab.content);
                        }
                    }

                    tabContentContainer.appendChild(contentDiv);
                });
            }

            tabsDisplay.appendChild(tabContentContainer);
            el.appendChild(tabsDisplay);

            // Initialize tabs component after a short delay to ensure DOM is ready
            setTimeout(() => {
                // Initialize the tabs with keyboard navigation and ARIA
                if (window.RSL && window.RSL.Tabs && window.RSL.Tabs.create) {
                    window.RSL.Tabs.create(tabsDisplay);
                }

                // Add skip links for accessibility
                if (typeof ADAcompliantNavigator === 'function') {
                    ADAcompliantNavigator({
                        'id-or-class': '.tabs-display',
                        'require-skip-below-link': 'true',
                        'require-skip-above-link': 'true',
                        'skip-below-link-text': 'Skip Below Tabbed Content',
                        'skip-above-link-text': 'Skip Above Tabbed Content',
                        'link-class': 'adaContentJump'
                    });
                }

                // Set up grid column calculation for dynamically added grids inside tabs
                const grids = tabsDisplay.querySelectorAll('.slot-layout:not(.tabs):not(.tabs-content)');
                grids.forEach(grid => {
                    // Calculate columns initially
                    this._calculateGridColumns(grid);

                    // Add resize listener to recalculate when window resizes
                    const resizeHandler = () => {
                        this._calculateGridColumns(grid);
                    };
                    window.addEventListener('resize', resizeHandler);

                    // Store handler for potential cleanup
                    grid._resizeHandler = resizeHandler;
                });
            }, 200);
        }

        /**
         * Render toast notification (wrapper for v1 Toast component)
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Toast configuration
         */
        _renderToast(el, config) {
            // Create toast element
            const toast = document.createElement('div');
            // Use 'mode' property for positioning type (fixed/absolute), not 'type' (which is the content type)
            const positionType = config.mode || 'fixed';
            toast.className = `rsl-toast rsl-${positionType} rsl-${config.position || 'top-right'}`;
            toast.style.opacity = 0; // Start invisible for fade-in

            // Set timeout data attribute
            if (config.timeout !== undefined) {
                toast.setAttribute('data-timeout', config.timeout);
            } else {
                toast.setAttribute('data-timeout', '3000'); // default
            }

            // Create header
            const header = document.createElement('div');
            header.className = 'rsl-toast-header';

            // Apply background color if specified
            if (config.bgColor) {
                header.style.backgroundColor = config.bgColor;
            }

            // Header text
            const headerText = document.createTextNode(config.header || 'Notification');
            header.appendChild(headerText);

            // Close button
            const closeButton = document.createElement('button');
            closeButton.type = 'button';
            closeButton.className = 'rsl-toast-close';
            closeButton.setAttribute('aria-label', 'Close');
            closeButton.innerHTML = '&times;';
            header.appendChild(closeButton);

            // Create body
            const body = document.createElement('div');
            body.className = 'rsl-toast-body';
            body.innerHTML = config.body || config.content || '';

            // Assemble toast
            toast.appendChild(header);
            toast.appendChild(body);

            // For fixed toasts, append directly to body for proper viewport positioning
            // For absolute toasts, append to the container element
            if (positionType === 'fixed') {
                document.body.appendChild(toast);
            } else {
                el.appendChild(toast);
            }

            // Fade in the toast
            setTimeout(() => {
                toast.style.transition = 'opacity 0.25s';
                toast.style.opacity = 1;
            }, 10);

            // Initialize toast component to set up close button and auto-dismiss
            setTimeout(() => {
                if (window.RSL && window.RSL.Toast && window.RSL.Toast.create) {
                    window.RSL.Toast.create(toast);
                }
            }, 50);
        }

        /**
         * Render carousel (wrapper for v1 Carousel component)
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Carousel configuration
         */
        _renderCarousel(el, config) {
            // Validate required properties
            if (!config.slides || !Array.isArray(config.slides) || config.slides.length === 0) {
                console.warn('Carousel component requires a "slides" array with at least one slide');
                return;
            }

            // Create main carousel container
            const carouselContainer = document.createElement('div');
            carouselContainer.className = 'responsive-slot-layout carousel-display';

            // Create slider element with auto-rotate data attributes
            const slider = document.createElement('div');
            slider.className = 'slider';

            if (config.autoRotate !== false) {
                slider.setAttribute('data-auto-rotate', 'true');
                slider.setAttribute('data-interval', config.interval || '3');
            }

            // Create indicators container
            const indicatorsContainer = document.createElement('div');
            indicatorsContainer.className = 'slider-indicators-container';

            // Create previous arrow
            const prevArrow = document.createElement('div');
            prevArrow.className = 'carousel-prev-arrow slider-indicator';
            prevArrow.innerHTML = '<i class="fas fa-chevron-left"></i>';

            // Create indicators scroll container
            const indicatorsScroll = document.createElement('div');
            indicatorsScroll.className = 'slider-indicators-scroll';

            const indicators = document.createElement('div');
            indicators.className = 'slider-indicators';

            // Create indicator dots
            config.slides.forEach((slide, index) => {
                const indicator = document.createElement('div');
                indicator.className = `slider-indicator${index === 0 ? ' active' : ''}`;
                indicator.textContent = index + 1;
                indicators.appendChild(indicator);
            });

            indicatorsScroll.appendChild(indicators);

            // Create next arrow
            const nextArrow = document.createElement('div');
            nextArrow.className = 'carousel-next-arrow slider-indicator';
            nextArrow.innerHTML = '<i class="fas fa-chevron-right"></i>';

            // Assemble indicators container
            indicatorsContainer.appendChild(prevArrow);
            indicatorsContainer.appendChild(indicatorsScroll);
            indicatorsContainer.appendChild(nextArrow);

            // Create pause container
            const pauseContainer = document.createElement('div');
            pauseContainer.className = 'pause-container';

            // Create carousel slides container
            const carousel = document.createElement('div');
            carousel.className = 'carousel';

            // Create slides
            config.slides.forEach((slide, index) => {
                const slideEl = document.createElement('div');
                slideEl.className = `carousel-slide${index === 0 ? ' active' : ''}`;

                // Add image if provided
                if (slide.image) {
                    const img = document.createElement('img');
                    img.src = slide.image;
                    img.alt = slide.alt || slide.title || `Slide ${index + 1}`;
                    slideEl.appendChild(img);
                }

                // Add caption if title or text provided
                if (slide.title || slide.text) {
                    const caption = document.createElement('div');
                    caption.className = 'carousel-caption';

                    if (slide.title) {
                        const title = document.createElement('h3');
                        title.textContent = slide.title;
                        caption.appendChild(title);
                    }

                    if (slide.text) {
                        const text = document.createElement('p');
                        text.textContent = slide.text;
                        caption.appendChild(text);
                    }

                    slideEl.appendChild(caption);
                }

                carousel.appendChild(slideEl);
            });

            // Assemble slider
            slider.appendChild(indicatorsContainer);
            slider.appendChild(pauseContainer);
            slider.appendChild(carousel);

            // Assemble carousel container
            carouselContainer.appendChild(slider);

            // Give the carousel a unique ID for ADA navigation
            const uniqueId = 'carousel-' + Date.now() + '-' + Math.random().toString(36).substr(2, 9);
            carouselContainer.id = uniqueId;

            el.appendChild(carouselContainer);

            // Initialize carousel component after a short delay
            setTimeout(() => {
                console.log('=== CAROUSEL V2 DEBUG ===');
                console.log('Carousel ID:', uniqueId);
                console.log('Carousel exists in DOM:', !!document.getElementById(uniqueId));
                console.log('ADAcompliantNavigator exists:', typeof ADAcompliantNavigator);

                if (window.RSL && window.RSL.Carousel && window.RSL.Carousel.create) {
                    window.RSL.Carousel.create(carouselContainer);
                }

                // Add skip links for accessibility - use ID to target this specific carousel
                if (typeof ADAcompliantNavigator === 'function') {
                    console.log('Calling ADAcompliantNavigator with ID:', '#' + uniqueId);
                    ADAcompliantNavigator({
                        'id-or-class': '#' + uniqueId,
                        'require-skip-below-link': 'true',
                        'require-skip-above-link': 'true',
                        'skip-below-link-text': 'Skip Below Carousel Content',
                        'skip-above-link-text': 'Skip Above Carousel Content',
                        'link-class': 'adaContentJump'
                    });

                    // Check what was created
                    setTimeout(() => {
                        console.log('Skip links created:', document.querySelectorAll('.skip-link').length);
                        const carouselEl = document.getElementById(uniqueId);
                        if (carouselEl) {
                            console.log('Skip links in carousel parent:', carouselEl.parentNode.querySelectorAll('.skip-link').length);
                        }
                    }, 100);
                }
            }, 200);
        }

        /**
         * Render off-canvas panel
         * @param {HTMLElement} el - Container element (for trigger button)
         * @param {Object} config - Off-canvas configuration
         *
         * @example
         * {
         *   type: "offcanvas",
         *   id: "myPanel",
         *   position: "right",            // left, right, top, bottom
         *   title: "Settings",
         *   content: "Panel content...",
         *   size: "400px",
         *   trigger: {                    // Optional trigger button
         *     text: "Open Panel",
         *     variant: "primary",
         *     icon: "fas fa-bars"
         *   },
         *   theme: {                      // Optional theming
         *     background: "#2c3e50",
         *     heading: "#f39c12",
         *     text: "#ecf0f1",
         *     shadow: "rgba(0,0,0,0.5)"
         *   }
         * }
         */
        _renderOffCanvas(el, config) {
            // Generate unique ID if not provided
            const panelId = config.id || `offcanvas-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
            const titleId = `${panelId}-title`;

            // Create off-canvas panel
            const panel = document.createElement('aside');
            panel.id = panelId;
            panel.className = 'off-canvas';
            panel.setAttribute('role', 'dialog');
            panel.setAttribute('aria-modal', 'true');
            panel.setAttribute('aria-labelledby', titleId);

            // Set position (default: right)
            const position = config.position || 'right';
            panel.setAttribute('data-off-canvas', position);

            // Apply theming via data attributes
            if (config.theme) {
                if (config.theme.background) {
                    panel.setAttribute('data-off-canvas-bg', config.theme.background);
                }
                if (config.theme.heading) {
                    panel.setAttribute('data-off-canvas-heading', config.theme.heading);
                }
                if (config.theme.text) {
                    panel.setAttribute('data-off-canvas-text', config.theme.text);
                }
                if (config.theme.shadow !== undefined) {
                    panel.setAttribute('data-off-canvas-shadow', config.theme.shadow);
                }
            }

            // Set size if provided
            if (config.size) {
                panel.setAttribute('data-off-canvas-size', config.size);
            }

            // Create header
            const header = document.createElement('header');
            header.className = 'off-canvas-header';

            // Add title
            if (config.title) {
                const title = document.createElement('h2');
                title.id = titleId;
                title.className = 'off-canvas-title';
                title.textContent = config.title;
                header.appendChild(title);
            }

            // Add close button
            const closeBtn = document.createElement('button');
            closeBtn.type = 'button';
            closeBtn.className = 'off-canvas-close';
            closeBtn.setAttribute('aria-label', 'Close');
            closeBtn.setAttribute('onclick', 'RSL.OffCanvas.closeAll()');
            closeBtn.innerHTML = '&times;';
            header.appendChild(closeBtn);

            panel.appendChild(header);

            // Create body
            const body = document.createElement('div');
            body.className = 'off-canvas-body';

            // Add content
            if (config.content) {
                if (typeof config.content === 'string') {
                    body.innerHTML = config.content;
                } else if (config.content.type) {
                    // Render nested content type
                    const renderer = this.contentRenderers[config.content.type];
                    if (renderer) {
                        renderer(body, config.content);
                    }
                } else if (config.content.html) {
                    body.innerHTML = config.content.html;
                }
            }

            panel.appendChild(body);

            // Add panel to document.body (off-canvas panels must be at body level)
            document.body.appendChild(panel);

            // Create trigger button if specified
            if (config.trigger) {
                const btn = document.createElement('button');
                btn.className = 'btn';

                // Apply button variant
                if (config.trigger.variant) {
                    btn.classList.add(`btn-${config.trigger.variant}`);
                } else {
                    btn.classList.add('btn-primary');
                }

                // Apply button size
                if (config.trigger.size) {
                    btn.classList.add(`btn-${config.trigger.size}`);
                }

                // Add icon if specified
                if (config.trigger.icon) {
                    const icon = document.createElement('i');
                    icon.className = config.trigger.icon;
                    btn.appendChild(icon);
                    btn.appendChild(document.createTextNode(' '));
                }

                // Add button text
                btn.appendChild(document.createTextNode(config.trigger.text || 'Open Panel'));

                // Add click handler
                btn.setAttribute('onclick', `RSL.OffCanvas.toggle('${panelId}')`);

                // Add button to container element
                el.appendChild(btn);
            }

            // Initialize off-canvas component after a short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.OffCanvas && window.RSL.OffCanvas.init) {
                    window.RSL.OffCanvas.init();
                }
            }, 100);
        }

        /**
         * Render breadcrumb - Creates a navigation breadcrumb trail
         * Uses the V1 Breadcrumb component (CSS-only)
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Breadcrumb configuration
         * @param {Array} config.items - Array of breadcrumb items
         * @param {string} config.items[].text - Item text
         * @param {string} [config.items[].url] - Item link URL (omit for current page)
         * @param {string} [config.items[].icon] - FontAwesome icon class
         * @param {string} [config.items[].ariaLabel] - ARIA label for icon-only items
         * @param {string} [config.ariaLabel] - ARIA label for the nav element (default: "breadcrumb")
         * @param {boolean} [config.compact] - Use compact variant
         * @param {boolean} [config.iconOnly] - Show only icons (requires icons on all items)
         */
        _renderBreadcrumb(el, config) {
            // Validate required properties
            if (!config.items || !Array.isArray(config.items) || config.items.length === 0) {
                console.warn('Breadcrumb component requires an "items" array with at least one item');
                return;
            }

            // Create nav wrapper
            const nav = document.createElement('nav');
            nav.setAttribute('aria-label', config.ariaLabel || 'breadcrumb');

            // Create breadcrumb list
            const ol = document.createElement('ol');
            ol.className = 'rsl-breadcrumb';

            // Add compact class if specified
            if (config.compact) {
                ol.classList.add('compact');
            }

            // Render breadcrumb items
            config.items.forEach((item, index) => {
                const li = document.createElement('li');

                // Determine if this is the current page (last item without URL)
                const isCurrentPage = index === config.items.length - 1 && !item.url;

                if (isCurrentPage) {
                    // Current page - plain text
                    li.setAttribute('aria-current', 'page');

                    if (item.icon) {
                        const icon = document.createElement('i');
                        icon.className = item.icon;
                        li.appendChild(icon);

                        // Add space after icon if not icon-only mode
                        if (!config.iconOnly && item.text) {
                            li.appendChild(document.createTextNode(' '));
                        }
                    }

                    if (!config.iconOnly || !item.icon) {
                        li.appendChild(document.createTextNode(item.text || ''));
                    }

                    // Add ARIA label for icon-only mode
                    if (config.iconOnly && item.ariaLabel) {
                        li.setAttribute('aria-label', item.ariaLabel);
                    }
                } else {
                    // Link item
                    const link = document.createElement('a');
                    link.href = item.url || '#';

                    if (item.icon) {
                        const icon = document.createElement('i');
                        icon.className = item.icon;
                        link.appendChild(icon);

                        // Add space after icon if not icon-only mode
                        if (!config.iconOnly && item.text) {
                            link.appendChild(document.createTextNode(' '));
                        }
                    }

                    if (!config.iconOnly || !item.icon) {
                        link.appendChild(document.createTextNode(item.text || ''));
                    }

                    // Add ARIA label for icon-only mode
                    if (config.iconOnly && item.ariaLabel) {
                        link.setAttribute('aria-label', item.ariaLabel);
                    }

                    // Add title attribute for truncated text
                    if (item.truncate && item.text) {
                        link.classList.add('truncate');
                        link.setAttribute('title', item.text);
                    }

                    li.appendChild(link);
                }

                ol.appendChild(li);
            });

            nav.appendChild(ol);
            el.appendChild(nav);
        }

        /**
         * Render skeleton - Creates animated loading placeholders
         * Uses the V1 Skeleton component (CSS-only with optional JS utilities)
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Skeleton configuration
         * @param {string} config.skeletonType - Skeleton type (text, title, paragraph, circle, rectangle, button, card, listItem, custom)
         * @param {string} [config.variant] - Shape variant (for title: sm/lg, for circle: sm/lg/xl, for rect: sm/lg/xl)
         * @param {string} [config.animation] - Animation type (shimmer, pulse, wave, static/none)
         * @param {number} [config.lines] - Number of lines for paragraph type (default: 3)
         * @param {string} [config.width] - Width for text type (full, 75, 50, 25, or custom CSS value)
         * @param {string} [config.height] - Custom height for rectangle type
         * @param {boolean} [config.avatar] - Include avatar for card/listItem types (default: true)
         * @param {Array} [config.items] - Array of skeleton configs for custom composite skeletons
         */
        _renderSkeleton(el, config) {
            // Validate required properties
            if (!config.skeletonType) {
                console.warn('Skeleton component requires a "skeletonType" property');
                return;
            }

            let skeleton;
            const animation = config.animation;

            switch(config.skeletonType) {
                case 'text':
                    skeleton = this._createTextSkeleton(config);
                    break;

                case 'title':
                    skeleton = this._createTitleSkeleton(config);
                    break;

                case 'paragraph':
                    skeleton = this._createParagraphSkeleton(config);
                    break;

                case 'circle':
                    skeleton = this._createCircleSkeleton(config);
                    break;

                case 'rectangle':
                    skeleton = this._createRectangleSkeleton(config);
                    break;

                case 'button':
                    skeleton = this._createButtonSkeleton(config);
                    break;

                case 'card':
                    skeleton = this._createCardSkeleton(config);
                    break;

                case 'listItem':
                    skeleton = this._createListItemSkeleton(config);
                    break;

                case 'custom':
                    // Custom composite skeleton with multiple items
                    if (config.items && Array.isArray(config.items)) {
                        const container = document.createElement('div');
                        container.className = 'rsl-skeleton-group';

                        config.items.forEach(itemConfig => {
                            const item = document.createElement('div');
                            this._renderSkeleton(item, itemConfig);
                            container.appendChild(item.firstChild);
                        });

                        skeleton = container;
                    }
                    break;

                default:
                    console.warn(`Unknown skeleton type: ${config.skeletonType}`);
                    return;
            }

            if (skeleton) {
                el.appendChild(skeleton);
            }
        }

        /**
         * Create text line skeleton
         * @private
         */
        _createTextSkeleton(config) {
            const skeleton = document.createElement('div');
            skeleton.className = 'rsl-skeleton rsl-skeleton-text';

            // Add width class or custom width
            if (config.width) {
                if (['full', '75', '50', '25'].includes(config.width)) {
                    skeleton.classList.add(`rsl-skeleton-text-${config.width}`);
                } else {
                    skeleton.style.width = config.width;
                }
            }

            this._addSkeletonAnimation(skeleton, config.animation);
            return skeleton;
        }

        /**
         * Create title/heading skeleton
         * @private
         */
        _createTitleSkeleton(config) {
            const skeleton = document.createElement('div');
            skeleton.className = 'rsl-skeleton rsl-skeleton-title';

            if (config.variant === 'sm') {
                skeleton.classList.add('rsl-skeleton-title-sm');
            } else if (config.variant === 'lg') {
                skeleton.classList.add('rsl-skeleton-title-lg');
            }

            this._addSkeletonAnimation(skeleton, config.animation);
            return skeleton;
        }

        /**
         * Create paragraph skeleton (multiple lines)
         * @private
         */
        _createParagraphSkeleton(config) {
            const lines = config.lines || 3;
            const container = document.createElement('div');
            container.className = 'rsl-skeleton-paragraph';

            for (let i = 0; i < lines; i++) {
                const line = this._createTextSkeleton({ animation: config.animation });
                if (i === lines - 1) {
                    line.style.width = '60%';
                }
                container.appendChild(line);
            }

            return container;
        }

        /**
         * Create circle skeleton (avatar, icon)
         * @private
         */
        _createCircleSkeleton(config) {
            const skeleton = document.createElement('div');
            skeleton.className = 'rsl-skeleton rsl-skeleton-circle';

            if (config.variant && config.variant !== 'md') {
                skeleton.classList.add(`rsl-skeleton-circle-${config.variant}`);
            }

            this._addSkeletonAnimation(skeleton, config.animation);
            return skeleton;
        }

        /**
         * Create rectangle skeleton (image, card)
         * @private
         */
        _createRectangleSkeleton(config) {
            const skeleton = document.createElement('div');
            skeleton.className = 'rsl-skeleton rsl-skeleton-rect';

            if (config.variant && config.variant !== 'md') {
                skeleton.classList.add(`rsl-skeleton-rect-${config.variant}`);
            }

            if (config.height) {
                skeleton.style.height = config.height;
            }

            this._addSkeletonAnimation(skeleton, config.animation);
            return skeleton;
        }

        /**
         * Create button skeleton
         * @private
         */
        _createButtonSkeleton(config) {
            const skeleton = document.createElement('div');
            skeleton.className = 'rsl-skeleton rsl-skeleton-button';

            if (config.variant && config.variant !== 'md') {
                skeleton.classList.add(`rsl-skeleton-button-${config.variant}`);
            }

            this._addSkeletonAnimation(skeleton, config.animation);
            return skeleton;
        }

        /**
         * Create card skeleton
         * @private
         */
        _createCardSkeleton(config) {
            const card = document.createElement('div');
            card.className = 'rsl-skeleton-card';

            // Header with avatar
            if (config.avatar !== false) {
                const header = document.createElement('div');
                header.className = 'rsl-skeleton-card-header';
                header.appendChild(this._createCircleSkeleton({ variant: 'lg', animation: config.animation }));

                const headerText = document.createElement('div');
                headerText.style.flex = '1';
                headerText.appendChild(this._createTextSkeleton({ width: '70%', animation: config.animation }));
                headerText.appendChild(this._createTextSkeleton({ width: '50%', animation: config.animation }));

                header.appendChild(headerText);
                card.appendChild(header);
            }

            // Body with text lines
            const body = document.createElement('div');
            body.className = 'rsl-skeleton-card-body';
            body.appendChild(this._createParagraphSkeleton({ lines: config.lines || 3, animation: config.animation }));
            card.appendChild(body);

            return card;
        }

        /**
         * Create list item skeleton
         * @private
         */
        _createListItemSkeleton(config) {
            const item = document.createElement('div');
            item.className = 'rsl-skeleton-list-item';

            if (config.avatar !== false) {
                item.appendChild(this._createCircleSkeleton({ animation: config.animation }));
            }

            const content = document.createElement('div');
            content.className = 'rsl-skeleton-list-item-content';
            content.appendChild(this._createTextSkeleton({ width: '60%', animation: config.animation }));
            content.appendChild(this._createTextSkeleton({ width: '40%', animation: config.animation }));

            item.appendChild(content);

            return item;
        }

        /**
         * Add animation class to skeleton
         * @private
         */
        _addSkeletonAnimation(element, animation) {
            if (animation === 'pulse') {
                element.classList.add('rsl-skeleton-pulse');
            } else if (animation === 'wave') {
                element.classList.add('rsl-skeleton-wave');
            } else if (animation === 'static' || animation === 'none') {
                element.classList.add('rsl-skeleton-static');
            }
            // Default is shimmer (no additional class needed)
        }

        /**
         * Render form - Creates a complete form with various field types
         * Uses the RSL Form Elements system (form-elements.css/js)
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Form configuration
         * @param {string} [config.id] - Form ID
         * @param {string} [config.action] - Form action URL
         * @param {string} [config.method] - Form method (get, post)
         * @param {string} [config.className] - Additional CSS classes
         * @param {Array} config.fields - Array of field configurations
         * @param {Object} [config.submitButton] - Submit button configuration
         * @param {Object} [config.cancelButton] - Cancel button configuration
         * @param {boolean} [config.inline] - Use inline layout
         *
         * Field types supported:
         * - text, email, password, tel, url, number, date, time: Text input fields
         * - textarea: Multi-line text input
         * - chips: Checkbox chip group
         * - choiceCards: Radio choice cards
         * - select: Custom dropdown select
         * - toggle: Toggle switch
         * - slider: Range slider
         * - file: File upload tile
         * - fieldset: Group of fields with legend
         *
         * @example
         * {
         *   type: "form",
         *   id: "contact-form",
         *   fields: [
         *     { fieldType: "text", name: "name", label: "Name", placeholder: "Enter name", required: true },
         *     { fieldType: "email", name: "email", label: "Email", placeholder: "Enter email" },
         *     { fieldType: "toggle", name: "subscribe", label: "Subscribe", helper: "Receive updates" },
         *     { fieldType: "chips", name: "interests", label: "Interests", options: [
         *       { value: "tech", label: "Technology" },
         *       { value: "design", label: "Design" }
         *     ]},
         *     { fieldType: "slider", name: "budget", label: "Budget", min: 0, max: 1000, value: 500 }
         *   ],
         *   submitButton: { text: "Submit", variant: "primary" }
         * }
         */
        /**
         * Render form - Creates a complete form with various field types
         * Supports both Modern Forms (form-elements.css) and Basic Forms (form.css)
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Form configuration
         * @param {string} [config.formStyle="modern"] - Form style: "modern" or "basic"
         * @param {string} [config.id] - Form ID
         * @param {string} [config.action] - Form action URL
         * @param {string} [config.method] - Form method (get, post)
         * @param {string} [config.className] - Additional CSS classes
         * @param {Array} config.fields - Array of field configurations
         * @param {Object} [config.submitButton] - Submit button configuration
         * @param {Object} [config.cancelButton] - Cancel button configuration
         * @param {boolean} [config.inline] - Use inline layout
         * @param {Object} [config.theme] - Form theming (for modern forms)
         */
        _renderForm(el, config) {
            const isBasicForm = config.formStyle === 'basic';
            const form = document.createElement('form');

            // Set form class based on style
            form.className = isBasicForm ? 'form' : 'rsl-form-demo';

            // Add novalidate for custom validation
            form.setAttribute('novalidate', '');

            if (config.id) {
                form.id = config.id;
            }

            if (config.action) {
                form.action = config.action;
            }

            if (config.method) {
                form.method = config.method;
            }

            if (config.className) {
                form.className += ' ' + config.className;
            }

            // Apply form-level theming (modern forms only)
            if (!isBasicForm && config.theme) {
                if (config.theme.fieldBg) form.setAttribute('data-field-bg', config.theme.fieldBg);
                if (config.theme.fieldBorder) form.setAttribute('data-field-border', config.theme.fieldBorder);
                if (config.theme.fieldFocus) form.setAttribute('data-field-focus', config.theme.fieldFocus);
                if (config.theme.fieldText) form.setAttribute('data-field-text', config.theme.fieldText);
                if (config.theme.fieldMuted) form.setAttribute('data-field-muted', config.theme.fieldMuted);
                if (config.theme.chipBg) form.setAttribute('data-chip-bg', config.theme.chipBg);
                if (config.theme.chipBorder) form.setAttribute('data-chip-border', config.theme.chipBorder);
                if (config.theme.choiceBg) form.setAttribute('data-choice-bg', config.theme.choiceBg);
                if (config.theme.selectBg) form.setAttribute('data-select-bg', config.theme.selectBg);
                if (config.theme.toggleOn) form.setAttribute('data-toggle-on', config.theme.toggleOn);
                if (config.theme.toggleOff) form.setAttribute('data-toggle-off', config.theme.toggleOff);
                if (config.theme.sliderTrack) form.setAttribute('data-slider-track', config.theme.sliderTrack);
                if (config.theme.sliderFill) form.setAttribute('data-slider-fill', config.theme.sliderFill);
                if (config.theme.fileBg) form.setAttribute('data-file-bg', config.theme.fileBg);
            }

            if (config.inline) {
                form.style.flexDirection = 'row';
                form.style.flexWrap = 'wrap';
                form.style.alignItems = 'flex-end';
            }

            // Render each field based on form style
            if (config.fields && Array.isArray(config.fields)) {
                config.fields.forEach(field => {
                    const fieldElement = isBasicForm
                        ? this._renderBasicFormField(field)
                        : this._renderFormField(field);
                    if (fieldElement) {
                        form.appendChild(fieldElement);
                    }
                });
            }

            // Render form actions (buttons)
            if (config.submitButton || config.cancelButton) {
                const actions = document.createElement('div');
                actions.className = isBasicForm ? 'form-group' : 'rsl-form-actions';

                if (config.submitButton) {
                    const submitBtn = document.createElement('button');
                    submitBtn.type = 'submit';

                    if (isBasicForm) {
                        // Basic form button styling
                        submitBtn.style.cssText = 'background: #6E7BFF; color: white; border: none; padding: 0.75rem 1.5rem; border-radius: 4px; cursor: pointer; font-weight: 600; margin-right: 0.5rem;';
                    } else {
                        submitBtn.className = config.submitButton.variant === 'ghost'
                            ? 'rsl-btn-ghost'
                            : 'rsl-btn-primary';
                    }

                    submitBtn.textContent = config.submitButton.text || 'Submit';

                    if (config.submitButton.icon) {
                        const icon = document.createElement('i');
                        icon.className = config.submitButton.icon;
                        submitBtn.insertBefore(icon, submitBtn.firstChild);
                        submitBtn.insertBefore(document.createTextNode(' '), submitBtn.lastChild);
                    }

                    actions.appendChild(submitBtn);
                }

                if (config.cancelButton) {
                    const cancelBtn = document.createElement('button');
                    cancelBtn.type = 'button';

                    if (isBasicForm) {
                        cancelBtn.style.cssText = 'background: transparent; color: #6E7BFF; border: 1px solid #6E7BFF; padding: 0.75rem 1.5rem; border-radius: 4px; cursor: pointer; font-weight: 600;';
                    } else {
                        cancelBtn.className = config.cancelButton.variant === 'primary'
                            ? 'rsl-btn-primary'
                            : 'rsl-btn-ghost';
                    }

                    cancelBtn.textContent = config.cancelButton.text || 'Cancel';

                    if (config.cancelButton.onClick) {
                        cancelBtn.addEventListener('click', () => {
                            if (typeof config.cancelButton.onClick === 'function') {
                                config.cancelButton.onClick();
                            }
                        });
                    }

                    actions.appendChild(cancelBtn);
                }

                form.appendChild(actions);
            }

            el.appendChild(form);

            // Initialize form elements after a short delay
            setTimeout(() => {
                if (isBasicForm) {
                    this._initBasicFormElements(form);
                } else {
                    this._initFormElements(form);
                }
            }, 100);
        }

        /**
         * Render a single form field based on its type
         * @private
         */
        _renderFormField(field) {
            switch (field.fieldType) {
                case 'text':
                case 'email':
                case 'password':
                case 'tel':
                case 'url':
                case 'number':
                case 'date':
                case 'time':
                    return this._createFieldTile(field);

                case 'textarea':
                    return this._createTextareaField(field);

                case 'chips':
                    return this._createChipsField(field);

                case 'choiceCards':
                    return this._createChoiceCardsField(field);

                case 'select':
                    return this._createSelectField(field);

                case 'toggle':
                    return this._createToggleField(field);

                case 'slider':
                    return this._createSliderField(field);

                case 'file':
                    return this._createFileField(field);

                case 'fieldset':
                    return this._createFieldset(field);

                default:
                    console.warn(`Unknown form field type: ${field.fieldType}`);
                    return null;
            }
        }

        /**
         * Create a field tile (text input variant)
         * @private
         */
        _createFieldTile(field) {
            const tile = document.createElement('div');
            tile.className = 'rsl-field-tile';

            // Apply custom theming via data attributes
            this._applyFieldTheming(tile, field);

            // Label
            if (field.label) {
                const label = document.createElement('label');
                label.className = 'rsl-field-label';
                label.textContent = field.label;
                if (field.name) {
                    label.setAttribute('for', field.name);
                }
                tile.appendChild(label);
            }

            // Input container
            const body = document.createElement('div');
            body.className = 'rsl-field-body';

            // Prefix icon
            if (field.prefixIcon) {
                const icon = document.createElement('i');
                icon.className = field.prefixIcon;
                icon.style.color = 'var(--rsl-field-muted)';
                body.appendChild(icon);
            }

            // Input element
            const input = document.createElement('input');
            input.type = field.fieldType;
            input.className = 'rsl-field-input';

            if (field.name) {
                input.name = field.name;
                input.id = field.name;
            }
            if (field.placeholder) {
                input.placeholder = field.placeholder;
            }
            if (field.value !== undefined) {
                input.value = field.value;
            }
            if (field.required) {
                input.required = true;
                input.classList.add('input-required');
            }
            if (field.disabled) {
                input.disabled = true;
            }
            if (field.readonly) {
                input.readOnly = true;
            }
            if (field.min !== undefined) {
                input.min = field.min;
            }
            if (field.max !== undefined) {
                input.max = field.max;
            }
            if (field.step !== undefined) {
                input.step = field.step;
            }
            if (field.pattern) {
                input.pattern = field.pattern;
            }
            if (field.autocomplete) {
                input.autocomplete = field.autocomplete;
            }

            body.appendChild(input);

            // Suffix icon
            if (field.suffixIcon) {
                const icon = document.createElement('i');
                icon.className = field.suffixIcon;
                icon.style.color = 'var(--rsl-field-muted)';
                body.appendChild(icon);
            }

            tile.appendChild(body);

            // Focus indicator bar
            const bar = document.createElement('div');
            bar.className = 'rsl-field-bar';
            tile.appendChild(bar);

            // Helper text
            if (field.helper) {
                const helper = document.createElement('span');
                helper.className = 'rsl-field-helper';
                helper.textContent = field.helper;
                tile.appendChild(helper);
            }

            return tile;
        }

        /**
         * Create a textarea field
         * @private
         */
        _createTextareaField(field) {
            const tile = document.createElement('div');
            tile.className = 'rsl-field-tile';

            this._applyFieldTheming(tile, field);

            if (field.label) {
                const label = document.createElement('label');
                label.className = 'rsl-field-label';
                label.textContent = field.label;
                if (field.name) {
                    label.setAttribute('for', field.name);
                }
                tile.appendChild(label);
            }

            const textarea = document.createElement('textarea');
            textarea.className = 'rsl-field-input';
            textarea.style.resize = field.resize || 'vertical';
            textarea.style.minHeight = field.minHeight || '80px';

            if (field.name) {
                textarea.name = field.name;
                textarea.id = field.name;
            }
            if (field.placeholder) {
                textarea.placeholder = field.placeholder;
            }
            if (field.value) {
                textarea.value = field.value;
            }
            if (field.required) {
                textarea.required = true;
                textarea.classList.add('input-required');
            }
            if (field.rows) {
                textarea.rows = field.rows;
            }
            if (field.maxlength) {
                textarea.maxLength = field.maxlength;
            }

            tile.appendChild(textarea);

            const bar = document.createElement('div');
            bar.className = 'rsl-field-bar';
            tile.appendChild(bar);

            if (field.helper) {
                const helper = document.createElement('span');
                helper.className = 'rsl-field-helper';
                helper.textContent = field.helper;
                tile.appendChild(helper);
            }

            return tile;
        }

        /**
         * Create chips (checkbox group) field
         * @private
         */
        _createChipsField(field) {
            const container = document.createElement('div');

            if (field.label) {
                const fieldset = document.createElement('fieldset');
                fieldset.className = 'rsl-fieldset';

                const legend = document.createElement('legend');
                legend.className = 'rsl-fieldset-legend';
                legend.textContent = field.label;
                fieldset.appendChild(legend);

                const chipRow = this._createChipRow(field);
                fieldset.appendChild(chipRow);

                container.appendChild(fieldset);
            } else {
                container.appendChild(this._createChipRow(field));
            }

            return container;
        }

        /**
         * Create the chip row with options
         * @private
         */
        _createChipRow(field) {
            const row = document.createElement('div');
            row.className = 'rsl-chip-row';

            if (field.options && Array.isArray(field.options)) {
                field.options.forEach((option, index) => {
                    const chip = document.createElement('label');
                    chip.className = 'rsl-chip';

                    const input = document.createElement('input');
                    input.type = 'checkbox';
                    input.className = 'rsl-chip-input';
                    input.name = field.name || `chip-${index}`;
                    input.value = option.value || option.label;

                    if (option.checked) {
                        input.checked = true;
                    }

                    chip.appendChild(input);

                    const check = document.createElement('span');
                    check.className = 'rsl-chip-check';
                    check.innerHTML = '✓';
                    chip.appendChild(check);

                    const label = document.createElement('span');
                    label.className = 'rsl-chip-label';
                    label.textContent = option.label;
                    chip.appendChild(label);

                    row.appendChild(chip);
                });
            }

            return row;
        }

        /**
         * Create choice cards (radio group) field
         * @private
         */
        _createChoiceCardsField(field) {
            const container = document.createElement('div');

            if (field.label) {
                const fieldset = document.createElement('fieldset');
                fieldset.className = 'rsl-fieldset';

                const legend = document.createElement('legend');
                legend.className = 'rsl-fieldset-legend';
                legend.textContent = field.label;
                fieldset.appendChild(legend);

                const grid = this._createChoiceCardsGrid(field);
                fieldset.appendChild(grid);

                container.appendChild(fieldset);
            } else {
                container.appendChild(this._createChoiceCardsGrid(field));
            }

            return container;
        }

        /**
         * Create the choice cards grid
         * @private
         */
        _createChoiceCardsGrid(field) {
            const grid = document.createElement('div');
            grid.className = 'slot-layout';
            grid.setAttribute('data-cols-xs', field.columns?.xs || '1');
            grid.setAttribute('data-cols-sm', field.columns?.sm || '2');
            grid.setAttribute('data-cols-md', field.columns?.md || field.options?.length || '3');
            grid.setAttribute('data-gap', field.gap || '0.75rem');

            if (field.options && Array.isArray(field.options)) {
                field.options.forEach((option, index) => {
                    const item = document.createElement('div');
                    item.className = 'slot-item';

                    const card = document.createElement('label');
                    card.className = 'rsl-choice-card';

                    const input = document.createElement('input');
                    input.type = 'radio';
                    input.className = 'rsl-choice-input';
                    input.name = field.name || 'choice';
                    input.value = option.value || option.title;

                    if (option.checked || (index === 0 && field.selectFirst)) {
                        input.checked = true;
                    }

                    card.appendChild(input);

                    const inner = document.createElement('div');
                    inner.className = 'rsl-choice-inner';

                    const header = document.createElement('div');
                    header.className = 'rsl-choice-header';

                    const title = document.createElement('span');
                    title.className = 'rsl-choice-title';
                    title.textContent = option.title || option.label;
                    header.appendChild(title);

                    if (option.price) {
                        const price = document.createElement('span');
                        price.className = 'rsl-choice-price';
                        price.textContent = option.price;
                        header.appendChild(price);
                    }

                    inner.appendChild(header);

                    if (option.description) {
                        const desc = document.createElement('span');
                        desc.className = 'rsl-choice-desc';
                        desc.textContent = option.description;
                        inner.appendChild(desc);
                    }

                    card.appendChild(inner);
                    item.appendChild(card);
                    grid.appendChild(item);
                });
            }

            return grid;
        }

        /**
         * Create custom select field
         * @private
         */
        _createSelectField(field) {
            const container = document.createElement('div');

            if (field.label) {
                const label = document.createElement('label');
                label.className = 'rsl-fieldset-legend';
                label.textContent = field.label;
                label.style.display = 'block';
                label.style.marginBottom = '0.35rem';
                container.appendChild(label);
            }

            const select = document.createElement('div');
            select.className = 'rsl-select';
            select.setAttribute('data-open', 'false');

            if (field.fullWidth) {
                select.style.maxWidth = 'none';
            }

            // Toggle button
            const toggle = document.createElement('button');
            toggle.type = 'button';
            toggle.className = 'rsl-select-toggle';
            toggle.setAttribute('aria-haspopup', 'listbox');
            toggle.setAttribute('aria-expanded', 'false');

            const valueSpan = document.createElement('span');
            valueSpan.className = 'rsl-select-value';
            valueSpan.textContent = field.placeholder || 'Select...';
            toggle.appendChild(valueSpan);

            const icon = document.createElement('span');
            icon.className = 'rsl-select-icon';
            icon.innerHTML = '▼';
            toggle.appendChild(icon);

            select.appendChild(toggle);

            // Options list
            const list = document.createElement('ul');
            list.className = 'rsl-select-list';
            list.setAttribute('role', 'listbox');
            list.hidden = true;

            if (field.options && Array.isArray(field.options)) {
                field.options.forEach(option => {
                    const li = document.createElement('li');
                    li.className = 'rsl-select-option';
                    li.setAttribute('role', 'option');
                    li.setAttribute('data-value', option.value || option.label);
                    li.textContent = option.label;

                    if (option.selected) {
                        li.setAttribute('aria-selected', 'true');
                        valueSpan.textContent = option.label;
                    }

                    list.appendChild(li);
                });
            }

            select.appendChild(list);

            // Hidden input for form submission
            const hiddenInput = document.createElement('input');
            hiddenInput.type = 'hidden';
            hiddenInput.name = field.name || 'select';

            // Set initial value if an option is selected
            const selectedOption = field.options?.find(o => o.selected);
            if (selectedOption) {
                hiddenInput.value = selectedOption.value || selectedOption.label;
            }

            select.appendChild(hiddenInput);

            container.appendChild(select);

            return container;
        }

        /**
         * Create toggle switch field
         * @private
         */
        _createToggleField(field) {
            const toggle = document.createElement('label');
            toggle.className = 'rsl-toggle';

            const input = document.createElement('input');
            input.type = 'checkbox';
            input.className = 'rsl-toggle-input';

            if (field.name) {
                input.name = field.name;
                input.id = field.name;
            }
            if (field.checked) {
                input.checked = true;
            }
            if (field.disabled) {
                input.disabled = true;
            }

            toggle.appendChild(input);

            const track = document.createElement('span');
            track.className = 'rsl-toggle-track';

            const thumb = document.createElement('span');
            thumb.className = 'rsl-toggle-thumb';
            track.appendChild(thumb);

            toggle.appendChild(track);

            if (field.label || field.helper) {
                const text = document.createElement('span');
                text.className = 'rsl-toggle-text';

                if (field.label) {
                    const label = document.createElement('span');
                    label.className = 'rsl-toggle-label';
                    label.textContent = field.label;
                    text.appendChild(label);
                }

                if (field.helper) {
                    const helper = document.createElement('span');
                    helper.className = 'rsl-toggle-helper';
                    helper.textContent = field.helper;
                    text.appendChild(helper);
                }

                toggle.appendChild(text);
            }

            // Apply custom theming
            if (field.onColor) {
                toggle.setAttribute('data-toggle-on', field.onColor);
            }
            if (field.offColor) {
                toggle.setAttribute('data-toggle-off', field.offColor);
            }

            return toggle;
        }

        /**
         * Create slider field
         * @private
         */
        _createSliderField(field) {
            const container = document.createElement('div');
            container.className = 'rsl-slider';

            if (field.fullWidth) {
                container.style.maxWidth = 'none';
            }

            // Apply custom theming
            if (field.trackColor) {
                container.setAttribute('data-slider-track', field.trackColor);
            }
            if (field.fillColor) {
                container.setAttribute('data-slider-fill', field.fillColor);
            }

            if (field.label) {
                const label = document.createElement('label');
                label.className = 'rsl-fieldset-legend';
                label.textContent = field.label;
                if (field.name) {
                    label.setAttribute('for', field.name);
                }
                container.appendChild(label);
            }

            const row = document.createElement('div');
            row.className = 'rsl-slider-row';

            const input = document.createElement('input');
            input.type = 'range';
            input.className = 'rsl-slider-input';

            if (field.name) {
                input.name = field.name;
                input.id = field.name;
            }

            input.min = field.min !== undefined ? field.min : 0;
            input.max = field.max !== undefined ? field.max : 100;
            input.value = field.value !== undefined ? field.value : 50;

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

            row.appendChild(input);

            // Value display
            if (field.showValue !== false) {
                const valueEl = document.createElement('span');
                valueEl.className = 'rsl-slider-value';
                valueEl.textContent = `${input.value}${field.suffix || '%'}`;
                row.appendChild(valueEl);
            }

            container.appendChild(row);

            if (field.helper) {
                const helper = document.createElement('span');
                helper.className = 'rsl-field-helper';
                helper.textContent = field.helper;
                container.appendChild(helper);
            }

            return container;
        }

        /**
         * Create file upload tile field
         * Supports drag-and-drop with image preview via data-enable-preview attribute
         * @private
         */
        _createFileField(field) {
            const tile = document.createElement('div');
            tile.className = 'rsl-file-tile';

            // Enable drag-and-drop preview if configured
            if (field.enablePreview !== false) {
                tile.setAttribute('data-enable-preview', 'true');
            }

            const label = document.createElement('label');
            label.className = 'rsl-file-label';

            // File icon
            const iconContainer = document.createElement('span');
            iconContainer.className = 'rsl-file-icon';
            iconContainer.innerHTML = field.icon || '<i class="fas fa-cloud-upload-alt"></i>';
            label.appendChild(iconContainer);

            // Text container
            const textContainer = document.createElement('span');
            textContainer.className = 'rsl-file-text';

            const title = document.createElement('span');
            title.className = 'rsl-file-title';
            title.textContent = field.title || 'Drag files here or click to upload';
            textContainer.appendChild(title);

            if (field.helper) {
                const helper = document.createElement('span');
                helper.className = 'rsl-file-helper';
                helper.textContent = field.helper;
                textContainer.appendChild(helper);
            }

            label.appendChild(textContainer);
            tile.appendChild(label);

            // File input
            const input = document.createElement('input');
            input.type = 'file';
            input.className = 'rsl-file-input';

            if (field.name) {
                input.name = field.name;
                input.id = field.name;
            }
            if (field.accept) {
                input.accept = field.accept;
            }
            if (field.multiple) {
                input.multiple = true;
            }
            if (field.required) {
                input.required = true;
                input.classList.add('input-required');
            }

            tile.appendChild(input);

            // Filename display (for non-preview mode)
            const filename = document.createElement('span');
            filename.className = 'rsl-file-filename';
            tile.appendChild(filename);

            return tile;
        }

        /**
         * Create fieldset with grouped fields
         * @private
         */
        _createFieldset(field) {
            const fieldset = document.createElement('fieldset');
            fieldset.className = 'rsl-fieldset';

            if (field.legend) {
                const legend = document.createElement('legend');
                legend.className = 'rsl-fieldset-legend';
                legend.textContent = field.legend;
                fieldset.appendChild(legend);
            }

            const innerContainer = document.createElement('div');
            innerContainer.className = 'rsl-form-demo';
            innerContainer.style.margin = '0';

            if (field.fields && Array.isArray(field.fields)) {
                field.fields.forEach(innerField => {
                    const fieldElement = this._renderFormField(innerField);
                    if (fieldElement) {
                        innerContainer.appendChild(fieldElement);
                    }
                });
            }

            fieldset.appendChild(innerContainer);

            return fieldset;
        }

        /**
         * Apply field theming via data attributes
         * @private
         */
        _applyFieldTheming(element, field) {
            if (field.bgColor) {
                element.setAttribute('data-field-bg', field.bgColor);
            }
            if (field.borderColor) {
                element.setAttribute('data-field-border', field.borderColor);
            }
            if (field.focusColor) {
                element.setAttribute('data-field-focus', field.focusColor);
            }
            if (field.textColor) {
                element.setAttribute('data-field-text', field.textColor);
            }
        }

        /**
         * Initialize form elements after render
         * Triggers the form-elements.js initialization functions
         * @private
         */
        _initFormElements(formElement) {
            // Initialize sliders
            const sliders = formElement.querySelectorAll('.rsl-slider-input');
            sliders.forEach(slider => {
                const wrapper = slider.closest('.rsl-slider');
                if (!wrapper) return;

                const valueEl = wrapper.querySelector('.rsl-slider-value');
                if (!valueEl) return;

                const updateValue = () => {
                    const suffix = valueEl.textContent.replace(/[\d.-]/g, '') || '%';
                    valueEl.textContent = `${slider.value}${suffix}`;
                };

                slider.addEventListener('input', updateValue);
            });

            // Initialize file upload tiles
            const fileTiles = formElement.querySelectorAll('.rsl-file-tile');
            fileTiles.forEach(tile => {
                const input = tile.querySelector('.rsl-file-input');
                const label = tile.querySelector('.rsl-file-label');
                const filenameEl = tile.querySelector('.rsl-file-filename');

                if (!input || !label || !filenameEl) return;

                label.setAttribute('tabindex', '0');

                label.addEventListener('keydown', (evt) => {
                    if (evt.key === 'Enter' || evt.key === ' ') {
                        evt.preventDefault();
                        input.click();
                    }
                });

                input.addEventListener('change', () => {
                    if (input.files && input.files.length > 0) {
                        filenameEl.textContent = input.files.length > 1
                            ? `${input.files.length} files selected`
                            : input.files[0].name;
                    } else {
                        filenameEl.textContent = '';
                    }
                });
            });

            // Initialize custom selects
            const selects = formElement.querySelectorAll('.rsl-select');
            selects.forEach(selectRoot => {
                const toggle = selectRoot.querySelector('.rsl-select-toggle');
                const list = selectRoot.querySelector('.rsl-select-list');
                const options = selectRoot.querySelectorAll('.rsl-select-option');
                const hiddenInput = selectRoot.querySelector('input[type="hidden"]');
                const valueSpan = selectRoot.querySelector('.rsl-select-value');

                if (!toggle || !list || !options.length || !hiddenInput || !valueSpan) return;

                const close = () => {
                    selectRoot.dataset.open = 'false';
                    list.hidden = true;
                    toggle.setAttribute('aria-expanded', 'false');
                };

                const open = () => {
                    selectRoot.dataset.open = 'true';
                    list.hidden = false;
                    toggle.setAttribute('aria-expanded', 'true');
                };

                const toggleOpen = () => {
                    if (selectRoot.dataset.open === 'true') {
                        close();
                    } else {
                        open();
                    }
                };

                toggle.addEventListener('click', toggleOpen);

                toggle.addEventListener('keydown', (evt) => {
                    if (evt.key === 'ArrowDown' || evt.key === 'ArrowUp') {
                        evt.preventDefault();
                        open();
                        const first = list.querySelector('.rsl-select-option');
                        if (first) first.focus();
                    } else if (evt.key === 'Escape') {
                        close();
                    }
                });

                options.forEach(opt => {
                    opt.setAttribute('tabindex', '-1');

                    const choose = () => {
                        const value = opt.dataset.value || '';
                        hiddenInput.value = value;
                        valueSpan.textContent = opt.textContent.trim();

                        options.forEach(o => o.setAttribute('aria-selected', 'false'));
                        opt.setAttribute('aria-selected', 'true');

                        close();
                        toggle.focus();
                    };

                    opt.addEventListener('click', choose);

                    opt.addEventListener('keydown', (evt) => {
                        if (evt.key === 'Enter' || evt.key === ' ') {
                            evt.preventDefault();
                            choose();
                        } else if (evt.key === 'Escape') {
                            evt.preventDefault();
                            close();
                            toggle.focus();
                        } else if (evt.key === 'ArrowDown') {
                            evt.preventDefault();
                            const next = opt.nextElementSibling;
                            if (next && next.classList.contains('rsl-select-option')) {
                                next.focus();
                            }
                        } else if (evt.key === 'ArrowUp') {
                            evt.preventDefault();
                            const prev = opt.previousElementSibling;
                            if (prev && prev.classList.contains('rsl-select-option')) {
                                prev.focus();
                            }
                        }
                    });
                });

                // Close on outside click
                document.addEventListener('click', (evt) => {
                    if (!selectRoot.contains(evt.target)) {
                        close();
                    }
                });
            });

            // Apply data attribute theming
            const dataAttrSelector = [
                '[data-field-bg]', '[data-field-border]', '[data-field-focus]',
                '[data-field-text]', '[data-slider-track]', '[data-slider-fill]',
                '[data-toggle-on]', '[data-toggle-off]'
            ].join(',');

            const themedElements = formElement.querySelectorAll(dataAttrSelector);
            themedElements.forEach(element => {
                const attrMap = {
                    'data-field-bg': '--rsl-field-bg',
                    'data-field-border': '--rsl-field-border',
                    'data-field-focus': '--rsl-field-focus',
                    'data-field-text': '--rsl-field-text',
                    'data-slider-track': '--rsl-slider-track',
                    'data-slider-fill': '--rsl-slider-fill',
                    'data-toggle-on': '--rsl-toggle-on',
                    'data-toggle-off': '--rsl-toggle-off'
                };

                Object.entries(attrMap).forEach(([attr, cssVar]) => {
                    if (element.hasAttribute(attr)) {
                        const value = element.getAttribute(attr);
                        if (value && value.trim() !== '') {
                            element.style.setProperty(cssVar, value.trim());
                        }
                    }
                });
            });

            // Initialize drag-drop for file tiles with preview enabled
            this._initDragDropForFileTiles(formElement);
        }

        /**
         * Initialize drag-and-drop functionality for file tiles
         * Replicates drag-drop-image.js behavior for dynamically created tiles
         * @private
         */
        _initDragDropForFileTiles(container) {
            const fileTiles = container.querySelectorAll('.rsl-file-tile[data-enable-preview="true"]');

            fileTiles.forEach(tile => {
                const fileInput = tile.querySelector('.rsl-file-input');
                if (!fileInput) return;

                // Create or get preview container
                let previewContainer = tile.querySelector('.rsl-file-preview');
                if (!previewContainer) {
                    previewContainer = document.createElement('div');
                    previewContainer.classList.add('rsl-file-preview');
                    tile.appendChild(previewContainer);
                }

                // Drag events
                tile.addEventListener('dragover', (event) => {
                    event.preventDefault();
                    tile.classList.add('dragover');
                });

                tile.addEventListener('dragleave', () => {
                    tile.classList.remove('dragover');
                });

                tile.addEventListener('drop', (event) => {
                    event.preventDefault();
                    tile.classList.remove('dragover');
                    const files = event.dataTransfer.files;
                    this._handleFilesForPreview(files, previewContainer);
                });

                // File input change
                fileInput.addEventListener('change', () => {
                    if (fileInput.files && fileInput.files.length > 0) {
                        this._handleFilesForPreview(fileInput.files, previewContainer);
                    }
                });
            });
        }

        /**
         * Handle files for preview display
         * Creates image thumbnails or file icons
         * @private
         */
        _handleFilesForPreview(files, previewContainer) {
            // Clear existing previews
            previewContainer.innerHTML = '';

            for (let i = 0; i < files.length; i++) {
                const file = files[i];
                const item = document.createElement('div');
                item.classList.add('rsl-dnd__preview-item');

                // Handle image files
                if (file.type.startsWith('image/')) {
                    const img = document.createElement('img');
                    img.classList.add('rsl-dnd__preview-img');
                    img.src = URL.createObjectURL(file);

                    // Clean up blob URL after image loads
                    img.onload = () => {
                        URL.revokeObjectURL(img.src);
                    };

                    item.appendChild(img);
                } else {
                    // Handle non-image files
                    const fileIcon = document.createElement('div');
                    fileIcon.classList.add('rsl-dnd__preview-file-icon');
                    fileIcon.innerHTML = '<i class="fa-solid fa-file"></i>';
                    item.appendChild(fileIcon);

                    const fileName = document.createElement('div');
                    fileName.classList.add('rsl-dnd__preview-file-name');
                    fileName.textContent = file.name;
                    item.appendChild(fileName);
                }

                // Create delete button
                const deleteButton = document.createElement('span');
                deleteButton.classList.add('rsl-dnd__preview-delete');
                deleteButton.textContent = '×';

                deleteButton.addEventListener('click', () => {
                    item.remove();
                });

                item.appendChild(deleteButton);
                previewContainer.appendChild(item);
            }
        }

        /**
         * Render a single BASIC form field based on its type
         * Uses form.css styling (lightweight, browser-native controls)
         * @private
         */
        _renderBasicFormField(field) {
            switch (field.fieldType) {
                case 'text':
                case 'email':
                case 'password':
                case 'tel':
                case 'url':
                case 'number':
                case 'date':
                case 'time':
                case 'search':
                    return this._createBasicInput(field);

                case 'textarea':
                    return this._createBasicTextarea(field);

                case 'select':
                    return this._createBasicSelect(field);

                case 'radio':
                    return this._createBasicRadioGroup(field);

                case 'checkbox':
                    return this._createBasicCheckboxGroup(field);

                case 'range':
                    return this._createBasicRange(field);

                case 'file':
                    return this._createBasicFile(field);

                case 'fieldset':
                    return this._createBasicFieldset(field);

                default:
                    console.warn(`Unknown basic form field type: ${field.fieldType}`);
                    return null;
            }
        }

        /**
         * Create a basic text input field
         * @private
         */
        _createBasicInput(field) {
            const group = document.createElement('div');
            group.className = 'form-group';

            if (field.label) {
                const label = document.createElement('label');
                label.className = 'form-label';
                label.textContent = field.label;
                if (field.name) {
                    label.setAttribute('for', field.name);
                }
                group.appendChild(label);
            }

            const input = document.createElement('input');
            input.type = field.fieldType;
            input.className = 'form-input';

            if (field.name) {
                input.name = field.name;
                input.id = field.name;
            }
            if (field.placeholder) {
                input.placeholder = field.placeholder;
            }
            if (field.value !== undefined) {
                input.value = field.value;
            }
            if (field.required) {
                input.required = true;
                input.classList.add('input-required');
            }
            if (field.disabled) {
                input.disabled = true;
            }
            if (field.readonly) {
                input.readOnly = true;
            }
            if (field.min !== undefined) {
                input.min = field.min;
            }
            if (field.max !== undefined) {
                input.max = field.max;
            }
            if (field.step !== undefined) {
                input.step = field.step;
            }
            if (field.pattern) {
                input.pattern = field.pattern;
            }
            if (field.autocomplete) {
                input.autocomplete = field.autocomplete;
            }
            if (field.size) {
                input.classList.add(field.size); // xs, md, lg
            }

            group.appendChild(input);

            if (field.helper) {
                const helper = document.createElement('span');
                helper.className = 'form-help';
                helper.textContent = field.helper;
                group.appendChild(helper);
            }

            return group;
        }

        /**
         * Create a basic textarea field
         * @private
         */
        _createBasicTextarea(field) {
            const group = document.createElement('div');
            group.className = 'form-group';

            if (field.label) {
                const label = document.createElement('label');
                label.className = 'form-label';
                label.textContent = field.label;
                if (field.name) {
                    label.setAttribute('for', field.name);
                }
                group.appendChild(label);
            }

            const textarea = document.createElement('textarea');
            textarea.className = 'form-textarea';

            if (field.name) {
                textarea.name = field.name;
                textarea.id = field.name;
            }
            if (field.placeholder) {
                textarea.placeholder = field.placeholder;
            }
            if (field.value) {
                textarea.value = field.value;
            }
            if (field.required) {
                textarea.required = true;
                textarea.classList.add('input-required');
            }
            if (field.rows) {
                textarea.rows = field.rows;
            }

            group.appendChild(textarea);

            if (field.helper) {
                const helper = document.createElement('span');
                helper.className = 'form-help';
                helper.textContent = field.helper;
                group.appendChild(helper);
            }

            return group;
        }

        /**
         * Create a basic select dropdown
         * @private
         */
        _createBasicSelect(field) {
            const group = document.createElement('div');
            group.className = 'form-group';

            if (field.label) {
                const label = document.createElement('label');
                label.className = 'form-label';
                label.textContent = field.label;
                if (field.name) {
                    label.setAttribute('for', field.name);
                }
                group.appendChild(label);
            }

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

            if (field.name) {
                select.name = field.name;
                select.id = field.name;
            }
            if (field.required) {
                select.required = true;
                select.classList.add('input-required');
            }

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

            // Add options
            if (field.options && Array.isArray(field.options)) {
                field.options.forEach(option => {
                    const opt = document.createElement('option');
                    opt.value = option.value || option.label;
                    opt.textContent = option.label;
                    if (option.selected) {
                        opt.selected = true;
                    }
                    select.appendChild(opt);
                });
            }

            group.appendChild(select);

            if (field.helper) {
                const helper = document.createElement('span');
                helper.className = 'form-help';
                helper.textContent = field.helper;
                group.appendChild(helper);
            }

            return group;
        }

        /**
         * Create a basic radio button group
         * @private
         */
        _createBasicRadioGroup(field) {
            const group = document.createElement('div');
            group.className = 'form-group';

            if (field.label) {
                const label = document.createElement('label');
                label.className = 'form-label';
                label.textContent = field.label;
                group.appendChild(label);
            }

            const radioContainer = document.createElement('div');
            radioContainer.style.marginTop = '0.5rem';

            if (field.options && Array.isArray(field.options)) {
                field.options.forEach((option, index) => {
                    const radioLabel = document.createElement('label');
                    radioLabel.className = 'form-radio';

                    const input = document.createElement('input');
                    input.type = 'radio';
                    input.name = field.name || 'radio';
                    input.value = option.value || option.label;

                    if (option.checked || (index === 0 && field.selectFirst)) {
                        input.checked = true;
                    }
                    if (field.required) {
                        input.classList.add('input-required');
                    }

                    radioLabel.appendChild(input);

                    const span = document.createElement('span');
                    radioLabel.appendChild(span);
                    radioLabel.appendChild(document.createTextNode(option.label));

                    radioContainer.appendChild(radioLabel);
                });
            }

            group.appendChild(radioContainer);

            return group;
        }

        /**
         * Create a basic checkbox group
         * @private
         */
        _createBasicCheckboxGroup(field) {
            const group = document.createElement('div');
            group.className = 'form-group';

            if (field.label) {
                const label = document.createElement('label');
                label.className = 'form-label';
                label.textContent = field.label;
                group.appendChild(label);
            }

            const checkboxContainer = document.createElement('div');
            checkboxContainer.style.marginTop = '0.5rem';

            if (field.options && Array.isArray(field.options)) {
                field.options.forEach((option) => {
                    const checkLabel = document.createElement('label');
                    checkLabel.className = 'form-checkbox';

                    const input = document.createElement('input');
                    input.type = 'checkbox';
                    input.name = field.name || 'checkbox';
                    input.value = option.value || option.label;

                    if (option.checked) {
                        input.checked = true;
                    }
                    if (field.required) {
                        input.classList.add('input-required');
                    }

                    checkLabel.appendChild(input);

                    const span = document.createElement('span');
                    checkLabel.appendChild(span);
                    checkLabel.appendChild(document.createTextNode(option.label));

                    checkboxContainer.appendChild(checkLabel);
                });
            }

            group.appendChild(checkboxContainer);

            return group;
        }

        /**
         * Create a basic range input
         * @private
         */
        _createBasicRange(field) {
            const group = document.createElement('div');
            group.className = 'form-group';

            if (field.label) {
                const labelContainer = document.createElement('div');
                labelContainer.style.display = 'flex';
                labelContainer.style.justifyContent = 'space-between';
                labelContainer.style.marginBottom = '0.5rem';

                const label = document.createElement('label');
                label.className = 'form-label';
                label.textContent = field.label;
                label.style.marginBottom = '0';
                if (field.name) {
                    label.setAttribute('for', field.name);
                }
                labelContainer.appendChild(label);

                if (field.showValue !== false) {
                    const valueDisplay = document.createElement('span');
                    valueDisplay.className = 'range-value';
                    valueDisplay.textContent = `${field.value || 50}${field.suffix || ''}`;
                    labelContainer.appendChild(valueDisplay);
                }

                group.appendChild(labelContainer);
            }

            const input = document.createElement('input');
            input.type = 'range';

            if (field.name) {
                input.name = field.name;
                input.id = field.name;
            }

            input.min = field.min !== undefined ? field.min : 0;
            input.max = field.max !== undefined ? field.max : 100;
            input.value = field.value !== undefined ? field.value : 50;

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

            group.appendChild(input);

            if (field.helper) {
                const helper = document.createElement('span');
                helper.className = 'form-help';
                helper.textContent = field.helper;
                group.appendChild(helper);
            }

            return group;
        }

        /**
         * Create a basic file input
         * @private
         */
        _createBasicFile(field) {
            const group = document.createElement('div');
            group.className = 'form-group';

            if (field.label) {
                const label = document.createElement('label');
                label.className = 'form-label';
                label.textContent = field.label;
                if (field.name) {
                    label.setAttribute('for', field.name);
                }
                group.appendChild(label);
            }

            // Legacy drag-and-drop area
            if (field.enableDragDrop) {
                const dndArea = document.createElement('div');
                dndArea.id = field.name ? `drag-and-drop-${field.name}` : 'drag-and-drop-area';
                dndArea.className = 'rsl-dnd';
                dndArea.innerHTML = `
                    <span class="rsl-dnd__icon"><i class="fas fa-cloud-upload-alt"></i></span>
                    <span class="rsl-dnd__message">${field.title || 'Drag files here or click to upload'}</span>
                `;
                group.appendChild(dndArea);

                const previewArea = document.createElement('div');
                previewArea.id = field.name ? `file-preview-${field.name}` : 'file-preview';
                previewArea.className = 'rsl-dnd__preview';
                group.appendChild(previewArea);

                // Initialize drag-drop for this area
                setTimeout(() => {
                    this._initLegacyDragDrop(dndArea, previewArea);
                }, 50);
            } else {
                const input = document.createElement('input');
                input.type = 'file';

                if (field.name) {
                    input.name = field.name;
                    input.id = field.name;
                }
                if (field.accept) {
                    input.accept = field.accept;
                }
                if (field.multiple) {
                    input.multiple = true;
                }
                if (field.required) {
                    input.required = true;
                    input.classList.add('input-required');
                }

                group.appendChild(input);
            }

            if (field.helper) {
                const helper = document.createElement('span');
                helper.className = 'form-help';
                helper.textContent = field.helper;
                group.appendChild(helper);
            }

            return group;
        }

        /**
         * Initialize legacy drag-and-drop area
         * @private
         */
        _initLegacyDragDrop(dndArea, previewArea) {
            dndArea.addEventListener('dragover', (event) => {
                event.preventDefault();
                dndArea.classList.add('dragover');
            });

            dndArea.addEventListener('dragleave', () => {
                dndArea.classList.remove('dragover');
            });

            dndArea.addEventListener('drop', (event) => {
                event.preventDefault();
                dndArea.classList.remove('dragover');
                const files = event.dataTransfer.files;
                this._handleFilesForPreview(files, previewArea);
            });

            dndArea.addEventListener('click', () => {
                const input = document.createElement('input');
                input.type = 'file';
                input.multiple = true;
                input.addEventListener('change', () => {
                    this._handleFilesForPreview(input.files, previewArea);
                });
                input.click();
            });
        }

        /**
         * Create a basic fieldset with grouped fields
         * @private
         */
        _createBasicFieldset(field) {
            const fieldset = document.createElement('fieldset');
            fieldset.style.cssText = 'border: 1px solid #e5e7eb; border-radius: 6px; padding: 1rem; margin-bottom: 1rem;';

            if (field.legend) {
                const legend = document.createElement('legend');
                legend.style.cssText = 'font-weight: 600; padding: 0 0.5rem; color: #374151;';
                legend.textContent = field.legend;
                fieldset.appendChild(legend);
            }

            if (field.fields && Array.isArray(field.fields)) {
                field.fields.forEach(innerField => {
                    const fieldElement = this._renderBasicFormField(innerField);
                    if (fieldElement) {
                        fieldset.appendChild(fieldElement);
                    }
                });
            }

            return fieldset;
        }

        /**
         * Initialize basic form elements after render
         * @private
         */
        _initBasicFormElements(formElement) {
            // Initialize range inputs with value display
            const rangeInputs = formElement.querySelectorAll('input[type="range"]');
            rangeInputs.forEach(input => {
                const group = input.closest('.form-group');
                if (!group) return;

                const valueDisplay = group.querySelector('.range-value');
                if (!valueDisplay) return;

                const suffix = valueDisplay.textContent.replace(/[\d.-]/g, '') || '';

                input.addEventListener('input', () => {
                    valueDisplay.textContent = `${input.value}${suffix}`;
                });
            });

            // Set up form validation error clearing
            const allInputs = formElement.querySelectorAll('.input-required, [data-required="true"]');
            allInputs.forEach(input => {
                input.addEventListener('input', () => {
                    if (input.value.trim()) {
                        input.classList.remove('input-error');
                    }
                });

                if (input.type === 'checkbox' || input.type === 'radio') {
                    input.addEventListener('change', () => {
                        const name = input.getAttribute('name');
                        if (name) {
                            const group = formElement.querySelectorAll(`[name="${name}"]`);
                            group.forEach(inp => inp.classList.remove('input-error'));
                        } else {
                            input.classList.remove('input-error');
                        }
                    });
                }
            });
        }

        /**
         * Render Inlay Alert component
         * Creates contextual notification alerts with support for multiple types,
         * icons, titles, details, drop shadows, and auto-dismiss functionality.
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Alert configuration
         * @param {string} [config.alertType] - Alert variant: 'success', 'danger', 'warning', 'info', or 'default'
         * @param {string} [config.message] - Alert title/heading text
         * @param {string} [config.details] - Alert body/description text
         * @param {string} [config.dropShadow] - Drop shadow variant: 'a', 'b', 'c', or 'd'
         * @param {string} [config.icon] - Custom FontAwesome icon class (overrides default)
         * @param {boolean} [config.dismissible=true] - Whether alert can be dismissed
         * @param {boolean} [config.dynamic=false] - Use generateAlert() for dynamic rendering
         * @param {number} [config.timeout] - Auto-dismiss after milliseconds (only for dynamic)
         * @param {string} [config.animation] - CSS animation class (only for dynamic)
         * @param {string} [config.wrapMessage] - Wrap details in styled container ('true' or 'false')
         * @param {string} [config.overrideBackgroundColor] - Custom background color
         * @param {string} [config.overrideTextColor] - Custom text color
         * @param {string} [config.overrideTitleColor] - Custom title color
         * @param {string} [config.overrideIconColor] - Custom icon color
         * @param {Function} [config.onShow] - Callback when alert is shown (dynamic only)
         * @param {Function} [config.onClose] - Callback when alert is closed
         */
        _renderInlayAlert(el, config) {
            // Determine alert type and default icon
            // Use alertType or variant (NOT type, which is reserved for content type)
            const alertType = config.alertType || config.variant || 'default';
            const alertIcons = {
                'success': 'fa-check-circle',
                'danger': 'fa-exclamation-triangle',
                'warning': 'fa-exclamation-triangle',
                'info': 'fa-info-circle',
                'default': 'fa-info-circle'
            };

            // If dynamic mode is enabled and generateAlert is available, use it
            if (config.dynamic && typeof window.generateAlert === 'function') {
                // Create a container for the dynamic alert
                const containerId = 'inlay-alert-' + Date.now();
                const container = document.createElement('div');
                container.id = containerId;
                el.appendChild(container);

                // Call generateAlert after a brief delay to ensure container is in DOM
                setTimeout(() => {
                    window.generateAlert({
                        type: alertType,
                        message: config.message || '',
                        details: config.details || '',
                        location: '#' + containerId,
                        dropShadow: config.dropShadow ? `alert-dropshadow-${config.dropShadow}` : '',
                        wrapMessage: config.wrapMessage,
                        animation: config.animation,
                        overrideIcon: config.icon,
                        overrideBackgroundColor: config.overrideBackgroundColor,
                        overrideTextColor: config.overrideTextColor,
                        overrideTitleColor: config.overrideTitleColor,
                        overrideIconColor: config.overrideIconColor,
                        overrideCloseColor: config.overrideCloseColor,
                        timeout: config.timeout,
                        onShow: config.onShow,
                        onClose: config.onClose
                    });
                }, 50);

                return;
            }

            // Static mode - create the alert HTML directly
            const alert = document.createElement('div');
            alert.className = `inlay-alert alert-${alertType}`;
            alert.setAttribute('role', 'alert');

            // Add drop shadow if specified
            if (config.dropShadow) {
                alert.classList.add(`alert-dropshadow-${config.dropShadow}`);
            }

            // Add custom class if specified
            if (config.className) {
                alert.classList.add(config.className);
            }

            // Set aria-label for accessibility
            const ariaLabel = `${alertType}: ${config.message || ''} ${config.details || ''}`.trim();
            alert.setAttribute('aria-label', ariaLabel);

            // Apply custom styling if specified
            if (config.overrideBackgroundColor) {
                alert.style.backgroundColor = config.overrideBackgroundColor;
            }
            if (config.overrideTextColor) {
                alert.style.color = config.overrideTextColor;
            }

            // Create icon
            const icon = document.createElement('i');
            icon.className = `fas ${config.icon || alertIcons[alertType]}`;
            icon.setAttribute('aria-hidden', 'true');
            if (config.overrideIconColor) {
                icon.style.color = config.overrideIconColor;
            }
            alert.appendChild(icon);

            // Create message structure based on whether there's a title or not
            // If title (config.message) exists: use .alert-message with <h4> and .message-wrapper with <p>
            // If no title but has details: use .message-wrapper directly with .alert-message-around span
            if (config.message) {
                // With title: use .alert-message wrapper
                const messageContainer = document.createElement('div');
                messageContainer.className = 'alert-message';

                const title = document.createElement('h4');
                title.textContent = config.message;
                if (config.overrideTitleColor) {
                    title.style.color = config.overrideTitleColor;
                }
                messageContainer.appendChild(title);

                // Add details if provided
                if (config.details) {
                    const detailsWrapper = document.createElement('div');
                    detailsWrapper.className = 'message-wrapper';

                    const detailsText = document.createElement('p');
                    detailsText.innerHTML = config.details; // Allow HTML in details
                    detailsWrapper.appendChild(detailsText);

                    messageContainer.appendChild(detailsWrapper);
                }

                alert.appendChild(messageContainer);
            } else if (config.details) {
                // No title, just details: use .message-wrapper with .alert-message-around span
                const messageWrapper = document.createElement('div');
                messageWrapper.className = 'message-wrapper';

                const messageSpan = document.createElement('span');
                messageSpan.className = 'alert-message-around';
                messageSpan.innerHTML = config.details; // Allow HTML in details
                messageWrapper.appendChild(messageSpan);

                alert.appendChild(messageWrapper);
            }

            // Add close button if dismissible (default true)
            if (config.dismissible !== false) {
                const closeBtn = document.createElement('button');
                closeBtn.className = 'close';
                closeBtn.setAttribute('aria-label', 'Close');
                if (config.overrideCloseColor) {
                    closeBtn.style.color = config.overrideCloseColor;
                }

                const closeIcon = document.createElement('i');
                closeIcon.className = 'fas fa-times';
                closeIcon.setAttribute('aria-hidden', 'true');
                closeBtn.appendChild(closeIcon);

                // Add close handler
                closeBtn.addEventListener('click', () => {
                    alert.style.opacity = '0';
                    setTimeout(() => {
                        alert.style.display = 'none';
                        if (config.onClose) {
                            config.onClose();
                        }
                    }, 150);
                });

                alert.appendChild(closeBtn);
            }

            el.appendChild(alert);

            // Fire onShow callback if provided
            if (config.onShow) {
                config.onShow();
            }
        }

        /**
         * Render Iframe component
         * Creates responsive iframe containers for videos, maps, and embedded content.
         * Uses the RSL .rsl-iframe-container CSS class for aspect ratio preservation.
         * Includes accessible skip links for keyboard navigation.
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Iframe configuration
         * @param {string} config.src - URL of embedded content (required)
         * @param {string} [config.title] - Accessible description for screen readers (required for accessibility)
         * @param {string} [config.aspectRatio="16:9"] - Aspect ratio: "16:9", "4:3", "1:1", "21:9", "3:2", or custom percentage
         * @param {boolean} [config.allowFullscreen=true] - Enable fullscreen mode for videos
         * @param {string} [config.loading="lazy"] - Loading behavior: "lazy" or "eager"
         * @param {string} [config.allow] - Feature permissions string (e.g., for YouTube: "accelerometer; autoplay; clipboard-write; encrypted-media; gyroscope; picture-in-picture")
         * @param {string} [config.height] - Fixed height instead of aspect ratio (e.g., "500px")
         * @param {string} [config.border] - Border style (e.g., "1px solid #dee2e6")
         * @param {string} [config.borderRadius] - Border radius (e.g., "8px")
         * @param {string} [config.width] - Width (default "100%")
         * @param {Object} [config.style] - Additional inline styles
         * @param {string[]} [config.classes] - Additional CSS classes
         * @param {boolean} [config.skipLinks=true] - Add keyboard skip links for accessibility
         * @param {string} [config.skipBeforeText="Skip embedded content"] - Text for skip-before link
         * @param {string} [config.skipAfterText="Return to before embedded content"] - Text for skip-after link
         */
        _renderIframe(el, config) {
            // Validate required src
            if (!config.src) {
                console.warn('Iframe component requires a "src" property');
                return;
            }

            // Accessibility warning for missing title
            if (!config.title) {
                console.warn('Iframe is missing "title" attribute for accessibility. Please provide a descriptive title.');
            }

            // Generate unique ID for this iframe instance
            const iframeId = this._iframeCounter++;
            const skipBeforeId = `rsl-iframe-skip-before-${iframeId}`;
            const skipAfterId = `rsl-iframe-skip-after-${iframeId}`;
            const targetBeforeId = `rsl-iframe-target-before-${iframeId}`;
            const targetAfterId = `rsl-iframe-target-after-${iframeId}`;

            // Skip links configuration (enabled by default for accessibility)
            const showSkipLinks = config.skipLinks !== false;
            const skipBeforeText = config.skipBeforeText || 'Skip embedded content';
            const skipAfterText = config.skipAfterText || 'Return to before embedded content';

            // Aspect ratio percentages mapping
            const aspectRatios = {
                '16:9': '56.25%',
                '4:3': '75%',
                '1:1': '100%',
                '21:9': '42.86%',
                '3:2': '66.67%',
                '9:16': '177.78%'
            };

            // Create wrapper for iframe and skip links
            const wrapper = document.createElement('div');
            wrapper.className = 'rsl-iframe-wrapper';

            // Create target anchor before iframe (for skip-after link)
            if (showSkipLinks) {
                const targetBefore = document.createElement('div');
                targetBefore.id = targetBeforeId;
                targetBefore.className = 'rsl-skip-target';
                targetBefore.setAttribute('tabindex', '-1');
                wrapper.appendChild(targetBefore);

                // Create skip-before link
                const skipBefore = document.createElement('a');
                skipBefore.href = `#${targetAfterId}`;
                skipBefore.id = skipBeforeId;
                skipBefore.className = 'rsl-skip-link';
                skipBefore.textContent = skipBeforeText;
                skipBefore.setAttribute('aria-label', `${skipBeforeText}. Press Enter to skip past the ${config.title || 'embedded content'}.`);
                wrapper.appendChild(skipBefore);
            }

            // Create iframe element
            const iframe = document.createElement('iframe');
            iframe.src = config.src;

            // Set title for accessibility
            if (config.title) {
                iframe.title = config.title;
            }

            // Set loading behavior (default to lazy for performance)
            iframe.loading = config.loading || 'lazy';

            // Set allowfullscreen (default true for videos)
            if (config.allowFullscreen !== false) {
                iframe.setAttribute('allowfullscreen', '');
            }

            // Set allow permissions if provided (for YouTube, etc.)
            if (config.allow) {
                iframe.setAttribute('allow', config.allow);
            }

            // Check if using fixed height or aspect ratio mode
            if (config.height) {
                // Fixed height mode - no container needed
                iframe.style.width = config.width || '100%';
                iframe.style.height = config.height;
                iframe.style.border = config.border || '0';

                if (config.borderRadius) {
                    iframe.style.borderRadius = config.borderRadius;
                }

                // Apply additional classes
                if (config.classes && Array.isArray(config.classes)) {
                    config.classes.forEach(cls => iframe.classList.add(cls));
                }

                // Apply additional styles
                if (config.style) {
                    this._applyStyles(iframe, config.style);
                }

                wrapper.appendChild(iframe);
            } else {
                // Aspect ratio mode - use container
                const container = document.createElement('div');
                container.className = 'rsl-iframe-container';

                // Apply custom aspect ratio if specified
                const ratio = config.aspectRatio || '16:9';
                const paddingBottom = aspectRatios[ratio] || ratio;

                // Only set padding-bottom if not default 16:9
                if (ratio !== '16:9') {
                    container.style.paddingBottom = paddingBottom;
                }

                // Apply border radius to container
                if (config.borderRadius) {
                    container.style.borderRadius = config.borderRadius;
                    container.style.overflow = 'hidden';
                }

                // Apply border to container
                if (config.border) {
                    container.style.border = config.border;
                }

                // Apply additional classes to container
                if (config.classes && Array.isArray(config.classes)) {
                    config.classes.forEach(cls => container.classList.add(cls));
                }

                // Apply additional styles to container
                if (config.style) {
                    this._applyStyles(container, config.style);
                }

                container.appendChild(iframe);
                wrapper.appendChild(container);
            }

            // Create skip-after link and target (after iframe)
            if (showSkipLinks) {
                const skipAfter = document.createElement('a');
                skipAfter.href = `#${targetBeforeId}`;
                skipAfter.id = skipAfterId;
                skipAfter.className = 'rsl-skip-link';
                skipAfter.textContent = skipAfterText;
                skipAfter.setAttribute('aria-label', `${skipAfterText}. Press Enter to return to before the ${config.title || 'embedded content'}.`);
                wrapper.appendChild(skipAfter);

                // Create target anchor after iframe (for skip-before link)
                const targetAfter = document.createElement('div');
                targetAfter.id = targetAfterId;
                targetAfter.className = 'rsl-skip-target';
                targetAfter.setAttribute('tabindex', '-1');
                wrapper.appendChild(targetAfter);
            }

            el.appendChild(wrapper);
        }

        /**
         * Render Image component
         * Creates responsive images with utility classes for size, shape, styling, and effects.
         * Uses the RSL images.css utility classes for consistent styling.
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Image configuration
         * @param {string} config.src - Image source URL (required)
         * @param {string} config.alt - Alt text for accessibility (required)
         * @param {boolean} [config.responsive=true] - Make image responsive (100% width)
         * @param {string} [config.maxWidth] - Maximum width: "100", "200", "300", "400", "500" (px)
         * @param {string} [config.minWidth] - Minimum width: "100", "200", "300" (px)
         * @param {boolean} [config.thumbnail=false] - Thumbnail size (150px max)
         * @param {boolean} [config.fullWidth=false] - Force 100% width
         * @param {string} [config.shape] - Shape: "rounded", "rounded-sm", "rounded-lg", "circle"
         * @param {boolean} [config.bordered=false] - Add border
         * @param {boolean} [config.borderedThick=false] - Add thick border
         * @param {string} [config.shadow] - Shadow: "shadow", "shadow-lg"
         * @param {boolean} [config.center=false] - Center image horizontally
         * @param {boolean} [config.grayscale=false] - Grayscale filter (color on hover)
         * @param {string} [config.aspectRatio] - Aspect ratio: "square", "video", "portrait"
         * @param {string} [config.objectFit] - Object fit: "cover", "contain"
         * @param {string} [config.loading="lazy"] - Loading behavior: "lazy" or "eager"
         * @param {string} [config.caption] - Optional caption text below image
         * @param {string[]} [config.classes] - Additional CSS classes
         * @param {Object} [config.style] - Additional inline styles
         * @param {Function} [config.onClick] - Click handler
         */
        _renderImage(el, config) {
            // Validate required properties
            if (!config.src) {
                console.warn('Image component requires a "src" property');
                return;
            }

            // Accessibility warning for missing alt
            if (!config.alt && config.alt !== '') {
                console.warn('Image is missing "alt" attribute for accessibility. Use alt="" for decorative images.');
            }

            // Create image element
            const img = document.createElement('img');
            img.src = config.src;
            img.alt = config.alt || '';

            // Build class list
            const classes = [];

            // Responsive (default true unless other sizing is specified)
            if (config.responsive !== false && !config.maxWidth && !config.minWidth && !config.thumbnail && !config.fullWidth) {
                classes.push('responsive-img');
            }

            // Size classes
            if (config.maxWidth) {
                classes.push(`max-width-${config.maxWidth}`);
            }
            if (config.minWidth) {
                classes.push(`min-width-${config.minWidth}`);
            }
            if (config.thumbnail) {
                classes.push('thumbnail');
            }
            if (config.fullWidth) {
                classes.push('full-width');
            }

            // Shape classes
            if (config.shape) {
                classes.push(config.shape);
            }

            // Border classes
            if (config.borderedThick) {
                classes.push('bordered-thick');
            } else if (config.bordered) {
                classes.push('bordered');
            }

            // Shadow classes
            if (config.shadow) {
                classes.push(config.shadow);
            }

            // Center
            if (config.center) {
                classes.push('center');
            }

            // Grayscale effect
            if (config.grayscale) {
                classes.push('grayscale');
            }

            // Aspect ratio
            if (config.aspectRatio) {
                classes.push(`aspect-${config.aspectRatio}`);
            }

            // Object fit
            if (config.objectFit) {
                classes.push(config.objectFit);
            }

            // Add custom classes
            if (config.classes && Array.isArray(config.classes)) {
                classes.push(...config.classes);
            }

            // Apply all classes
            if (classes.length > 0) {
                img.className = classes.join(' ');
            }

            // Set loading behavior (default lazy for performance)
            img.loading = config.loading || 'lazy';

            // Apply additional inline styles
            if (config.style) {
                this._applyStyles(img, config.style);
            }

            // Add click handler if specified
            if (config.onClick && typeof config.onClick === 'function') {
                img.style.cursor = 'pointer';
                img.addEventListener('click', (e) => {
                    config.onClick(e, img);
                });
            }

            // Handle caption if provided
            if (config.caption) {
                const figure = document.createElement('figure');
                figure.style.margin = '0';
                figure.style.textAlign = config.center ? 'center' : 'left';

                figure.appendChild(img);

                const figcaption = document.createElement('figcaption');
                figcaption.textContent = config.caption;
                figcaption.style.marginTop = '0.5rem';
                figcaption.style.fontSize = '0.875rem';
                figcaption.style.color = '#666';
                figure.appendChild(figcaption);

                el.appendChild(figure);
            } else {
                el.appendChild(img);
            }
        }

        /**
         * Render Gallery component
         * Creates a masonry-style image gallery with filtering, lightbox, and accessibility support.
         * Uses the RSL Gallery component (gallery.css + gallery.js).
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Gallery configuration
         * @param {Object[]} config.items - Array of gallery items (required)
         * @param {string} config.items[].src - Thumbnail image source (required)
         * @param {string} config.items[].href - Full-size image source for lightbox
         * @param {string} config.items[].alt - Alt text for accessibility (required)
         * @param {string} [config.items[].title] - Image title
         * @param {string} [config.items[].meta] - Image meta text (category, date, etc.)
         * @param {string} [config.items[].category] - Category for filtering
         * @param {string} [config.items[].size] - Item size: "tall", "wide" (optional)
         * @param {string[]} [config.categories] - Array of category names for filter buttons
         * @param {boolean} [config.showFilter=true] - Show filter buttons
         * @param {boolean} [config.showLightbox=true] - Enable lightbox functionality
         * @param {string} [config.id] - Unique ID for the gallery (auto-generated if not provided)
         * @param {number} [config.cols] - Fixed number of columns (default: auto-fit)
         * @param {Object} [config.breakpoints] - Responsive column counts { xs: 1, sm: 2, md: 3, lg: 4 }
         */
        _renderGallery(el, config) {
            // Validate required properties
            if (!config.items || !Array.isArray(config.items) || config.items.length === 0) {
                console.warn('Gallery component requires an "items" array with at least one item');
                return;
            }

            // Generate unique IDs
            const galleryId = config.id || `gallery-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
            const filterId = `${galleryId}-filter`;
            const lightboxId = `${galleryId}-lightbox`;
            const statusId = `${galleryId}-status`;

            // Extract categories from items if not explicitly provided
            const categories = config.categories || [...new Set(
                config.items
                    .map(item => item.category)
                    .filter(Boolean)
            )];

            const showFilter = config.showFilter !== false && categories.length > 0;
            const showLightbox = config.showLightbox !== false;

            // Create gallery wrapper
            const wrapper = document.createElement('div');
            wrapper.className = 'rsl-gallery-wrapper';

            // Create live region for filter announcements
            const statusRegion = document.createElement('div');
            statusRegion.className = 'rsl-gallery-status';
            statusRegion.id = statusId;
            statusRegion.setAttribute('aria-live', 'polite');
            statusRegion.setAttribute('aria-atomic', 'true');
            wrapper.appendChild(statusRegion);

            // Create filter buttons if enabled
            if (showFilter) {
                const filterContainer = document.createElement('div');
                filterContainer.className = 'rsl-gallery-filter';
                filterContainer.id = filterId;
                filterContainer.setAttribute('role', 'tablist');
                filterContainer.setAttribute('aria-label', 'Filter gallery by category');

                // "All" button
                const allBtn = document.createElement('button');
                allBtn.className = 'rsl-gallery-filter-btn active';
                allBtn.setAttribute('role', 'tab');
                allBtn.setAttribute('aria-selected', 'true');
                allBtn.setAttribute('data-filter', 'all');
                allBtn.textContent = 'All';
                filterContainer.appendChild(allBtn);

                // Category buttons
                categories.forEach(category => {
                    const btn = document.createElement('button');
                    btn.className = 'rsl-gallery-filter-btn';
                    btn.setAttribute('role', 'tab');
                    btn.setAttribute('aria-selected', 'false');
                    btn.setAttribute('data-filter', category);
                    btn.textContent = category.charAt(0).toUpperCase() + category.slice(1);
                    filterContainer.appendChild(btn);
                });

                wrapper.appendChild(filterContainer);
            }

            // Create gallery grid
            const gallery = document.createElement('div');
            gallery.className = 'rsl-gallery';
            gallery.id = galleryId;
            gallery.setAttribute('role', 'list');
            gallery.setAttribute('aria-label', config.ariaLabel || 'Photo gallery');

            if (showFilter) {
                gallery.setAttribute('data-filter', filterId);
            }
            if (showLightbox) {
                gallery.setAttribute('data-lightbox', lightboxId);
            }

            // Set responsive columns if provided
            if (config.breakpoints) {
                Object.entries(config.breakpoints).forEach(([bp, cols]) => {
                    gallery.setAttribute(`data-cols-${bp}`, cols);
                });
            } else if (config.cols) {
                gallery.setAttribute('data-cols', config.cols);
            }

            // Create gallery items
            config.items.forEach((item, index) => {
                const article = document.createElement('article');
                article.className = 'rsl-gallery-item';
                article.setAttribute('role', 'listitem');

                // Add size modifier classes
                if (item.size === 'tall') {
                    article.classList.add('rsl-gallery-item-tall');
                } else if (item.size === 'wide') {
                    article.classList.add('rsl-gallery-item-wide');
                }

                // Add category data attribute
                if (item.category) {
                    article.setAttribute('data-category', item.category);
                }

                // Create link wrapper
                const link = document.createElement('a');
                link.href = item.href || item.src;
                link.className = 'rsl-gallery-link';
                link.setAttribute('aria-label', `View ${item.title || item.alt || `photo ${index + 1}`} in lightbox`);

                // Create image container
                const imageContainer = document.createElement('div');
                imageContainer.className = 'rsl-gallery-image';

                const img = document.createElement('img');
                img.src = item.src;
                img.alt = item.alt || '';
                img.loading = 'lazy';
                imageContainer.appendChild(img);

                link.appendChild(imageContainer);

                // Create overlay
                const overlay = document.createElement('div');
                overlay.className = 'rsl-gallery-overlay';

                const info = document.createElement('div');
                info.className = 'rsl-gallery-info';

                if (item.title) {
                    const title = document.createElement('h3');
                    title.className = 'rsl-gallery-title';
                    title.textContent = item.title;
                    info.appendChild(title);
                }

                if (item.meta) {
                    const meta = document.createElement('p');
                    meta.className = 'rsl-gallery-meta';
                    meta.textContent = item.meta;
                    info.appendChild(meta);
                }

                overlay.appendChild(info);

                // Add expand icon
                const iconSpan = document.createElement('span');
                iconSpan.className = 'rsl-gallery-icon';
                iconSpan.setAttribute('aria-hidden', 'true');
                iconSpan.innerHTML = '<i class="fas fa-expand"></i>';
                overlay.appendChild(iconSpan);

                link.appendChild(overlay);
                article.appendChild(link);
                gallery.appendChild(article);
            });

            wrapper.appendChild(gallery);

            // Create lightbox if enabled
            if (showLightbox) {
                const lightbox = document.createElement('div');
                lightbox.className = 'rsl-lightbox';
                lightbox.id = lightboxId;
                lightbox.setAttribute('role', 'dialog');
                lightbox.setAttribute('aria-modal', 'true');
                lightbox.setAttribute('aria-label', 'Image gallery viewer');
                lightbox.hidden = true;

                // Close button
                const closeBtn = document.createElement('button');
                closeBtn.className = 'rsl-lightbox-close';
                closeBtn.setAttribute('aria-label', 'Close gallery');
                closeBtn.innerHTML = '<i class="fas fa-times"></i>';
                lightbox.appendChild(closeBtn);

                // Previous button
                const prevBtn = document.createElement('button');
                prevBtn.className = 'rsl-lightbox-prev';
                prevBtn.setAttribute('aria-label', 'Previous image');
                prevBtn.innerHTML = '<i class="fas fa-chevron-left"></i>';
                lightbox.appendChild(prevBtn);

                // Next button
                const nextBtn = document.createElement('button');
                nextBtn.className = 'rsl-lightbox-next';
                nextBtn.setAttribute('aria-label', 'Next image');
                nextBtn.innerHTML = '<i class="fas fa-chevron-right"></i>';
                lightbox.appendChild(nextBtn);

                // Content area
                const content = document.createElement('div');
                content.className = 'rsl-lightbox-content';

                const lightboxImg = document.createElement('img');
                lightboxImg.className = 'rsl-lightbox-image';
                lightboxImg.src = '';
                lightboxImg.alt = '';
                content.appendChild(lightboxImg);

                const caption = document.createElement('div');
                caption.className = 'rsl-lightbox-caption';
                caption.innerHTML = '<h3 class="rsl-lightbox-title"></h3><p class="rsl-lightbox-meta"></p>';
                content.appendChild(caption);

                lightbox.appendChild(content);

                // Counter
                const counter = document.createElement('div');
                counter.className = 'rsl-lightbox-counter';
                counter.setAttribute('aria-live', 'polite');
                counter.innerHTML = `<span class="rsl-lightbox-current">1</span> / <span class="rsl-lightbox-total">${config.items.length}</span>`;
                lightbox.appendChild(counter);

                wrapper.appendChild(lightbox);
            }

            el.appendChild(wrapper);

            // Initialize gallery component after short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.Gallery && window.RSL.Gallery.init) {
                    window.RSL.Gallery.init();
                }
            }, 100);
        }

        /**
         * Render Chart component - Pure SVG charts with zero dependencies
         * Uses the V1 Charts component via data attributes
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Chart configuration
         * @param {string} config.chartType - Chart type (bar, line, area, pie, doughnut, sparkline, sparkline-bar)
         * @param {Array} config.values - Data values array
         * @param {Array} [config.labels] - Data labels array
         * @param {string} [config.title] - Chart title
         * @param {string} [config.colorScheme] - Color scheme (primary, success, warm, cool, mono, rainbow, accessible)
         * @param {boolean} [config.animate] - Enable animation (default: true)
         * @param {boolean} [config.showValues] - Show value labels on bars/points
         * @param {boolean} [config.showLegend] - Show legend for pie/doughnut charts
         * @param {boolean} [config.showTooltip] - Show tooltips on hover
         * @param {boolean} [config.curved] - Use curved lines for line/area charts
         * @param {string} [config.size] - Sparkline size (xs, sm, md, lg)
         * @param {string} [config.height] - Chart height (e.g., "200px", "300px")
         * @param {boolean} [config.animateOnView] - Animate when chart enters viewport
         *
         * @example
         * // Bar chart
         * { type: "chart", chartType: "bar", values: [25, 50, 75, 100], labels: ["A", "B", "C", "D"] }
         *
         * @example
         * // Line chart with animation
         * { type: "chart", chartType: "line", values: [20, 45, 35, 60], animate: true, curved: true }
         *
         * @example
         * // Pie chart with legend
         * { type: "chart", chartType: "pie", values: [35, 25, 20, 15], labels: ["A", "B", "C", "D"], showLegend: true }
         *
         * @example
         * // Sparkline in a card
         * { type: "chart", chartType: "sparkline", values: [10, 15, 12, 18, 20], colorScheme: "success", size: "md" }
         */
        _renderChart(el, config) {
            // Validate required properties
            if (!config.values || !Array.isArray(config.values)) {
                console.warn('Chart component requires a "values" array');
                return;
            }

            if (!config.chartType) {
                console.warn('Chart component requires a "chartType" property');
                return;
            }

            // Create chart container
            const chart = document.createElement('div');
            chart.setAttribute('data-rsl-chart', '');

            // Chart type (required)
            chart.setAttribute('data-type', config.chartType);

            // Values (required) - convert to JSON string
            chart.setAttribute('data-values', JSON.stringify(config.values));

            // Labels (optional)
            if (config.labels && Array.isArray(config.labels)) {
                chart.setAttribute('data-labels', JSON.stringify(config.labels));
            }

            // Title (optional)
            if (config.title) {
                chart.setAttribute('data-title', config.title);
            }

            // Color scheme (optional)
            if (config.colorScheme) {
                chart.setAttribute('data-color-scheme', config.colorScheme);
            }

            // Animation (default: true)
            if (config.animate !== false) {
                chart.setAttribute('data-animate', '');
            }

            // Animate on view (optional)
            if (config.animateOnView) {
                chart.removeAttribute('data-animate');
                chart.setAttribute('data-animate-on-view', '');
            }

            // Show values (optional)
            if (config.showValues) {
                chart.setAttribute('data-show-values', '');
            }

            // Show legend (optional - for pie/doughnut)
            if (config.showLegend) {
                chart.setAttribute('data-show-legend', '');
            }

            // Show tooltip (optional)
            if (config.showTooltip) {
                chart.setAttribute('data-show-tooltip', '');
            }

            // Curved lines (optional - for line/area)
            if (config.curved !== undefined) {
                chart.setAttribute('data-curved', String(config.curved));
            }

            // Sparkline size (optional)
            if (config.size) {
                chart.setAttribute('data-size', config.size);
            }

            // Height (optional - for bar, line, pie, etc.)
            if (config.height) {
                chart.style.height = config.height;
            }

            // Width (optional)
            if (config.width) {
                chart.style.width = config.width;
            }

            // Custom class (optional)
            if (config.className) {
                chart.className = config.className;
            }

            el.appendChild(chart);

            // Initialize chart component after short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.Charts && window.RSL.Charts.init) {
                    window.RSL.Charts.init();
                }
            }, 100);
        }

        /**
         * Render KPI Card - Creates a KPI card component
         * Uses the V1 KPICards component via data attributes
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - KPI card configuration
         * @param {string|number} config.value - The main value to display
         * @param {string} [config.label] - Label/title for the KPI
         * @param {string} [config.trend] - Trend direction (up, down, neutral)
         * @param {string} [config.trendValue] - Trend value text (e.g., "+12%")
         * @param {string} [config.comparison] - Comparison text (e.g., "vs last month")
         * @param {string} [config.icon] - FontAwesome icon class
         * @param {Array|string} [config.sparkline] - Sparkline data points
         * @param {string} [config.colorScheme] - Color scheme (blue, green, red, orange, purple, pink, teal, indigo, slate)
         * @param {string} [config.size] - Card size (compact, default, large)
         * @param {number} [config.progress] - Progress bar value (0-100)
         * @param {number} [config.progressMax] - Progress bar max value
         * @param {string} [config.progressLabel] - Progress bar label
         * @param {string|number} [config.secondaryValue] - Secondary value
         * @param {string} [config.secondaryLabel] - Secondary value label
         * @param {string} [config.prefix] - Value prefix (e.g., "$")
         * @param {string} [config.suffix] - Value suffix (e.g., "%")
         * @param {boolean} [config.animate] - Enable count-up animation
         * @param {number} [config.animationDuration] - Animation duration in ms
         * @param {number} [config.decimalPlaces] - Decimal places for value
         * @param {boolean} [config.clickable] - Make card clickable
         * @param {string} [config.href] - Link URL when clickable
         * @param {boolean} [config.glow] - Enable glow effect
         * @param {boolean} [config.accent] - Enable accent styling
         * @param {boolean} [config.accentValue] - Apply accent to value
         * @param {boolean} [config.loading] - Show loading skeleton state
         * @param {string} [config.className] - Additional CSS classes
         */
        _renderKPI(el, config) {
            // Validate required value property
            if (config.value === undefined && !config.loading) {
                console.warn('KPI component requires a "value" property (or "loading: true" for skeleton)');
                return;
            }

            // Create KPI card container
            const kpi = document.createElement('div');
            kpi.className = 'rsl-kpi-card';
            kpi.setAttribute('data-rsl-kpi', '');

            // Value (required unless loading)
            if (config.value !== undefined) {
                kpi.setAttribute('data-value', String(config.value));
            }

            // Label/title (optional)
            if (config.label) {
                kpi.setAttribute('data-label', config.label);
            }

            // Trend (optional)
            if (config.trend) {
                kpi.setAttribute('data-trend', config.trend);
            }

            // Trend value (optional)
            if (config.trendValue) {
                kpi.setAttribute('data-trend-value', config.trendValue);
            }

            // Comparison text (optional)
            if (config.comparison) {
                kpi.setAttribute('data-comparison', config.comparison);
            }

            // Icon (optional)
            if (config.icon) {
                kpi.setAttribute('data-icon', config.icon);
            }

            // Sparkline data (optional)
            if (config.sparkline) {
                const sparkData = Array.isArray(config.sparkline)
                    ? config.sparkline.join(',')
                    : config.sparkline;
                kpi.setAttribute('data-sparkline', sparkData);
            }

            // Color scheme (optional)
            if (config.colorScheme) {
                kpi.setAttribute('data-color-scheme', config.colorScheme);
            }

            // Size (optional)
            if (config.size) {
                kpi.setAttribute('data-size', config.size);
            }

            // Progress bar (optional)
            if (config.progress !== undefined) {
                kpi.setAttribute('data-progress', String(config.progress));
            }

            if (config.progressMax !== undefined) {
                kpi.setAttribute('data-progress-max', String(config.progressMax));
            }

            if (config.progressLabel) {
                kpi.setAttribute('data-progress-label', config.progressLabel);
            }

            // Secondary value (optional)
            if (config.secondaryValue !== undefined) {
                kpi.setAttribute('data-secondary-value', String(config.secondaryValue));
            }

            if (config.secondaryLabel) {
                kpi.setAttribute('data-secondary-label', config.secondaryLabel);
            }

            // Prefix/suffix (optional)
            if (config.prefix) {
                kpi.setAttribute('data-prefix', config.prefix);
            }

            if (config.suffix) {
                kpi.setAttribute('data-suffix', config.suffix);
            }

            // Animation (optional)
            if (config.animate) {
                kpi.setAttribute('data-animate', '');
            }

            if (config.animationDuration) {
                kpi.setAttribute('data-animation-duration', String(config.animationDuration));
            }

            // Decimal places (optional)
            if (config.decimalPlaces !== undefined) {
                kpi.setAttribute('data-decimal-places', String(config.decimalPlaces));
            }

            // Clickable (optional)
            if (config.clickable) {
                kpi.setAttribute('data-clickable', '');
            }

            if (config.href) {
                kpi.setAttribute('data-href', config.href);
            }

            // Glow effect (optional)
            if (config.glow) {
                kpi.setAttribute('data-glow', '');
            }

            // Accent styling (optional)
            if (config.accent) {
                kpi.setAttribute('data-accent', '');
            }

            if (config.accentValue) {
                kpi.setAttribute('data-accent-value', '');
            }

            // Loading state (optional)
            if (config.loading) {
                kpi.setAttribute('data-loading', 'true');
            }

            // Custom class (optional)
            if (config.className) {
                kpi.className += ' ' + config.className;
            }

            // Inline styles (optional)
            if (config.style) {
                Object.assign(kpi.style, config.style);
            }

            el.appendChild(kpi);

            // Initialize KPI Cards component after short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.KPICards && window.RSL.KPICards.init) {
                    window.RSL.KPICards.init();
                }
            }, 100);
        }

        /**
         * Render single Stat - Lightweight statistics display
         * Uses the V1 Stats component via data attributes
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Stat configuration
         * @param {number|string} config.value - The main numeric value
         * @param {string} [config.label] - Description text below the value
         * @param {string} [config.prefix] - Text/symbol before the value
         * @param {string} [config.suffix] - Text/symbol after the value
         * @param {string} [config.icon] - FontAwesome icon class
         * @param {string} [config.variant] - Layout variant: default, compact, inline, featured, card
         * @param {string} [config.size] - Size: xs, sm, md, lg, xl
         * @param {string} [config.colorScheme] - Color theme: primary, success, warning, danger, info
         * @param {string} [config.align] - Text alignment: left, center, right
         * @param {boolean} [config.animate] - Enable count-up animation
         * @param {number} [config.duration] - Animation duration in ms
         * @param {string} [config.easing] - Easing function
         * @param {number} [config.decimals] - Decimal places
         * @param {string} [config.separator] - Thousands separator
         * @param {boolean} [config.clickable] - Make clickable
         * @param {string} [config.href] - URL to navigate on click
         * @param {string} [config.filterSubscribe] - FilterBus key to subscribe to
         * @param {string} [config.filterValue] - Filter value(s) this stat matches
         * @param {string} [config.className] - Additional CSS classes
         */
        _renderStat(el, config) {
            // Validate required value property
            if (config.value === undefined) {
                console.warn('Stat component requires a "value" property');
                return;
            }

            // Create stat container
            const stat = document.createElement('div');
            stat.className = 'rsl-stat';

            // Value (required)
            stat.setAttribute('data-value', String(config.value));

            // Label (optional)
            if (config.label) {
                stat.setAttribute('data-label', config.label);
            }

            // Prefix (optional)
            if (config.prefix) {
                stat.setAttribute('data-prefix', config.prefix);
            }

            // Suffix (optional)
            if (config.suffix) {
                stat.setAttribute('data-suffix', config.suffix);
            }

            // Icon (optional)
            if (config.icon) {
                stat.setAttribute('data-icon', config.icon);
            }

            // Variant (optional)
            if (config.variant) {
                stat.setAttribute('data-variant', config.variant);
            }

            // Size (optional)
            if (config.size) {
                stat.setAttribute('data-size', config.size);
            }

            // Color scheme (optional)
            if (config.colorScheme) {
                stat.setAttribute('data-color-scheme', config.colorScheme);
            }

            // Alignment (optional)
            if (config.align) {
                stat.setAttribute('data-align', config.align);
            }

            // Animation (optional)
            if (config.animate) {
                stat.setAttribute('data-animate', '');
            }

            if (config.duration) {
                stat.setAttribute('data-duration', String(config.duration));
            }

            if (config.easing) {
                stat.setAttribute('data-easing', config.easing);
            }

            if (config.decimals !== undefined) {
                stat.setAttribute('data-decimals', String(config.decimals));
            }

            if (config.separator) {
                stat.setAttribute('data-separator', config.separator);
            }

            // Clickable (optional)
            if (config.clickable) {
                stat.setAttribute('data-clickable', '');
            }

            if (config.href) {
                stat.setAttribute('data-href', config.href);
            }

            // FilterBus integration (optional)
            if (config.filterSubscribe) {
                stat.setAttribute('data-filter-subscribe', config.filterSubscribe);
            }

            if (config.filterValue) {
                stat.setAttribute('data-filter-value', config.filterValue);
            }

            // Custom class (optional)
            if (config.className) {
                stat.className += ' ' + config.className;
            }

            // Inline styles (optional)
            if (config.style) {
                Object.assign(stat.style, config.style);
            }

            el.appendChild(stat);

            // Initialize Stats component after short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.Stats && window.RSL.Stats.init) {
                    window.RSL.Stats.init();
                }
            }, 100);
        }

        /**
         * Render Stats group - Container for multiple stats
         * Uses the V1 Stats component via data attributes
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Stats group configuration
         * @param {Array} config.items - Array of stat configurations
         * @param {string} [config.variant] - Layout variant applied to all stats
         * @param {string} [config.gap] - CSS gap value between stats
         * @param {boolean} [config.dividers] - Show divider lines between stats
         * @param {string} [config.className] - Additional CSS classes
         */
        _renderStats(el, config) {
            // Validate required items property
            if (!config.items || !Array.isArray(config.items) || config.items.length === 0) {
                console.warn('Stats component requires an "items" array with at least one stat');
                return;
            }

            // Create stats container
            const stats = document.createElement('div');
            stats.className = 'rsl-stats';

            // Variant (optional - applied to container)
            if (config.variant) {
                stats.setAttribute('data-variant', config.variant);
            }

            // Gap (optional)
            if (config.gap) {
                stats.setAttribute('data-gap', config.gap);
            }

            // Dividers (optional)
            if (config.dividers) {
                stats.setAttribute('data-dividers', '');
            }

            // Custom class (optional)
            if (config.className) {
                stats.className += ' ' + config.className;
            }

            // Inline styles (optional)
            if (config.style) {
                Object.assign(stats.style, config.style);
            }

            // Render each stat item
            config.items.forEach(itemConfig => {
                const statEl = document.createElement('div');
                statEl.className = 'rsl-stat';

                // Apply container variant to individual stats if not overridden
                const variant = itemConfig.variant || config.variant;
                if (variant) {
                    statEl.setAttribute('data-variant', variant);
                }

                // Value (required)
                if (itemConfig.value !== undefined) {
                    statEl.setAttribute('data-value', String(itemConfig.value));
                }

                // Label (optional)
                if (itemConfig.label) {
                    statEl.setAttribute('data-label', itemConfig.label);
                }

                // Prefix (optional)
                if (itemConfig.prefix) {
                    statEl.setAttribute('data-prefix', itemConfig.prefix);
                }

                // Suffix (optional)
                if (itemConfig.suffix) {
                    statEl.setAttribute('data-suffix', itemConfig.suffix);
                }

                // Icon (optional)
                if (itemConfig.icon) {
                    statEl.setAttribute('data-icon', itemConfig.icon);
                }

                // Size (optional)
                if (itemConfig.size) {
                    statEl.setAttribute('data-size', itemConfig.size);
                }

                // Color scheme (optional)
                if (itemConfig.colorScheme) {
                    statEl.setAttribute('data-color-scheme', itemConfig.colorScheme);
                }

                // Alignment (optional)
                if (itemConfig.align) {
                    statEl.setAttribute('data-align', itemConfig.align);
                }

                // Animation (optional)
                if (itemConfig.animate) {
                    statEl.setAttribute('data-animate', '');
                }

                if (itemConfig.duration) {
                    statEl.setAttribute('data-duration', String(itemConfig.duration));
                }

                if (itemConfig.easing) {
                    statEl.setAttribute('data-easing', itemConfig.easing);
                }

                if (itemConfig.decimals !== undefined) {
                    statEl.setAttribute('data-decimals', String(itemConfig.decimals));
                }

                if (itemConfig.separator) {
                    statEl.setAttribute('data-separator', itemConfig.separator);
                }

                // Clickable (optional)
                if (itemConfig.clickable) {
                    statEl.setAttribute('data-clickable', '');
                }

                if (itemConfig.href) {
                    statEl.setAttribute('data-href', itemConfig.href);
                }

                // FilterBus integration (optional)
                if (itemConfig.filterSubscribe) {
                    statEl.setAttribute('data-filter-subscribe', itemConfig.filterSubscribe);
                }

                if (itemConfig.filterValue) {
                    statEl.setAttribute('data-filter-value', itemConfig.filterValue);
                }

                // Custom class (optional)
                if (itemConfig.className) {
                    statEl.className += ' ' + itemConfig.className;
                }

                // Inline styles (optional)
                if (itemConfig.style) {
                    Object.assign(statEl.style, itemConfig.style);
                }

                stats.appendChild(statEl);
            });

            el.appendChild(stats);

            // Initialize Stats component after short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.Stats && window.RSL.Stats.init) {
                    window.RSL.Stats.init();
                }
            }, 100);
        }

        /**
         * Render Gantt chart - Interactive project timeline visualization
         * Uses the V1 Gantt component via data attributes
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Gantt configuration
         * @param {string} [config.zoom] - Zoom level: day, week, month, quarter, year
         * @param {boolean} [config.editable] - Whether tasks can be edited (default: true)
         * @param {boolean} [config.showToolbar] - Show toolbar (default: true)
         * @param {boolean} [config.showProgress] - Show progress bars (default: true)
         * @param {boolean} [config.showDependencies] - Show dependency arrows (default: true)
         * @param {boolean} [config.showTaskList] - Show task list panel (default: true)
         * @param {Array} [config.tasks] - Array of task objects
         * @param {string} [config.height] - Container height (e.g., '400px')
         * @param {string} [config.className] - Additional CSS classes
         */
        _renderGantt(el, config) {
            // Create Gantt container
            const gantt = document.createElement('div');
            gantt.setAttribute('data-rsl-gantt', '');

            // Title/name for accessibility (optional)
            if (config.title || config.name) {
                gantt.setAttribute('data-gantt-title', config.title || config.name);
            }

            // Zoom level (optional, default: week)
            if (config.zoom) {
                gantt.setAttribute('data-gantt-zoom', config.zoom);
            }

            // Editable (optional, default: true)
            if (config.editable === false) {
                gantt.setAttribute('data-gantt-editable', 'false');
            }

            // Show toolbar (optional, default: true)
            if (config.showToolbar === false) {
                gantt.setAttribute('data-gantt-show-toolbar', 'false');
            }

            // Show progress (optional, default: true)
            if (config.showProgress === false) {
                gantt.setAttribute('data-gantt-show-progress', 'false');
            }

            // Show dependencies (optional, default: true)
            if (config.showDependencies === false) {
                gantt.setAttribute('data-gantt-show-dependencies', 'false');
            }

            // Show task list (optional, default: true)
            if (config.showTaskList === false) {
                gantt.setAttribute('data-gantt-show-task-list', 'false');
            }

            // Height (optional)
            if (config.height) {
                gantt.style.minHeight = config.height;
            } else {
                gantt.style.minHeight = '400px';
            }

            // Custom class (optional)
            if (config.className) {
                gantt.className += ' ' + config.className;
            }

            // If tasks are provided, create a table structure
            if (config.tasks && Array.isArray(config.tasks) && config.tasks.length > 0) {
                const table = document.createElement('table');

                // Create thead
                const thead = document.createElement('thead');
                const headerRow = document.createElement('tr');
                ['Task', 'Start', 'End', 'Progress'].forEach(header => {
                    const th = document.createElement('th');
                    th.textContent = header;
                    headerRow.appendChild(th);
                });
                thead.appendChild(headerRow);
                table.appendChild(thead);

                // Create tbody
                const tbody = document.createElement('tbody');
                config.tasks.forEach(task => {
                    const row = document.createElement('tr');

                    // Set task data attributes
                    if (task.id) row.setAttribute('data-task-id', task.id);
                    if (task.type) row.setAttribute('data-task-type', task.type);
                    if (task.parentId) row.setAttribute('data-task-parent', task.parentId);
                    if (task.color) row.setAttribute('data-task-color', task.color);
                    if (task.depends) {
                        const deps = Array.isArray(task.depends) ? task.depends.join(',') : task.depends;
                        row.setAttribute('data-task-depends', deps);
                    }

                    // Task name
                    const nameCell = document.createElement('td');
                    nameCell.textContent = task.name || task.title || '';
                    row.appendChild(nameCell);

                    // Start date
                    const startCell = document.createElement('td');
                    startCell.textContent = task.start || '';
                    row.appendChild(startCell);

                    // End date
                    const endCell = document.createElement('td');
                    endCell.textContent = task.end || '';
                    row.appendChild(endCell);

                    // Progress
                    const progressCell = document.createElement('td');
                    progressCell.textContent = task.progress !== undefined ? task.progress : '0';
                    row.appendChild(progressCell);

                    tbody.appendChild(row);
                });
                table.appendChild(tbody);
                gantt.appendChild(table);
            }

            el.appendChild(gantt);

            // Initialize Gantt component after short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.Gantt && window.RSL.Gantt.init) {
                    window.RSL.Gantt.init();
                }
            }, 100);
        }

        /**
         * Render Smart Table component
         * Creates a data table with sorting, filtering, pagination, and export features
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Smart Table configuration
         * @param {string} [config.title] - Table title for accessibility
         * @param {Array} config.columns - Column definitions [{key, label, sortable, type, width}]
         * @param {Array} config.data - Row data array
         * @param {boolean} [config.searchable=true] - Enable search
         * @param {boolean} [config.exportable=true] - Enable export
         * @param {boolean} [config.selectable=false] - Enable row selection
         * @param {boolean} [config.sortable=true] - Enable sorting
         * @param {boolean} [config.striped=true] - Enable striped rows
         * @param {number} [config.pageSize=10] - Rows per page
         * @param {string} [config.responsive='card'] - Responsive mode (card, scroll, stack)
         * @param {boolean} [config.stickyHeader=false] - Enable sticky header
         * @param {boolean} [config.rowActions=false] - Enable row action menu
         * @param {Array} [config.rowActionItems] - Row action items
         */
        _renderSmartTable(el, config) {
            // Create table element
            const table = document.createElement('table');
            table.setAttribute('data-rsl-smart-table', '');

            // Title/name for accessibility
            if (config.title || config.name) {
                table.setAttribute('aria-label', config.title || config.name);
            }

            // Apply configuration via data attributes
            if (config.searchable !== false) {
                table.setAttribute('data-searchable', '');
            }
            if (config.exportable !== false) {
                table.setAttribute('data-exportable', '');
            }
            if (config.selectable) {
                table.setAttribute('data-selectable', '');
            }
            if (config.striped !== false) {
                table.setAttribute('data-striped', '');
            }
            if (config.stickyHeader) {
                table.setAttribute('data-sticky-header', '');
            }
            if (config.pageSize) {
                table.setAttribute('data-page-size', config.pageSize);
            }
            if (config.responsive) {
                table.setAttribute('data-responsive', config.responsive);
            }
            if (config.rowActions) {
                table.setAttribute('data-row-actions', '');
            }
            if (config.rowActionItems && config.rowActionItems.length > 0) {
                table.setAttribute('data-row-action-items', config.rowActionItems.join(','));
            }
            if (config.exportFormats && config.exportFormats.length > 0) {
                table.setAttribute('data-export-formats', config.exportFormats.join(','));
            }
            if (config.inlineEditing) {
                table.setAttribute('data-inline-editing', '');
            }
            if (config.columnResizing) {
                table.setAttribute('data-column-resizing', '');
            }
            if (config.columnReordering) {
                table.setAttribute('data-column-reordering', '');
            }
            if (config.expandableRows) {
                table.setAttribute('data-expandable-rows', '');
            }
            if (config.summaryRow) {
                table.setAttribute('data-summary-row', '');
            }

            // Create thead
            if (config.columns && Array.isArray(config.columns) && config.columns.length > 0) {
                const thead = document.createElement('thead');
                const headerRow = document.createElement('tr');

                config.columns.forEach(col => {
                    const th = document.createElement('th');

                    // Column key
                    if (col.key) {
                        th.setAttribute('data-col', col.key);
                    }

                    // Sortable
                    if (col.sortable !== false && config.sortable !== false) {
                        th.setAttribute('data-sortable', '');
                    }

                    // Data type
                    if (col.type) {
                        th.setAttribute('data-type', col.type);
                    }

                    // Width
                    if (col.width) {
                        th.style.width = col.width;
                    }

                    // Filterable
                    if (col.filterable) {
                        th.setAttribute('data-filterable', '');
                    }

                    // Label
                    th.textContent = col.label || col.key || '';

                    headerRow.appendChild(th);
                });

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

            // Create tbody with data
            if (config.data && Array.isArray(config.data) && config.data.length > 0) {
                const tbody = document.createElement('tbody');
                const columns = config.columns || [];

                config.data.forEach(rowData => {
                    const row = document.createElement('tr');

                    // Add row ID if present
                    if (rowData.id) {
                        row.setAttribute('data-row-id', rowData.id);
                    }

                    columns.forEach(col => {
                        const td = document.createElement('td');
                        const key = col.key;
                        const value = rowData[key];

                        // Add data-label for responsive card mode
                        td.setAttribute('data-label', col.label || col.key || '');

                        // Handle different value types
                        if (value === undefined || value === null) {
                            td.textContent = '';
                        } else if (typeof value === 'object' && value.html) {
                            // Allow HTML content for badges, status, etc.
                            td.innerHTML = value.html;
                        } else if (col.type === 'status' && typeof value === 'string') {
                            // Auto-create status badge
                            const badge = document.createElement('span');
                            badge.className = 'rsl-status-badge';
                            const statusClass = this._getStatusClass(value);
                            if (statusClass) {
                                badge.classList.add(statusClass);
                            }
                            badge.textContent = value;
                            td.appendChild(badge);
                        } else if (col.type === 'currency' && typeof value === 'number') {
                            td.textContent = new Intl.NumberFormat('en-US', {
                                style: 'currency',
                                currency: col.currency || 'USD'
                            }).format(value);
                        } else if (col.type === 'date' && value) {
                            td.textContent = new Date(value).toLocaleDateString();
                        } else if (col.type === 'number' && typeof value === 'number') {
                            td.textContent = value.toLocaleString();
                        } else {
                            td.textContent = String(value);
                        }

                        row.appendChild(td);
                    });

                    tbody.appendChild(row);
                });

                table.appendChild(tbody);
            }

            el.appendChild(table);

            // Initialize Smart Table component after short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.SmartTable && window.RSL.SmartTable.init) {
                    window.RSL.SmartTable.init();
                }
            }, 100);
        }

        /**
         * Render Date Picker component
         * Creates a date picker input with V1 data attributes for initialization
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Date picker configuration
         * @param {string} [config.mode='single'] - Selection mode: 'single', 'range', or 'multiple'
         * @param {string} [config.format='MM/DD/YYYY'] - Display format
         * @param {string} [config.placeholder='Select date'] - Placeholder text
         * @param {string} [config.placeholderStart='Start date'] - Start date placeholder (range mode)
         * @param {string} [config.placeholderEnd='End date'] - End date placeholder (range mode)
         * @param {string} [config.minDate] - Minimum selectable date (date string or 'today', 'tomorrow', 'yesterday')
         * @param {string} [config.maxDate] - Maximum selectable date (date string or 'today', 'tomorrow', 'yesterday')
         * @param {string} [config.value] - Initial value
         * @param {boolean} [config.required=false] - Whether field is required
         * @param {boolean} [config.disabled=false] - Whether field is disabled
         * @param {boolean} [config.showDualCalendar=false] - Show two months side by side (range mode)
         * @param {boolean} [config.showPresets=false] - Show preset date ranges
         * @param {string} [config.presets] - Comma-separated preset names (today,yesterday,last7,last30,thisMonth,lastMonth)
         * @param {boolean} [config.inline=false] - Display calendar inline (always visible)
         * @param {string} [config.disabledDates] - Comma-separated dates to disable
         * @param {string} [config.disabledDays] - Comma-separated day numbers (0-6) to disable
         * @param {number} [config.firstDay=0] - First day of week (0=Sunday, 1=Monday)
         * @param {string} [config.locale='en-US'] - Locale for date formatting
         * @param {string} [config.linkedTo] - ID of another date picker to link
         * @param {number} [config.numberOfMonths=1] - Number of months to display
         * @param {string} [config.ariaLabel] - Accessibility label
         * @param {string} [config.id] - Unique ID for the input
         * @param {string} [config.name] - Form field name
         * @param {Array} [config.classes] - Additional CSS classes
         * @param {Function} [config.onChange] - Callback when date changes
         */
        _renderDatePicker(el, config) {
            // Create input element with data attributes
            const input = document.createElement('input');
            input.type = 'text';
            input.setAttribute('data-rsl-date-picker', '');

            // Generate unique ID if not provided
            const inputId = config.id || `datepicker-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
            input.id = inputId;

            // Set name for form submission
            if (config.name) {
                input.name = config.name;
            }

            // Mode: single (default), range, or multiple
            if (config.mode) {
                input.setAttribute('data-mode', config.mode);
            }

            // Display format
            if (config.format) {
                input.setAttribute('data-format', config.format);
            }

            // Placeholder(s)
            if (config.placeholder) {
                input.setAttribute('data-placeholder', config.placeholder);
            }
            if (config.placeholderStart) {
                input.setAttribute('data-placeholder-start', config.placeholderStart);
            }
            if (config.placeholderEnd) {
                input.setAttribute('data-placeholder-end', config.placeholderEnd);
            }

            // Date constraints - support keywords: today, tomorrow, yesterday
            if (config.minDate) {
                input.setAttribute('data-min-date', config.minDate);
            }
            if (config.maxDate) {
                input.setAttribute('data-max-date', config.maxDate);
            }

            // Initial value
            if (config.value) {
                input.setAttribute('data-value', config.value);
            }

            // Required/disabled states
            if (config.required) {
                input.setAttribute('data-required', 'true');
                input.required = true;
            }
            if (config.disabled) {
                input.setAttribute('data-disabled', 'true');
                input.disabled = true;
            }

            // Dual calendar for range mode
            if (config.showDualCalendar) {
                input.setAttribute('data-show-dual-calendar', 'true');
            }

            // Presets (e.g., "Today", "Last 7 days")
            if (config.showPresets) {
                input.setAttribute('data-show-presets', 'true');
            }
            if (config.presets) {
                // Can be array or comma-separated string
                const presetsStr = Array.isArray(config.presets) ? config.presets.join(',') : config.presets;
                input.setAttribute('data-presets', presetsStr);
            }

            // Inline mode (calendar always visible)
            if (config.inline) {
                input.setAttribute('data-inline', 'true');
            }

            // Disabled dates and days
            if (config.disabledDates) {
                const datesStr = Array.isArray(config.disabledDates) ? config.disabledDates.join(',') : config.disabledDates;
                input.setAttribute('data-disabled-dates', datesStr);
            }
            if (config.disabledDays) {
                const daysStr = Array.isArray(config.disabledDays) ? config.disabledDays.join(',') : config.disabledDays;
                input.setAttribute('data-disabled-days', daysStr);
            }

            // First day of week (0=Sunday, 1=Monday, etc.)
            if (config.firstDay !== undefined) {
                input.setAttribute('data-first-day', config.firstDay.toString());
            }

            // Locale
            if (config.locale) {
                input.setAttribute('data-locale', config.locale);
            }

            // Linked picker (for range dependencies)
            if (config.linkedTo) {
                input.setAttribute('data-linked-to', config.linkedTo);
            }

            // Number of months to display
            if (config.numberOfMonths) {
                input.setAttribute('data-number-of-months', config.numberOfMonths.toString());
            }

            // Accessibility
            if (config.ariaLabel) {
                input.setAttribute('data-aria-label', config.ariaLabel);
                input.setAttribute('aria-label', config.ariaLabel);
            }

            // Auto-close on select
            if (config.closeOnSelect !== undefined) {
                input.setAttribute('data-close-on-select', config.closeOnSelect.toString());
            }

            // Add custom CSS classes
            if (config.classes) {
                config.classes.forEach(cls => input.classList.add(cls));
            }

            // Add inline styles if provided
            if (config.style) {
                Object.entries(config.style).forEach(([key, value]) => {
                    input.style[key] = value;
                });
            }

            // Add to container
            el.appendChild(input);

            // Store onChange handler for after initialization
            if (config.onChange) {
                input._v2OnChange = config.onChange;
            }

            // Note: DatePicker will be initialized by _initializeComponents()
            // We add a custom event listener after init
            setTimeout(() => {
                if (window.RSL && window.RSL.DatePicker) {
                    // Find the instance after it's been created
                    const instance = window.RSL.DatePicker.instances.get(input);
                    if (instance && config.onChange) {
                        // The date picker fires 'change' events on the original input
                        const container = instance.element;
                        if (container) {
                            container.addEventListener('change', (e) => {
                                const value = window.RSL.DatePicker.getValue(instance);
                                config.onChange(e, value, instance);
                            });
                        }
                    }
                }
            }, 200);
        }

        /**
         * Render time picker component (wrapper for v1 TimePicker component)
         * Creates a time picker with clock dial, presets, and range support
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - TimePicker configuration
         *
         * Config options:
         * - id: string - Input ID (auto-generated if not provided)
         * - name: string - Input name for form submission
         * - mode: 'single'|'range' - Selection mode (default: 'single')
         * - format: '12'|'24' - Time format (default: '12')
         * - step: number - Minute increment (1, 5, 15, 30, 60) (default: 5)
         * - minTime: string - Minimum time 'HH:mm'
         * - maxTime: string - Maximum time 'HH:mm'
         * - defaultTime: string - Initial time or 'now'
         * - placeholder: string - Placeholder text
         * - placeholderStart: string - Start time placeholder (range mode)
         * - placeholderEnd: string - End time placeholder (range mode)
         * - showPresets: boolean - Show quick preset buttons (default: true)
         * - showDial: boolean - Show clock dial (default: true)
         * - inline: boolean - Always visible (no popover)
         * - clearable: boolean - Allow clearing selection (default: true)
         * - closeOnSelect: boolean - Close after selection (default: false)
         * - autoApply: boolean - Auto-apply without confirm button (default: true)
         * - required: boolean - Mark as required
         * - disabled: boolean - Disable input
         * - readOnly: boolean - Read-only mode
         * - ariaLabel: string - Accessible label
         * - filterBusPublish: string - FilterBus key for cross-component filtering
         * - onChange: function(event, value, instance) - Change callback
         * - className: string - Additional CSS classes
         * - style: object - Inline styles
         */
        _renderTimePicker(el, config) {
            // Create input element with data attributes
            const input = document.createElement('input');
            input.type = 'text';
            input.setAttribute('data-rsl-time-picker', '');

            // Generate unique ID if not provided
            const inputId = config.id || `timepicker-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
            input.id = inputId;

            // Set name for form submission
            if (config.name) {
                input.name = config.name;
            }

            // Mode: single (default) or range
            if (config.mode) {
                input.setAttribute('data-mode', config.mode);
            }

            // Time format: 12 (AM/PM) or 24
            if (config.format) {
                input.setAttribute('data-format', config.format);
            }

            // Minute step interval
            if (config.step) {
                input.setAttribute('data-step', config.step);
            }

            // Placeholder(s)
            if (config.placeholder) {
                input.setAttribute('data-placeholder', config.placeholder);
            }
            if (config.placeholderStart) {
                input.setAttribute('data-placeholder-start', config.placeholderStart);
            }
            if (config.placeholderEnd) {
                input.setAttribute('data-placeholder-end', config.placeholderEnd);
            }

            // Time constraints
            if (config.minTime) {
                input.setAttribute('data-min-time', config.minTime);
            }
            if (config.maxTime) {
                input.setAttribute('data-max-time', config.maxTime);
            }

            // Initial value
            if (config.defaultTime) {
                input.setAttribute('data-default-time', config.defaultTime);
            }
            if (config.value) {
                input.value = config.value;
            }

            // Required/disabled/readonly states
            if (config.required) {
                input.setAttribute('data-required', 'true');
                input.required = true;
            }
            if (config.disabled) {
                input.setAttribute('data-disabled', 'true');
                input.disabled = true;
            }
            if (config.readOnly) {
                input.setAttribute('data-read-only', 'true');
                input.readOnly = true;
            }

            // Show presets (Now, Morning, Noon, etc.)
            if (config.showPresets !== undefined) {
                input.setAttribute('data-show-presets', config.showPresets.toString());
            }

            // Show clock dial
            if (config.showDial !== undefined) {
                input.setAttribute('data-show-dial', config.showDial.toString());
            }

            // Inline mode (always visible)
            if (config.inline) {
                input.setAttribute('data-inline', 'true');
            }

            // Clearable
            if (config.clearable !== undefined) {
                input.setAttribute('data-clearable', config.clearable.toString());
            }

            // Close on select
            if (config.closeOnSelect !== undefined) {
                input.setAttribute('data-close-on-select', config.closeOnSelect.toString());
            }

            // Auto-apply
            if (config.autoApply !== undefined) {
                input.setAttribute('data-auto-apply', config.autoApply.toString());
            }

            // Accessibility
            if (config.ariaLabel) {
                input.setAttribute('data-aria-label', config.ariaLabel);
            }

            // FilterBus integration
            if (config.filterBusPublish) {
                input.setAttribute('data-filterbus-publish', config.filterBusPublish);
            }

            // Additional classes
            if (config.className) {
                input.className = config.className;
            }

            // Custom styles
            if (config.style) {
                Object.entries(config.style).forEach(([key, value]) => {
                    input.style[key] = value;
                });
            }

            // Add to container
            el.appendChild(input);

            // Store onChange handler for after initialization
            if (config.onChange) {
                input._v2OnChange = config.onChange;
            }

            // Note: TimePicker will be initialized by _initializeComponents()
            // We add a custom event listener after init
            setTimeout(() => {
                if (window.RSL && window.RSL.TimePicker) {
                    // Find the instance after it's been created
                    const instance = window.RSL.TimePicker.instances.get(input);
                    if (instance && config.onChange) {
                        // The time picker fires 'rsl-time-change' events
                        input.addEventListener('rsl-time-change', (e) => {
                            const value = window.RSL.TimePicker.getValue(input);
                            config.onChange(e, value, instance);
                        });
                    }
                }
            }, 200);
        }

        /**
         * Render filter component (wrapper for v1 Filter component)
         * Creates a Filter UI with buttons/pills/chips/dropdown that publishes to FilterBus
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Filter configuration
         * @param {string} config.key - FilterBus key to publish to (required)
         * @param {Array} config.options - Filter options array [{value, label, icon?}]
         * @param {string} [config.style='pills'] - UI style: pills, buttons, dropdown, chips, toggle, search, radio, checkbox
         * @param {boolean} [config.multi=false] - Allow multiple selections
         * @param {string|Array} [config.defaultValue] - Default selected value(s)
         * @param {boolean} [config.persist=false] - Persist to localStorage
         * @param {string} [config.size='md'] - Size: sm, md, lg
         * @param {string} [config.color='primary'] - Color theme: primary, success, warning, danger, info
         * @param {string} [config.placeholder] - Placeholder for search/dropdown styles
         * @param {number} [config.debounce=300] - Debounce time for search style (ms)
         * @param {string} [config.label] - Accessible label for the filter
         * @param {string} [config.layout='horizontal'] - Layout: horizontal, vertical
         * @param {boolean} [config.showClear=true] - Show clear button
         * @param {boolean} [config.showCount=false] - Show option count badges
         * @param {boolean} [config.announce=true] - Announce changes to screen readers
         * @param {Array} [config.classes] - Additional CSS classes
         * @param {Function} [config.onChange] - Callback when filter changes
         */
        _renderFilter(el, config) {
            if (!config.key) {
                console.error('[RSL.JSONLayout] Filter component requires a "key" property');
                return;
            }

            // Create filter container with data attributes
            const container = document.createElement('div');
            container.setAttribute('data-rsl-filter', '');

            // Map V2 config to V1 data attributes
            container.setAttribute('data-filter-key', config.key);

            if (config.style) {
                container.setAttribute('data-filter-style', config.style);
            }

            if (config.multi === true) {
                container.setAttribute('data-filter-multi', 'true');
            }

            if (config.defaultValue !== undefined) {
                const defaultVal = Array.isArray(config.defaultValue)
                    ? config.defaultValue.join(',')
                    : config.defaultValue;
                container.setAttribute('data-filter-default', defaultVal);
            }

            if (config.persist === true) {
                container.setAttribute('data-filter-persist', 'true');
            }

            if (config.size) {
                container.setAttribute('data-filter-size', config.size);
            }

            if (config.color) {
                container.setAttribute('data-filter-color', config.color);
            }

            if (config.placeholder) {
                container.setAttribute('data-filter-placeholder', config.placeholder);
            }

            if (config.debounce !== undefined) {
                container.setAttribute('data-filter-debounce', config.debounce.toString());
            }

            if (config.label) {
                container.setAttribute('data-filter-label', config.label);
                container.setAttribute('aria-label', config.label);
            }

            if (config.layout) {
                container.setAttribute('data-filter-layout', config.layout);
            }

            if (config.showClear === false) {
                container.setAttribute('data-filter-show-clear', 'false');
            }

            if (config.showCount === true) {
                container.setAttribute('data-filter-show-count', 'true');
            }

            if (config.announce === false) {
                container.setAttribute('data-filter-announce', 'false');
            }

            // Add options as child elements based on style
            const style = config.style || 'pills';
            const options = config.options || [];

            if (style === 'dropdown') {
                // Dropdown style uses <option> elements
                options.forEach(opt => {
                    const option = document.createElement('option');
                    option.setAttribute('data-filter-value', opt.value);
                    option.textContent = opt.label || opt.text || opt.value;
                    if (opt.disabled) {
                        option.disabled = true;
                    }
                    container.appendChild(option);
                });
            } else if (style === 'search') {
                // Search style generates its own input, no options needed
                // Just set data attributes - Filter component handles the rest
            } else {
                // Button-based styles (pills, buttons, chips, toggle, radio, checkbox)
                options.forEach(opt => {
                    const button = document.createElement('button');
                    button.setAttribute('data-filter-value', opt.value);
                    button.type = 'button';

                    // Add icon if provided
                    if (opt.icon) {
                        const icon = document.createElement('i');
                        icon.className = opt.icon;
                        button.appendChild(icon);
                        button.appendChild(document.createTextNode(' '));
                    }

                    button.appendChild(document.createTextNode(opt.label || opt.text || opt.value));

                    if (opt.disabled) {
                        button.disabled = true;
                    }

                    container.appendChild(button);
                });
            }

            // Add custom CSS classes
            if (config.classes) {
                config.classes.forEach(cls => container.classList.add(cls));
            }

            // Add inline styles if provided
            if (config.style && typeof config.style === 'object') {
                // Note: config.style can be both a string (UI style) or object (CSS)
                // If it's an object, apply as inline styles
                Object.entries(config.style).forEach(([key, value]) => {
                    container.style[key] = value;
                });
            }

            // Add to container
            el.appendChild(container);

            // Handle onChange callback via FilterBus subscription
            if (config.onChange) {
                // Generate unique subscriber ID
                const subscriberId = `filter-v2-${config.key}-${Date.now()}`;

                // Wait for Filter to initialize, then subscribe
                setTimeout(() => {
                    if (window.RSL && window.RSL.FilterBus) {
                        window.RSL.FilterBus.subscribe(subscriberId, (state, meta) => {
                            const value = state[config.key];
                            config.onChange(value, state, meta);
                        }, { keys: [config.key] });
                    }
                }, 100);
            }

            // Note: Filter will be initialized by _initializeComponents()
        }

        /**
         * Render Full Page Calendar component
         * Creates an ADA-compliant calendar with day, week, month, year views
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Calendar configuration
         *
         * Config options:
         * - id: string - Calendar ID (auto-generated if not provided)
         * - view: 'day'|'week'|'month'|'year' - Initial view (default: 'month')
         * - date: string - Initial date (ISO format, default: today)
         * - firstDay: number - Week start: 0=Sun, 1=Mon (default: 0)
         * - editable: boolean - Enable event editing (default: true)
         * - showToolbar: boolean - Show navigation toolbar (default: true)
         * - showWeekNumbers: boolean - Show week numbers (default: false)
         * - filterKey: string - FilterBus key for event category filtering
         * - events: array - Initial events array
         * - categories: array - Event categories [{id, name, color}]
         * - height: string - Calendar height (default: '600px')
         * - locale: string - Locale for date formatting (default: browser locale)
         * - className: string - Additional CSS classes
         * - style: object - Inline styles
         * - onEventClick: function(event) - Event click callback
         * - onEventAdd: function(event) - Event add callback
         * - onEventUpdate: function(event) - Event update callback
         * - onEventDelete: function(eventId) - Event delete callback
         * - onViewChange: function(view) - View change callback
         * - onDateChange: function(date) - Date navigation callback
         */
        _renderCalendar(el, config) {
            // Create calendar container
            const calendar = document.createElement('div');
            calendar.setAttribute('data-rsl-calendar', '');

            // Generate unique ID if not provided
            const calendarId = config.id || `calendar-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
            calendar.id = calendarId;

            // View: day, week, month, year (default: month)
            if (config.view) {
                calendar.setAttribute('data-calendar-view', config.view);
            }

            // Initial date (ISO format)
            if (config.date) {
                calendar.setAttribute('data-calendar-date', config.date);
            }

            // First day of week (0=Sunday, 1=Monday, etc.)
            if (config.firstDay !== undefined) {
                calendar.setAttribute('data-calendar-first-day', config.firstDay.toString());
            }

            // Editable mode (default: true)
            if (config.editable === false) {
                calendar.setAttribute('data-calendar-editable', 'false');
            }

            // Show toolbar (default: true)
            if (config.showToolbar === false) {
                calendar.setAttribute('data-calendar-show-toolbar', 'false');
            }

            // Show week numbers
            if (config.showWeekNumbers === true) {
                calendar.setAttribute('data-calendar-show-week-numbers', 'true');
            }

            // FilterBus key for category filtering
            if (config.filterKey) {
                calendar.setAttribute('data-calendar-filter-key', config.filterKey);
            }

            // Initial events (JSON array)
            if (config.events && Array.isArray(config.events)) {
                calendar.setAttribute('data-calendar-events', JSON.stringify(config.events));
            }

            // Event categories (JSON array)
            if (config.categories && Array.isArray(config.categories)) {
                calendar.setAttribute('data-calendar-categories', JSON.stringify(config.categories));
            }

            // Upcoming events configuration
            if (config.upcoming) {
                calendar.setAttribute('data-calendar-upcoming', config.upcoming);
            }
            if (config.upcomingCount !== undefined) {
                calendar.setAttribute('data-calendar-upcoming-count', config.upcomingCount.toString());
            }
            if (config.upcomingDays !== undefined) {
                calendar.setAttribute('data-calendar-upcoming-days', config.upcomingDays.toString());
            }
            if (config.upcomingTitle) {
                calendar.setAttribute('data-calendar-upcoming-title', config.upcomingTitle);
            }

            // Height
            if (config.height) {
                calendar.style.minHeight = config.height;
            } else {
                calendar.style.minHeight = '600px';
            }

            // Locale for date formatting
            if (config.locale) {
                calendar.setAttribute('data-calendar-locale', config.locale);
            }

            // Add custom CSS classes
            if (config.className) {
                calendar.className += ' ' + config.className;
            }
            if (config.classes) {
                config.classes.forEach(cls => calendar.classList.add(cls));
            }

            // Add inline styles if provided
            if (config.style && typeof config.style === 'object') {
                Object.entries(config.style).forEach(([key, value]) => {
                    calendar.style[key] = value;
                });
            }

            // Add to container
            el.appendChild(calendar);

            // Store callbacks for post-initialization
            calendar._v2Callbacks = {
                onEventClick: config.onEventClick,
                onEventAdd: config.onEventAdd,
                onEventUpdate: config.onEventUpdate,
                onEventDelete: config.onEventDelete,
                onViewChange: config.onViewChange,
                onDateChange: config.onDateChange
            };

            // Initialize calendar and attach event listeners after short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.Calendar) {
                    // Initialize all calendars (including this one)
                    if (window.RSL.Calendar.init) {
                        window.RSL.Calendar.init();
                    }

                    // Get the instance for this calendar
                    const instance = window.RSL.Calendar.getInstance('#' + calendarId);
                    if (instance && calendar._v2Callbacks) {
                        // Attach event listeners
                        if (calendar._v2Callbacks.onEventClick) {
                            calendar.addEventListener('rsl-calendar-event-click', (e) => {
                                calendar._v2Callbacks.onEventClick(e.detail.event);
                            });
                        }
                        if (calendar._v2Callbacks.onEventAdd) {
                            calendar.addEventListener('rsl-calendar-event-add', (e) => {
                                calendar._v2Callbacks.onEventAdd(e.detail.event);
                            });
                        }
                        if (calendar._v2Callbacks.onEventUpdate) {
                            calendar.addEventListener('rsl-calendar-event-update', (e) => {
                                calendar._v2Callbacks.onEventUpdate(e.detail.event);
                            });
                        }
                        if (calendar._v2Callbacks.onEventDelete) {
                            calendar.addEventListener('rsl-calendar-event-delete', (e) => {
                                calendar._v2Callbacks.onEventDelete(e.detail.eventId);
                            });
                        }
                        if (calendar._v2Callbacks.onViewChange) {
                            calendar.addEventListener('rsl-calendar-view-change', (e) => {
                                calendar._v2Callbacks.onViewChange(e.detail.view);
                            });
                        }
                        if (calendar._v2Callbacks.onDateChange) {
                            calendar.addEventListener('rsl-calendar-date-change', (e) => {
                                calendar._v2Callbacks.onDateChange(e.detail.date);
                            });
                        }
                    }
                }
            }, 200);
        }

        /**
         * Render Hero component
         * Creates a fully-featured hero section with background, overlay, content, and effects
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Hero configuration
         * @param {string} [config.size] - Size: sm, md, lg, full (default: md)
         * @param {string} [config.layout] - Layout: center, split-left, split-right (default: center)
         * @param {string} [config.align] - Text alignment: left, center, right
         * @param {string} [config.background] - Background type: gradient, gradient-dark, gradient-warm, gradient-cool, gradient-nature, gradient-sunset, gradient-animated, image, video, solid, none
         * @param {string} [config.backgroundImage] - Image URL for image background
         * @param {string} [config.backgroundVideo] - Video URL for video background
         * @param {string} [config.backgroundColor] - Color for solid background
         * @param {string} [config.overlay] - Overlay type: dark, light, gradient
         * @param {string|number} [config.overlayOpacity] - Overlay opacity: 25, 50, 75, 90
         * @param {string} [config.eyebrow] - Eyebrow text above heading
         * @param {string} [config.eyebrowIcon] - Icon class for eyebrow
         * @param {string} config.heading - Main heading text
         * @param {string} [config.headingId] - ID for heading (for aria-labelledby)
         * @param {string} [config.subheading] - Subheading text
         * @param {Array} [config.buttons] - Array of button configs {text, href, variant, icon}
         * @param {Array} [config.features] - Array of feature configs {icon, text}
         * @param {Object} [config.media] - Media config for split layouts {src, alt}
         * @param {boolean} [config.parallax] - Enable parallax effect
         * @param {number} [config.parallaxSpeed] - Parallax speed (default: 0.5)
         * @param {boolean} [config.animateBg] - Enable animated gradient background
         * @param {boolean} [config.animateIn] - Enable fade-in animation for content
         * @param {boolean} [config.textShadow] - Add text shadow for readability
         * @param {boolean} [config.scrollIndicator] - Show scroll indicator
         * @param {string} [config.scrollTarget] - Scroll target selector
         * @param {string} [config.typewriter] - Enable typewriter effect on text
         */
        _renderHero(el, config) {
            // Create hero section
            const hero = document.createElement('section');
            hero.className = 'rsl-hero';

            // Add size variant
            if (config.size) {
                hero.setAttribute('data-hero-size', config.size);
            }

            // Add layout variant
            if (config.layout) {
                hero.setAttribute('data-hero-layout', config.layout);
            }

            // Add text alignment
            if (config.align) {
                hero.setAttribute('data-hero-align', config.align);
            }

            // Add background type
            const bgType = config.background || 'gradient';
            if (bgType === 'gradient-animated' || config.animateBg) {
                hero.setAttribute('data-hero-animate-bg', '');
            } else if (bgType === 'image' || config.backgroundImage) {
                hero.setAttribute('data-hero-bg', 'image');
            } else if (bgType === 'video' || config.backgroundVideo) {
                hero.setAttribute('data-hero-bg', 'video');
            } else if (bgType === 'solid') {
                hero.setAttribute('data-hero-bg', 'solid');
                if (config.backgroundColor) {
                    hero.style.setProperty('--rsl-hero-bg-color', config.backgroundColor);
                }
            } else if (bgType === 'none') {
                hero.setAttribute('data-hero-bg', 'none');
            } else {
                hero.setAttribute('data-hero-bg', bgType);
            }

            // Add overlay
            if (config.overlay) {
                hero.setAttribute('data-hero-overlay', config.overlay);
            }
            if (config.overlayOpacity) {
                hero.setAttribute('data-hero-overlay-opacity', config.overlayOpacity.toString());
            }

            // Add parallax
            if (config.parallax) {
                hero.setAttribute('data-hero-parallax', '');
                if (config.parallaxSpeed) {
                    hero.setAttribute('data-hero-parallax-speed', config.parallaxSpeed.toString());
                }
            }

            // Add animate-in effect
            if (config.animateIn) {
                hero.setAttribute('data-hero-animate-in', '');
            }

            // Add text shadow utility
            if (config.textShadow) {
                hero.classList.add('rsl-hero-text-shadow');
            }

            // Add scroll target
            if (config.scrollTarget) {
                hero.setAttribute('data-hero-scroll-target', config.scrollTarget);
            }

            // ARIA attributes
            hero.setAttribute('role', 'region');
            const headingId = config.headingId || `hero-heading-${Date.now()}`;
            hero.setAttribute('aria-labelledby', headingId);

            // Create background element if needed
            if (config.backgroundImage || config.backgroundVideo) {
                const bgEl = document.createElement('div');
                bgEl.className = 'rsl-hero-background';

                if (config.backgroundImage) {
                    const img = document.createElement('img');
                    img.src = config.backgroundImage;
                    img.alt = '';
                    img.setAttribute('aria-hidden', 'true');
                    bgEl.appendChild(img);
                } else if (config.backgroundVideo) {
                    const video = document.createElement('video');
                    video.src = config.backgroundVideo;
                    video.muted = true;
                    video.loop = true;
                    video.playsInline = true;
                    video.autoplay = true;
                    video.setAttribute('aria-hidden', 'true');
                    bgEl.appendChild(video);
                }

                hero.appendChild(bgEl);
            }

            // Create overlay element if overlay specified
            if (config.overlay) {
                const overlayEl = document.createElement('div');
                overlayEl.className = 'rsl-hero-overlay';
                overlayEl.setAttribute('aria-hidden', 'true');
                hero.appendChild(overlayEl);
            }

            // Create inner container
            const inner = document.createElement('div');
            inner.className = 'rsl-hero-inner';

            // Create content container
            const content = document.createElement('div');
            content.className = 'rsl-hero-content';

            // Add eyebrow
            if (config.eyebrow) {
                const eyebrow = document.createElement('span');
                eyebrow.className = 'rsl-hero-eyebrow';
                if (config.eyebrowIcon) {
                    const icon = document.createElement('i');
                    icon.className = config.eyebrowIcon;
                    eyebrow.appendChild(icon);
                    eyebrow.appendChild(document.createTextNode(' ' + config.eyebrow));
                } else {
                    eyebrow.textContent = config.eyebrow;
                }
                content.appendChild(eyebrow);
            }

            // Add heading
            if (config.heading) {
                const heading = document.createElement('h1');
                heading.id = headingId;
                heading.className = 'rsl-hero-heading';

                // Check for typewriter effect
                if (config.typewriter) {
                    heading.setAttribute('data-hero-typewriter', '');
                }

                // Support HTML in heading (for line breaks, accents)
                heading.innerHTML = config.heading;
                content.appendChild(heading);
            }

            // Add subheading
            if (config.subheading) {
                const subheading = document.createElement('p');
                subheading.className = 'rsl-hero-subheading';
                subheading.innerHTML = config.subheading;
                content.appendChild(subheading);
            }

            // Add buttons/actions
            if (config.buttons && Array.isArray(config.buttons) && config.buttons.length > 0) {
                const actions = document.createElement('div');
                actions.className = 'rsl-hero-actions';

                config.buttons.forEach(btn => {
                    const link = document.createElement('a');
                    link.href = btn.href || '#';
                    link.className = 'btn';

                    // Add variant class
                    if (btn.variant) {
                        link.classList.add(`btn-${btn.variant}`);
                    } else {
                        link.classList.add('btn-primary');
                    }

                    // Add icon if specified
                    if (btn.icon) {
                        const icon = document.createElement('i');
                        icon.className = btn.icon;
                        link.appendChild(icon);
                        link.appendChild(document.createTextNode(' '));
                    }

                    link.appendChild(document.createTextNode(btn.text || 'Button'));

                    // Add click handler if specified
                    if (btn.onClick && typeof btn.onClick === 'function') {
                        link.addEventListener('click', (e) => {
                            e.preventDefault();
                            btn.onClick(e, link);
                        });
                    }

                    actions.appendChild(link);
                });

                content.appendChild(actions);
            }

            // Add features
            if (config.features && Array.isArray(config.features) && config.features.length > 0) {
                const features = document.createElement('div');
                features.className = 'rsl-hero-features';

                config.features.forEach(feature => {
                    const featureEl = document.createElement('div');
                    featureEl.className = 'rsl-hero-feature';

                    if (feature.icon) {
                        const iconContainer = document.createElement('div');
                        iconContainer.className = 'rsl-hero-feature-icon';
                        const icon = document.createElement('i');
                        icon.className = feature.icon;
                        iconContainer.appendChild(icon);
                        featureEl.appendChild(iconContainer);
                    }

                    if (feature.text) {
                        const text = document.createElement('span');
                        text.className = 'rsl-hero-feature-text';
                        text.textContent = feature.text;
                        featureEl.appendChild(text);
                    }

                    features.appendChild(featureEl);
                });

                content.appendChild(features);
            }

            inner.appendChild(content);

            // Add media for split layouts
            if (config.media && (config.layout === 'split-left' || config.layout === 'split-right')) {
                const media = document.createElement('div');
                media.className = 'rsl-hero-media';

                const img = document.createElement('img');
                img.src = config.media.src;
                img.alt = config.media.alt || '';
                media.appendChild(img);

                inner.appendChild(media);
            }

            hero.appendChild(inner);

            // Add scroll indicator
            if (config.scrollIndicator) {
                const scroll = document.createElement('button');
                scroll.className = 'rsl-hero-scroll';
                scroll.setAttribute('aria-label', 'Scroll to next section');

                const scrollIcon = document.createElement('div');
                scrollIcon.className = 'rsl-hero-scroll-icon';
                scroll.appendChild(scrollIcon);

                const scrollText = document.createElement('span');
                scrollText.textContent = 'Scroll';
                scroll.appendChild(scrollText);

                hero.appendChild(scroll);
            }

            // Add custom classes
            if (config.className) {
                hero.className += ' ' + config.className;
            }
            if (config.classes && Array.isArray(config.classes)) {
                config.classes.forEach(cls => hero.classList.add(cls));
            }

            // Add inline styles
            if (config.style && typeof config.style === 'object') {
                Object.entries(config.style).forEach(([key, value]) => {
                    hero.style[key] = value;
                });
            }

            el.appendChild(hero);

            // Note: Hero will be initialized by _initializeComponents() via RSL.Hero.init()
        }

        /**
         * Render announcements component
         * Creates an announcement bar/panel with navigation and optional auto-rotation
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Announcements configuration
         * @param {Array} config.items - Array of announcement items
         * @param {string} config.items[].text - Announcement text
         * @param {string} [config.items[].priority] - Priority level (urgent, event, news, reminder)
         * @param {string} [config.items[].link] - Link URL
         * @param {string} [config.items[].date] - Date string (YYYY-MM-DD)
         * @param {string} [config.items[].category] - Category for filtering
         * @param {boolean} [config.items[].isNew] - Mark as new
         * @param {boolean} [config.autoRotate] - Enable auto-rotation (default: false)
         * @param {number} [config.interval] - Rotation interval in seconds (default: 5)
         * @param {boolean} [config.pauseOnHover] - Pause on hover (default: true)
         * @param {string} [config.variant] - Color variant (info, success, warning, danger, neutral)
         * @param {string} [config.filterKey] - FilterBus integration key
         */
        _renderAnnouncements(el, config) {
            // Validate items
            if (!config.items || !Array.isArray(config.items) || config.items.length === 0) {
                console.warn('Announcements component requires an "items" array');
                return;
            }

            // Create container with data attributes
            const container = document.createElement('div');
            container.className = 'rsl-announcements';
            container.setAttribute('data-rsl-announcements', '');

            // Add configuration data attributes
            if (config.autoRotate) {
                container.setAttribute('data-auto-rotate', 'true');
            }

            if (config.interval) {
                container.setAttribute('data-interval', config.interval.toString());
            }

            if (config.pauseOnHover === false) {
                container.setAttribute('data-pause-on-hover', 'false');
            }

            if (config.variant) {
                container.setAttribute('data-variant', config.variant);
            }

            if (config.filterKey) {
                container.setAttribute('data-filter-key', config.filterKey);
            }

            // Create announcement items
            config.items.forEach((item, index) => {
                const itemEl = document.createElement('div');
                itemEl.className = 'rsl-announcement-item';

                // Add item attributes
                if (item.priority) {
                    itemEl.setAttribute('data-priority', item.priority);
                }

                if (item.link) {
                    itemEl.setAttribute('data-link', item.link);
                }

                if (item.date) {
                    itemEl.setAttribute('data-date', item.date);
                }

                if (item.category) {
                    itemEl.setAttribute('data-category', item.category);
                }

                if (item.isNew) {
                    itemEl.setAttribute('data-new', '');
                }

                // Set the text content
                itemEl.textContent = item.text || '';

                container.appendChild(itemEl);
            });

            el.appendChild(container);

            // Note: Announcements will be initialized by _initializeComponents() via RSL.Announcements.init()
        }

        /**
         * Render Icon Picker component (V2 semantic content type)
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Icon picker configuration
         */
        _renderIconPicker(el, config) {
            // Create input element with data attributes
            const input = document.createElement('input');
            input.type = 'text';
            input.setAttribute('data-rsl-icon-picker', '');

            // Generate unique ID if not provided
            const inputId = config.id || `iconpicker-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
            input.id = inputId;

            // Set name for form submission
            if (config.name) {
                input.name = config.name;
            }

            // Icon sources: 'all', 'fa', 'rsl', or comma-separated
            if (config.sources) {
                input.setAttribute('data-sources', config.sources);
            }

            // Default source filter: 'all', 'fa', 'rsl'
            if (config.defaultSource) {
                input.setAttribute('data-default-source', config.defaultSource);
            }

            // Default category filter
            if (config.defaultCategory) {
                input.setAttribute('data-default-category', config.defaultCategory);
            }

            // Show recent icons section
            if (config.showRecent === false) {
                input.setAttribute('data-show-recent', 'false');
            }

            // Show preview panel
            if (config.showPreview === false) {
                input.setAttribute('data-show-preview', 'false');
            }

            // Show text labels under icons
            if (config.showLabels === false) {
                input.setAttribute('data-show-labels', 'false');
            }

            // Show source badges
            if (config.showBadges === false) {
                input.setAttribute('data-show-badges', 'false');
            }

            // Icons per row
            if (config.columns) {
                input.setAttribute('data-columns', config.columns.toString());
            }

            // Inline mode (embedded vs popup)
            if (config.inline) {
                input.setAttribute('data-inline', 'true');
            }

            // FilterBus integration key
            if (config.filterKey) {
                input.setAttribute('data-filter-key', config.filterKey);
            }

            // Placeholder text
            if (config.placeholder) {
                input.setAttribute('data-placeholder', config.placeholder);
            }

            // Pre-selected value
            if (config.value) {
                input.setAttribute('data-value', config.value);
            }

            // Disabled state
            if (config.disabled) {
                input.setAttribute('data-disabled', 'true');
                input.disabled = true;
            }

            // Max recent icons to show
            if (config.maxRecent) {
                input.setAttribute('data-max-recent', config.maxRecent.toString());
            }

            // Close picker on selection
            if (config.closeOnSelect === true) {
                input.setAttribute('data-close-on-select', 'true');
            }

            // ARIA label
            if (config.ariaLabel) {
                input.setAttribute('data-aria-label', config.ariaLabel);
            }

            // Custom RSL icons path
            if (config.rslIconsPath) {
                input.setAttribute('data-rsl-icons-path', config.rslIconsPath);
            }

            // Custom classes
            if (config.className) {
                input.className = config.className;
            }

            el.appendChild(input);

            // Note: IconPicker will be initialized by _initializeComponents() via RSL.IconPicker.init()
        }

        /**
         * Render star rating component (wrapper for v1 StarRating component)
         * Creates an accessible star rating for input, display, or filter modes
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - StarRating configuration
         *
         * Config options:
         * - value: number - Initial rating value (0-max, supports half values like 3.5)
         * - max: number - Maximum stars (default: 5)
         * - half: boolean - Allow half-star ratings (default: true)
         * - readonly: boolean - Display-only mode (default: false)
         * - size: 'small'|'medium'|'large'|'xl' - Star size (default: 'medium')
         * - icon: 'star'|'heart'|'thumb' - Icon type (default: 'star')
         * - showValue: boolean - Show numeric value next to stars (default: false)
         * - clearable: boolean - Show clear button (default: false)
         * - name: string - Form field name for submission
         * - required: boolean - Mark as required field
         * - label: string - Accessible label for the rating
         * - color: string - Custom filled star color (CSS color value)
         * - emptyColor: string - Custom empty star color (CSS color value)
         * - filterField: string - FilterBus field name for cross-component filtering
         * - classes: array - Additional CSS classes
         * - onChange: function(event, value, element) - Change callback
         *
         * Example usage:
         * {
         *   type: 'star-rating',
         *   value: 4.5,
         *   max: 5,
         *   half: true,
         *   readonly: true,
         *   showValue: true,
         *   size: 'large'
         * }
         */
        _renderStarRating(el, config) {
            // Create container div with data attributes
            const container = document.createElement('div');
            container.setAttribute('data-rsl-star-rating', '');

            // Generate unique ID if not provided
            const containerId = config.id || `star-rating-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
            container.id = containerId;

            // Value (supports decimals like 3.5)
            if (config.value !== undefined) {
                container.setAttribute('data-star-value', config.value.toString());
            }

            // Maximum stars
            if (config.max !== undefined) {
                container.setAttribute('data-star-max', config.max.toString());
            }

            // Half-star support (default true, so only set if explicitly false)
            if (config.half === false) {
                container.setAttribute('data-star-half', 'false');
            }

            // Readonly mode
            if (config.readonly) {
                container.setAttribute('data-star-readonly', 'true');
            }

            // Size variant
            if (config.size) {
                container.setAttribute('data-star-size', config.size);
            }

            // Icon type
            if (config.icon) {
                container.setAttribute('data-star-icon', config.icon);
            }

            // Show numeric value
            if (config.showValue) {
                container.setAttribute('data-star-show-value', 'true');
            }

            // Clearable
            if (config.clearable) {
                container.setAttribute('data-star-clearable', 'true');
            }

            // Form field name
            if (config.name) {
                container.setAttribute('data-star-name', config.name);
            }

            // Required field
            if (config.required) {
                container.setAttribute('data-star-required', 'true');
            }

            // Accessible label
            if (config.label) {
                container.setAttribute('data-star-label', config.label);
            }

            // Custom colors
            if (config.color) {
                container.setAttribute('data-star-color', config.color);
            }
            if (config.emptyColor) {
                container.setAttribute('data-star-empty-color', config.emptyColor);
            }

            // FilterBus integration
            if (config.filterField) {
                container.setAttribute('data-filterbus-field', config.filterField);
            }

            // Additional CSS classes
            if (config.classes) {
                config.classes.forEach(cls => container.classList.add(cls));
            }

            // Add to parent element
            el.appendChild(container);

            // Store onChange handler for after initialization
            if (config.onChange) {
                container._v2OnChange = config.onChange;

                // Add event listener after component initializes
                setTimeout(() => {
                    container.addEventListener('rsl-star-change', (e) => {
                        config.onChange(e, e.detail.value, container);
                    });
                }, 200);
            }

            // Note: StarRating will be initialized by _initializeComponents() via RSL.StarRating.init()
        }

        /**
         * Render star rating filter component
         * Creates a filter panel with star rating options that integrates with FilterBus
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Filter configuration
         *
         * Config options:
         * - max: number - Maximum stars (default: 5)
         * - field: string - FilterBus field name (default: 'rating')
         * - showCounts: boolean - Show count badges (default: false)
         * - counts: object - Count values by rating, e.g., { 5: 45, 4: 82, 3: 30, 2: 10, 1: 5 }
         * - inline: boolean - Horizontal layout (default: false)
         * - upAndAbove: boolean - Show "4+ stars" vs "4 stars" (default: true)
         * - classes: array - Additional CSS classes
         *
         * Example usage:
         * {
         *   type: 'star-rating-filter',
         *   field: 'product_rating',
         *   max: 5,
         *   showCounts: true,
         *   counts: { 5: 45, 4: 82, 3: 30, 2: 10, 1: 5 },
         *   upAndAbove: true
         * }
         */
        _renderStarRatingFilter(el, config) {
            // Create container div
            const container = document.createElement('div');

            // Generate unique ID if not provided
            const containerId = config.id || `star-filter-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
            container.id = containerId;

            // Additional CSS classes
            if (config.classes) {
                config.classes.forEach(cls => container.classList.add(cls));
            }

            el.appendChild(container);

            // Use RSL.StarRating.createFilter if available
            setTimeout(() => {
                if (window.RSL && window.RSL.StarRating && window.RSL.StarRating.createFilter) {
                    window.RSL.StarRating.createFilter(container, {
                        max: config.max || 5,
                        field: config.field || 'rating',
                        showCounts: config.showCounts || false,
                        counts: config.counts || {},
                        inline: config.inline || false,
                        upAndAbove: config.upAndAbove !== false
                    });
                }
            }, 100);
        }

        /**
         * Render testimonial component (wrapper for v1 Testimonial component)
         * Creates an accessible testimonial/quote card with rating, avatar, and variants
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Testimonial configuration
         *
         * Config options:
         * - quote: string - The testimonial quote text (required)
         * - name: string - Author name (required)
         * - title: string - Author job title
         * - company: string - Author company
         * - avatar: string - Avatar image URL
         * - rating: number - Star rating (0-5, supports decimals like 4.5)
         * - variant: 'card'|'minimal'|'featured'|'bubble' - Display variant (default: 'card')
         * - size: 'sm'|'md'|'lg' - Size variant (default: 'md')
         * - accent: string - Accent color: 'purple', 'green', 'orange', 'red', 'teal', or custom hex
         * - verified: boolean - Show verified badge
         * - category: string - Category label
         * - date: string - Date string (YYYY-MM-DD format)
         * - animate: boolean - Enable scroll animation
         * - filterCategory: string - FilterBus category field name
         * - filterRating: string - FilterBus rating field name
         * - classes: array - Additional CSS classes
         *
         * Example usage:
         * {
         *   type: 'testimonial',
         *   quote: 'RSL has transformed how we build our dashboards.',
         *   name: 'Sarah Johnson',
         *   title: 'Product Manager',
         *   company: 'TechCorp',
         *   rating: 5,
         *   variant: 'featured',
         *   avatar: 'https://i.pravatar.cc/150?img=5',
         *   verified: true
         * }
         */
        _renderTestimonial(el, config) {
            // Create testimonial container with required data attributes
            const container = document.createElement('div');
            container.className = 'rsl-testimonial';
            container.setAttribute('data-rsl-testimonial', '');

            // Generate unique ID if not provided
            const containerId = config.id || `testimonial-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`;
            container.id = containerId;

            // Name (required)
            if (config.name) {
                container.setAttribute('data-testimonial-name', config.name);
            }

            // Title
            if (config.title) {
                container.setAttribute('data-testimonial-title', config.title);
            }

            // Company
            if (config.company) {
                container.setAttribute('data-testimonial-company', config.company);
            }

            // Avatar URL
            if (config.avatar) {
                container.setAttribute('data-testimonial-avatar', config.avatar);
            }

            // Rating (supports decimals)
            if (config.rating !== undefined) {
                container.setAttribute('data-testimonial-rating', config.rating.toString());
            }

            // Variant: card (default), minimal, featured, bubble
            if (config.variant) {
                container.setAttribute('data-testimonial-variant', config.variant);
            }

            // Size: sm, md (default), lg
            if (config.size) {
                container.setAttribute('data-testimonial-size', config.size);
            }

            // Accent color: purple, green, orange, red, teal, or custom hex
            if (config.accent) {
                container.setAttribute('data-testimonial-accent', config.accent);
            }

            // Verified badge
            if (config.verified) {
                container.setAttribute('data-testimonial-verified', 'true');
            }

            // Category label
            if (config.category) {
                container.setAttribute('data-testimonial-category', config.category);
                // Also set data-category for FilterBus
                container.setAttribute('data-category', config.category);
            }

            // Date
            if (config.date) {
                container.setAttribute('data-testimonial-date', config.date);
            }

            // Animate on scroll
            if (config.animate) {
                container.setAttribute('data-testimonial-animate', 'true');
            }

            // FilterBus integration - category field
            if (config.filterCategory) {
                container.setAttribute('data-filterbus-category', config.filterCategory);
            }

            // FilterBus integration - rating field
            if (config.filterRating) {
                container.setAttribute('data-filterbus-rating', config.filterRating);
                // Also set data-rating for FilterBus matching
                if (config.rating !== undefined) {
                    container.setAttribute('data-rating', config.rating.toString());
                }
            }

            // Additional CSS classes
            if (config.classes) {
                config.classes.forEach(cls => container.classList.add(cls));
            }

            // Create blockquote with quote text (required)
            const blockquote = document.createElement('blockquote');
            blockquote.textContent = config.quote || '';
            container.appendChild(blockquote);

            el.appendChild(container);

            // Note: Testimonial component will be initialized by _initializeComponents() via RSL.Testimonial.init()
        }

        /**
         * Render pricing table component
         * Creates pricing tiers with features, toggle, and CTAs using V1 data attributes
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Pricing table configuration
         * @param {string} [config.variant] - Variant: cards (default), comparison, compact, horizontal
         * @param {string} [config.currency] - Currency symbol (default: $)
         * @param {string} [config.currencyPosition] - before or after (default: before)
         * @param {string} [config.billingPeriod] - Period text (default: mo)
         * @param {string} [config.toggleMonthly] - Monthly toggle label (default: Monthly)
         * @param {string} [config.toggleAnnual] - Annual toggle label (default: Annual)
         * @param {string} [config.savingsTemplate] - Savings text template (default: Save {{percent}}%)
         * @param {boolean} [config.animate] - Enable scroll animations
         * @param {boolean} [config.stickyHeader] - Enable sticky header (comparison variant)
         * @param {boolean} [config.mobileAccordion] - Enable accordion on mobile
         * @param {Array} config.tiers - Array of tier configurations
         * @param {string} config.tiers[].name - Tier name
         * @param {string} [config.tiers[].description] - Tier description
         * @param {number} [config.tiers[].priceMonthly] - Monthly price
         * @param {number} [config.tiers[].priceAnnual] - Annual price (per month)
         * @param {string} [config.tiers[].customPrice] - Custom price text (e.g., "Free", "Contact Sales")
         * @param {number} [config.tiers[].originalPrice] - Original price (strikethrough)
         * @param {string} [config.tiers[].badge] - Badge text (e.g., "Most Popular")
         * @param {string} [config.tiers[].badgeVariant] - Badge variant
         * @param {boolean} [config.tiers[].highlighted] - Highlight this tier
         * @param {string} [config.tiers[].ctaText] - CTA button text (default: Get Started)
         * @param {string} [config.tiers[].ctaUrl] - CTA button URL
         * @param {string} [config.tiers[].ctaVariant] - CTA button variant (primary, secondary)
         * @param {string} [config.tiers[].priceNote] - Note below price
         * @param {Array} [config.tiers[].features] - Array of features
         * @param {string} config.tiers[].features[].text - Feature text
         * @param {boolean|string} config.tiers[].features[].included - true, false, or "partial"
         * @param {string} [config.tiers[].features[].tooltip] - Feature tooltip text
         * @param {string} [config.tiers[].features[].category] - Feature category heading
         *
         * @example
         * content: {
         *   type: "pricing-table",
         *   currency: "$",
         *   animate: true,
         *   tiers: [
         *     {
         *       name: "Starter",
         *       description: "Perfect for individuals",
         *       priceMonthly: 9,
         *       priceAnnual: 7,
         *       ctaText: "Get Started",
         *       ctaUrl: "#signup",
         *       features: [
         *         { text: "5 Projects", included: true },
         *         { text: "10GB Storage", included: true },
         *         { text: "API Access", included: false }
         *       ]
         *     },
         *     {
         *       name: "Professional",
         *       description: "For growing teams",
         *       priceMonthly: 29,
         *       priceAnnual: 24,
         *       badge: "Most Popular",
         *       highlighted: true,
         *       ctaText: "Start Free Trial",
         *       ctaUrl: "#signup",
         *       features: [
         *         { text: "Unlimited Projects", included: true },
         *         { text: "100GB Storage", included: true },
         *         { text: "API Access", included: true }
         *       ]
         *     }
         *   ]
         * }
         */
        _renderPricingTable(el, config) {
            // Validate required properties
            if (!config.tiers || !Array.isArray(config.tiers) || config.tiers.length === 0) {
                console.warn('Pricing table component requires a "tiers" array with at least one tier');
                return;
            }

            // Create main pricing table container
            const container = document.createElement('div');
            container.setAttribute('data-rsl-pricing-table', '');

            // Apply configuration via data attributes
            if (config.variant) {
                container.setAttribute('data-pricing-variant', config.variant);
            }
            if (config.currency) {
                container.setAttribute('data-pricing-currency', config.currency);
            }
            if (config.currencyPosition) {
                container.setAttribute('data-pricing-currency-position', config.currencyPosition);
            }
            if (config.billingPeriod) {
                container.setAttribute('data-pricing-period', config.billingPeriod);
            }
            if (config.toggleMonthly) {
                container.setAttribute('data-pricing-toggle-monthly', config.toggleMonthly);
            }
            if (config.toggleAnnual) {
                container.setAttribute('data-pricing-toggle-annual', config.toggleAnnual);
            }
            if (config.savingsTemplate) {
                container.setAttribute('data-pricing-savings-template', config.savingsTemplate);
            }
            if (config.animate) {
                container.setAttribute('data-pricing-animate', 'true');
            }
            if (config.stickyHeader) {
                container.setAttribute('data-pricing-sticky-header', 'true');
            }
            if (config.mobileAccordion) {
                container.setAttribute('data-pricing-mobile-accordion', 'true');
            }
            if (config.filterKey) {
                container.setAttribute('data-filterbus-key', config.filterKey);
            }

            // Create tier elements
            config.tiers.forEach(tier => {
                const tierEl = document.createElement('div');

                // Required: tier name
                if (tier.name) {
                    tierEl.setAttribute('data-tier-name', tier.name);
                }

                // Optional tier attributes
                if (tier.description) {
                    tierEl.setAttribute('data-tier-description', tier.description);
                }
                if (tier.priceMonthly !== undefined && tier.priceMonthly !== null) {
                    tierEl.setAttribute('data-tier-price-monthly', tier.priceMonthly.toString());
                }
                if (tier.priceAnnual !== undefined && tier.priceAnnual !== null) {
                    tierEl.setAttribute('data-tier-price-annual', tier.priceAnnual.toString());
                }
                if (tier.customPrice) {
                    tierEl.setAttribute('data-tier-custom-price', tier.customPrice);
                }
                if (tier.originalPrice !== undefined && tier.originalPrice !== null) {
                    tierEl.setAttribute('data-tier-original-price', tier.originalPrice.toString());
                }
                if (tier.badge) {
                    tierEl.setAttribute('data-tier-badge', tier.badge);
                }
                if (tier.badgeVariant) {
                    tierEl.setAttribute('data-tier-badge-variant', tier.badgeVariant);
                }
                if (tier.highlighted) {
                    tierEl.setAttribute('data-tier-highlighted', 'true');
                }
                if (tier.ctaText) {
                    tierEl.setAttribute('data-tier-cta-text', tier.ctaText);
                }
                if (tier.ctaUrl) {
                    tierEl.setAttribute('data-tier-cta-url', tier.ctaUrl);
                }
                if (tier.ctaVariant) {
                    tierEl.setAttribute('data-tier-cta-variant', tier.ctaVariant);
                }
                if (tier.priceNote) {
                    tierEl.setAttribute('data-tier-price-note', tier.priceNote);
                }
                if (tier.filterValue) {
                    tierEl.setAttribute('data-filter-value', tier.filterValue);
                }

                // Create feature elements inside tier
                if (tier.features && Array.isArray(tier.features)) {
                    tier.features.forEach(feature => {
                        const featureEl = document.createElement('div');

                        if (feature.text) {
                            featureEl.setAttribute('data-feature-text', feature.text);
                        }

                        // Handle included: true, false, or "partial"
                        if (feature.included !== undefined) {
                            featureEl.setAttribute('data-feature-included', feature.included.toString());
                        }

                        if (feature.tooltip) {
                            featureEl.setAttribute('data-feature-tooltip', feature.tooltip);
                        }

                        if (feature.category) {
                            featureEl.setAttribute('data-feature-category', feature.category);
                        }

                        tierEl.appendChild(featureEl);
                    });
                }

                container.appendChild(tierEl);
            });

            el.appendChild(container);

            // Note: PricingTable component will be initialized by _initializeComponents() via RSL.PricingTable.init()
        }

        /**
         * Render video player component
         * Supports YouTube, Vimeo, and self-hosted MP4/WebM videos
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Video player configuration
         * @param {string} config.src - Video URL (YouTube, Vimeo, or direct file)
         * @param {string} [config.title] - Video title for accessibility
         * @param {string} [config.poster] - Poster/thumbnail image URL
         * @param {string} [config.aspect] - Aspect ratio (16:9, 4:3, 1:1, 9:16, 21:9)
         * @param {string} [config.size] - Size variant (sm, md, lg, xl, full)
         * @param {boolean} [config.autoplay] - Auto-play video
         * @param {boolean} [config.muted] - Start muted
         * @param {boolean} [config.loop] - Loop video
         * @param {boolean} [config.controls] - Show custom controls (default: true)
         * @param {boolean} [config.lazy] - Lazy load (default: true)
         * @param {number} [config.start] - Start time in seconds
         * @param {number} [config.end] - End time in seconds
         * @param {string} [config.captions] - Captions file URL (VTT format)
         * @param {string} [config.captionsLabel] - Captions label
         * @param {string} [config.captionsLang] - Captions language code
         * @param {string} [config.preload] - Preload strategy (none, metadata, auto)
         * @param {string} [config.category] - FilterBus category for video galleries
         */
        _renderVideoPlayer(el, config) {
            // Validate required properties
            if (!config.src) {
                console.warn('Video player component requires a "src" property');
                return;
            }

            // Create video player container
            const player = document.createElement('div');
            player.className = 'rsl-video-player';
            player.setAttribute('data-rsl-video', '');

            // Set video source
            player.setAttribute('data-video-src', config.src);

            // Optional attributes
            if (config.title) {
                player.setAttribute('data-video-title', config.title);
            }
            if (config.poster) {
                player.setAttribute('data-video-poster', config.poster);
            }
            if (config.aspect) {
                player.setAttribute('data-video-aspect', config.aspect);
            }
            if (config.size) {
                player.setAttribute('data-video-size', config.size);
            }
            if (config.autoplay) {
                player.setAttribute('data-video-autoplay', 'true');
            }
            if (config.muted) {
                player.setAttribute('data-video-muted', 'true');
            }
            if (config.loop) {
                player.setAttribute('data-video-loop', 'true');
            }
            if (config.controls === false) {
                player.setAttribute('data-video-controls', 'false');
            }
            if (config.lazy === false) {
                player.setAttribute('data-video-lazy', 'false');
            }
            if (config.start) {
                player.setAttribute('data-video-start', config.start.toString());
            }
            if (config.end) {
                player.setAttribute('data-video-end', config.end.toString());
            }
            if (config.captions) {
                player.setAttribute('data-video-captions', config.captions);
            }
            if (config.captionsLabel) {
                player.setAttribute('data-video-captions-label', config.captionsLabel);
            }
            if (config.captionsLang) {
                player.setAttribute('data-video-captions-lang', config.captionsLang);
            }
            if (config.preload) {
                player.setAttribute('data-video-preload', config.preload);
            }
            if (config.category) {
                player.setAttribute('data-video-category', config.category);
            }

            // Apply inline styles if specified
            if (config.style) {
                Object.keys(config.style).forEach(prop => {
                    player.style[prop] = config.style[prop];
                });
            }

            el.appendChild(player);

            // Note: VideoPlayer component will be initialized by _initializeComponents() via RSL.VideoPlayer.init()
        }

        /**
         * Render loader component
         * Creates loading indicators with multiple variants, sizes, colors, and modes
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Loader configuration
         *
         * Configuration options:
         * - variant: 'spinner' | 'dual' | 'dots' | 'bars' | 'pulse' | 'ripple' | 'square' | 'progress-circle' | 'progress-bar'
         * - mode: 'inline' | 'overlay' | 'center' | 'fullscreen' | 'button'
         * - size: 'sm' | 'md' | 'lg' | 'xl'
         * - color: 'primary' | 'success' | 'warning' | 'danger' | 'info' | 'light' | 'dark'
         * - message: Optional loading message text
         * - progress: Progress value 0-100 (for progress-circle and progress-bar variants)
         * - dismissible: true | false - Allow user to dismiss the loader
         * - dismissText: Custom dismiss button text
         * - autoHide: Number of milliseconds before auto-hiding
         * - show: true | false - Whether to show immediately (default: true for inline mode)
         *
         * Example:
         * {
         *   content: {
         *     type: "loader",
         *     variant: "spinner",
         *     size: "lg",
         *     color: "primary",
         *     message: "Loading..."
         *   }
         * }
         */
        _renderLoader(el, config) {
            // Create the loader container element directly (not relying on init())
            // The Loader component is designed for programmatic show/hide, but for V2 JSON API
            // we need to render inline loaders directly

            const loader = document.createElement('div');
            loader.className = 'rsl-loader';

            // Center the loader within its container by default (using !important via inline styles)
            loader.style.cssText = 'display: flex !important; flex-direction: column; align-items: center; justify-content: center; width: 100%; min-height: 120px; padding: 1.5rem; box-sizing: border-box;';

            // Add mode class if specified (but not inline, since we handle that with custom styles)
            const mode = config.mode || 'inline';
            if (mode !== 'inline') {
                loader.classList.add('rsl-loader-' + mode);
            }

            // Add size class
            if (config.size && config.size !== 'md') {
                loader.classList.add('rsl-loader-' + config.size);
            }

            // Add color class
            if (config.color) {
                loader.classList.add('rsl-loader-' + config.color);
            }

            // Add ARIA attributes
            loader.setAttribute('role', 'status');
            loader.setAttribute('aria-live', 'polite');

            // Create spinner element based on variant
            const variant = config.variant || 'spinner';
            const spinnerEl = this._createLoaderSpinner(variant, config.progress);
            loader.appendChild(spinnerEl);

            // Add message if provided
            if (config.message) {
                const message = document.createElement('div');
                message.className = 'rsl-loader-message';
                message.textContent = config.message;
                loader.appendChild(message);
            }

            // Apply custom classes
            if (config.classes) {
                const classArray = Array.isArray(config.classes) ? config.classes : config.classes.split(' ');
                classArray.forEach(cls => loader.classList.add(cls));
            }

            // Apply inline styles if specified
            if (config.style) {
                Object.keys(config.style).forEach(prop => {
                    loader.style[prop] = config.style[prop];
                });
            }

            el.appendChild(loader);
        }

        /**
         * Create loader spinner element based on variant
         * @private
         */
        _createLoaderSpinner(variant, progress) {
            let container;

            switch (variant) {
                case 'dual':
                    container = document.createElement('div');
                    container.className = 'rsl-loader-dual';
                    container.setAttribute('aria-hidden', 'true');
                    break;

                case 'dots':
                    container = document.createElement('div');
                    container.className = 'rsl-loader-dots';
                    container.setAttribute('aria-hidden', 'true');
                    for (let i = 0; i < 3; i++) {
                        const dot = document.createElement('div');
                        dot.className = 'dot';
                        container.appendChild(dot);
                    }
                    break;

                case 'bars':
                    container = document.createElement('div');
                    container.className = 'rsl-loader-bars';
                    container.setAttribute('aria-hidden', 'true');
                    for (let i = 0; i < 5; i++) {
                        const bar = document.createElement('div');
                        bar.className = 'bar';
                        container.appendChild(bar);
                    }
                    break;

                case 'pulse':
                    container = document.createElement('div');
                    container.className = 'rsl-loader-pulse';
                    container.setAttribute('aria-hidden', 'true');
                    break;

                case 'ripple':
                    container = document.createElement('div');
                    container.className = 'rsl-loader-ripple';
                    container.setAttribute('aria-hidden', 'true');
                    for (let i = 0; i < 2; i++) {
                        const ripple = document.createElement('div');
                        ripple.className = 'ripple';
                        container.appendChild(ripple);
                    }
                    break;

                case 'square':
                    container = document.createElement('div');
                    container.className = 'rsl-loader-square';
                    container.setAttribute('aria-hidden', 'true');
                    break;

                case 'progress-circle':
                    container = document.createElement('div');
                    container.className = 'rsl-loader-progress-circle';
                    container.setAttribute('role', 'progressbar');
                    container.setAttribute('aria-valuemin', '0');
                    container.setAttribute('aria-valuemax', '100');
                    container.setAttribute('aria-valuenow', String(progress || 0));

                    const svg = document.createElementNS('http://www.w3.org/2000/svg', 'svg');
                    svg.setAttribute('viewBox', '0 0 44 44');

                    const track = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
                    track.setAttribute('class', 'track');
                    track.setAttribute('cx', '22');
                    track.setAttribute('cy', '22');
                    track.setAttribute('r', '20');

                    const progressCircle = document.createElementNS('http://www.w3.org/2000/svg', 'circle');
                    progressCircle.setAttribute('class', 'progress');
                    progressCircle.setAttribute('cx', '22');
                    progressCircle.setAttribute('cy', '22');
                    progressCircle.setAttribute('r', '20');

                    // Set initial progress
                    if (progress !== null && progress !== undefined) {
                        const circumference = 126;
                        const offset = circumference - (progress / 100) * circumference;
                        progressCircle.style.strokeDashoffset = String(offset);
                    }

                    svg.appendChild(track);
                    svg.appendChild(progressCircle);
                    container.appendChild(svg);

                    // Add percentage text
                    const value = document.createElement('div');
                    value.className = 'value';
                    value.textContent = (progress || 0) + '%';
                    container.appendChild(value);
                    break;

                case 'progress-bar':
                    container = document.createElement('div');
                    container.className = 'rsl-loader-progress-bar';
                    if (progress === null || progress === undefined) {
                        container.classList.add('indeterminate');
                    }
                    container.setAttribute('role', 'progressbar');
                    container.setAttribute('aria-valuemin', '0');
                    container.setAttribute('aria-valuemax', '100');
                    container.setAttribute('aria-valuenow', String(progress || 0));

                    const fill = document.createElement('div');
                    fill.className = 'fill';
                    if (progress !== null && progress !== undefined) {
                        fill.style.width = progress + '%';
                    }
                    container.appendChild(fill);
                    break;

                case 'spinner':
                default:
                    container = document.createElement('div');
                    container.className = 'rsl-loader-spinner';
                    container.setAttribute('aria-hidden', 'true');
                    break;
            }

            return container;
        }

        /**
         * Render sticky element container
         * Creates a container with sticky positioning and optional content
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Sticky configuration
         * @param {string} [config.variant] - Preset: header, sidebar, tabs, toc, action, table-header
         * @param {string} [config.offset] - Offset from top: none, xs, sm, md, lg, xl
         * @param {string} [config.breakpoint] - Only sticky at breakpoint and up: xs, sm, md, lg, xl, xxl
         * @param {string} [config.shadow] - Shadow on stuck: none, sm, default, lg
         * @param {string} [config.z] - Z-index level: low, base, high, overlay
         * @param {string} [config.direction] - Show on scroll direction: up
         * @param {string} [config.group] - Group name for stacking multiple sticky elements
         * @param {number} [config.stack] - Order within a sticky group
         * @param {boolean} [config.bgStuck] - Apply frosted glass background when stuck
         * @param {boolean} [config.border] - Show bottom border when stuck
         * @param {boolean} [config.scale] - Slight scale-down effect when stuck
         * @param {boolean} [config.skipLink] - Add accessibility skip link
         * @param {string} [config.label] - Label for screen reader announcements
         * @param {string} [config.filterBusPublish] - FilterBus key to publish stuck state
         * @param {Object} [config.content] - Nested content to render inside sticky container
         * @param {string} [config.html] - Raw HTML content (alternative to content)
         * @param {Array} [config.classes] - Additional CSS classes
         * @param {Object} [config.style] - Inline styles
         * @example
         * // Basic sticky header
         * { type: "sticky", variant: "header", content: { type: "html", value: "<nav>...</nav>" } }
         *
         * // Sticky sidebar TOC
         * { type: "sticky", variant: "toc", offset: "lg", content: { type: "list", items: [...] } }
         *
         * // Show on scroll up
         * { type: "sticky", direction: "up", variant: "header", html: "<nav>...</nav>" }
         */
        _renderSticky(el, config) {
            // Create the sticky container
            const sticky = document.createElement('div');

            // Apply the V2 data attribute to trigger sticky behavior
            sticky.setAttribute('data-rsl-sticky', '');

            // Apply variant if specified
            if (config.variant) {
                sticky.setAttribute('data-sticky-variant', config.variant);
            }

            // Apply offset
            if (config.offset) {
                sticky.setAttribute('data-sticky-offset', config.offset);
            }

            // Apply breakpoint
            if (config.breakpoint) {
                sticky.setAttribute('data-sticky-breakpoint', config.breakpoint);
            }

            // Apply shadow
            if (config.shadow) {
                sticky.setAttribute('data-sticky-shadow', config.shadow);
            }

            // Apply z-index level
            if (config.z) {
                sticky.setAttribute('data-sticky-z', config.z);
            }

            // Apply scroll direction
            if (config.direction) {
                sticky.setAttribute('data-sticky-direction', config.direction);
            }

            // Apply group for stacking
            if (config.group) {
                sticky.setAttribute('data-sticky-group', config.group);
            }

            // Apply stack order
            if (config.stack !== undefined) {
                sticky.setAttribute('data-sticky-stack', String(config.stack));
            }

            // Apply visual effects
            if (config.bgStuck) {
                sticky.setAttribute('data-sticky-bg-stuck', 'true');
            }
            if (config.border) {
                sticky.setAttribute('data-sticky-border', 'true');
            }
            if (config.scale) {
                sticky.setAttribute('data-sticky-scale', 'true');
            }

            // Apply accessibility options
            if (config.skipLink !== undefined) {
                sticky.setAttribute('data-sticky-skip-link', String(config.skipLink));
            }
            if (config.label) {
                sticky.setAttribute('data-sticky-label', config.label);
            }

            // Apply FilterBus integration
            if (config.filterBusPublish) {
                sticky.setAttribute('data-filterbus-publish', config.filterBusPublish);
            }

            // Apply custom classes
            if (config.classes) {
                const classArray = Array.isArray(config.classes) ? config.classes : config.classes.split(' ');
                classArray.forEach(cls => sticky.classList.add(cls));
            }

            // Apply inline styles
            if (config.style) {
                Object.keys(config.style).forEach(prop => {
                    sticky.style[prop] = config.style[prop];
                });
            }

            // Render nested content
            if (config.content) {
                // Use the content rendering system
                this._setItemContent(sticky, config.content);
            } else if (config.html) {
                // Raw HTML content
                sticky.innerHTML = config.html;
            }

            el.appendChild(sticky);

            // Note: Sticky component will be initialized by _initializeComponents() via RSL.Sticky.init()
        }

        /**
         * Render Timeline component
         * Creates chronological event displays with various layouts and styles
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Timeline configuration
         *
         * Configuration options:
         * - variant: 'default' | 'card' | 'minimal' | 'split' - Visual style
         * - orientation: 'vertical' | 'horizontal' - Layout direction
         * - collapsible: true | false - Enable expand/collapse on events
         * - alternate: true | false - Alternate events left/right (split variant)
         * - animate: true | false - Enable scroll animations
         * - connectorStyle: 'solid' | 'dashed' | 'dotted' - Line style
         * - ariaLabel: Accessible label for the timeline
         * - events: Array of event objects
         *
         * Event object properties:
         * - id: Unique identifier
         * - date: Date/time string
         * - title: Event title
         * - description: Event description
         * - status: 'completed' | 'current' | 'upcoming'
         * - icon: Font Awesome icon class
         * - meta: Additional metadata (array of {icon, text} objects)
         * - details: Expandable details content (for collapsible mode)
         *
         * Example:
         * {
         *   content: {
         *     type: "timeline",
         *     variant: "card",
         *     orientation: "vertical",
         *     ariaLabel: "Project timeline",
         *     events: [
         *       { id: "1", date: "Jan 2024", title: "Kickoff", status: "completed", icon: "fas fa-flag" },
         *       { id: "2", date: "Mar 2024", title: "Development", status: "current", icon: "fas fa-code" },
         *       { id: "3", date: "Jun 2024", title: "Launch", status: "upcoming", icon: "fas fa-rocket" }
         *     ]
         *   }
         * }
         */
        _renderTimeline(el, config) {
            // Create timeline container
            const timeline = document.createElement('ol');
            timeline.className = 'rsl-timeline';
            timeline.setAttribute('data-rsl-timeline', '');

            // Apply orientation
            const orientation = config.orientation || 'vertical';
            timeline.classList.add(`rsl-timeline-${orientation}`);
            if (orientation === 'horizontal') {
                timeline.setAttribute('data-timeline-orientation', 'horizontal');
            }

            // Apply variant
            if (config.variant) {
                timeline.classList.add(`rsl-timeline-${config.variant}`);
                timeline.setAttribute('data-timeline-variant', config.variant);
            }

            // Apply collapsible
            if (config.collapsible) {
                timeline.classList.add('rsl-timeline-collapsible');
                timeline.setAttribute('data-timeline-collapsible', 'true');
            }

            // Apply alternate (split layout)
            if (config.alternate) {
                timeline.setAttribute('data-timeline-alternate', 'true');
            }

            // Apply animate
            if (config.animate) {
                timeline.setAttribute('data-timeline-animate', 'true');
            }

            // Apply connector style
            if (config.connectorStyle) {
                timeline.setAttribute('data-timeline-connector-style', config.connectorStyle);
            }

            // Apply aria label
            if (config.ariaLabel) {
                timeline.setAttribute('aria-label', config.ariaLabel);
            }

            // Apply FilterBus subscription
            if (config.filterSubscribe) {
                timeline.setAttribute('data-filter-subscribe', config.filterSubscribe);
            }

            // Render events
            if (config.events && Array.isArray(config.events)) {
                config.events.forEach((event, index) => {
                    const eventEl = document.createElement('li');
                    eventEl.className = 'rsl-timeline-event';

                    // Apply event ID
                    if (event.id) {
                        eventEl.setAttribute('data-event-id', event.id);
                    }

                    // Apply status
                    if (event.status) {
                        eventEl.setAttribute('data-status', event.status);
                        if (event.status === 'current') {
                            eventEl.setAttribute('aria-current', 'step');
                        }
                    }

                    // Create marker
                    const marker = document.createElement('div');
                    marker.className = 'rsl-timeline-marker';
                    if (event.icon) {
                        const icon = document.createElement('i');
                        icon.className = event.icon;
                        icon.setAttribute('aria-hidden', 'true');
                        marker.appendChild(icon);
                    } else if (event.status === 'completed') {
                        const icon = document.createElement('i');
                        icon.className = 'fas fa-check';
                        icon.setAttribute('aria-hidden', 'true');
                        marker.appendChild(icon);
                    }
                    eventEl.appendChild(marker);

                    // Create content
                    const content = document.createElement('div');
                    content.className = 'rsl-timeline-content';

                    // Date
                    if (event.date) {
                        const dateEl = document.createElement('time');
                        dateEl.className = 'rsl-timeline-date';
                        if (event.datetime) {
                            dateEl.setAttribute('datetime', event.datetime);
                        }
                        dateEl.textContent = event.date;
                        content.appendChild(dateEl);
                    }

                    // Title
                    if (event.title) {
                        const titleEl = document.createElement('h3');
                        titleEl.className = 'rsl-timeline-title';
                        titleEl.textContent = event.title;
                        content.appendChild(titleEl);
                    }

                    // Description
                    if (event.description) {
                        const descEl = document.createElement('p');
                        descEl.className = 'rsl-timeline-description';
                        descEl.textContent = event.description;
                        content.appendChild(descEl);
                    }

                    // Details (for collapsible)
                    if (event.details && config.collapsible) {
                        const detailsEl = document.createElement('div');
                        detailsEl.className = 'rsl-timeline-details';
                        if (typeof event.details === 'string') {
                            detailsEl.innerHTML = event.details;
                        } else if (event.details.html) {
                            detailsEl.innerHTML = event.details.html;
                        }
                        content.appendChild(detailsEl);
                    }

                    // Meta information
                    if (event.meta && Array.isArray(event.meta)) {
                        const metaEl = document.createElement('div');
                        metaEl.className = 'rsl-timeline-meta';
                        event.meta.forEach(metaItem => {
                            const span = document.createElement('span');
                            if (metaItem.icon) {
                                const icon = document.createElement('i');
                                icon.className = metaItem.icon;
                                span.appendChild(icon);
                                span.appendChild(document.createTextNode(' '));
                            }
                            span.appendChild(document.createTextNode(metaItem.text || ''));
                            metaEl.appendChild(span);
                        });
                        content.appendChild(metaEl);
                    }

                    // Tags/categories for filtering
                    if (event.tags && Array.isArray(event.tags)) {
                        eventEl.setAttribute('data-tags', event.tags.join(','));
                    }
                    if (event.category) {
                        eventEl.setAttribute('data-category', event.category);
                    }

                    eventEl.appendChild(content);
                    timeline.appendChild(eventEl);
                });
            }

            // Apply custom classes
            if (config.classes) {
                const classArray = Array.isArray(config.classes) ? config.classes : config.classes.split(' ');
                classArray.forEach(cls => timeline.classList.add(cls));
            }

            // Apply inline styles
            if (config.style) {
                Object.keys(config.style).forEach(prop => {
                    timeline.style[prop] = config.style[prop];
                });
            }

            el.appendChild(timeline);

            // Note: Timeline component will be initialized by _initializeComponents() via RSL.Timeline.init()
        }

        /**
         * Helper to get status badge class based on status value
         * @private
         */
        _getStatusClass(status) {
            const statusLower = status.toLowerCase();
            if (statusLower.includes('active') || statusLower.includes('success') || statusLower.includes('complete') || statusLower.includes('approved')) {
                return 'rsl-status-badge-success';
            } else if (statusLower.includes('pending') || statusLower.includes('warning') || statusLower.includes('review')) {
                return 'rsl-status-badge-warning';
            } else if (statusLower.includes('inactive') || statusLower.includes('error') || statusLower.includes('failed') || statusLower.includes('rejected')) {
                return 'rsl-status-badge-error';
            } else if (statusLower.includes('info') || statusLower.includes('new')) {
                return 'rsl-status-badge-info';
            }
            return null;
        }

        /**
         * Render alert button - Creates a button that triggers a modal alert dialog
         * Uses the V1 Alerts component via data attributes
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Button configuration
         * @param {string} config.text - Button text
         * @param {string} config.message - Alert message to display
         * @param {string} [config.title] - Alert dialog title
         * @param {string} [config.alertType] - Alert type (success, error, warning, info)
         * @param {string} [config.variant] - Button variant (primary, success, danger, warning, info, default)
         * @param {string} [config.size] - Button size (sm, lg)
         * @param {string} [config.icon] - Font Awesome icon class
         * @param {string} [config.animation] - Animation type (slide-down, zoom-in, fade-in)
         */
        _renderAlertButton(el, config) {
            const btn = document.createElement('button');
            btn.className = 'btn';

            // Apply button variant
            if (config.variant) {
                btn.classList.add(`btn-${config.variant}`);
            } else {
                btn.classList.add('btn-primary');
            }

            // Apply button size
            if (config.size) {
                btn.classList.add(`btn-${config.size}`);
            }

            // Add alert data attributes for V1 Alerts component
            btn.setAttribute('data-rsl-alert', config.message || '');

            if (config.title) {
                btn.setAttribute('data-rsl-alert-title', config.title);
            }

            if (config.alertType) {
                btn.setAttribute('data-rsl-alert-type', config.alertType);
            }

            // Add animation if specified
            if (config.animation) {
                btn.setAttribute('data-rsl-alert-animation', config.animation);
            }

            // Add icon if specified
            if (config.icon) {
                const icon = document.createElement('i');
                icon.className = config.icon;
                btn.appendChild(icon);
                btn.appendChild(document.createTextNode(' '));
            }

            // Add button text
            btn.appendChild(document.createTextNode(config.text || 'Show Alert'));

            el.appendChild(btn);

            // Initialize Alerts component after a short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.Alerts && window.RSL.Alerts.init) {
                    window.RSL.Alerts.init();
                }
            }, 100);
        }

        /**
         * Render confirm button - Creates a button that triggers a modal confirm dialog
         * Uses the V1 Alerts component via data attributes
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Button configuration
         * @param {string} config.text - Button text
         * @param {string} config.message - Confirm message to display
         * @param {string} [config.title] - Confirm dialog title
         * @param {string} [config.confirmType] - Confirm type (success, error, warning, info)
         * @param {string} [config.variant] - Button variant (primary, success, danger, warning, info, default)
         * @param {string} [config.size] - Button size (sm, lg)
         * @param {string} [config.icon] - Font Awesome icon class
         * @param {string} [config.animation] - Animation type (slide-down, zoom-in, fade-in)
         */
        _renderConfirmButton(el, config) {
            const btn = document.createElement('button');
            btn.className = 'btn';

            // Apply button variant
            if (config.variant) {
                btn.classList.add(`btn-${config.variant}`);
            } else {
                btn.classList.add('btn-warning');
            }

            // Apply button size
            if (config.size) {
                btn.classList.add(`btn-${config.size}`);
            }

            // Add confirm data attributes for V1 Alerts component
            btn.setAttribute('data-rsl-confirm', config.message || '');

            if (config.title) {
                btn.setAttribute('data-rsl-confirm-title', config.title);
            }

            if (config.confirmType) {
                btn.setAttribute('data-rsl-confirm-type', config.confirmType);
            }

            // Add animation if specified
            if (config.animation) {
                btn.setAttribute('data-rsl-confirm-animation', config.animation);
            }

            // Add icon if specified
            if (config.icon) {
                const icon = document.createElement('i');
                icon.className = config.icon;
                btn.appendChild(icon);
                btn.appendChild(document.createTextNode(' '));
            }

            // Add button text
            btn.appendChild(document.createTextNode(config.text || 'Show Confirm'));

            el.appendChild(btn);

            // Initialize Alerts component after a short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.Alerts && window.RSL.Alerts.init) {
                    window.RSL.Alerts.init();
                }
            }, 100);
        }

        /**
         * Render prompt button - Creates a button that triggers a modal prompt dialog
         * Uses the V1 Alerts component via data attributes
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Button configuration
         * @param {string} config.text - Button text
         * @param {string} config.message - Prompt message to display
         * @param {string} [config.title] - Prompt dialog title
         * @param {string} [config.promptType] - Prompt type (success, error, warning, info)
         * @param {string} [config.placeholder] - Input placeholder text
         * @param {boolean} [config.required] - Whether input is required
         * @param {string} [config.variant] - Button variant (primary, success, danger, warning, info, default)
         * @param {string} [config.size] - Button size (sm, lg)
         * @param {string} [config.icon] - Font Awesome icon class
         * @param {string} [config.animation] - Animation type (slide-down, zoom-in, fade-in)
         */
        _renderPromptButton(el, config) {
            const btn = document.createElement('button');
            btn.className = 'btn';

            // Apply button variant
            if (config.variant) {
                btn.classList.add(`btn-${config.variant}`);
            } else {
                btn.classList.add('btn-info');
            }

            // Apply button size
            if (config.size) {
                btn.classList.add(`btn-${config.size}`);
            }

            // Add prompt data attributes for V1 Alerts component
            btn.setAttribute('data-rsl-prompt', config.message || '');

            if (config.title) {
                btn.setAttribute('data-rsl-prompt-title', config.title);
            }

            if (config.promptType) {
                btn.setAttribute('data-rsl-prompt-type', config.promptType);
            }

            if (config.placeholder) {
                btn.setAttribute('data-rsl-prompt-placeholder', config.placeholder);
            }

            if (config.required) {
                btn.setAttribute('data-rsl-prompt-required', 'true');
            }

            // Add animation if specified
            if (config.animation) {
                btn.setAttribute('data-rsl-prompt-animation', config.animation);
            }

            // Add icon if specified
            if (config.icon) {
                const icon = document.createElement('i');
                icon.className = config.icon;
                btn.appendChild(icon);
                btn.appendChild(document.createTextNode(' '));
            }

            // Add button text
            btn.appendChild(document.createTextNode(config.text || 'Show Prompt'));

            el.appendChild(btn);

            // Initialize Alerts component after a short delay
            setTimeout(() => {
                if (window.RSL && window.RSL.Alerts && window.RSL.Alerts.init) {
                    window.RSL.Alerts.init();
                }
            }, 100);
        }

        /**
         * Render navbar - Creates a responsive navigation bar
         * Uses the V1 Navbar component structure
         *
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Navbar configuration
         * @param {Object} config.brand - Brand/logo configuration
         * @param {string} [config.brand.text] - Brand text
         * @param {string} [config.brand.href] - Brand link URL
         * @param {string} [config.brand.image] - Brand logo image URL
         * @param {string} [config.brand.icon] - Brand icon class (Font Awesome)
         * @param {string} [config.layout] - Layout type (default, logo-right, logo-center)
         * @param {string} [config.theme] - Theme (light, dark)
         * @param {boolean} [config.hoverDropdowns] - Enable hover dropdowns
         * @param {boolean} [config.sticky] - Make navbar sticky
         * @param {Array} config.menuItems - Array of menu item objects
         * @param {Array} [config.actions] - Array of action items (buttons, theme toggle)
         */
        _renderNavbar(el, config) {
            const nav = document.createElement('nav');
            nav.className = 'rsl-navbar';
            nav.setAttribute('aria-label', config.ariaLabel || 'Main navigation');

            // Apply layout
            if (config.layout) {
                nav.setAttribute('data-layout', config.layout);
            }

            // Apply theme
            if (config.theme === 'dark') {
                nav.classList.add('dark-theme');
            }

            // Apply hover dropdowns
            if (config.hoverDropdowns) {
                nav.setAttribute('data-hover-dropdowns', 'true');
            }

            // Apply sticky positioning
            if (config.sticky) {
                nav.classList.add('sticky-top');
            }

            // Create brand/logo
            if (config.brand) {
                const brand = document.createElement('a');
                brand.className = 'rsl-navbar-brand';
                brand.href = config.brand.href || '#';

                if (config.brand.image) {
                    const img = document.createElement('img');
                    img.src = config.brand.image;
                    img.alt = config.brand.text || 'Logo';
                    if (config.brand.imageHeight) {
                        img.style.height = config.brand.imageHeight;
                    }
                    if (config.brand.imageWidth) {
                        img.style.width = config.brand.imageWidth;
                    }
                    brand.appendChild(img);
                }

                if (config.brand.icon && !config.brand.image) {
                    const icon = document.createElement('i');
                    icon.className = config.brand.icon;
                    brand.appendChild(icon);
                    if (config.brand.text) {
                        brand.appendChild(document.createTextNode(' '));
                    }
                }

                if (config.brand.text && !config.brand.image) {
                    brand.appendChild(document.createTextNode(config.brand.text));
                }

                nav.appendChild(brand);
            }

            // Create mobile toggle button
            const toggle = document.createElement('button');
            toggle.className = 'rsl-navbar-toggle';
            toggle.setAttribute('aria-label', 'Toggle navigation menu');
            toggle.setAttribute('aria-expanded', 'false');

            // Add toggle spans (hamburger icon)
            for (let i = 0; i < 3; i++) {
                const span = document.createElement('span');
                toggle.appendChild(span);
            }

            nav.appendChild(toggle);

            // Create menu
            if (config.menuItems && config.menuItems.length > 0) {
                const menu = document.createElement('ul');
                menu.className = 'rsl-navbar-menu';

                config.menuItems.forEach(item => {
                    const li = this._createNavbarMenuItem(item);
                    menu.appendChild(li);
                });

                nav.appendChild(menu);
            }

            // Create actions section
            if (config.actions && config.actions.length > 0) {
                const actions = document.createElement('div');
                actions.className = 'rsl-navbar-actions';

                config.actions.forEach(action => {
                    if (action.type === 'themeToggle') {
                        const themeBtn = document.createElement('button');
                        themeBtn.className = 'rsl-theme-toggle';
                        themeBtn.setAttribute('aria-label', 'Toggle dark mode');
                        themeBtn.innerHTML = `
                            <i class="fas fa-sun icon-sun"></i>
                            <i class="fas fa-moon icon-moon"></i>
                        `;
                        actions.appendChild(themeBtn);
                    } else if (action.type === 'button') {
                        const btn = document.createElement('button');
                        btn.className = 'btn';
                        if (action.variant) {
                            btn.classList.add(`btn-${action.variant}`);
                        }
                        if (action.size) {
                            btn.classList.add(`btn-${action.size}`);
                        }
                        if (action.icon) {
                            const icon = document.createElement('i');
                            icon.className = action.icon;
                            btn.appendChild(icon);
                            btn.appendChild(document.createTextNode(' '));
                        }
                        btn.appendChild(document.createTextNode(action.text || ''));
                        if (action.onClick) {
                            btn.onclick = action.onClick;
                        }
                        if (action.href) {
                            const link = document.createElement('a');
                            link.href = action.href;
                            link.className = btn.className;
                            link.innerHTML = btn.innerHTML;
                            actions.appendChild(link);
                        } else {
                            actions.appendChild(btn);
                        }
                    }
                });

                nav.appendChild(actions);
            }

            el.appendChild(nav);
        }

        /**
         * Create a navbar menu item (helper for _renderNavbar)
         * @private
         */
        _createNavbarMenuItem(item) {
            const li = document.createElement('li');
            li.className = 'rsl-navbar-item';

            // Set menu type for mega menus
            if (item.megaMenu) {
                li.setAttribute('data-menu-type', 'mega');
            }

            // Create link
            const link = document.createElement('a');
            link.className = 'rsl-navbar-link';
            link.href = item.href || '#';

            if (item.active) {
                link.classList.add('active');
            }

            // Add ARIA attributes for dropdowns
            if (item.dropdown || item.megaMenu) {
                link.setAttribute('aria-haspopup', 'true');
                link.setAttribute('aria-expanded', 'false');
            }

            // Add icon
            if (item.icon) {
                const icon = document.createElement('i');
                icon.className = item.icon;
                link.appendChild(icon);
                link.appendChild(document.createTextNode(' '));
            }

            // Add text
            link.appendChild(document.createTextNode(item.text));

            // Add dropdown icon
            if (item.dropdown || item.megaMenu) {
                link.appendChild(document.createTextNode(' '));
                const dropdownIcon = document.createElement('i');
                dropdownIcon.className = 'fas fa-chevron-down dropdown-icon';
                link.appendChild(dropdownIcon);
            }

            li.appendChild(link);

            // Create regular dropdown
            if (item.dropdown && Array.isArray(item.dropdown)) {
                const dropdown = document.createElement('ul');
                dropdown.className = 'rsl-navbar-dropdown';

                item.dropdown.forEach(subItem => {
                    const subLi = document.createElement('li');
                    subLi.className = 'rsl-navbar-item';

                    const subLink = document.createElement('a');
                    subLink.className = 'rsl-navbar-link';
                    subLink.href = subItem.href || '#';

                    if (subItem.icon) {
                        const icon = document.createElement('i');
                        icon.className = subItem.icon;
                        subLink.appendChild(icon);
                        subLink.appendChild(document.createTextNode(' '));
                    }

                    subLink.appendChild(document.createTextNode(subItem.text));

                    subLi.appendChild(subLink);
                    dropdown.appendChild(subLi);
                });

                li.appendChild(dropdown);
            }

            // Create mega menu
            if (item.megaMenu && item.megaMenu.columns) {
                const megaMenu = document.createElement('div');
                megaMenu.className = 'rsl-navbar-mega-menu';

                // Create slot layout for columns
                const slotLayout = document.createElement('div');
                slotLayout.className = 'slot-layout';
                slotLayout.setAttribute('data-cols-xs', '1');
                slotLayout.setAttribute('data-cols-md', item.megaMenu.columns.length.toString());

                item.megaMenu.columns.forEach(column => {
                    const slotItem = document.createElement('div');
                    slotItem.className = 'slot-item mega-section';

                    // Add column title
                    if (column.title) {
                        const title = document.createElement('h4');
                        if (column.icon) {
                            const icon = document.createElement('i');
                            icon.className = column.icon;
                            title.appendChild(icon);
                            title.appendChild(document.createTextNode(' '));
                        }
                        title.appendChild(document.createTextNode(column.title));
                        slotItem.appendChild(title);
                    }

                    // Add column items
                    if (column.items && Array.isArray(column.items)) {
                        column.items.forEach(colItem => {
                            const itemLink = document.createElement('a');
                            itemLink.href = colItem.href || '#';

                            if (colItem.icon) {
                                const icon = document.createElement('i');
                                icon.className = colItem.icon;
                                itemLink.appendChild(icon);
                                itemLink.appendChild(document.createTextNode(' '));
                            }

                            itemLink.appendChild(document.createTextNode(colItem.text));
                            slotItem.appendChild(itemLink);

                            if (colItem.description) {
                                const desc = document.createElement('span');
                                desc.className = 'mega-description';
                                desc.textContent = colItem.description;
                                slotItem.appendChild(desc);
                            }
                        });
                    }

                    // Handle featured section
                    if (column.featured) {
                        const featured = document.createElement('div');
                        featured.className = 'mega-featured';

                        if (column.title) {
                            const title = document.createElement('h4');
                            if (column.icon) {
                                const icon = document.createElement('i');
                                icon.className = column.icon;
                                title.appendChild(icon);
                                title.appendChild(document.createTextNode(' '));
                            }
                            title.appendChild(document.createTextNode(column.title));
                            featured.appendChild(title);
                        }

                        const link = document.createElement('a');
                        link.href = column.featured.href || '#';
                        if (column.featured.strong) {
                            const strong = document.createElement('strong');
                            strong.textContent = column.featured.text;
                            link.appendChild(strong);
                        } else {
                            link.textContent = column.featured.text;
                        }
                        featured.appendChild(link);

                        if (column.featured.description) {
                            const desc = document.createElement('span');
                            desc.className = 'mega-description';
                            desc.textContent = column.featured.description;
                            featured.appendChild(desc);
                        }

                        slotItem.appendChild(featured);
                    }

                    slotLayout.appendChild(slotItem);
                });

                megaMenu.appendChild(slotLayout);
                li.appendChild(megaMenu);
            }

            return li;
        }

        /**
         * Render pagination component
         * Creates pagination controls with page numbers and navigation
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Pagination configuration
         * @param {number} [config.totalPages=1] - Total number of pages
         * @param {number} [config.currentPage=1] - Currently active page
         * @param {boolean} [config.showFirstLast=false] - Show First/Last buttons
         * @param {boolean} [config.showPrevNext=true] - Show Previous/Next buttons
         * @param {number} [config.maxVisible=5] - Maximum number of visible page links
         * @private
         */
        _renderPagination(el, config) {
            const pagination = document.createElement('ul');
            pagination.className = 'rsl-pagination';

            const totalPages = config.totalPages || 1;
            const currentPage = config.currentPage || 1;
            const showFirstLast = config.showFirstLast !== undefined ? config.showFirstLast : false;
            const showPrevNext = config.showPrevNext !== undefined ? config.showPrevNext : true;
            const maxVisible = config.maxVisible || 5;

            // First button
            if (showFirstLast) {
                const firstLi = document.createElement('li');
                if (currentPage === 1) {
                    firstLi.classList.add('disabled');
                }
                const firstLink = document.createElement('a');
                firstLink.href = '#';
                firstLink.textContent = 'First';
                if (currentPage === 1) {
                    firstLink.setAttribute('aria-disabled', 'true');
                }
                firstLi.appendChild(firstLink);
                pagination.appendChild(firstLi);
            }

            // Previous button
            if (showPrevNext) {
                const prevLi = document.createElement('li');
                if (currentPage === 1) {
                    prevLi.classList.add('disabled');
                }
                const prevLink = document.createElement('a');
                prevLink.href = '#';
                prevLink.textContent = 'Previous';
                if (currentPage === 1) {
                    prevLink.setAttribute('aria-disabled', 'true');
                }
                prevLi.appendChild(prevLink);
                pagination.appendChild(prevLi);
            }

            // Calculate page range to display
            let startPage = 1;
            let endPage = totalPages;

            if (totalPages > maxVisible) {
                const half = Math.floor(maxVisible / 2);
                startPage = Math.max(1, currentPage - half);
                endPage = Math.min(totalPages, startPage + maxVisible - 1);

                // Adjust if we're at the end
                if (endPage - startPage + 1 < maxVisible) {
                    startPage = Math.max(1, endPage - maxVisible + 1);
                }
            }

            // Page number links
            for (let i = startPage; i <= endPage; i++) {
                const pageLi = document.createElement('li');
                if (i === currentPage) {
                    pageLi.classList.add('active');
                }
                const pageLink = document.createElement('a');
                pageLink.href = '#';
                pageLink.textContent = i.toString();
                if (i === currentPage) {
                    pageLink.setAttribute('aria-current', 'page');
                }
                pageLi.appendChild(pageLink);
                pagination.appendChild(pageLi);
            }

            // Next button
            if (showPrevNext) {
                const nextLi = document.createElement('li');
                if (currentPage === totalPages) {
                    nextLi.classList.add('disabled');
                }
                const nextLink = document.createElement('a');
                nextLink.href = '#';
                nextLink.textContent = 'Next';
                if (currentPage === totalPages) {
                    nextLink.setAttribute('aria-disabled', 'true');
                }
                nextLi.appendChild(nextLink);
                pagination.appendChild(nextLi);
            }

            // Last button
            if (showFirstLast) {
                const lastLi = document.createElement('li');
                if (currentPage === totalPages) {
                    lastLi.classList.add('disabled');
                }
                const lastLink = document.createElement('a');
                lastLink.href = '#';
                lastLink.textContent = 'Last';
                if (currentPage === totalPages) {
                    lastLink.setAttribute('aria-disabled', 'true');
                }
                lastLi.appendChild(lastLink);
                pagination.appendChild(lastLi);
            }

            el.appendChild(pagination);

            // Initialize pagination after a short delay to ensure table is in DOM
            setTimeout(() => {
                if (window.RSL && window.RSL.Pagination) {
                    // Find the nearest table to associate with this pagination
                    const container = el.closest('.slot-layout, .demo-output, .demo-section, .container');
                    if (container) {
                        const table = container.querySelector('.rsl-table');
                        if (table) {
                            // Initialize pagination for this specific table
                            window.RSL.Pagination.create(table, pagination, config.rowsPerPage || 10);
                        }
                    }
                }
            }, 100);
        }

        /**
         * Render sidebar component
         * Creates sidebar layouts with left, right, or dual sidebars
         * @param {HTMLElement} el - Container element
         * @param {Object} config - Sidebar configuration
         * @param {string} [config.position="left"] - Sidebar position: "left", "right", or "both"
         * @param {Object} [config.sidebar] - Sidebar content (for left/right positions)
         * @param {Object} [config.leftSidebar] - Left sidebar content (for "both" position)
         * @param {Object} [config.rightSidebar] - Right sidebar content (for "both" position)
         * @param {Object} config.main - Main content area
         * @param {Object} [config.below] - Optional full-width section below sidebar layout
         * @private
         */
        _renderSidebar(el, config) {
            const position = config.position || 'left';

            // Create the main sidebar container
            const container = document.createElement('div');
            container.className = 'rsl-sidebar-auto';
            container.setAttribute('data-sidebar', position);

            // For "both" position, create left sidebar
            if (position === 'both') {
                const leftAside = document.createElement('aside');
                leftAside.setAttribute('data-sidebar-slot', 'left');

                if (config.leftSidebar) {
                    if (config.leftSidebar.type) {
                        const renderer = this.contentRenderers[config.leftSidebar.type];
                        if (renderer) {
                            renderer(leftAside, config.leftSidebar);
                        }
                    } else if (config.leftSidebar.value) {
                        leftAside.innerHTML = config.leftSidebar.value;
                    }
                }

                container.appendChild(leftAside);
            }

            // For "both" position, create right sidebar
            if (position === 'both') {
                const rightAside = document.createElement('aside');
                rightAside.setAttribute('data-sidebar-slot', 'right');

                if (config.rightSidebar) {
                    if (config.rightSidebar.type) {
                        const renderer = this.contentRenderers[config.rightSidebar.type];
                        if (renderer) {
                            renderer(rightAside, config.rightSidebar);
                        }
                    } else if (config.rightSidebar.value) {
                        rightAside.innerHTML = config.rightSidebar.value;
                    }
                }

                container.appendChild(rightAside);
            }

            // For left/right position, create single sidebar
            if (position === 'left' || position === 'right') {
                const aside = document.createElement('aside');
                aside.setAttribute('data-sidebar-slot', 'sidebar');

                if (config.sidebar) {
                    if (config.sidebar.type) {
                        const renderer = this.contentRenderers[config.sidebar.type];
                        if (renderer) {
                            renderer(aside, config.sidebar);
                        }
                    } else if (config.sidebar.value) {
                        aside.innerHTML = config.sidebar.value;
                    }
                }

                container.appendChild(aside);
            }

            // Create main content area
            const main = document.createElement('main');
            main.setAttribute('data-sidebar-slot', 'main');

            if (config.main) {
                if (config.main.type) {
                    const renderer = this.contentRenderers[config.main.type];
                    if (renderer) {
                        renderer(main, config.main);
                    }
                } else if (config.main.value) {
                    main.innerHTML = config.main.value;
                }
            }

            container.appendChild(main);

            // Add optional below section
            if (config.below) {
                const section = document.createElement('section');
                section.setAttribute('data-sidebar-slot', 'below');

                if (config.below.type) {
                    const renderer = this.contentRenderers[config.below.type];
                    if (renderer) {
                        renderer(section, config.below);
                    }
                } else if (config.below.value) {
                    section.innerHTML = config.below.value;
                }

                container.appendChild(section);
            }

            el.appendChild(container);

            // Initialize sidebar after a short delay to ensure DOM is ready
            setTimeout(() => {
                if (window.RSL && window.RSL.Sidebar) {
                    window.RSL.Sidebar.init();
                }
            }, 50);
        }

        /**
         * Calculate and apply column count for a grid layout
         * This replicates layout.js column calculation for dynamically added grids
         * @private
         */
        _calculateGridColumns(layout) {
            const layoutWidth = layout.offsetWidth;

            // Read column settings from data attributes
            const colsXs = this._getColsAttr(layout, 'data-cols-xs');
            const colsSm = this._getColsAttr(layout, 'data-cols-sm');
            const colsMd = this._getColsAttr(layout, 'data-cols-md');
            const colsLg = this._getColsAttr(layout, 'data-cols-lg');
            const colsXl = this._getColsAttr(layout, 'data-cols-xl');
            const colsXxl = this._getColsAttr(layout, 'data-cols-xxl');

            let cols = 1; // default

            // Determine columns based on layout width with cascading inheritance
            if (layoutWidth <= 576) {
                // XS breakpoint
                cols = colsXs ?? 1;
            } else if (layoutWidth <= 768) {
                // SM breakpoint
                cols = colsSm ?? colsXs ?? 1;
            } else if (layoutWidth <= 992) {
                // MD breakpoint
                cols = colsMd ?? colsSm ?? colsXs ?? 2;
            } else if (layoutWidth <= 1200) {
                // LG breakpoint
                cols = colsLg ?? colsMd ?? colsSm ?? colsXs ?? 3;
            } else if (layoutWidth <= 1600) {
                // XL breakpoint
                cols = colsXl ?? colsLg ?? colsMd ?? colsSm ?? colsXs ?? 3;
            } else {
                // XXL breakpoint
                cols = colsXxl ?? colsXl ?? colsLg ?? colsMd ?? colsSm ?? colsXs ?? 4;
            }

            // Apply the column count
            layout.style.setProperty('--dynamic-cols', cols);
        }

        /**
         * Read column count from data attribute
         * @private
         */
        _getColsAttr(layout, attrName) {
            const val = layout.getAttribute(attrName);
            if (val === null || val === '') return null;
            const parsed = parseInt(val, 10);
            return Number.isNaN(parsed) ? null : parsed;
        }

        // ====================================================================
        // COMPONENT PRESETS
        // ====================================================================

        /**
         * Render a component preset
         * @public
         */
        renderPreset(container, presetName, config) {
            const preset = this.presets[presetName];

            if (!preset) {
                throw new Error(`Unknown preset: ${presetName}`);
            }

            const layoutConfig = preset(config);
            return this.renderLayout(container, layoutConfig);
        }

        /**
         * Hero preset
         * @private
         */
        _presetHero(config) {
            return {
                version: 2,
                layoutId: config.id || 'hero-section',
                wrapper: {
                    tag: 'section',
                    classes: ['rsl-hero', config.variant || 'primary'],
                    renderMode: 'direct'
                },
                breakpoints: { xs: 1 },
                items: [{
                    id: 'hero-content',
                    content: {
                        type: 'html',
                        value: `
                            <div class="rsl-hero-content">
                                ${config.badge ? `<span class="rsl-badge ${config.badgeVariant || 'primary'}">${config.badge}</span>` : ''}
                                <h1 class="rsl-hero-title">${config.title || 'Hero Title'}</h1>
                                ${config.subtitle ? `<p class="rsl-hero-subtitle">${config.subtitle}</p>` : ''}
                                ${config.text ? `<p class="rsl-hero-text">${config.text}</p>` : ''}
                                ${config.buttons ? `
                                    <div class="rsl-hero-actions">
                                        ${config.buttons.map(btn => `
                                            <a href="${btn.href || '#'}" class="rsl-btn rsl-btn-${btn.variant || 'primary'} ${btn.size ? 'rsl-btn-' + btn.size : ''}">
                                                ${btn.icon ? `<i class="${btn.icon}"></i> ` : ''}${btn.text}
                                            </a>
                                        `).join('')}
                                    </div>
                                ` : ''}
                            </div>
                            ${config.image ? `<div class="rsl-hero-image"><img src="${config.image}" alt="${config.imageAlt || config.title}"></div>` : ''}
                        `
                    }
                }]
            };
        }

        /**
         * Features preset
         * @private
         */
        _presetFeatures(config) {
            const features = config.features || [];

            return {
                version: 2,
                layoutId: config.id || 'features-section',
                wrapper: config.wrapper,
                breakpoints: config.breakpoints || { xs: 1, sm: 2, md: 3 },
                gap: config.gap || '2rem',
                template: {
                    data: features,
                    item: {
                        content: {
                            type: 'card',
                            icon: '{{icon}}',
                            title: '{{title}}',
                            body: '{{description}}',
                            variant: config.variant || 'default'
                        },
                        style: {
                            textAlign: 'center'
                        }
                    }
                }
            };
        }

        /**
         * Pricing preset
         * @private
         */
        _presetPricing(config) {
            const plans = config.plans || [];

            return {
                version: 2,
                layoutId: config.id || 'pricing-section',
                breakpoints: config.breakpoints || { xs: 1, md: 2, lg: plans.length },
                gap: config.gap || '2rem',
                template: {
                    data: plans,
                    item: {
                        content: {
                            type: 'card',
                            badge: '{{featured ? "Popular" : ""}}',
                            title: '{{name}}',
                            price: '{{price}}',
                            body: '{{description}}',
                            footer: `<ul class="rsl-pricing-features">{{features}}</ul>`,
                            button: {
                                text: '{{buttonText}}',
                                variant: '{{featured ? "primary" : "secondary"}}'
                            },
                            variant: 'pricing'
                        }
                    }
                }
            };
        }

        /**
         * Testimonials preset
         * @private
         */
        _presetTestimonials(config) {
            const testimonials = config.testimonials || [];

            return {
                version: 2,
                layoutId: config.id || 'testimonials-section',
                breakpoints: config.breakpoints || { xs: 1, sm: 2, md: 3 },
                gap: config.gap || '2rem',
                template: {
                    data: testimonials,
                    item: {
                        content: {
                            type: 'card',
                            body: '"{{quote}}"',
                            meta: '{{author}} - {{role}}',
                            image: '{{avatar}}',
                            variant: 'testimonial'
                        }
                    }
                }
            };
        }

        /**
         * Gallery preset
         * @private
         */
        _presetGallery(config) {
            const images = config.images || [];

            return {
                version: 2,
                layoutId: config.id || 'gallery-section',
                breakpoints: config.breakpoints || { xs: 2, sm: 3, md: 4, lg: 5 },
                gap: config.gap || '1rem',
                template: {
                    data: images,
                    item: {
                        content: {
                            type: 'image',
                            src: '{{src}}',
                            alt: '{{alt}}',
                            caption: '{{caption}}',
                            objectFit: 'cover'
                        }
                    }
                }
            };
        }

        /**
         * Stats preset
         * @private
         */
        _presetStats(config) {
            const stats = config.stats || [];

            return {
                version: 2,
                layoutId: config.id || 'stats-section',
                breakpoints: config.breakpoints || { xs: 2, md: 4 },
                gap: config.gap || '2rem',
                template: {
                    data: stats,
                    item: {
                        content: {
                            type: 'html',
                            value: `
                                <div class="rsl-stat">
                                    <div class="rsl-stat-value">{{value}}</div>
                                    <div class="rsl-stat-label">{{label}}</div>
                                </div>
                            `
                        },
                        style: {
                            textAlign: 'center'
                        }
                    }
                }
            };
        }

        /**
         * CTA preset
         * @private
         */
        _presetCTA(config) {
            return {
                version: 2,
                layoutId: config.id || 'cta-section',
                wrapper: {
                    tag: 'section',
                    classes: ['rsl-cta', config.variant || 'primary'],
                    renderMode: 'direct'
                },
                breakpoints: { xs: 1 },
                items: [{
                    id: 'cta-content',
                    content: {
                        type: 'html',
                        value: `
                            <div class="rsl-cta-content">
                                <h2>${config.title || 'Ready to get started?'}</h2>
                                ${config.text ? `<p>${config.text}</p>` : ''}
                                <div class="rsl-cta-actions">
                                    ${config.buttons ? config.buttons.map(btn => `
                                        <a href="${btn.href || '#'}" class="rsl-btn rsl-btn-${btn.variant || 'primary'} rsl-btn-lg">
                                            ${btn.text}
                                        </a>
                                    `).join('') : ''}
                                </div>
                            </div>
                        `
                    }
                }]
            };
        }

        /**
         * Team preset
         * @private
         */
        _presetTeam(config) {
            const members = config.members || [];

            return {
                version: 2,
                layoutId: config.id || 'team-section',
                breakpoints: config.breakpoints || { xs: 1, sm: 2, md: 3, lg: 4 },
                gap: config.gap || '2rem',
                template: {
                    data: members,
                    item: {
                        content: {
                            type: 'card',
                            image: '{{photo}}',
                            title: '{{name}}',
                            subtitle: '{{role}}',
                            text: '{{bio}}',
                            variant: 'team'
                        },
                        style: {
                            textAlign: 'center'
                        }
                    }
                }
            };
        }

        // ====================================================================
        // UTILITY METHODS
        // ====================================================================

        /**
         * Apply inline styles to element
         * @private
         */
        _applyStyles(el, styles) {
            Object.entries(styles).forEach(([prop, value]) => {
                // Convert camelCase to kebab-case
                const cssProp = prop.replace(/[A-Z]/g, m => '-' + m.toLowerCase());
                el.style.setProperty(cssProp, value);
            });
        }

        /**
         * Apply spacing utilities
         * @private
         */
        _applySpacing(el, spacing) {
            if (spacing.margin) {
                el.style.margin = spacing.margin;
            }
            if (spacing.marginTop) {
                el.style.marginTop = spacing.marginTop;
            }
            if (spacing.marginBottom) {
                el.style.marginBottom = spacing.marginBottom;
            }
            if (spacing.padding) {
                el.style.padding = spacing.padding;
            }
            if (spacing.paddingTop) {
                el.style.paddingTop = spacing.paddingTop;
            }
            if (spacing.paddingBottom) {
                el.style.paddingBottom = spacing.paddingBottom;
            }
        }

        /**
         * Apply grid positioning
         * Sets both data attributes and CSS variables for grid placement
         * Supports RSL responsive column spanning via data-span-* attributes
         * @private
         */
        _applyGridPosition(el, grid) {
            if (grid.rowStart) {
                el.setAttribute('data-row-start', grid.rowStart);
                el.style.setProperty('--row-start', grid.rowStart);
            }
            if (grid.rowEnd) {
                el.setAttribute('data-row-end', grid.rowEnd);
                el.style.setProperty('--row-end', grid.rowEnd);
            }
            if (grid.columnStart) {
                el.setAttribute('data-col-start', grid.columnStart);
                el.style.setProperty('--column-start', grid.columnStart);
            }
            if (grid.columnEnd) {
                el.setAttribute('data-col-end', grid.columnEnd);
                el.style.setProperty('--column-end', grid.columnEnd);
            }

            // RSL responsive column spanning (data-span-xs/sm/md/lg/xl/xxl)
            // Accepts object like: { xs: 1, md: 2, lg: 3 } or number for all breakpoints
            if (grid.span !== undefined) {
                if (typeof grid.span === 'object') {
                    // Responsive spanning object
                    const breakpoints = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
                    breakpoints.forEach(bp => {
                        if (grid.span[bp] !== undefined) {
                            el.setAttribute(`data-span-${bp}`, grid.span[bp]);
                        }
                    });
                } else {
                    // Single value applies to xs (base)
                    el.setAttribute('data-span-xs', grid.span);
                }
            }

            // RSL row spanning for subgrid layouts (data-row-span)
            if (grid.rowSpan) {
                el.setAttribute('data-row-span', grid.rowSpan);
            }

            // RSL subgrid mode (data-subgrid)
            if (grid.subgrid) {
                el.setAttribute('data-subgrid', grid.subgrid);
            }

            // Grid area assignment for named grid areas (data-area)
            if (grid.area) {
                el.setAttribute('data-area', grid.area);
            }
        }

        /**
         * Attach click handler
         * @private
         */
        _attachClickHandler(el, handler, context) {
            if (typeof handler === 'string') {
                // Handler is a function name
                el.addEventListener('click', (e) => {
                    if (window[handler]) {
                        window[handler](e, context);
                    } else {
                        console.warn(`Click handler not found: ${handler}`);
                    }
                });
            } else if (typeof handler === 'function') {
                el.addEventListener('click', (e) => handler(e, context));
            }
        }

        /**
         * Attach custom events
         * @private
         */
        _attachEvents(el, events, context) {
            Object.entries(events).forEach(([eventName, handler]) => {
                if (typeof handler === 'string') {
                    el.addEventListener(eventName, (e) => {
                        if (window[handler]) {
                            window[handler](e, context);
                        }
                    });
                } else if (typeof handler === 'function') {
                    el.addEventListener(eventName, (e) => handler(e, context));
                }
            });
        }

        /**
         * Calculate initial columns for viewport
         * @private
         */
        _calculateInitialColumns(breakpoints) {
            const width = window.innerWidth;
            let columns = breakpoints.xs || 1;

            if (width >= 1601 && breakpoints.xxl) {
                columns = breakpoints.xxl;
            } else if (width >= 1201 && breakpoints.xl) {
                columns = breakpoints.xl;
            } else if (width >= 993 && breakpoints.lg) {
                columns = breakpoints.lg;
            } else if (width >= 768 && breakpoints.md) {
                columns = breakpoints.md;
            } else if (width >= 480 && breakpoints.sm) {
                columns = breakpoints.sm;
            }

            return columns;
        }

        /**
         * Initialize RSL components
         * @private
         */
        _initializeComponents(container) {
            const components = [
                'Select', 'Tooltip', 'Popover', 'Accordion', 'Tabs',
                'Modal', 'Toast', 'Carousel', 'OffCanvas', 'Alerts',
                'Navbar', 'Pagination', 'Sidebar', 'Cards', 'Thumbnail',
                'Gallery', 'Badge', 'Progress', 'DatePicker', 'TimePicker', 'Filter',
                'Hero', 'Announcements', 'IconPicker', 'StarRating', 'Testimonial',
                'PricingTable', 'VideoPlayer', 'KPICards', 'Stats', 'Loader', 'Sticky',
                'Timeline'
            ];

            components.forEach(name => {
                if (window.RSL && window.RSL[name] && window.RSL[name].init) {
                    window.RSL[name].init();
                }
            });
        }

        /**
         * Render legacy component (backward compatible)
         * @private
         */
        _renderLegacyComponent(container, config) {
            // Forward to v1 implementation if needed
            if (config.componentType === 'navbar') {
                return this._renderNavbar(container, config);
            }
            throw new Error(`Unknown component type: ${config.componentType}`);
        }

        /**
         * Build JSON configuration from existing DOM layout
         *
         * Extracts layout configuration including wrapper, breakpoints, gap settings,
         * and all items with their properties. Useful for converting hand-authored
         * HTML into JSON format.
         *
         * @param {string|HTMLElement} container - Container with .slot-layout
         * @returns {Object} JSON layout configuration
         * @throws {Error} If container or layout not found
         */
        buildFromDOM(container) {
            const containerEl = typeof container === 'string'
                ? document.querySelector(container)
                : container;

            if (!containerEl) {
                throw new Error('Container not found');
            }

            const layoutEl = containerEl.querySelector('.slot-layout');
            if (!layoutEl) {
                throw new Error('No .slot-layout found in container');
            }

            // Build config object
            const config = {
                version: 1,
                layoutId: layoutEl.id || 'layout-' + Date.now(),
                breakpoints: {},
                items: []
            };

            // Check if layout has a parent wrapper we should preserve
            const wrapper = layoutEl.parentElement;
            if (wrapper && wrapper !== containerEl && wrapper !== document.body) {
                config.wrapper = {
                    id: wrapper.id || null,
                    classes: Array.from(wrapper.classList),
                    tag: wrapper.tagName.toLowerCase()
                };

                // Store any data attributes from wrapper
                const wrapperDataAttrs = Array.from(wrapper.attributes)
                    .filter(attr => attr.name.startsWith('data-'))
                    .reduce((acc, attr) => {
                        acc[attr.name.replace('data-', '')] = attr.value;
                        return acc;
                    }, {});

                if (Object.keys(wrapperDataAttrs).length > 0) {
                    config.wrapper.data = wrapperDataAttrs;
                }
            }

            // Extract breakpoints
            const breakpoints = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
            breakpoints.forEach(bp => {
                const value = layoutEl.getAttribute(`data-cols-${bp}`);
                if (value) {
                    config.breakpoints[bp] = parseInt(value, 10);
                }
            });

            // Extract gap
            const gap = layoutEl.getAttribute('data-gap');
            if (gap) {
                config.gap = gap;
            }

            // Extract items
            const items = layoutEl.querySelectorAll(':scope > .slot-item, :scope > .nested-slot-item');
            items.forEach((itemEl, index) => {
                const itemConfig = {
                    id: itemEl.id || `item-${index}`,
                    classes: Array.from(itemEl.classList).filter(c => c !== 'slot-item'),
                    visible: !itemEl.classList.contains('hidden')
                };

                // Extract grid positioning
                const rowStart = itemEl.style.getPropertyValue('--row-start');
                const rowEnd = itemEl.style.getPropertyValue('--row-end');
                const columnStart = itemEl.style.getPropertyValue('--column-start');
                const columnEnd = itemEl.style.getPropertyValue('--column-end');

                if (rowStart || rowEnd || columnStart || columnEnd) {
                    itemConfig.grid = {};
                    if (rowStart) itemConfig.grid.rowStart = parseInt(rowStart, 10);
                    if (rowEnd) itemConfig.grid.rowEnd = parseInt(rowEnd, 10);
                    if (columnStart) itemConfig.grid.columnStart = parseInt(columnStart, 10);
                    if (columnEnd) itemConfig.grid.columnEnd = parseInt(columnEnd, 10);
                }

                // Extract order
                const order = itemEl.style.order;
                if (order && order !== 'auto') {
                    itemConfig.order = parseInt(order, 10);
                }

                // Extract data attributes
                const dataAttrs = Array.from(itemEl.attributes)
                    .filter(attr => attr.name.startsWith('data-'))
                    .reduce((acc, attr) => {
                        const key = attr.name.replace('data-', '');
                        if (key !== 'component' && key !== 'props') {
                            acc[key] = attr.value;
                        }
                        return acc;
                    }, {});

                if (Object.keys(dataAttrs).length > 0) {
                    itemConfig.data = dataAttrs;
                }

                // Extract content (simplified - just store inner HTML)
                if (itemEl.innerHTML.trim()) {
                    itemConfig.content = {
                        type: 'html',
                        value: itemEl.innerHTML
                    };
                }

                config.items.push(itemConfig);
            });

            return config;
        }

        /**
         * Convert HTML to JSON Configuration (Advanced)
         *
         * Comprehensive HTML-to-JSON converter that handles:
         * - Full HTML documents (extracts body content)
         * - Multiple slot-layouts anywhere in the document
         * - Nested slot-layouts with placeholder system
         * - Mixed content (HTML sections between grids)
         * - Item-level details (grid positioning, order, visibility, classes, data attributes)
         *
         * @param {string|HTMLElement} input - HTML string, selector, or DOM element
         * @param {Object} options - Conversion options
         * @param {number} options.version - Output version (1 or 2), default 2
         * @param {string} options.layoutId - Custom layout ID, default 'converted-layout'
         * @param {boolean} options.preserveComments - Keep HTML comments, default false
         * @returns {Object} JSON layout configuration with items array
         *
         * @example
         * // From HTML string
         * const config = RSL.JSONLayout.convertHTMLtoJSON('<div class="slot-layout">...</div>');
         *
         * // From existing DOM
         * const config = RSL.JSONLayout.convertHTMLtoJSON('#my-container');
         *
         * // With options
         * const config = RSL.JSONLayout.convertHTMLtoJSON(html, { version: 2, layoutId: 'my-page' });
         */
        convertHTMLtoJSON(input, options = {}) {
            const {
                version = 2,
                layoutId = 'converted-layout',
                preserveComments = false
            } = options;

            let html;
            let tempDiv;

            // Handle different input types
            if (typeof input === 'string') {
                // Check if it's a selector or HTML
                if (input.trim().startsWith('<') || input.includes('<!DOCTYPE') || input.includes('<html')) {
                    // It's HTML string
                    html = input.trim();
                } else {
                    // It's a selector - get innerHTML
                    const el = document.querySelector(input);
                    if (!el) {
                        throw new Error(`Element not found: ${input}`);
                    }
                    html = el.innerHTML;
                }
            } else if (input instanceof HTMLElement) {
                html = input.innerHTML;
            } else {
                throw new Error('Input must be HTML string, selector, or HTMLElement');
            }

            // Check if this is a full HTML document
            const isFullDocument = html.includes('<!DOCTYPE') ||
                                   html.includes('<html') ||
                                   html.includes('<head') ||
                                   html.includes('<body');

            // If full document, extract just the body content
            if (isFullDocument) {
                const bodyMatch = html.match(/<body[^>]*>([\s\S]*)<\/body>/i);
                if (bodyMatch) {
                    html = bodyMatch[1];
                }
            }

            // Create a temporary container
            tempDiv = document.createElement('div');
            tempDiv.innerHTML = html;

            // Tags to skip (not content)
            const skipTags = ['SCRIPT', 'LINK', 'META', 'STYLE', 'TITLE', 'NOSCRIPT'];

            // Find ALL slot-layouts anywhere in the document (nested or not)
            const allSlotLayouts = tempDiv.querySelectorAll('.slot-layout');

            // Mark slot-layouts so we know not to include them as raw HTML
            allSlotLayouts.forEach(sl => sl.setAttribute('data-converter-processed', 'true'));

            const items = [];
            let itemCounter = 1;
            let slotLayoutCount = 0;
            let htmlCount = 0;

            // Reference to this for nested functions
            const self = this;

            /**
             * Extract detailed item configuration from a slot-item element
             * Combines playground's simplicity with buildFromDOM's detail extraction
             */
            function extractItemDetails(itemEl, index) {
                const itemConfig = {
                    id: itemEl.id || `item-${itemCounter++}`
                };

                // Extract classes (filter out slot-item/nested-slot-item)
                const classes = Array.from(itemEl.classList).filter(c =>
                    c !== 'slot-item' && c !== 'nested-slot-item'
                );
                if (classes.length > 0) {
                    itemConfig.classes = classes;
                }

                // Extract visibility state
                if (itemEl.classList.contains('hidden')) {
                    itemConfig.visible = false;
                }

                // Extract grid positioning from CSS custom properties
                const rowStart = itemEl.style.getPropertyValue('--row-start');
                const rowEnd = itemEl.style.getPropertyValue('--row-end');
                const columnStart = itemEl.style.getPropertyValue('--column-start');
                const columnEnd = itemEl.style.getPropertyValue('--column-end');

                if (rowStart || rowEnd || columnStart || columnEnd) {
                    itemConfig.grid = {};
                    if (rowStart) itemConfig.grid.rowStart = parseInt(rowStart, 10);
                    if (rowEnd) itemConfig.grid.rowEnd = parseInt(rowEnd, 10);
                    if (columnStart) itemConfig.grid.columnStart = parseInt(columnStart, 10);
                    if (columnEnd) itemConfig.grid.columnEnd = parseInt(columnEnd, 10);
                }

                // Extract order
                const order = itemEl.style.order;
                if (order && order !== 'auto' && order !== '0') {
                    itemConfig.order = parseInt(order, 10);
                }

                // Extract span attributes
                const breakpoints = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
                breakpoints.forEach(bp => {
                    const span = itemEl.getAttribute(`data-span-${bp}`);
                    if (span) {
                        itemConfig[`span-${bp}`] = parseInt(span, 10);
                    }
                });

                // Extract data attributes (except internal ones)
                const dataAttrs = Array.from(itemEl.attributes)
                    .filter(attr => attr.name.startsWith('data-') &&
                                   !attr.name.startsWith('data-span-') &&
                                   attr.name !== 'data-converter-processed')
                    .reduce((acc, attr) => {
                        const key = attr.name.replace('data-', '');
                        acc[key] = attr.value;
                        return acc;
                    }, {});

                if (Object.keys(dataAttrs).length > 0) {
                    itemConfig.data = dataAttrs;
                }

                // Extract content
                if (itemEl.innerHTML.trim()) {
                    itemConfig.content = {
                        type: 'html',
                        value: itemEl.innerHTML.trim()
                    };
                }

                return itemConfig;
            }

            /**
             * Extract slot-layout configuration including all items with details
             */
            function extractSlotLayout(slotLayout) {
                slotLayoutCount++;

                // Extract breakpoints
                const breakpoints = ['xs', 'sm', 'md', 'lg', 'xl', 'xxl'];
                const bpConfig = {};
                breakpoints.forEach(bp => {
                    const value = slotLayout.getAttribute(`data-cols-${bp}`);
                    if (value) {
                        bpConfig[bp] = parseInt(value, 10);
                    }
                });

                // Extract gap
                const gap = slotLayout.getAttribute('data-gap');

                // Extract additional layout attributes
                const density = slotLayout.getAttribute('data-rsl-density');
                const autoFit = slotLayout.getAttribute('data-auto-fit');
                const autoFill = slotLayout.getAttribute('data-auto-fill');

                // Get the slot-items inside (direct children only)
                const slotItems = slotLayout.querySelectorAll(':scope > .slot-item, :scope > .nested-slot-item');

                const layoutItems = [];
                slotItems.forEach((slotItem, idx) => {
                    layoutItems.push(extractItemDetails(slotItem, idx));
                });

                const layoutConfig = {
                    breakpoints: Object.keys(bpConfig).length > 0 ? bpConfig : { xs: 1 },
                    gap: gap || '1.5rem',
                    items: layoutItems
                };

                // Add optional attributes if present
                if (density) layoutConfig.density = density;
                if (autoFit) layoutConfig.autoFit = autoFit;
                if (autoFill) layoutConfig.autoFill = autoFill;

                // Preserve layout ID if it has one
                if (slotLayout.id) {
                    layoutConfig.id = slotLayout.id;
                }

                // Preserve layout classes
                const layoutClasses = Array.from(slotLayout.classList).filter(c =>
                    c !== 'slot-layout' && c !== 'nested-slot-layout'
                );
                if (layoutClasses.length > 0) {
                    layoutConfig.classes = layoutClasses;
                }

                return layoutConfig;
            }

            /**
             * Check if element contains a slot-layout
             */
            function containsSlotLayout(el) {
                return el.querySelector('.slot-layout') !== null;
            }

            /**
             * Check if element IS a slot-layout
             */
            function isSlotLayout(el) {
                return el.classList && el.classList.contains('slot-layout');
            }

            /**
             * Check if element is a "preserve-whole" component that should NOT
             * have its inner slot-layouts extracted (modals, accordions, tabs, etc.)
             * These components need their full HTML structure to function correctly.
             */
            function shouldPreserveWhole(el) {
                if (!el.classList) return false;

                // List of component classes that should be preserved as-is
                const preserveClasses = [
                    'modal-container',  // Modals with forms
                    'modal',
                    'accordion',        // Accordion panels
                    'tabs',             // Tab containers
                    'tabs-display',
                    'offcanvas',        // Off-canvas panels
                    'rsl-sidebar',      // Sidebars
                    'carousel',         // Carousels
                    'rsl-hero',         // Hero sections
                    'rsl-cards-grid'    // Cards grids from Page Builder
                ];

                return preserveClasses.some(cls => el.classList.contains(cls)) ||
                       el.closest('.modal-container') !== null ||
                       el.closest('.modal') !== null;
            }

            /**
             * Process top-level children, recursively finding slot-layouts
             */
            function processElement(el) {
                // Skip non-content tags
                if (skipTags.includes(el.tagName)) {
                    return;
                }

                // Skip comments unless preserving
                if (el.nodeType === Node.COMMENT_NODE && !preserveComments) {
                    return;
                }

                // IMPORTANT: Certain components should be preserved as-is
                // even if they contain slot-layouts (modals, accordions, tabs, etc.)
                if (shouldPreserveWhole(el)) {
                    htmlCount++;
                    items.push({
                        id: el.id || `preserved-${itemCounter++}`,
                        content: {
                            type: 'html',
                            value: el.outerHTML
                        }
                    });
                    return;
                }

                if (isSlotLayout(el)) {
                    // Direct slot-layout - extract it
                    const layoutConfig = extractSlotLayout(el);

                    // Add as a nested grid if it has items
                    if (layoutConfig.items.length > 0) {
                        const gridItem = {
                            id: layoutConfig.id || `layout-${slotLayoutCount}`,
                            content: {
                                type: 'grid',
                                breakpoints: layoutConfig.breakpoints,
                                gap: layoutConfig.gap,
                                items: layoutConfig.items
                            }
                        };

                        // Preserve additional grid properties
                        if (layoutConfig.density) gridItem.content.density = layoutConfig.density;
                        if (layoutConfig.autoFit) gridItem.content.autoFit = layoutConfig.autoFit;
                        if (layoutConfig.autoFill) gridItem.content.autoFill = layoutConfig.autoFill;
                        if (layoutConfig.classes) gridItem.classes = layoutConfig.classes;

                        items.push(gridItem);
                    }
                } else if (containsSlotLayout(el)) {
                    // Element contains slot-layout(s) - need to process recursively
                    // First, capture any content BEFORE the slot-layout
                    const clone = el.cloneNode(true);
                    const nestedSlotLayouts = clone.querySelectorAll('.slot-layout');

                    // Replace slot-layouts with placeholders to extract surrounding HTML
                    nestedSlotLayouts.forEach((sl, idx) => {
                        const placeholder = document.createElement('div');
                        placeholder.setAttribute('data-slot-layout-placeholder', idx);
                        sl.parentNode.replaceChild(placeholder, sl);
                    });

                    // Check if there's meaningful content around the slot-layouts
                    const surroundingHTML = clone.innerHTML.trim();
                    const hasOnlyPlaceholders = surroundingHTML.replace(/<div data-slot-layout-placeholder="\d+"><\/div>/g, '').trim() === '';

                    if (!hasOnlyPlaceholders) {
                        // There's wrapper content - include it as HTML with a note
                        htmlCount++;
                        items.push({
                            id: `wrapper-${itemCounter++}`,
                            _note: 'Wrapper element containing slot-layout placeholders',
                            content: {
                                type: 'html',
                                value: clone.outerHTML
                            }
                        });
                    }

                    // Now extract the actual slot-layouts from the original element
                    const originalNestedSlotLayouts = el.querySelectorAll('.slot-layout');
                    originalNestedSlotLayouts.forEach(sl => {
                        // Only process top-level nested slot-layouts (not deeply nested)
                        const parent = sl.parentElement;
                        if (parent && !parent.closest('.slot-layout')) {
                            const layoutConfig = extractSlotLayout(sl);
                            if (layoutConfig.items.length > 0) {
                                const gridItem = {
                                    id: layoutConfig.id || `layout-${slotLayoutCount}`,
                                    content: {
                                        type: 'grid',
                                        breakpoints: layoutConfig.breakpoints,
                                        gap: layoutConfig.gap,
                                        items: layoutConfig.items
                                    }
                                };

                                if (layoutConfig.density) gridItem.content.density = layoutConfig.density;
                                if (layoutConfig.autoFit) gridItem.content.autoFit = layoutConfig.autoFit;
                                if (layoutConfig.autoFill) gridItem.content.autoFill = layoutConfig.autoFill;
                                if (layoutConfig.classes) gridItem.classes = layoutConfig.classes;

                                items.push(gridItem);
                            }
                        }
                    });
                } else {
                    // Regular element with no slot-layouts - wrap as HTML
                    htmlCount++;
                    items.push({
                        id: `item-${itemCounter++}`,
                        content: {
                            type: 'html',
                            value: el.outerHTML
                        }
                    });
                }
            }

            // Process all top-level children
            Array.from(tempDiv.children).forEach(child => {
                processElement(child);
            });

            // Build the output config
            const output = {
                version: version,
                layoutId: layoutId,
                breakpoints: { xs: 1 },
                gap: '1.5rem',
                items: items,
                _meta: {
                    convertedAt: new Date().toISOString(),
                    source: isFullDocument ? 'full-document' : 'fragment',
                    stats: {
                        htmlSections: htmlCount,
                        slotLayouts: slotLayoutCount,
                        totalItems: items.length
                    }
                }
            };

            return output;
        }

        /**
         * Update from JSON (v1 compatible)
         */
        updateLayoutFromJSON(container, config) {
            // Keep v1 implementation with v2 enhancements
            // ... (existing code)
        }

        /**
         * Export to JSON
         */
        exportJSON(config, pretty = true) {
            return pretty ? JSON.stringify(config, null, 2) : JSON.stringify(config);
        }

        /**
         * Import from JSON
         */
        importJSON(jsonString) {
            try {
                const config = JSON.parse(jsonString);
                const validation = this.validateSchema(config);

                if (!validation.valid) {
                    throw new Error('Invalid schema: ' + validation.errors.join(', '));
                }

                return config;
            } catch (error) {
                console.error('Failed to import JSON:', error);
                throw error;
            }
        }
    }

    // ========================================================================
    // INITIALIZE & EXPOSE API
    // ========================================================================

    window.RSL = window.RSL || {};

    // Replace existing JSONLayout with v2
    const v2Engine = new JSONLayoutEngineV2();

    // Keep v1 reference for compatibility
    window.RSL.JSONLayoutV1 = window.RSL.JSONLayout;

    // Set v2 as default
    window.RSL.JSONLayout = v2Engine;

    // Emit ready event
    window.dispatchEvent(new CustomEvent('rsl:jsonlayout:v2:ready'));

    console.log('✨ RSL JSON Layout Engine v2.0 initialized');
    console.log('📚 See documentation at: https://rslayout.com/docs/json-layout-v2');

})();
