/**
 * RSL Full Page Calendar Component
 * Version: 1.0.0
 *
 * A fully accessible, ADA-compliant calendar component with
 * Day, Week, Month, and Year views. Supports events, categories,
 * recurrence, and FilterBus integration.
 *
 * Public API:
 * - RSL.Calendar.init()           - Initialize all calendars on page
 * - RSL.Calendar.create(element)  - Initialize a specific calendar
 * - RSL.Calendar.getInstance(el)  - Get calendar instance for element
 *
 * Data Attributes:
 * - data-rsl-calendar             - Marks element as calendar
 * - data-calendar-view            - Initial view: day, week, month, year
 * - data-calendar-date            - Initial date (ISO format)
 * - data-calendar-first-day       - Week start: 0=Sun, 1=Mon
 * - data-calendar-editable        - Enable event editing: true/false
 * - data-calendar-show-toolbar    - Show toolbar: true/false
 * - data-calendar-show-week-numbers - Show week numbers: true/false
 * - data-calendar-filter-key      - FilterBus key for event filtering
 * - data-calendar-events          - JSON array of initial events
 * - data-calendar-categories      - JSON array of categories
 *
 * Upcoming Events Data Attributes:
 * - data-calendar-upcoming        - Display mode: none, below, sidebar, only
 * - data-calendar-upcoming-count  - Number of events to show (default: 5)
 * - data-calendar-upcoming-days   - Days ahead to look (default: 30)
 * - data-calendar-upcoming-title  - Section title (default: "Upcoming Events")
 */

(function() {
    'use strict';

    // Ensure RSL namespace exists
    window.RSL = window.RSL || {};

    // Instance tracking
    var instances = new Map();

    /**
     * Calendar Class
     */
    function Calendar(element, options) {
        this.element = element;
        this.config = this._parseConfig(options);
        this.currentDate = this._parseLocalDate(this.config.date);
        this.selectedDate = null;
        this.events = this.config.events || [];
        this.categories = this.config.categories || this._getDefaultCategories();
        this.filteredCategory = null;
        this.focusedDate = new Date(this.currentDate);
        this.panelOpen = false;
        this.editingEvent = null;

        // DOM references
        this.dom = {};

        this._init();
    }

    /**
     * Default configuration
     */
    Calendar.DEFAULTS = {
        view: 'month',
        date: new Date().toISOString().split('T')[0],
        firstDay: 0,
        editable: true,
        showToolbar: true,
        showWeekNumbers: false,
        filterKey: null,
        events: [],
        categories: null,
        locale: 'en-US',
        timeFormat: '12h',
        minHour: 6,
        maxHour: 22,
        // Upcoming events configuration
        upcoming: 'none',         // none, below, sidebar, only
        upcomingCount: 5,         // Number of events to show
        upcomingDays: 30,         // Days ahead to look
        upcomingTitle: 'Upcoming Events'
    };

    /**
     * Upcoming display modes
     */
    Calendar.UPCOMING_MODES = ['none', 'below', 'sidebar', 'only'];

    /**
     * View types
     */
    Calendar.VIEWS = ['day', 'week', 'month', 'year'];

    /**
     * Parse configuration from data attributes and options
     */
    Calendar.prototype._parseConfig = function(options) {
        var el = this.element;
        var config = Object.assign({}, Calendar.DEFAULTS, options || {});

        // Parse data attributes
        if (el.hasAttribute('data-calendar-view')) {
            config.view = el.getAttribute('data-calendar-view');
        }
        if (el.hasAttribute('data-calendar-date')) {
            config.date = el.getAttribute('data-calendar-date');
        }
        if (el.hasAttribute('data-calendar-first-day')) {
            config.firstDay = parseInt(el.getAttribute('data-calendar-first-day'), 10);
        }
        if (el.hasAttribute('data-calendar-editable')) {
            config.editable = el.getAttribute('data-calendar-editable') !== 'false';
        }
        if (el.hasAttribute('data-calendar-show-toolbar')) {
            config.showToolbar = el.getAttribute('data-calendar-show-toolbar') !== 'false';
        }
        if (el.hasAttribute('data-calendar-show-week-numbers')) {
            config.showWeekNumbers = el.getAttribute('data-calendar-show-week-numbers') === 'true';
        }
        if (el.hasAttribute('data-calendar-filter-key')) {
            config.filterKey = el.getAttribute('data-calendar-filter-key');
        }
        if (el.hasAttribute('data-calendar-events')) {
            try {
                config.events = JSON.parse(el.getAttribute('data-calendar-events'));
            } catch (e) {
                console.error('RSL Calendar: Invalid events JSON', e);
            }
        }
        if (el.hasAttribute('data-calendar-categories')) {
            try {
                config.categories = JSON.parse(el.getAttribute('data-calendar-categories'));
            } catch (e) {
                console.error('RSL Calendar: Invalid categories JSON', e);
            }
        }

        // Upcoming events configuration
        if (el.hasAttribute('data-calendar-upcoming')) {
            var upcomingMode = el.getAttribute('data-calendar-upcoming');
            if (Calendar.UPCOMING_MODES.includes(upcomingMode)) {
                config.upcoming = upcomingMode;
            }
        }
        if (el.hasAttribute('data-calendar-upcoming-count')) {
            config.upcomingCount = parseInt(el.getAttribute('data-calendar-upcoming-count'), 10) || 5;
        }
        if (el.hasAttribute('data-calendar-upcoming-days')) {
            config.upcomingDays = parseInt(el.getAttribute('data-calendar-upcoming-days'), 10) || 30;
        }
        if (el.hasAttribute('data-calendar-upcoming-title')) {
            config.upcomingTitle = el.getAttribute('data-calendar-upcoming-title');
        }

        return config;
    };

    /**
     * Get default categories
     */
    Calendar.prototype._getDefaultCategories = function() {
        return [
            { id: 'work', label: 'Work', color: '#4285f4' },
            { id: 'personal', label: 'Personal', color: '#0f9d58' },
            { id: 'holiday', label: 'Holiday', color: '#db4437' },
            { id: 'meeting', label: 'Meeting', color: '#f4b400' },
            { id: 'travel', label: 'Travel', color: '#ab47bc' },
            { id: 'health', label: 'Health', color: '#00acc1' }
        ];
    };

    /**
     * Initialize the calendar
     */
    Calendar.prototype._init = function() {
        this._buildDOM();
        this._bindEvents();
        this._setupFilterBus();
        this._render();
        this._announce('Calendar loaded. Showing ' + this._getViewLabel() + ' for ' + this._formatMonthYear());
    };

    /**
     * Build the DOM structure
     */
    Calendar.prototype._buildDOM = function() {
        var self = this;
        this.element.classList.add('rsl-calendar');
        this.element.setAttribute('data-view', this.config.view);

        // Set upcoming mode as data attribute for CSS
        if (this.config.upcoming !== 'none') {
            this.element.setAttribute('data-upcoming', this.config.upcoming);
        }

        // Create live region for announcements
        this.dom.liveRegion = document.createElement('div');
        this.dom.liveRegion.className = 'rsl-calendar-live-region';
        this.dom.liveRegion.setAttribute('role', 'status');
        this.dom.liveRegion.setAttribute('aria-live', 'polite');
        this.dom.liveRegion.setAttribute('aria-atomic', 'true');
        this.element.appendChild(this.dom.liveRegion);

        // Build toolbar (hide in "only" mode since there's no calendar to navigate)
        if (this.config.showToolbar && this.config.upcoming !== 'only') {
            this._buildToolbar();
        }

        // Create main content wrapper for sidebar layout
        if (this.config.upcoming === 'sidebar') {
            this.dom.mainWrapper = document.createElement('div');
            this.dom.mainWrapper.className = 'rsl-calendar-main-wrapper';
            this.element.appendChild(this.dom.mainWrapper);
        }

        // Build grid container (skip in "only" mode)
        if (this.config.upcoming !== 'only') {
            this.dom.grid = document.createElement('div');
            this.dom.grid.className = 'rsl-calendar-grid';
            this.dom.grid.setAttribute('role', 'application');
            this.dom.grid.setAttribute('aria-label', 'Calendar');

            if (this.config.upcoming === 'sidebar') {
                this.dom.mainWrapper.appendChild(this.dom.grid);
            } else {
                this.element.appendChild(this.dom.grid);
            }
        }

        // Build event panel
        if (this.config.editable) {
            this._buildEventPanel();
        }
    };

    /**
     * Build the toolbar
     */
    Calendar.prototype._buildToolbar = function() {
        var self = this;
        this.dom.toolbar = document.createElement('div');
        this.dom.toolbar.className = 'rsl-calendar-toolbar';

        // Navigation section
        var nav = document.createElement('div');
        nav.className = 'rsl-calendar-nav';

        // Previous button
        this.dom.prevBtn = this._createButton(this._getPrevButtonLabel(), 'rsl-calendar-btn rsl-calendar-btn-icon', function() {
            self._navigatePrev();
        });
        this.dom.prevBtn.innerHTML = '<svg viewBox="0 0 24 24"><path d="M15.41 7.41L14 6l-6 6 6 6 1.41-1.41L10.83 12z"/></svg>';
        nav.appendChild(this.dom.prevBtn);

        // Today button
        this.dom.todayBtn = this._createButton('Go to today', 'rsl-calendar-btn', function() {
            self._goToToday();
        });
        this.dom.todayBtn.textContent = 'Today';
        nav.appendChild(this.dom.todayBtn);

        // Next button
        this.dom.nextBtn = this._createButton(this._getNextButtonLabel(), 'rsl-calendar-btn rsl-calendar-btn-icon', function() {
            self._navigateNext();
        });
        this.dom.nextBtn.innerHTML = '<svg viewBox="0 0 24 24"><path d="M10 6L8.59 7.41 13.17 12l-4.58 4.59L10 18l6-6z"/></svg>';
        nav.appendChild(this.dom.nextBtn);

        // Title
        this.dom.title = document.createElement('h2');
        this.dom.title.className = 'rsl-calendar-title';
        this.dom.title.setAttribute('aria-live', 'polite');
        nav.appendChild(this.dom.title);

        this.dom.toolbar.appendChild(nav);

        // View switcher
        var views = document.createElement('div');
        views.className = 'rsl-calendar-views';
        views.setAttribute('role', 'group');
        views.setAttribute('aria-label', 'Calendar view');

        Calendar.VIEWS.forEach(function(view) {
            var btn = self._createButton(view.charAt(0).toUpperCase() + view.slice(1) + ' view', 'rsl-calendar-btn', function() {
                self._setView(view);
            });
            btn.textContent = view.charAt(0).toUpperCase() + view.slice(1);
            btn.setAttribute('aria-pressed', view === self.config.view ? 'true' : 'false');
            btn.setAttribute('data-view', view);
            views.appendChild(btn);
        });

        this.dom.views = views;
        this.dom.toolbar.appendChild(views);

        // Actions
        if (this.config.editable) {
            var actions = document.createElement('div');
            actions.className = 'rsl-calendar-actions';

            this.dom.addEventBtn = this._createButton('Add event', 'rsl-calendar-btn rsl-calendar-btn-primary', function() {
                self._openEventPanel();
            });
            this.dom.addEventBtn.innerHTML = '<svg viewBox="0 0 24 24" style="width:16px;height:16px;margin-right:4px;fill:currentColor"><path d="M19 13h-6v6h-2v-6H5v-2h6V5h2v6h6v2z"/></svg> Add Event';
            actions.appendChild(this.dom.addEventBtn);

            this.dom.toolbar.appendChild(actions);
        }

        this.element.insertBefore(this.dom.toolbar, this.element.firstChild);
    };

    /**
     * Build the event panel
     */
    Calendar.prototype._buildEventPanel = function() {
        var self = this;

        // Overlay
        this.dom.overlay = document.createElement('div');
        this.dom.overlay.className = 'rsl-calendar-overlay';
        this.dom.overlay.addEventListener('click', function() {
            self._closeEventPanel();
        });
        document.body.appendChild(this.dom.overlay);

        // Panel
        this.dom.panel = document.createElement('div');
        this.dom.panel.className = 'rsl-calendar-panel';
        this.dom.panel.setAttribute('role', 'dialog');
        this.dom.panel.setAttribute('aria-labelledby', 'rsl-calendar-panel-title');
        this.dom.panel.setAttribute('aria-modal', 'true');

        // Panel header
        var header = document.createElement('div');
        header.className = 'rsl-calendar-panel-header';

        this.dom.panelTitle = document.createElement('h3');
        this.dom.panelTitle.className = 'rsl-calendar-panel-title';
        this.dom.panelTitle.id = 'rsl-calendar-panel-title';
        this.dom.panelTitle.textContent = 'New Event';
        header.appendChild(this.dom.panelTitle);

        var closeBtn = this._createButton('Close', 'rsl-calendar-panel-close', function() {
            self._closeEventPanel();
        });
        closeBtn.innerHTML = '<svg viewBox="0 0 24 24" style="width:20px;height:20px;fill:currentColor"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>';
        header.appendChild(closeBtn);

        this.dom.panel.appendChild(header);

        // Panel body (form)
        var body = document.createElement('div');
        body.className = 'rsl-calendar-panel-body';

        body.innerHTML = this._getFormHTML();
        this.dom.panel.appendChild(body);

        // Panel footer
        var footer = document.createElement('div');
        footer.className = 'rsl-calendar-panel-footer';

        this.dom.deleteBtn = this._createButton('Delete event', 'rsl-calendar-btn rsl-calendar-btn-danger', function() {
            self._deleteEvent();
        });
        this.dom.deleteBtn.textContent = 'Delete';
        this.dom.deleteBtn.style.display = 'none';
        footer.appendChild(this.dom.deleteBtn);

        var cancelBtn = this._createButton('Cancel', 'rsl-calendar-btn', function() {
            self._closeEventPanel();
        });
        cancelBtn.textContent = 'Cancel';
        footer.appendChild(cancelBtn);

        this.dom.saveBtn = this._createButton('Save event', 'rsl-calendar-btn rsl-calendar-btn-primary', function() {
            self._saveEvent();
        });
        this.dom.saveBtn.textContent = 'Save Event';
        footer.appendChild(this.dom.saveBtn);

        this.dom.panel.appendChild(footer);
        document.body.appendChild(this.dom.panel);

        // Store form references (before date picker init transforms inputs)
        this.dom.form = {
            title: body.querySelector('#event-title'),
            startDate: body.querySelector('#event-start-date'),
            startTime: body.querySelector('#event-start-time'),
            endDate: body.querySelector('#event-end-date'),
            endTime: body.querySelector('#event-end-time'),
            category: body.querySelector('#event-category'),
            recurrence: body.querySelector('#event-recurrence'),
            description: body.querySelector('#event-description')
        };

        // Initialize RSL date pickers, time pickers, and select components
        this._initDatePickers();
        this._initTimePickers();
        this._initSelectComponents();
    };

    /**
     * Build the upcoming events section
     */
    Calendar.prototype._buildUpcomingEvents = function() {
        var self = this;

        // Remove existing upcoming section if present
        if (this.dom.upcoming) {
            this.dom.upcoming.remove();
        }

        // Don't build if mode is 'none'
        if (this.config.upcoming === 'none') {
            return;
        }

        var upcomingEvents = this._getUpcomingEvents();

        // Create upcoming events container
        this.dom.upcoming = document.createElement('aside');
        this.dom.upcoming.className = 'rsl-calendar-upcoming';
        this.dom.upcoming.setAttribute('aria-label', this.config.upcomingTitle);

        // Header with title
        var header = document.createElement('div');
        header.className = 'rsl-calendar-upcoming-header';

        var title = document.createElement('h3');
        title.className = 'rsl-calendar-upcoming-title';
        title.textContent = this.config.upcomingTitle;
        header.appendChild(title);

        // Event count badge
        var countBadge = document.createElement('span');
        countBadge.className = 'rsl-calendar-upcoming-count';
        countBadge.textContent = upcomingEvents.length;
        countBadge.setAttribute('aria-label', upcomingEvents.length + ' upcoming events');
        header.appendChild(countBadge);

        this.dom.upcoming.appendChild(header);

        // Events list
        var list = document.createElement('ul');
        list.className = 'rsl-calendar-upcoming-list';
        list.setAttribute('role', 'list');

        if (upcomingEvents.length === 0) {
            var emptyItem = document.createElement('li');
            emptyItem.className = 'rsl-calendar-upcoming-empty';
            emptyItem.innerHTML = '<span class="rsl-calendar-upcoming-empty-icon">📅</span>' +
                '<span class="rsl-calendar-upcoming-empty-text">No upcoming events</span>';
            list.appendChild(emptyItem);
        } else {
            upcomingEvents.forEach(function(event) {
                var item = self._createUpcomingEventItem(event);
                list.appendChild(item);
            });
        }

        this.dom.upcoming.appendChild(list);

        return this.dom.upcoming;
    };

    /**
     * Create an upcoming event list item
     */
    Calendar.prototype._createUpcomingEventItem = function(event) {
        var self = this;
        var item = document.createElement('li');
        item.className = 'rsl-calendar-upcoming-item';
        item.setAttribute('tabindex', '0');
        item.setAttribute('role', 'button');
        item.setAttribute('data-event-id', event.id);

        // Get category info
        var category = this.categories.find(function(c) { return c.id === event.category; });
        var categoryColor = category ? category.color : (event.color || '#1976d2');
        var categoryLabel = category ? category.label : (event.category || 'Event');

        // Parse date
        var startDate = new Date(event.start);
        var today = new Date();
        today.setHours(0, 0, 0, 0);

        var eventDay = new Date(startDate);
        eventDay.setHours(0, 0, 0, 0);

        // Determine relative date text
        var dateText;
        var diffDays = Math.floor((eventDay - today) / (1000 * 60 * 60 * 24));
        if (diffDays === 0) {
            dateText = 'Today';
        } else if (diffDays === 1) {
            dateText = 'Tomorrow';
        } else if (diffDays < 7) {
            dateText = startDate.toLocaleDateString(this.config.locale, { weekday: 'long' });
        } else {
            dateText = startDate.toLocaleDateString(this.config.locale, { month: 'short', day: 'numeric' });
        }

        // Format time
        var timeText = this._formatTime(startDate);

        // Build item HTML
        item.innerHTML = [
            '<div class="rsl-calendar-upcoming-item-indicator" style="background-color: ' + categoryColor + '"></div>',
            '<div class="rsl-calendar-upcoming-item-content">',
            '  <div class="rsl-calendar-upcoming-item-title">' + this._escapeHtml(event.title) + '</div>',
            '  <div class="rsl-calendar-upcoming-item-meta">',
            '    <span class="rsl-calendar-upcoming-item-date">' + dateText + '</span>',
            '    <span class="rsl-calendar-upcoming-item-time">' + timeText + '</span>',
            '  </div>',
            '  <div class="rsl-calendar-upcoming-item-category">' + this._escapeHtml(categoryLabel) + '</div>',
            '</div>'
        ].join('\n');

        // Build accessible label
        var ariaLabel = event.title + ', ' + dateText + ' at ' + timeText + ', ' + categoryLabel;
        item.setAttribute('aria-label', ariaLabel);

        // Click handler - navigate to event date
        item.addEventListener('click', function() {
            self._handleUpcomingEventClick(event);
        });

        item.addEventListener('keydown', function(e) {
            if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                self._handleUpcomingEventClick(event);
            }
        });

        return item;
    };

    /**
     * Handle click on an upcoming event item
     */
    Calendar.prototype._handleUpcomingEventClick = function(event) {
        var self = this;
        var eventDate = this._parseLocalDate(event.start.split('T')[0]);
        var targetEl = this.dom.upcoming.querySelector('[data-event-id="' + event.id + '"]');

        // If in "only" mode, show popover or edit panel (no calendar to navigate to)
        if (this.config.upcoming === 'only') {
            if (this.config.editable) {
                this._openEventPanel(event);
            } else if (targetEl) {
                this._showEventPopover(event, targetEl);
            }
        } else {
            // For "below" or "sidebar" mode
            if (this.config.editable) {
                // Navigate to the event's date in day view and open edit panel
                this.currentDate = new Date(eventDate);
                this.focusedDate = new Date(eventDate);
                this._setView('day');

                setTimeout(function() {
                    self._openEventPanel(event);
                }, 100);
            } else {
                // Read-only mode: show popover positioned at the clicked item
                if (targetEl) {
                    this._showEventPopover(event, targetEl);
                }
            }
        }

        this._announce('Selected event: ' + event.title);
    };

    /**
     * Build event detail popover (for read-only mode)
     */
    Calendar.prototype._buildEventPopover = function() {
        var self = this;

        this.dom.popover = document.createElement('div');
        this.dom.popover.className = 'rsl-calendar-event-popover';
        this.dom.popover.setAttribute('role', 'dialog');
        this.dom.popover.setAttribute('aria-labelledby', 'rsl-calendar-popover-title');

        document.body.appendChild(this.dom.popover);

        // Close popover when clicking outside
        document.addEventListener('click', function(e) {
            if (self.dom.popover &&
                self.dom.popover.classList.contains('visible') &&
                !self.dom.popover.contains(e.target) &&
                !e.target.closest('.rsl-calendar-event') &&
                !e.target.closest('.rsl-calendar-upcoming-item')) {
                self._closeEventPopover();
            }
        });

        // Close on Escape
        document.addEventListener('keydown', function(e) {
            if (e.key === 'Escape' && self.dom.popover && self.dom.popover.classList.contains('visible')) {
                self._closeEventPopover();
            }
        });

        // Close on scroll
        window.addEventListener('scroll', function() {
            if (self.dom.popover && self.dom.popover.classList.contains('visible')) {
                self._closeEventPopover();
            }
        }, true); // Use capture to catch all scroll events
    };

    /**
     * Show event detail popover
     */
    Calendar.prototype._showEventPopover = function(event, targetEl) {
        var self = this;

        // Build popover if not exists
        if (!this.dom.popover) {
            this._buildEventPopover();
        }

        // Get category info
        var category = this.categories.find(function(c) { return c.id === event.category; });
        var categoryLabel = category ? category.label : (event.category || 'Uncategorized');
        var categoryColor = category ? category.color : (event.color || '#1976d2');

        // Format date/time
        var startDate = event.start ? new Date(event.start) : null;
        var endDate = event.end ? new Date(event.end) : null;

        var dateStr = startDate ? this._formatFullDate(startDate) : '';
        var timeStr = '';
        if (startDate) {
            timeStr = this._formatTime(startDate);
            if (endDate) {
                timeStr += ' - ' + this._formatTime(endDate);
            }
        }

        // Build popover content
        var html = [
            '<div class="rsl-calendar-event-popover-header">',
            '  <h4 id="rsl-calendar-popover-title">' + this._escapeHtml(event.title) + '</h4>',
            '  <button class="rsl-calendar-event-popover-close" aria-label="Close">',
            '    <svg viewBox="0 0 24 24"><path d="M19 6.41L17.59 5 12 10.59 6.41 5 5 6.41 10.59 12 5 17.59 6.41 19 12 13.41 17.59 19 19 17.59 13.41 12z"/></svg>',
            '  </button>',
            '</div>',
            '<div class="rsl-calendar-event-popover-body">',
            '  <div class="rsl-calendar-event-popover-meta">'
        ];

        // Date row
        if (dateStr) {
            html.push(
                '    <div class="rsl-calendar-event-popover-row">',
                '      <svg viewBox="0 0 24 24"><path d="M19 4h-1V2h-2v2H8V2H6v2H5c-1.11 0-1.99.9-1.99 2L3 20a2 2 0 002 2h14c1.1 0 2-.9 2-2V6c0-1.1-.9-2-2-2zm0 16H5V9h14v11zM9 11H7v2h2v-2zm4 0h-2v2h2v-2zm4 0h-2v2h2v-2z"/></svg>',
                '      <span>' + dateStr + '</span>',
                '    </div>'
            );
        }

        // Time row
        if (timeStr) {
            html.push(
                '    <div class="rsl-calendar-event-popover-row">',
                '      <svg viewBox="0 0 24 24"><path d="M11.99 2C6.47 2 2 6.48 2 12s4.47 10 9.99 10C17.52 22 22 17.52 22 12S17.52 2 11.99 2zM12 20c-4.42 0-8-3.58-8-8s3.58-8 8-8 8 3.58 8 8-3.58 8-8 8zm.5-13H11v6l5.25 3.15.75-1.23-4.5-2.67z"/></svg>',
                '      <span>' + timeStr + '</span>',
                '    </div>'
            );
        }

        // Category row
        html.push(
            '    <div class="rsl-calendar-event-popover-row">',
            '      <svg viewBox="0 0 24 24"><path d="M17.63 5.84C17.27 5.33 16.67 5 16 5L5 5.01C3.9 5.01 3 5.9 3 7v10c0 1.1.9 1.99 2 1.99L16 19c.67 0 1.27-.33 1.63-.84L22 12l-4.37-6.16z"/></svg>',
            '      <span class="rsl-calendar-event-popover-category">',
            '        <span class="rsl-calendar-event-popover-category-dot" style="background:' + categoryColor + '"></span>',
            '        ' + this._escapeHtml(categoryLabel),
            '      </span>',
            '    </div>'
        );

        html.push('  </div>');

        // Description
        if (event.description) {
            html.push(
                '  <div class="rsl-calendar-event-popover-description">',
                '    <p>' + this._escapeHtml(event.description) + '</p>',
                '  </div>'
            );
        }

        html.push('</div>');

        this.dom.popover.innerHTML = html.join('\n');

        // Position popover near target element
        var rect = targetEl.getBoundingClientRect();
        var popoverWidth = 320;
        var popoverHeight = 200; // Approximate

        var left = rect.left + (rect.width / 2) - (popoverWidth / 2);
        var top = rect.bottom + 8;

        // Ensure it stays within viewport
        if (left < 10) left = 10;
        if (left + popoverWidth > window.innerWidth - 10) {
            left = window.innerWidth - popoverWidth - 10;
        }
        if (top + popoverHeight > window.innerHeight - 10) {
            top = rect.top - popoverHeight - 8;
        }

        this.dom.popover.style.left = left + 'px';
        this.dom.popover.style.top = top + 'px';

        // Show popover
        this.dom.popover.classList.add('visible');

        // Store trigger element for focus return
        this._popoverTrigger = targetEl;

        // Bind close button
        var closeBtn = this.dom.popover.querySelector('.rsl-calendar-event-popover-close');
        if (closeBtn) {
            closeBtn.addEventListener('click', function(e) {
                e.stopPropagation();
                self._closeEventPopover();
            });
        }

        // Add focus trapping within popover
        this._bindPopoverFocusTrap();

        // Focus close button for accessibility
        setTimeout(function() {
            if (closeBtn) closeBtn.focus();
        }, 100);

        // Announce to screen readers
        this._announce('Event details: ' + event.title);
    };

    /**
     * Bind focus trap within the event popover
     */
    Calendar.prototype._bindPopoverFocusTrap = function() {
        var self = this;
        var popover = this.dom.popover;

        // Remove any existing handler
        if (this._popoverKeydownHandler) {
            popover.removeEventListener('keydown', this._popoverKeydownHandler);
        }

        this._popoverKeydownHandler = function(e) {
            if (e.key !== 'Tab') return;

            var focusableElements = popover.querySelectorAll(
                'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
            );

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

            var firstEl = focusableElements[0];
            var lastEl = focusableElements[focusableElements.length - 1];

            if (e.shiftKey) {
                // Shift + Tab
                if (document.activeElement === firstEl) {
                    e.preventDefault();
                    lastEl.focus();
                }
            } else {
                // Tab
                if (document.activeElement === lastEl) {
                    e.preventDefault();
                    firstEl.focus();
                }
            }
        };

        popover.addEventListener('keydown', this._popoverKeydownHandler);
    };

    /**
     * Close event popover
     */
    Calendar.prototype._closeEventPopover = function() {
        if (this.dom.popover) {
            this.dom.popover.classList.remove('visible');

            // Return focus to trigger element
            if (this._popoverTrigger && typeof this._popoverTrigger.focus === 'function') {
                this._popoverTrigger.focus();
            }
            this._popoverTrigger = null;
        }
    };

    /**
     * Get form HTML
     */
    Calendar.prototype._getFormHTML = function() {
        var categoryOptions = this.categories.map(function(cat) {
            return '<option value="' + cat.id + '">' + cat.label + '</option>';
        }).join('');

        return [
            '<div class="rsl-calendar-form-group">',
            '  <label class="rsl-calendar-form-label" id="event-title-label">Event Title <span aria-hidden="true">*</span></label>',
            '  <input type="text" id="event-title" class="rsl-calendar-form-input" required aria-required="true" aria-labelledby="event-title-label" placeholder="Enter event title">',
            '</div>',
            '<div class="rsl-calendar-form-row">',
            '  <div class="rsl-calendar-form-group rsl-calendar-form-group-date">',
            '    <label class="rsl-calendar-form-label" id="event-start-date-label">Start Date <span aria-hidden="true">*</span></label>',
            '    <input type="text" id="event-start-date" data-rsl-date-picker data-mode="single" data-format="MM/DD/YYYY" data-output-format="YYYY-MM-DD" class="rsl-calendar-form-input" required aria-required="true" aria-labelledby="event-start-date-label" placeholder="Select date">',
            '  </div>',
            '  <div class="rsl-calendar-form-group">',
            '    <label class="rsl-calendar-form-label" id="event-start-time-label">Start Time</label>',
            '    <input type="text" id="event-start-time" data-rsl-time-picker data-format="12" data-placeholder="Select time" data-aria-label="Start time" class="rsl-calendar-form-input" aria-labelledby="event-start-time-label">',
            '  </div>',
            '</div>',
            '<div class="rsl-calendar-form-row">',
            '  <div class="rsl-calendar-form-group rsl-calendar-form-group-date">',
            '    <label class="rsl-calendar-form-label" id="event-end-date-label">End Date</label>',
            '    <input type="text" id="event-end-date" data-rsl-date-picker data-mode="single" data-format="MM/DD/YYYY" data-output-format="YYYY-MM-DD" class="rsl-calendar-form-input" aria-labelledby="event-end-date-label" placeholder="Select date">',
            '  </div>',
            '  <div class="rsl-calendar-form-group">',
            '    <label class="rsl-calendar-form-label" id="event-end-time-label">End Time</label>',
            '    <input type="text" id="event-end-time" data-rsl-time-picker data-format="12" data-placeholder="Select time" data-aria-label="End time" class="rsl-calendar-form-input" aria-labelledby="event-end-time-label">',
            '  </div>',
            '</div>',
            '<div class="rsl-calendar-form-row">',
            '  <div class="rsl-calendar-form-group">',
            '    <label class="rsl-calendar-form-label" id="event-category-label">Category</label>',
            '    <select id="event-category" data-rsl-select data-rsl-select-placeholder="Select category" aria-labelledby="event-category-label">',
            '      ' + categoryOptions,
            '    </select>',
            '  </div>',
            '  <div class="rsl-calendar-form-group">',
            '    <label class="rsl-calendar-form-label" id="event-recurrence-label">Recurrence</label>',
            '    <select id="event-recurrence" data-rsl-select data-rsl-select-placeholder="Select recurrence" aria-labelledby="event-recurrence-label">',
            '      <option value="">None</option>',
            '      <option value="daily">Daily</option>',
            '      <option value="weekly">Weekly</option>',
            '      <option value="monthly">Monthly</option>',
            '      <option value="yearly">Yearly</option>',
            '    </select>',
            '  </div>',
            '</div>',
            '<div class="rsl-calendar-form-group">',
            '  <label class="rsl-calendar-form-label" id="event-description-label">Description</label>',
            '  <textarea id="event-description" class="rsl-calendar-form-textarea" aria-labelledby="event-description-label" placeholder="Add event description (optional)"></textarea>',
            '</div>'
        ].join('\n');
    };

    /**
     * Initialize date pickers in the event panel
     */
    Calendar.prototype._initDatePickers = function() {
        if (!window.RSL || !window.RSL.DatePicker) {
            console.warn('RSL DatePicker component not available');
            return;
        }

        var panel = this.dom.panel;
        if (!panel) return;

        // Find date picker inputs in the panel
        var dateInputs = panel.querySelectorAll('[data-rsl-date-picker]');

        dateInputs.forEach(function(input) {
            // Create date picker instance for each input
            window.RSL.DatePicker.create(input);
        });

        // Store references to the date picker instances
        var startDateContainer = panel.querySelector('#event-start-date');
        var endDateContainer = panel.querySelector('#event-end-date');

        if (startDateContainer) {
            this._startDatePicker = window.RSL.DatePicker.instances.get(
                startDateContainer.closest('.rsl-date-picker') || startDateContainer
            );
        }
        if (endDateContainer) {
            this._endDatePicker = window.RSL.DatePicker.instances.get(
                endDateContainer.closest('.rsl-date-picker') || endDateContainer
            );
        }
    };

    /**
     * Initialize RSL Select components in the event panel
     */
    Calendar.prototype._initSelectComponents = function() {
        if (!window.RSL || !window.RSL.Select) {
            console.warn('RSL Select component not available');
            return;
        }

        var panel = this.dom.panel;
        if (!panel) return;

        // Find select elements in the panel
        var selectInputs = panel.querySelectorAll('[data-rsl-select]');

        selectInputs.forEach(function(select) {
            // Create select instance for each element
            window.RSL.Select.create(select);
        });
    };

    /**
     * Initialize RSL Time Picker components in the event panel
     */
    Calendar.prototype._initTimePickers = function() {
        if (!window.RSL || !window.RSL.TimePicker) {
            console.warn('RSL TimePicker component not available');
            return;
        }

        var panel = this.dom.panel;
        if (!panel) return;

        // Find time picker inputs in the panel
        var timeInputs = panel.querySelectorAll('[data-rsl-time-picker]');

        timeInputs.forEach(function(input) {
            // Create time picker instance for each input
            window.RSL.TimePicker.create(input);
        });

        // Store references to the time picker instances
        var startTimeInput = panel.querySelector('#event-start-time');
        var endTimeInput = panel.querySelector('#event-end-time');

        if (startTimeInput) {
            this._startTimePicker = window.RSL.TimePicker.instances.get(startTimeInput);
        }
        if (endTimeInput) {
            this._endTimePicker = window.RSL.TimePicker.instances.get(endTimeInput);
        }
    };

    /**
     * Set RSL Time Picker value
     */
    Calendar.prototype._setTimePickerValue = function(which, value) {
        var timeInput = this.dom.form[which + 'Time'];
        if (!timeInput) return;

        if (window.RSL && window.RSL.TimePicker) {
            window.RSL.TimePicker.setValue(timeInput, value);
        } else {
            // Fallback to native input
            timeInput.value = value;
        }
    };

    /**
     * Get RSL Time Picker value
     */
    Calendar.prototype._getTimePickerValue = function(which) {
        var timeInput = this.dom.form[which + 'Time'];
        if (!timeInput) return '';

        if (window.RSL && window.RSL.TimePicker) {
            return window.RSL.TimePicker.getValue(timeInput) || '';
        } else {
            // Fallback to native input
            return timeInput.value || '';
        }
    };

    /**
     * Set RSL Select value
     */
    Calendar.prototype._setSelectValue = function(selectEl, value) {
        if (window.RSL && window.RSL.Select) {
            window.RSL.Select.setValue(selectEl, value);
        } else {
            // Fallback to native select
            selectEl.value = value;
        }
    };

    /**
     * Get RSL Select value
     */
    Calendar.prototype._getSelectValue = function(selectEl) {
        if (window.RSL && window.RSL.Select) {
            var values = window.RSL.Select.getValue(selectEl);
            return values && values.length > 0 ? values[0] : '';
        } else {
            // Fallback to native select
            return selectEl.value;
        }
    };

    /**
     * Create a button element
     */
    Calendar.prototype._createButton = function(label, className, onClick) {
        var btn = document.createElement('button');
        btn.type = 'button';
        btn.className = className;
        btn.setAttribute('aria-label', label);
        btn.addEventListener('click', onClick);
        return btn;
    };

    /**
     * Bind event listeners
     */
    Calendar.prototype._bindEvents = function() {
        var self = this;

        // Keyboard navigation
        this.element.addEventListener('keydown', function(e) {
            self._handleKeydown(e);
        });

        // Window resize - debounced to avoid excessive re-renders
        this._lastWidth = window.innerWidth;
        this._resizeTimeout = null;
        this._resizeHandler = function() {
            clearTimeout(self._resizeTimeout);
            self._resizeTimeout = setTimeout(function() {
                // Only re-render if we crossed a breakpoint
                var newWidth = window.innerWidth;
                var breakpoints = [400, 576, 768, 1024];
                var crossedBreakpoint = false;

                for (var i = 0; i < breakpoints.length; i++) {
                    var bp = breakpoints[i];
                    if ((self._lastWidth <= bp && newWidth > bp) ||
                        (self._lastWidth > bp && newWidth <= bp)) {
                        crossedBreakpoint = true;
                        break;
                    }
                }

                if (crossedBreakpoint) {
                    self._lastWidth = newWidth;
                    self._render();
                }
            }, 150);
        };
        window.addEventListener('resize', this._resizeHandler);
    };

    /**
     * Setup FilterBus integration
     */
    Calendar.prototype._setupFilterBus = function() {
        var self = this;
        if (this.config.filterKey && window.RSL && window.RSL.FilterBus) {
            window.RSL.FilterBus.subscribe('rsl-calendar-' + this._generateId(), function(state) {
                var category = state[self.config.filterKey];
                self.filteredCategory = category === 'all' ? null : category;
                self._render();
            }, { keys: [this.config.filterKey] });
        }
    };

    /**
     * Render the calendar based on current view
     */
    Calendar.prototype._render = function() {
        this._updateTitle();
        this.element.setAttribute('data-view', this.config.view);

        // Render calendar view (unless in "only" mode)
        if (this.config.upcoming !== 'only') {
            switch (this.config.view) {
                case 'day':
                    this._renderDayView();
                    break;
                case 'week':
                    this._renderWeekView();
                    break;
                case 'year':
                    this._renderYearView();
                    break;
                case 'month':
                default:
                    this._renderMonthView();
            }
        }

        // Render upcoming events section
        this._renderUpcomingEvents();
    };

    /**
     * Render the upcoming events section based on mode
     */
    Calendar.prototype._renderUpcomingEvents = function() {
        // Skip if mode is 'none'
        if (this.config.upcoming === 'none') {
            return;
        }

        // Build or rebuild the upcoming events section
        this._buildUpcomingEvents();

        if (!this.dom.upcoming) {
            return;
        }

        // Place according to mode
        switch (this.config.upcoming) {
            case 'below':
                // Insert after the grid
                if (this.dom.grid && this.dom.grid.parentNode) {
                    this.dom.grid.parentNode.insertBefore(
                        this.dom.upcoming,
                        this.dom.grid.nextSibling
                    );
                }
                break;

            case 'sidebar':
                // Insert into the main wrapper alongside the grid
                if (this.dom.mainWrapper) {
                    this.dom.mainWrapper.appendChild(this.dom.upcoming);
                }
                break;

            case 'only':
                // Just the upcoming section, append to element
                this.element.appendChild(this.dom.upcoming);
                break;
        }
    };

    /**
     * Update the title
     */
    Calendar.prototype._updateTitle = function() {
        if (!this.dom.title) return;

        var text = '';
        switch (this.config.view) {
            case 'day':
                text = this._formatFullDate(this.currentDate);
                break;
            case 'week':
                var weekStart = this._getWeekStart(this.currentDate);
                var weekEnd = new Date(weekStart);
                weekEnd.setDate(weekEnd.getDate() + 6);
                text = this._formatDateRange(weekStart, weekEnd);
                break;
            case 'year':
                text = this.currentDate.getFullYear();
                break;
            case 'month':
            default:
                text = this._formatMonthYear();
        }

        this.dom.title.textContent = text;
    };

    /**
     * Render month view
     */
    Calendar.prototype._renderMonthView = function() {
        var self = this;
        var grid = this.dom.grid;
        grid.innerHTML = '';

        // Header
        var header = document.createElement('div');
        header.className = 'rsl-calendar-header';
        header.setAttribute('role', 'row');

        var dayNames = this._getDayNames();
        dayNames.forEach(function(name, index) {
            var cell = document.createElement('div');
            cell.className = 'rsl-calendar-header-cell';
            cell.setAttribute('role', 'columnheader');
            cell.textContent = name;
            if (index === 0 || index === 6) {
                cell.classList.add('weekend');
            }
            header.appendChild(cell);
        });
        grid.appendChild(header);

        // Body
        var body = document.createElement('div');
        body.className = 'rsl-calendar-body';
        body.setAttribute('role', 'grid');
        body.setAttribute('aria-label', 'Calendar for ' + this._formatMonthYear());

        var days = this._getMonthDays();
        var today = new Date();
        today.setHours(0, 0, 0, 0);

        days.forEach(function(day, index) {
            var cell = self._createMonthCell(day, today);
            body.appendChild(cell);
        });

        grid.appendChild(body);
    };

    /**
     * Create a month view cell
     */
    Calendar.prototype._createMonthCell = function(day, today) {
        var self = this;
        var cell = document.createElement('div');
        cell.className = 'rsl-calendar-cell';
        cell.setAttribute('role', 'gridcell');
        cell.setAttribute('tabindex', this._isSameDay(day, this.focusedDate) ? '0' : '-1');
        cell.setAttribute('data-date', this._formatISO(day));
        cell.setAttribute('aria-label', this._formatFullDate(day));

        // Determine cell state
        if (!this._isSameMonth(day, this.currentDate)) {
            cell.classList.add('outside-month');
        }

        if (this._isSameDay(day, today)) {
            cell.setAttribute('aria-current', 'date');
        }

        if (this.selectedDate && this._isSameDay(day, this.selectedDate)) {
            cell.setAttribute('aria-selected', 'true');
        }

        var dayOfWeek = day.getDay();
        if (dayOfWeek === 0 || dayOfWeek === 6) {
            cell.classList.add('weekend');
        }

        // Day number
        var dayNumber = document.createElement('span');
        dayNumber.className = 'rsl-calendar-day-number';
        dayNumber.textContent = day.getDate();
        cell.appendChild(dayNumber);

        // Events for this day
        var dayEvents = this._getEventsForDate(day);
        if (dayEvents.length > 0) {
            var eventsContainer = document.createElement('div');
            eventsContainer.className = 'rsl-calendar-events';

            var maxVisible = 3;
            dayEvents.slice(0, maxVisible).forEach(function(event) {
                var eventEl = self._createEventElement(event);
                eventsContainer.appendChild(eventEl);
            });

            if (dayEvents.length > maxVisible) {
                var more = document.createElement('div');
                more.className = 'rsl-calendar-event-more';
                more.textContent = '+' + (dayEvents.length - maxVisible) + ' more';
                more.setAttribute('role', 'button');
                more.setAttribute('tabindex', '0');
                more.addEventListener('click', function(e) {
                    e.stopPropagation();
                    self._setView('day');
                    self.currentDate = new Date(day);
                    self._render();
                });
                eventsContainer.appendChild(more);
            }

            cell.appendChild(eventsContainer);
        }

        // Click handler
        cell.addEventListener('click', function(e) {
            // Don't open panel if clicking on an event (events have their own click handler)
            if (e.target.closest('.rsl-calendar-event')) return;

            self._selectDate(day);
            if (self.config.editable) {
                self._openEventPanel(null, day);
            }
        });

        return cell;
    };

    /**
     * Create an event element
     */
    Calendar.prototype._createEventElement = function(event) {
        var self = this;
        var el = document.createElement('div');
        el.className = 'rsl-calendar-event';
        el.setAttribute('role', 'button');
        el.setAttribute('tabindex', '0');
        el.setAttribute('data-event-id', event.id);
        el.setAttribute('data-category', event.category || 'work');

        if (event.color) {
            el.style.backgroundColor = event.color;
        }

        var time = '';
        var eventDate = null;
        if (event.start) {
            var startDate = new Date(event.start);
            eventDate = startDate;
            time = this._formatTime(startDate);
        }

        el.innerHTML = (time ? '<span class="rsl-calendar-event-time">' + time + '</span>' : '') +
                       '<span class="rsl-calendar-event-title">' + this._escapeHtml(event.title) + '</span>';

        // Build accessible label with full date, time, and description
        var ariaLabel = event.title;
        if (eventDate) {
            ariaLabel += ', ' + this._formatFullDate(eventDate);
            if (time) {
                ariaLabel += ' at ' + time;
            }
        }
        if (event.description) {
            ariaLabel += '. ' + event.description;
        }
        el.setAttribute('aria-label', ariaLabel);

        // Click handler - edit panel if editable, otherwise show detail popover
        el.addEventListener('click', function(e) {
            e.stopPropagation();
            if (self.config.editable) {
                self._openEventPanel(event);
            } else {
                self._showEventPopover(event, el);
            }
        });

        el.addEventListener('keydown', function(e) {
            if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                e.stopPropagation();
                if (self.config.editable) {
                    self._openEventPanel(event);
                } else {
                    self._showEventPopover(event, el);
                }
            }
        });

        return el;
    };

    /**
     * Render week view
     */
    Calendar.prototype._renderWeekView = function() {
        var self = this;
        var grid = this.dom.grid;
        grid.innerHTML = '';

        var weekStart = this._getWeekStart(this.currentDate);
        var today = new Date();
        today.setHours(0, 0, 0, 0);

        // Header
        var header = document.createElement('div');
        header.className = 'rsl-calendar-header';
        header.setAttribute('role', 'row');

        // Time gutter header
        var gutterHeader = document.createElement('div');
        gutterHeader.className = 'rsl-calendar-header-cell rsl-calendar-time-gutter';
        header.appendChild(gutterHeader);

        // Day headers
        var dayNames = this._getDayNames();
        for (var d = 0; d < 7; d++) {
            var day = new Date(weekStart);
            day.setDate(day.getDate() + d);

            var cell = document.createElement('div');
            cell.className = 'rsl-calendar-header-cell';
            cell.setAttribute('role', 'columnheader');

            if (this._isSameDay(day, today)) {
                cell.setAttribute('aria-current', 'date');
            }

            cell.innerHTML = '<span class="day-name">' + dayNames[d] + '</span>' +
                            '<span class="day-number">' + day.getDate() + '</span>';

            header.appendChild(cell);
        }
        grid.appendChild(header);

        // Week grid
        var weekGrid = document.createElement('div');
        weekGrid.className = 'rsl-calendar-week-grid';

        // Time gutter
        var timeGutter = document.createElement('div');
        timeGutter.className = 'rsl-calendar-time-gutter';

        for (var h = this.config.minHour; h <= this.config.maxHour; h++) {
            var slot = document.createElement('div');
            slot.className = 'rsl-calendar-time-slot';
            slot.textContent = this._formatHour(h);
            timeGutter.appendChild(slot);
        }
        weekGrid.appendChild(timeGutter);

        // Day columns
        for (var d = 0; d < 7; d++) {
            var day = new Date(weekStart);
            day.setDate(day.getDate() + d);

            var column = document.createElement('div');
            column.className = 'rsl-calendar-week-column';
            column.setAttribute('data-date', this._formatISO(day));

            // Hour cells
            for (var h = this.config.minHour; h <= this.config.maxHour; h++) {
                var cell = document.createElement('div');
                cell.className = 'rsl-calendar-week-cell';
                cell.setAttribute('data-hour', h);
                cell.setAttribute('tabindex', '-1');

                cell.addEventListener('click', (function(currentDay, hour) {
                    return function() {
                        var date = new Date(currentDay);
                        date.setHours(hour, 0, 0, 0);
                        self._selectDate(date);
                        if (self.config.editable) {
                            self._openEventPanel(null, date);
                        }
                    };
                })(day, h));

                column.appendChild(cell);
            }

            // Render events for this day
            var dayEvents = this._getEventsForDate(day);
            dayEvents.forEach(function(event) {
                self._renderWeekEvent(column, event, day);
            });

            // Current time indicator
            if (this._isSameDay(day, today)) {
                this._renderCurrentTimeIndicator(column);
            }

            weekGrid.appendChild(column);
        }

        grid.appendChild(weekGrid);
    };

    /**
     * Render an event in week view
     */
    Calendar.prototype._renderWeekEvent = function(column, event, day) {
        var self = this;
        var startDate = new Date(event.start);
        var endDate = event.end ? new Date(event.end) : new Date(startDate.getTime() + 60 * 60 * 1000);

        var startHour = startDate.getHours() + startDate.getMinutes() / 60;
        var endHour = endDate.getHours() + endDate.getMinutes() / 60;

        // Clamp to visible range
        startHour = Math.max(startHour, this.config.minHour);
        endHour = Math.min(endHour, this.config.maxHour + 1);

        if (startHour >= endHour) return;

        var cellHeight = this.config.view === 'week' ? 60 : 60;
        var top = (startHour - this.config.minHour) * cellHeight;
        var height = (endHour - startHour) * cellHeight;

        var el = document.createElement('div');
        el.className = 'rsl-calendar-week-event';
        el.setAttribute('role', 'button');
        el.setAttribute('tabindex', '0');
        el.setAttribute('data-event-id', event.id);
        el.setAttribute('data-category', event.category || 'work');
        el.style.top = top + 'px';
        el.style.height = Math.max(height - 4, 20) + 'px';

        if (event.color) {
            el.style.backgroundColor = event.color;
        }

        el.innerHTML = '<div class="rsl-calendar-week-event-title">' + this._escapeHtml(event.title) + '</div>' +
                      '<div class="rsl-calendar-week-event-time">' + this._formatTime(startDate) + ' - ' + this._formatTime(endDate) + '</div>';

        // Build accessible label with full date, time range, and description
        var ariaLabel = event.title + ', ' + this._formatFullDate(startDate) + ', from ' + this._formatTime(startDate) + ' to ' + this._formatTime(endDate);
        if (event.description) {
            ariaLabel += '. ' + event.description;
        }
        el.setAttribute('aria-label', ariaLabel);

        el.addEventListener('click', function(e) {
            e.stopPropagation();
            if (self.config.editable) {
                self._openEventPanel(event);
            } else {
                self._showEventPopover(event, el);
            }
        });

        el.addEventListener('keydown', function(e) {
            if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                if (self.config.editable) {
                    self._openEventPanel(event);
                } else {
                    self._showEventPopover(event, el);
                }
            }
        });

        column.appendChild(el);
    };

    /**
     * Render current time indicator
     */
    Calendar.prototype._renderCurrentTimeIndicator = function(column) {
        var now = new Date();
        var currentHour = now.getHours() + now.getMinutes() / 60;

        if (currentHour < this.config.minHour || currentHour > this.config.maxHour) return;

        var cellHeight = 60;
        var top = (currentHour - this.config.minHour) * cellHeight;

        var indicator = document.createElement('div');
        indicator.className = 'rsl-calendar-current-time';
        indicator.style.top = top + 'px';
        indicator.setAttribute('aria-hidden', 'true');

        column.appendChild(indicator);
    };

    /**
     * Render day view
     */
    Calendar.prototype._renderDayView = function() {
        var self = this;
        var grid = this.dom.grid;
        grid.innerHTML = '';

        var today = new Date();
        today.setHours(0, 0, 0, 0);

        // Header
        var header = document.createElement('div');
        header.className = 'rsl-calendar-header';
        header.setAttribute('role', 'row');

        // Time gutter header
        var gutterHeader = document.createElement('div');
        gutterHeader.className = 'rsl-calendar-header-cell rsl-calendar-time-gutter';
        header.appendChild(gutterHeader);

        // Day header
        var dayHeader = document.createElement('div');
        dayHeader.className = 'rsl-calendar-header-cell';
        dayHeader.setAttribute('role', 'columnheader');
        dayHeader.innerHTML = '<span class="day-full">' + this._formatFullDate(this.currentDate) + '</span>';

        if (this._isSameDay(this.currentDate, today)) {
            dayHeader.setAttribute('aria-current', 'date');
        }

        header.appendChild(dayHeader);
        grid.appendChild(header);

        // Day grid
        var dayGrid = document.createElement('div');
        dayGrid.className = 'rsl-calendar-day-grid';

        // Time gutter
        var timeGutter = document.createElement('div');
        timeGutter.className = 'rsl-calendar-time-gutter';

        for (var h = this.config.minHour; h <= this.config.maxHour; h++) {
            var slot = document.createElement('div');
            slot.className = 'rsl-calendar-time-slot';
            slot.textContent = this._formatHour(h);
            timeGutter.appendChild(slot);
        }
        dayGrid.appendChild(timeGutter);

        // Day column
        var column = document.createElement('div');
        column.className = 'rsl-calendar-day-column';
        column.setAttribute('data-date', this._formatISO(this.currentDate));

        // Hour cells
        for (var h = this.config.minHour; h <= this.config.maxHour; h++) {
            var cell = document.createElement('div');
            cell.className = 'rsl-calendar-day-cell';
            cell.setAttribute('data-hour', h);
            cell.setAttribute('tabindex', '-1');

            cell.addEventListener('click', (function(hour) {
                return function() {
                    var date = new Date(self.currentDate);
                    date.setHours(hour, 0, 0, 0);
                    self._selectDate(date);
                    if (self.config.editable) {
                        self._openEventPanel(null, date);
                    }
                };
            })(h));

            column.appendChild(cell);
        }

        // Render events
        var dayEvents = this._getEventsForDate(this.currentDate);
        dayEvents.forEach(function(event) {
            self._renderDayEvent(column, event);
        });

        // Current time indicator
        if (this._isSameDay(this.currentDate, today)) {
            this._renderCurrentTimeIndicator(column);
        }

        dayGrid.appendChild(column);
        grid.appendChild(dayGrid);
    };

    /**
     * Render an event in day view
     */
    Calendar.prototype._renderDayEvent = function(column, event) {
        var self = this;
        var startDate = new Date(event.start);
        var endDate = event.end ? new Date(event.end) : new Date(startDate.getTime() + 60 * 60 * 1000);

        var startHour = startDate.getHours() + startDate.getMinutes() / 60;
        var endHour = endDate.getHours() + endDate.getMinutes() / 60;

        // Clamp to visible range
        startHour = Math.max(startHour, this.config.minHour);
        endHour = Math.min(endHour, this.config.maxHour + 1);

        if (startHour >= endHour) return;

        var cellHeight = 60;
        var top = (startHour - this.config.minHour) * cellHeight;
        var height = (endHour - startHour) * cellHeight;

        var el = document.createElement('div');
        el.className = 'rsl-calendar-day-event';
        el.setAttribute('role', 'button');
        el.setAttribute('tabindex', '0');
        el.setAttribute('data-event-id', event.id);
        el.setAttribute('data-category', event.category || 'work');
        el.style.top = top + 'px';
        el.style.height = Math.max(height - 4, 40) + 'px';

        if (event.color) {
            el.style.backgroundColor = event.color;
        }

        el.innerHTML = '<div class="rsl-calendar-day-event-title">' + this._escapeHtml(event.title) + '</div>' +
                      '<div class="rsl-calendar-day-event-time">' + this._formatTime(startDate) + ' - ' + this._formatTime(endDate) + '</div>' +
                      (event.description ? '<div class="rsl-calendar-day-event-description">' + this._escapeHtml(event.description) + '</div>' : '');

        // Build accessible label with full date, time range, and description
        var ariaLabel = event.title + ', ' + this._formatFullDate(startDate) + ', from ' + this._formatTime(startDate) + ' to ' + this._formatTime(endDate);
        if (event.description) {
            ariaLabel += '. ' + event.description;
        }
        el.setAttribute('aria-label', ariaLabel);

        el.addEventListener('click', function(e) {
            e.stopPropagation();
            if (self.config.editable) {
                self._openEventPanel(event);
            } else {
                self._showEventPopover(event, el);
            }
        });

        el.addEventListener('keydown', function(e) {
            if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                if (self.config.editable) {
                    self._openEventPanel(event);
                } else {
                    self._showEventPopover(event, el);
                }
            }
        });

        column.appendChild(el);
    };

    /**
     * Render year view
     */
    Calendar.prototype._renderYearView = function() {
        var self = this;
        var grid = this.dom.grid;
        grid.innerHTML = '';

        var year = this.currentDate.getFullYear();
        var today = new Date();
        today.setHours(0, 0, 0, 0);

        for (var m = 0; m < 12; m++) {
            var miniMonth = this._createMiniMonth(year, m, today);
            grid.appendChild(miniMonth);
        }
    };

    /**
     * Create a mini month for year view
     */
    Calendar.prototype._createMiniMonth = function(year, month, today) {
        var self = this;
        var container = document.createElement('div');
        container.className = 'rsl-calendar-mini-month';

        // Header
        var header = document.createElement('div');
        header.className = 'rsl-calendar-mini-month-header';
        header.setAttribute('role', 'button');
        header.setAttribute('tabindex', '0');
        header.textContent = new Date(year, month, 1).toLocaleString(this.config.locale, { month: 'long' });

        header.addEventListener('click', function() {
            self.currentDate = new Date(year, month, 1);
            self._setView('month');
        });

        header.addEventListener('keydown', function(e) {
            if (e.key === 'Enter' || e.key === ' ') {
                e.preventDefault();
                self.currentDate = new Date(year, month, 1);
                self._setView('month');
            }
        });

        container.appendChild(header);

        // Mini grid
        var miniGrid = document.createElement('div');
        miniGrid.className = 'rsl-calendar-mini-grid';

        // Day headers
        var dayNames = this._getDayNames(true);
        dayNames.forEach(function(name) {
            var headerCell = document.createElement('div');
            headerCell.className = 'rsl-calendar-mini-header';
            headerCell.textContent = name;
            miniGrid.appendChild(headerCell);
        });

        // Days
        var firstDay = new Date(year, month, 1);
        var startDay = firstDay.getDay() - this.config.firstDay;
        if (startDay < 0) startDay += 7;

        var daysInMonth = new Date(year, month + 1, 0).getDate();

        // Previous month days
        for (var i = 0; i < startDay; i++) {
            var prevDay = document.createElement('div');
            prevDay.className = 'rsl-calendar-mini-day outside';
            miniGrid.appendChild(prevDay);
        }

        // Current month days
        for (var d = 1; d <= daysInMonth; d++) {
            var day = new Date(year, month, d);
            var dayEl = document.createElement('div');
            dayEl.className = 'rsl-calendar-mini-day';
            dayEl.setAttribute('tabindex', '-1');
            dayEl.textContent = d;

            if (this._isSameDay(day, today)) {
                dayEl.classList.add('today');
            }

            var dayEvents = this._getEventsForDate(day);
            if (dayEvents.length > 0) {
                dayEl.classList.add('has-events');
            }

            dayEl.addEventListener('click', (function(currentDay) {
                return function() {
                    self.currentDate = new Date(currentDay);
                    self._setView('day');
                };
            })(day));

            miniGrid.appendChild(dayEl);
        }

        container.appendChild(miniGrid);
        return container;
    };

    /**
     * Handle keyboard navigation
     */
    Calendar.prototype._handleKeydown = function(e) {
        var key = e.key;
        var handled = false;

        // Panel navigation
        if (this.panelOpen) {
            if (key === 'Escape') {
                this._closeEventPanel();
                handled = true;
            }
            return;
        }

        // Grid navigation
        switch (key) {
            case 'ArrowLeft':
                this._navigateFocus(-1);
                handled = true;
                break;
            case 'ArrowRight':
                this._navigateFocus(1);
                handled = true;
                break;
            case 'ArrowUp':
                this._navigateFocus(-7);
                handled = true;
                break;
            case 'ArrowDown':
                this._navigateFocus(7);
                handled = true;
                break;
            case 'PageUp':
                if (e.shiftKey) {
                    this._navigateYear(-1);
                } else {
                    this._navigatePrev();
                }
                handled = true;
                break;
            case 'PageDown':
                if (e.shiftKey) {
                    this._navigateYear(1);
                } else {
                    this._navigateNext();
                }
                handled = true;
                break;
            case 'Home':
                this._goToToday();
                handled = true;
                break;
            case 'Enter':
            case ' ':
                // Only handle Enter/Space if focus is on a calendar cell, not on toolbar buttons
                var activeElement = document.activeElement;
                var isToolbarButton = activeElement && (
                    activeElement.closest('.rsl-calendar-toolbar') ||
                    activeElement.closest('.rsl-calendar-nav') ||
                    activeElement.closest('.rsl-calendar-views') ||
                    activeElement.closest('.rsl-calendar-actions')
                );

                if (!isToolbarButton) {
                    var focused = this.element.querySelector('[tabindex="0"][data-date]');
                    if (focused && document.activeElement === focused) {
                        var date = this._parseLocalDate(focused.getAttribute('data-date'));
                        this._selectDate(date);
                        if (this.config.editable) {
                            this._openEventPanel(null, date);
                        }
                        handled = true;
                    }
                }
                break;
        }

        if (handled) {
            e.preventDefault();
            e.stopPropagation();
        }
    };

    /**
     * Navigate focus by delta days
     */
    Calendar.prototype._navigateFocus = function(delta) {
        this.focusedDate.setDate(this.focusedDate.getDate() + delta);

        // If moved to different month/week, update view
        if (this.config.view === 'month' && !this._isSameMonth(this.focusedDate, this.currentDate)) {
            this.currentDate = new Date(this.focusedDate);
            this._render();
        } else if (this.config.view === 'week') {
            var weekStart = this._getWeekStart(this.currentDate);
            var weekEnd = new Date(weekStart);
            weekEnd.setDate(weekEnd.getDate() + 6);
            if (this.focusedDate < weekStart || this.focusedDate > weekEnd) {
                this.currentDate = new Date(this.focusedDate);
                this._render();
            }
        }

        this._updateFocus();
    };

    /**
     * Update focus on the grid
     */
    Calendar.prototype._updateFocus = function() {
        // Remove tabindex from all cells
        var cells = this.element.querySelectorAll('[data-date]');
        cells.forEach(function(cell) {
            cell.setAttribute('tabindex', '-1');
        });

        // Set tabindex on focused cell
        var focusedCell = this.element.querySelector('[data-date="' + this._formatISO(this.focusedDate) + '"]');
        if (focusedCell) {
            focusedCell.setAttribute('tabindex', '0');
            focusedCell.focus();
        }
    };

    /**
     * Navigate to previous period
     */
    Calendar.prototype._navigatePrev = function() {
        switch (this.config.view) {
            case 'day':
                this.currentDate.setDate(this.currentDate.getDate() - 1);
                break;
            case 'week':
                this.currentDate.setDate(this.currentDate.getDate() - 7);
                break;
            case 'year':
                this.currentDate.setFullYear(this.currentDate.getFullYear() - 1);
                break;
            case 'month':
            default:
                this.currentDate.setMonth(this.currentDate.getMonth() - 1);
        }
        this.focusedDate = new Date(this.currentDate);
        this._render();
        this._announce('Showing ' + this._getViewLabel() + ' for ' + this.dom.title.textContent);
    };

    /**
     * Navigate to next period
     */
    Calendar.prototype._navigateNext = function() {
        switch (this.config.view) {
            case 'day':
                this.currentDate.setDate(this.currentDate.getDate() + 1);
                break;
            case 'week':
                this.currentDate.setDate(this.currentDate.getDate() + 7);
                break;
            case 'year':
                this.currentDate.setFullYear(this.currentDate.getFullYear() + 1);
                break;
            case 'month':
            default:
                this.currentDate.setMonth(this.currentDate.getMonth() + 1);
        }
        this.focusedDate = new Date(this.currentDate);
        this._render();
        this._announce('Showing ' + this._getViewLabel() + ' for ' + this.dom.title.textContent);
    };

    /**
     * Navigate by year
     */
    Calendar.prototype._navigateYear = function(delta) {
        this.currentDate.setFullYear(this.currentDate.getFullYear() + delta);
        this.focusedDate = new Date(this.currentDate);
        this._render();
        this._announce('Showing ' + this.dom.title.textContent);
    };

    /**
     * Go to today
     */
    Calendar.prototype._goToToday = function() {
        this.currentDate = new Date();
        this.focusedDate = new Date();
        this._render();
        this._announce('Showing today, ' + this._formatFullDate(this.currentDate));
    };

    /**
     * Set the view
     */
    Calendar.prototype._setView = function(view) {
        if (!Calendar.VIEWS.includes(view)) return;

        this.config.view = view;

        // Update view buttons
        if (this.dom.views) {
            var buttons = this.dom.views.querySelectorAll('[data-view]');
            buttons.forEach(function(btn) {
                btn.setAttribute('aria-pressed', btn.getAttribute('data-view') === view ? 'true' : 'false');
            });
        }

        // Update navigation button labels for new view
        this._updateNavButtonLabels();

        this._render();
        this._announce('Switched to ' + this._getViewLabel());
    };

    /**
     * Select a date
     */
    Calendar.prototype._selectDate = function(date) {
        this.selectedDate = new Date(date);
        this.focusedDate = new Date(date);

        // Update selection styling
        var cells = this.element.querySelectorAll('[data-date]');
        cells.forEach(function(cell) {
            cell.setAttribute('aria-selected', 'false');
        });

        var selectedCell = this.element.querySelector('[data-date="' + this._formatISO(date) + '"]');
        if (selectedCell) {
            selectedCell.setAttribute('aria-selected', 'true');
        }

        // Dispatch custom event
        this.element.dispatchEvent(new CustomEvent('rsl-calendar-select', {
            detail: { date: this.selectedDate },
            bubbles: true
        }));
    };

    /**
     * Open event panel
     */
    Calendar.prototype._openEventPanel = function(event, defaultDate) {
        if (!this.config.editable) return;

        this.editingEvent = event;
        this.panelOpen = true;

        // Update panel title
        this.dom.panelTitle.textContent = event ? 'Edit Event' : 'New Event';
        this.dom.deleteBtn.style.display = event ? 'block' : 'none';

        // Populate form
        var form = this.dom.form;
        if (event) {
            form.title.value = event.title || '';
            this._setDatePickerValue('start', event.start ? event.start.split('T')[0] : '');
            this._setTimePickerValue('start', event.start && event.start.includes('T') ? event.start.split('T')[1].substring(0, 5) : '');
            this._setDatePickerValue('end', event.end ? event.end.split('T')[0] : '');
            this._setTimePickerValue('end', event.end && event.end.includes('T') ? event.end.split('T')[1].substring(0, 5) : '');
            this._setSelectValue(form.category, event.category || 'work');
            this._setSelectValue(form.recurrence, event.recurrence ? event.recurrence.frequency : '');
            form.description.value = event.description || '';
        } else {
            var date = defaultDate || this.selectedDate || this.currentDate;
            form.title.value = '';
            this._setDatePickerValue('start', this._formatISO(date));
            this._setTimePickerValue('start', date.getHours() ? this._padZero(date.getHours()) + ':00' : '09:00');
            this._setDatePickerValue('end', this._formatISO(date));
            this._setTimePickerValue('end', date.getHours() ? this._padZero(date.getHours() + 1) + ':00' : '10:00');
            this._setSelectValue(form.category, 'work');
            this._setSelectValue(form.recurrence, '');
            form.description.value = '';
        }

        // Show panel and overlay
        this.dom.overlay.classList.add('visible');
        this.dom.panel.classList.add('open');

        // Focus first input
        setTimeout(function() {
            form.title.focus();
        }, 100);

        // Trap focus
        this._trapFocus(this.dom.panel);
    };

    /**
     * Set date picker value
     */
    Calendar.prototype._setDatePickerValue = function(type, dateStr) {
        var form = this.dom.form;

        // Fallback to direct input value if DatePicker not available
        if (type === 'start') {
            form.startDate.value = dateStr;
        } else {
            form.endDate.value = dateStr;
        }

        // Use DatePicker API if available
        if (window.RSL && window.RSL.DatePicker) {
            var instance = type === 'start' ? this._startDatePicker : this._endDatePicker;
            if (instance) {
                window.RSL.DatePicker.setValue(instance, dateStr);
            }
        }
    };

    /**
     * Get date picker value
     */
    Calendar.prototype._getDatePickerValue = function(type) {
        var form = this.dom.form;

        // Use DatePicker API if available
        if (window.RSL && window.RSL.DatePicker) {
            var instance = type === 'start' ? this._startDatePicker : this._endDatePicker;
            if (instance) {
                var value = window.RSL.DatePicker.getValue(instance);
                if (value) {
                    // Format as ISO date string (YYYY-MM-DD)
                    var year = value.getFullYear();
                    var month = String(value.getMonth() + 1).padStart(2, '0');
                    var day = String(value.getDate()).padStart(2, '0');
                    return year + '-' + month + '-' + day;
                }
                return '';
            }
        }

        // Fallback to direct input value
        return type === 'start' ? form.startDate.value : form.endDate.value;
    };

    /**
     * Close event panel
     */
    Calendar.prototype._closeEventPanel = function() {
        this.panelOpen = false;
        this.editingEvent = null;

        this.dom.overlay.classList.remove('visible');
        this.dom.panel.classList.remove('open');

        // Return focus
        if (this.dom.addEventBtn) {
            this.dom.addEventBtn.focus();
        }
    };

    /**
     * Save event
     */
    Calendar.prototype._saveEvent = function() {
        var form = this.dom.form;
        var startDateValue = this._getDatePickerValue('start');
        var endDateValue = this._getDatePickerValue('end');

        // Validate
        if (!form.title.value.trim()) {
            form.title.focus();
            this._announce('Please enter an event title');
            return;
        }

        if (!startDateValue) {
            // Focus the date picker trigger instead of hidden input
            var startDateField = this.dom.panel.querySelector('.rsl-calendar-form-group-date input[type="text"]');
            if (startDateField) startDateField.focus();
            this._announce('Please select a start date');
            return;
        }

        // Get time values from RSL Time Pickers
        var startTimeValue = this._getTimePickerValue('start');
        var endTimeValue = this._getTimePickerValue('end');

        // Build event object
        var event = {
            id: this.editingEvent ? this.editingEvent.id : this._generateId(),
            title: form.title.value.trim(),
            start: startDateValue + (startTimeValue ? 'T' + startTimeValue : ''),
            end: endDateValue ? endDateValue + (endTimeValue ? 'T' + endTimeValue : '') : null,
            category: this._getSelectValue(form.category),
            description: form.description.value.trim(),
            recurrence: this._getSelectValue(form.recurrence) ? { frequency: this._getSelectValue(form.recurrence) } : null
        };

        // Get category color
        var category = this.categories.find(function(c) { return c.id === event.category; });
        if (category) {
            event.color = category.color;
        }

        if (this.editingEvent) {
            // Update existing event
            var index = this.events.findIndex(function(e) { return e.id === event.id; });
            if (index !== -1) {
                this.events[index] = event;
            }
            this._announce('Event updated: ' + event.title);
        } else {
            // Add new event
            this.events.push(event);
            this._announce('Event created: ' + event.title);
        }

        // Dispatch custom event
        this.element.dispatchEvent(new CustomEvent('rsl-calendar-event-save', {
            detail: { event: event, isNew: !this.editingEvent },
            bubbles: true
        }));

        this._closeEventPanel();
        this._render();
    };

    /**
     * Delete event
     */
    Calendar.prototype._deleteEvent = function() {
        if (!this.editingEvent) return;

        var eventTitle = this.editingEvent.title;
        var eventId = this.editingEvent.id;

        this.events = this.events.filter(function(e) { return e.id !== eventId; });

        // Dispatch custom event
        this.element.dispatchEvent(new CustomEvent('rsl-calendar-event-delete', {
            detail: { eventId: eventId },
            bubbles: true
        }));

        this._announce('Event deleted: ' + eventTitle);
        this._closeEventPanel();
        this._render();
    };

    /**
     * Focus trap for modal
     */
    Calendar.prototype._trapFocus = function(container) {
        var self = this;
        var focusableElements = container.querySelectorAll(
            'button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])'
        );
        var firstFocusable = focusableElements[0];
        var lastFocusable = focusableElements[focusableElements.length - 1];

        container.addEventListener('keydown', function(e) {
            if (e.key === 'Tab') {
                if (e.shiftKey) {
                    if (document.activeElement === firstFocusable) {
                        e.preventDefault();
                        lastFocusable.focus();
                    }
                } else {
                    if (document.activeElement === lastFocusable) {
                        e.preventDefault();
                        firstFocusable.focus();
                    }
                }
            }
        });
    };

    /**
     * Get events for a specific date
     */
    Calendar.prototype._getEventsForDate = function(date) {
        var self = this;
        var dateStr = this._formatISO(date);

        return this.events.filter(function(event) {
            // Filter by category if set
            if (self.filteredCategory && event.category !== self.filteredCategory) {
                return false;
            }

            var eventDate = event.start.split('T')[0];
            return eventDate === dateStr;
        });
    };

    /**
     * Get upcoming events from today
     * Returns events sorted by start date, limited by config
     */
    Calendar.prototype._getUpcomingEvents = function() {
        var self = this;
        var today = new Date();
        today.setHours(0, 0, 0, 0);

        var maxDate = new Date(today);
        maxDate.setDate(maxDate.getDate() + this.config.upcomingDays);

        // Filter events within date range
        var upcoming = this.events.filter(function(event) {
            // Filter by category if set
            if (self.filteredCategory && event.category !== self.filteredCategory) {
                return false;
            }

            var eventDate = self._parseLocalDate(event.start.split('T')[0]);
            eventDate.setHours(0, 0, 0, 0);

            // Must be today or in the future, and within the days limit
            return eventDate >= today && eventDate <= maxDate;
        });

        // Sort by start date/time
        upcoming.sort(function(a, b) {
            return new Date(a.start) - new Date(b.start);
        });

        // Limit by count
        return upcoming.slice(0, this.config.upcomingCount);
    };

    /**
     * Get days for month view
     */
    Calendar.prototype._getMonthDays = function() {
        var year = this.currentDate.getFullYear();
        var month = this.currentDate.getMonth();

        var firstDay = new Date(year, month, 1);
        var lastDay = new Date(year, month + 1, 0);

        var startDay = firstDay.getDay() - this.config.firstDay;
        if (startDay < 0) startDay += 7;

        var days = [];

        // Previous month days
        for (var i = startDay - 1; i >= 0; i--) {
            var day = new Date(year, month, -i);
            days.push(day);
        }

        // Current month days
        for (var d = 1; d <= lastDay.getDate(); d++) {
            days.push(new Date(year, month, d));
        }

        // Next month days to fill grid (always show 6 weeks)
        var remaining = 42 - days.length;
        for (var i = 1; i <= remaining; i++) {
            days.push(new Date(year, month + 1, i));
        }

        return days;
    };

    /**
     * Get week start date
     */
    Calendar.prototype._getWeekStart = function(date) {
        var d = new Date(date);
        var day = d.getDay() - this.config.firstDay;
        if (day < 0) day += 7;
        d.setDate(d.getDate() - day);
        return d;
    };

    /**
     * Check if viewport is mobile width
     */
    Calendar.prototype._isMobileView = function() {
        return window.innerWidth <= 576;
    };

    /**
     * Get day names
     */
    Calendar.prototype._getDayNames = function(short) {
        var days = [];
        var date = new Date(2024, 0, 7 + this.config.firstDay); // Sunday is Jan 7, 2024
        // Auto-detect mobile and use narrow names
        var useNarrow = short || this._isMobileView();

        for (var i = 0; i < 7; i++) {
            days.push(date.toLocaleString(this.config.locale, { weekday: useNarrow ? 'narrow' : 'short' }));
            date.setDate(date.getDate() + 1);
        }

        return days;
    };

    /**
     * Format helpers
     */
    Calendar.prototype._formatMonthYear = function() {
        return this.currentDate.toLocaleString(this.config.locale, { month: 'long', year: 'numeric' });
    };

    Calendar.prototype._formatFullDate = function(date) {
        return date.toLocaleString(this.config.locale, { weekday: 'long', month: 'long', day: 'numeric', year: 'numeric' });
    };

    Calendar.prototype._formatDateRange = function(start, end) {
        if (start.getMonth() === end.getMonth()) {
            return start.toLocaleString(this.config.locale, { month: 'long' }) + ' ' +
                   start.getDate() + ' - ' + end.getDate() + ', ' + start.getFullYear();
        } else {
            return start.toLocaleString(this.config.locale, { month: 'short', day: 'numeric' }) + ' - ' +
                   end.toLocaleString(this.config.locale, { month: 'short', day: 'numeric', year: 'numeric' });
        }
    };

    Calendar.prototype._formatTime = function(date) {
        if (this.config.timeFormat === '24h') {
            return this._padZero(date.getHours()) + ':' + this._padZero(date.getMinutes());
        } else {
            var hours = date.getHours();
            var ampm = hours >= 12 ? 'pm' : 'am';
            hours = hours % 12 || 12;
            return hours + ':' + this._padZero(date.getMinutes()) + ampm;
        }
    };

    Calendar.prototype._formatHour = function(hour) {
        if (this.config.timeFormat === '24h') {
            return this._padZero(hour) + ':00';
        } else {
            var ampm = hour >= 12 ? 'PM' : 'AM';
            var h = hour % 12 || 12;
            return h + ' ' + ampm;
        }
    };

    Calendar.prototype._formatISO = function(date) {
        return date.getFullYear() + '-' + this._padZero(date.getMonth() + 1) + '-' + this._padZero(date.getDate());
    };

    /**
     * Parse a date string (YYYY-MM-DD) as local date, not UTC
     * This prevents timezone issues where "2025-12-18" becomes Dec 17 in US timezones
     */
    Calendar.prototype._parseLocalDate = function(dateStr) {
        if (!dateStr) return new Date();
        if (dateStr instanceof Date) return dateStr;

        // Split the date string and create a local date
        var parts = dateStr.split('-');
        if (parts.length === 3) {
            return new Date(parseInt(parts[0], 10), parseInt(parts[1], 10) - 1, parseInt(parts[2], 10));
        }

        // Fallback for other formats
        return new Date(dateStr);
    };

    Calendar.prototype._padZero = function(n) {
        return n < 10 ? '0' + n : String(n);
    };

    /**
     * Date comparison helpers
     */
    Calendar.prototype._isSameDay = function(a, b) {
        return a.getFullYear() === b.getFullYear() &&
               a.getMonth() === b.getMonth() &&
               a.getDate() === b.getDate();
    };

    Calendar.prototype._isSameMonth = function(a, b) {
        return a.getFullYear() === b.getFullYear() &&
               a.getMonth() === b.getMonth();
    };

    /**
     * Get view label
     */
    Calendar.prototype._getViewLabel = function() {
        return this.config.view.charAt(0).toUpperCase() + this.config.view.slice(1) + ' view';
    };

    /**
     * Get previous button aria-label based on current view
     */
    Calendar.prototype._getPrevButtonLabel = function() {
        switch (this.config.view) {
            case 'day':
                return 'Previous day';
            case 'week':
                return 'Previous week';
            case 'year':
                return 'Previous year';
            case 'month':
            default:
                return 'Previous month';
        }
    };

    /**
     * Get next button aria-label based on current view
     */
    Calendar.prototype._getNextButtonLabel = function() {
        switch (this.config.view) {
            case 'day':
                return 'Next day';
            case 'week':
                return 'Next week';
            case 'year':
                return 'Next year';
            case 'month':
            default:
                return 'Next month';
        }
    };

    /**
     * Update navigation button labels
     */
    Calendar.prototype._updateNavButtonLabels = function() {
        if (this.dom.prevBtn) {
            this.dom.prevBtn.setAttribute('aria-label', this._getPrevButtonLabel());
        }
        if (this.dom.nextBtn) {
            this.dom.nextBtn.setAttribute('aria-label', this._getNextButtonLabel());
        }
    };

    /**
     * Generate unique ID
     */
    Calendar.prototype._generateId = function() {
        return 'rsl-cal-' + Math.random().toString(36).substr(2, 9);
    };

    /**
     * Escape HTML
     */
    Calendar.prototype._escapeHtml = function(text) {
        var div = document.createElement('div');
        div.textContent = text;
        return div.innerHTML;
    };

    /**
     * Announce to screen readers
     */
    Calendar.prototype._announce = function(message) {
        if (this.dom.liveRegion) {
            this.dom.liveRegion.textContent = message;
        }
    };

    /**
     * Destroy the calendar
     */
    Calendar.prototype.destroy = function() {
        // Remove event listeners
        window.removeEventListener('resize', this._resizeHandler);

        // Remove panel and overlay from body
        if (this.dom.panel) {
            this.dom.panel.remove();
        }
        if (this.dom.overlay) {
            this.dom.overlay.remove();
        }
        if (this.dom.popover) {
            this.dom.popover.remove();
        }

        // Clear element
        this.element.innerHTML = '';
        this.element.classList.remove('rsl-calendar');
        this.element.removeAttribute('data-view');
        this.element.removeAttribute('data-upcoming');

        // Remove from instances
        instances.delete(this.element);
    };

    /**
     * Public API Methods
     */
    Calendar.prototype.getEvents = function() {
        return this.events.slice();
    };

    Calendar.prototype.setEvents = function(events) {
        this.events = events || [];
        this._render();
    };

    Calendar.prototype.addEvent = function(event) {
        if (!event.id) {
            event.id = this._generateId();
        }
        this.events.push(event);
        this._render();
        return event;
    };

    Calendar.prototype.updateEvent = function(eventId, updates) {
        var index = this.events.findIndex(function(e) { return e.id === eventId; });
        if (index !== -1) {
            Object.assign(this.events[index], updates);
            this._render();
            return this.events[index];
        }
        return null;
    };

    Calendar.prototype.removeEvent = function(eventId) {
        this.events = this.events.filter(function(e) { return e.id !== eventId; });
        this._render();
    };

    Calendar.prototype.setView = function(view) {
        this._setView(view);
    };

    Calendar.prototype.getView = function() {
        return this.config.view;
    };

    Calendar.prototype.goToDate = function(date) {
        this.currentDate = new Date(date);
        this.focusedDate = new Date(date);
        this._render();
    };

    Calendar.prototype.getDate = function() {
        return new Date(this.currentDate);
    };

    Calendar.prototype.getUpcomingEvents = function() {
        return this._getUpcomingEvents();
    };

    Calendar.prototype.setUpcomingMode = function(mode) {
        if (!Calendar.UPCOMING_MODES.includes(mode)) {
            return;
        }

        var oldMode = this.config.upcoming;
        this.config.upcoming = mode;

        // Update data attribute
        if (mode === 'none') {
            this.element.removeAttribute('data-upcoming');
        } else {
            this.element.setAttribute('data-upcoming', mode);
        }

        // Remove existing upcoming section
        if (this.dom.upcoming) {
            this.dom.upcoming.remove();
            this.dom.upcoming = null;
        }

        // Handle structural changes based on mode transitions
        var needsToolbar = this.config.showToolbar && mode !== 'only';
        var needsGrid = mode !== 'only';
        var needsWrapper = mode === 'sidebar';

        // Handle toolbar visibility
        if (this.dom.toolbar) {
            this.dom.toolbar.style.display = needsToolbar ? '' : 'none';
        } else if (needsToolbar) {
            this._buildToolbar();
        }

        // Handle grid visibility and wrapper
        if (this.dom.grid) {
            this.dom.grid.style.display = needsGrid ? '' : 'none';
        }

        // Handle main wrapper for sidebar mode
        if (needsWrapper && !this.dom.mainWrapper) {
            // Create wrapper and move grid into it
            this.dom.mainWrapper = document.createElement('div');
            this.dom.mainWrapper.className = 'rsl-calendar-main-wrapper';

            // Insert wrapper after toolbar (or at beginning if no toolbar)
            if (this.dom.toolbar && this.dom.toolbar.parentNode === this.element) {
                this.element.insertBefore(this.dom.mainWrapper, this.dom.toolbar.nextSibling);
            } else {
                this.element.insertBefore(this.dom.mainWrapper, this.element.firstChild);
            }

            // Move grid into wrapper
            if (this.dom.grid) {
                this.dom.mainWrapper.appendChild(this.dom.grid);
            }
        } else if (!needsWrapper && this.dom.mainWrapper) {
            // Remove wrapper and move grid back to main element
            if (this.dom.grid && this.dom.mainWrapper.contains(this.dom.grid)) {
                // Insert grid after toolbar or at position of wrapper
                if (this.dom.toolbar && this.dom.toolbar.parentNode === this.element) {
                    this.element.insertBefore(this.dom.grid, this.dom.mainWrapper);
                } else {
                    this.element.insertBefore(this.dom.grid, this.dom.mainWrapper);
                }
            }
            this.dom.mainWrapper.remove();
            this.dom.mainWrapper = null;
        }

        // Re-render to build upcoming section in correct location
        this._render();
    };

    /**
     * Public API
     */
    window.RSL.Calendar = {
        /**
         * Initialize all calendars on page
         */
        init: function() {
            var calendars = document.querySelectorAll('[data-rsl-calendar]');
            calendars.forEach(function(el) {
                if (!instances.has(el)) {
                    instances.set(el, new Calendar(el));
                }
            });
        },

        /**
         * Create calendar on specific element
         */
        create: function(element, options) {
            if (typeof element === 'string') {
                element = document.querySelector(element);
            }
            if (!element) return null;

            if (instances.has(element)) {
                return instances.get(element);
            }

            var instance = new Calendar(element, options);
            instances.set(element, instance);
            return instance;
        },

        /**
         * Get calendar instance
         */
        getInstance: function(element) {
            if (typeof element === 'string') {
                element = document.querySelector(element);
            }
            return instances.get(element) || null;
        },

        /**
         * Destroy calendar instance
         */
        destroy: function(element) {
            if (typeof element === 'string') {
                element = document.querySelector(element);
            }
            var instance = instances.get(element);
            if (instance) {
                instance.destroy();
            }
        }
    };

    // Auto-initialize on DOMContentLoaded
    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', function() {
            window.RSL.Calendar.init();
        });
    } else {
        window.RSL.Calendar.init();
    }

})();
