Код:
<!--HTML-->
    <style>
        .advent-calendar {
            display: grid;
            grid-template-columns: repeat(4, 1fr);
            gap: 15px;
            max-width: 800px;
            margin: 0 auto;
            padding: 20px;
            font-family: Arial, sans-serif;
        }

        .calendar-cell {
            position: relative;
            aspect-ratio: 1;
            border: 2px solid #efefef;
            border-radius: 10px;
            /*background: linear-gradient(90deg, #21985e 0%, #ffffff 99%, #ffffff 49%);*/
            display: flex;
            align-items: center;
            justify-content: center;
            color: white;
            font-weight: bold;
            font-size: 1.5em;
            overflow: hidden;
            transition: all 0.3s ease;
        }

        .cell-content {
            width: 100%;
            height: 100%;
            display: flex;
            align-items: center;
            justify-content: center;
            border-radius: 8px;
            padding: 10px;
            box-sizing: border-box;
            text-align: center;
            word-wrap: break-word;
            overflow: hidden;   
            font-size: 12px;
            background: #efefef;
        }

        /* Стили для закрытых ячеек */
        .closed .cell-content {
            background-image: url(https://upforme.ru/uploads/0010/a8/ca/7506/19647.png);
            font-size: 1.2em;
            color: transparent;
        }

        /* Стили для открытых ячеек */
        .opened .cell-content {
            background: white;
            color: #333;
            font-size: 12px;
            font-weight: normal;
            line-height: 1.3;
            overflow-y: auto;
            flex-direction: column;
            gap: 5px;
        }

       .opened .cell-content a {
            color: #27ae60;
            text-decoration: none;
            font-weight: bold;
            padding: 3px 8px;
            border: 1px solid #27ae60;
            border-radius: 5px;
            background: white;
            transition: all 0.3s ease;
            font-size: 0.8em;
            text-transform: uppercase;
        }

        .opened .cell-content a:hover {
            background: white;
            border: 1px solid black;
            color: black;
        }

        /* Стили для завершенных ячеек */
        .completed .cell-content {
            /*background-size: cover;*/
            background-position: center;
            background-repeat: no-repeat;
            position: relative;
        }
    
      .completed .cell-date {
            display: none;
        }

        .completed .cell-content::after {
            content: attr(title);
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    /* background: rgba(0, 0, 0, 0.7); */
    color: black;
    padding: 5px;
    font-size: 10px;
    text-align: center;
    font-weight: normal;
            text-align: center;
        }

        .cell-number {
            position: absolute;
            top: 5px;
            right: 5px;
            color: black;
            padding: 2px 8px;
            border-radius: 50%;
            font-size: 0.8em;
            z-index: 2;
        }

        .cell-date {
            position: absolute;
            bottom: 5px;
            left: 5px;
            background: rgba(0,0,0,0.6);
            color: white;
            padding: 2px 6px;
            border-radius: 5px;
            font-size: 0.6em;
            z-index: 2;
        }

        /* Индикатор статуса */
        .status-indicator {
            position: absolute;
            top: 5px;
            left: 5px;
            padding: 2px 6px;
            border-radius: 10px;
            font-size: 0.6em;
            background: rgba(0,0,0,0.7);
            text-transform: uppercase;
            color: white;
            z-index: 2;
        }

        .closed .status-indicator { 
            background: #bc1131; 
        }
        .opened .status-indicator { 
            background: #f39c12; 
        }
        .completed .status-indicator { 
            background: #27ae60; 
        }

        @media (max-width: 768px) {
            .advent-calendar {
                grid-template-columns: repeat(2, 1fr);
            }
            
            .opened .cell-content {
                font-size: 0.75em;
            }
        }

        @media (max-width: 480px) {
            .advent-calendar {
                grid-template-columns: 1fr;
            }
        }
    </style>
</head>
<body>
    <div class="advent-calendar" id="adventCalendar">
        <!-- Ячейки будут созданы через JavaScript -->
    </div>

    <script>
        // Данные для адвент-календаря
        const calendarData = {
            completed: [
['1','https://i.imgur.com/TTKMSyE.png','50 фишек тотемов'],
['2','https://i.imgur.com/rHIceK0.png','аватар в подарок'],
['3','https://i.imgur.com/DX69oiJ.png','случайный необычный купон'],
['4','https://i.imgur.com/ZBpk6Xr.png','25 000 сакр'],
['5','https://i.imgur.com/7i7mtQD.png','случайный ключ'],
['6','https://i.imgur.com/7hKbPsS.png','подарок в профиль'],
['7','https://i.imgur.com/Fj9vd6p.png','специальная плашка'],
['8','https://i.imgur.com/TTKMSyE.png','50 фишек тотемов'],
['9','https://i.imgur.com/cCpA6TY.png','тотем воин'],
['10','https://i.imgur.com/ZBpk6Xr.png','50 000 сакр'],
['11','https://i.imgur.com/WPzCJ12.png','случайный редкий купон'],
['12','https://i.imgur.com/oJgatHn.png','тотем люцифер'],
['13','https://i.imgur.com/TaHIWuO.png','иконка в подарок'],
['14','https://i.imgur.com/Nhmg1eG.png','подарок в профиль'],
['15','https://i.imgur.com/TTKMSyE.png','50 фишек тотемов'],
['16','https://i.imgur.com/rHIceK0.png','аватар в подарок'],
['17','https://i.imgur.com/7i7mtQD.png','случайный ключ'],
['18','https://i.imgur.com/WFDkjhG.png','тотем золотой воин'],
['19','https://i.imgur.com/7i7mtQD.png','случайный ключ'],
['20','https://i.imgur.com/PD4qXI6.png','случайный эпический купон'],
['21','https://i.imgur.com/TaHIWuO.png','иконка в подарок'],
['22','https://i.imgur.com/IF3GSet.png','подарок в профиль'],
['23','https://i.imgur.com/ZBpk6Xr.png','100 000 сакр'],
['24','https://i.imgur.com/svt1U8O.png','тотем викинг'],
['25','https://i.imgur.com/TTKMSyE.png','50 фишек тотемов'],
['26','https://i.imgur.com/Fj9vd6p.png','специальная плашка'],
['27','https://i.imgur.com/7i7mtQD.png','универсальный ключ'],
['28','https://i.imgur.com/ZBpk6Xr.png','150 000 сакр'],
['29','https://i.imgur.com/TaHIWuO.png','иконка в подарок'],
['30','https://i.imgur.com/PD4qXI6.png','случайный эпический купон'],
['31','https://i.imgur.com/ZBpk6Xr.png','200 000 сакр'],
            ],
            opened: [
                ['1', 'поздравить сакру с др в теме', 'https://sacramento.rusff.me/viewtopic.php?id=50878#p5167068' ],
['2', 'отметиться в онлайне', 'https://sacramento.rusff.me/viewtopic.php?id=50521' ],
['3', 'выложить вечериночный пост в инстаграм', 'https://sacramento.rusff.me/viewtopic.php?id=50110' ],
['4', 'отметиться в я люблю тебя (100 символов)', 'https://sacramento.rusff.me/viewtopic.php?id=50527' ],
['5', 'поставить 10 плюсов', '' ],
['6', 'отметиться в смайломании', 'https://sacramento.rusff.me/viewtopic.php?id=49683' ],
['7', 'отметиться в топотыке', 'https://sacramento.rusff.me/viewtopic.php?id=50548' ],
['8', 'выложить летнюю фотку в инсту', 'https://sacramento.rusff.me/viewtopic.php?id=50110' ],
['9', 'отметиться в бутылочке', 'https://sacramento.rusff.me/viewtopic.php?id=50618' ],
['10', 'оставить соо в клубах по интересам', 'https://sacramento.rusff.me/viewforum.php?id=105' ],
['11', 'выложить мем в тему адвента', '' ],
['12', 'принести рандомное заполненное бинго', 'https://sacramento.rusff.me/viewtopic.php?id=50086' ],
['13', 'оставить 10 сообщений в игротеке', 'https://sacramento.rusff.me/viewforum.php?id=30' ],
['14', 'отметиться в теме адвента', '' ],
['15', 'отметиться в онлайне', 'https://sacramento.rusff.me/viewtopic.php?id=50521' ],
['16', 'оставить осмысленную мысль в мыслях', 'https://sacramento.rusff.me/viewtopic.php?id=50855' ],
['17', 'отметиться в плюсомании', 'https://sacramento.rusff.me/viewtopic.php?id=50574' ],
['18', 'выложить трек дня в колонки', 'https://sacramento.rusff.me/viewtopic.php?id=50049' ],
['19', 'выложить фотку любимого летнего блюда в foodporn', 'https://sacramento.rusff.me/viewtopic.php?id=20361' ],
['20', 'рассказать что по погоде', 'https://sacramento.rusff.me/viewtopic.php?id=45093' ],
['21', 'написать доброе пожелание в теме адвента', '' ],
['22', 'играем в слова прямо в теме адвента! я начну: слово "праздник" - первому в теме на "к" и так далее друг за другом', '' ],
['23', 'отметиться в топотыке', 'https://sacramento.rusff.me/viewtopic.php?id=50548' ],
['24', 'рассказать про планы на лето в теме адвента', '' ],
['25', 'написать летний факт о себе', 'https://sacramento.rusff.me/viewtopic.php?id=49501' ],
['26', 'поставить 10 плюсов', '' ],
['27', 'отметиться в онлайне', 'https://sacramento.rusff.me/viewtopic.php?id=50521' ],
['28', 'написать рандомный факт о персонаже', 'https://sacramento.rusff.me/viewtopic.php?id=50276' ],
['29', 'выложить подборку', 'https://sacramento.rusff.me/viewtopic.php?id=50112#p5069518' ],
['30', 'отметиться в топотыке', 'https://sacramento.rusff.me/viewtopic.php?id=50548' ],
['31', 'отметиться в теме адвента', '' ],
            ]
        };

        // Настройка дат: 1 ячейка = 13 июня 2026
        const START_DATE = new Date(2026, 5, 13); // 13 июня 2026 (месяц 5 = июнь)
        
        // Функция для получения статуса ячейки на основе даты
        function getCellStatusByDate(cellIndex) {
            const now = new Date();
            const currentDate = new Date(now.getFullYear(), now.getMonth(), now.getDate());
            
            // Вычисляем дату для этой ячейки (индекс начинается с 1)
            const cellDate = new Date(START_DATE);
            cellDate.setDate(START_DATE.getDate() + (cellIndex - 1));
            const cellDateOnly = new Date(cellDate.getFullYear(), cellDate.getMonth(), cellDate.getDate());
            
            // Вычисляем дату следующего дня (когда ячейка становится completed)
            const nextDayDate = new Date(cellDateOnly);
            nextDayDate.setDate(cellDateOnly.getDate() + 1);
            
            // Определяем статус
            if (currentDate >= nextDayDate) {
                return 'completed';
            } else if (currentDate >= cellDateOnly) {
                return 'opened';
            } else {
                return 'closed';
            }
        }
        
        // Функция для форматирования даты
        function formatDate(date) {
            const months = ['янв', 'фев', 'мар', 'апр', 'май', 'июн', 'июл', 'авг', 'сен', 'окт', 'ноя', 'дек'];
            return `${date.getDate()} ${months[date.getMonth()]}`;
        }
        
        // Функция для обновления статуса одной ячейки
        function updateCellStatus(cellElement, cellId, newStatus) {
            const oldStatus = cellElement.className.split(' ')[1];
            if (oldStatus === newStatus) return;
            
            // Обновляем класс
            cellElement.className = `calendar-cell ${newStatus}`;
            
            // Обновляем содержимое
            const content = cellElement.querySelector('.cell-content');
            const statusIndicator = cellElement.querySelector('.status-indicator');
            
            // Очищаем содержимое
            content.innerHTML = '';
            
            if (newStatus === 'closed') {
                content.textContent = cellId;
                statusIndicator.textContent = 'Закрыто';
            } else if (newStatus === 'opened') {
                const taskData = calendarData.opened.find(item => item[0] === cellId);
                if (taskData) {
                    const taskText = document.createElement('span');
                    taskText.textContent = taskData[1];
                    content.appendChild(taskText);
                    
                    if (taskData[2]) {
                        const link = document.createElement('a');
                        link.href = taskData[2];
                        link.target = '_blank';
                        link.textContent = 'Перейти →';
                        content.appendChild(link);
                    }
                } else {
                    content.textContent = 'Задание не найдено';
                }
                statusIndicator.textContent = 'Открыто';
            } else if (newStatus === 'completed') {
                const completedItem = calendarData.completed.find(item => item[0] === cellId);
                if (completedItem) {
                    content.style.backgroundImage = `url('${completedItem[1]}')`;
                    content.setAttribute('title', completedItem[2]);
                    content.textContent = '';
                }
                statusIndicator.textContent = 'Выполнено';
            }
            
            // Сохраняем статус в localStorage
            saveCellStatus(cellId, newStatus);
        }
        
        // Сохранение статуса ячейки
        function saveCellStatus(cellId, status) {
            let savedStatuses = localStorage.getItem('adventCalendarStatuses');
            savedStatuses = savedStatuses ? JSON.parse(savedStatuses) : {};
            savedStatuses[cellId] = status;
            localStorage.setItem('adventCalendarStatuses', JSON.stringify(savedStatuses));
        }
        
        // Загрузка сохраненных статусов
        function loadSavedStatus(cellId) {
            const savedStatuses = localStorage.getItem('adventCalendarStatuses');
            if (savedStatuses) {
                const statuses = JSON.parse(savedStatuses);
                return statuses[cellId] || null;
            }
            return null;
        }
        
        // Проверка и обновление всех ячеек
        function updateAllCells() {
            for (let i = 1; i <= 31; i++) {
                const cell = document.querySelector(`.calendar-cell[data-id='${i}']`);
                if (cell) {
                    const calculatedStatus = getCellStatusByDate(i);
                    const savedStatus = loadSavedStatus(i);
                    
                    // Используем сохраненный статус, если он есть (чтобы не перезаписывать completed)
                    let finalStatus = calculatedStatus;
                    if (savedStatus === 'completed' && calculatedStatus !== 'completed') {
                        // Если пользователь вручную отметил как выполненное, сохраняем этот статус
                        finalStatus = 'completed';
                    } else if (savedStatus === 'opened' && calculatedStatus === 'closed') {
                        finalStatus = 'opened';
                    } else {
                        finalStatus = calculatedStatus;
                    }
                    
                    updateCellStatus(cell, i.toString(), finalStatus);
                }
            }
        }
        
        // Функция для создания календаря
        function createCalendar() {
            const calendar = document.getElementById('adventCalendar');
            calendar.innerHTML = '';
            
            for (let i = 1; i <= 31; i++) {
                const cell = document.createElement('div');
                cell.className = 'calendar-cell';
                cell.dataset.id = i.toString();
                
                // Вычисляем дату для этой ячейки
                const cellDate = new Date(START_DATE);
                cellDate.setDate(START_DATE.getDate() + (i - 1));
                
                const content = document.createElement('div');
                content.className = 'cell-content';
                
                const number = document.createElement('div');
                number.className = 'cell-number';
                number.textContent = i;
                
                const dateElement = document.createElement('div');
                dateElement.className = 'cell-date';
                dateElement.textContent = formatDate(cellDate);
                
                const status = document.createElement('div');
                status.className = 'status-indicator';
                
                // Определяем начальный статус
                let cellStatus = getCellStatusByDate(i);
                const savedStatus = loadSavedStatus(i.toString());
                
                // Применяем сохраненный статус, если он есть и не противоречит логике
                if (savedStatus === 'completed') {
                    cellStatus = 'completed';
                } else if (savedStatus === 'opened' && cellStatus === 'closed') {
                    cellStatus = 'opened';
                }
                
                // Устанавливаем класс
                cell.classList.add(cellStatus);
                
                // Заполняем контент
                if (cellStatus === 'closed') {
                    content.textContent = i;
                    status.textContent = 'Закрыто';
                } else if (cellStatus === 'opened') {
                    const taskData = calendarData.opened.find(item => item[0] === i.toString());
                    if (taskData) {
                        const taskText = document.createElement('span');
                        taskText.textContent = taskData[1];
                        content.appendChild(taskText);
                        
                        if (taskData[2]) {
                            const link = document.createElement('a');
                            link.href = taskData[2];
                            link.target = '_blank';
                            link.textContent = 'Перейти →';
                            content.appendChild(link);
                        }
                    } else {
                        content.textContent = 'Задание не найдено';
                    }
                    status.textContent = 'Открыто';
                } else if (cellStatus === 'completed') {
                    const completedItem = calendarData.completed.find(item => item[0] === i.toString());
                    if (completedItem) {
                        content.style.backgroundImage = `url('${completedItem[1]}')`;
                        content.setAttribute('title', completedItem[2]);
                        content.textContent = '';
                    }
                    status.textContent = 'Выполнено';
                }
                
                cell.appendChild(content);
                cell.appendChild(number);
                cell.appendChild(dateElement);
                cell.appendChild(status);
                
                // Добавляем обработчик клика для ручного завершения задания
                if (cellStatus === 'opened') {
                    cell.style.cursor = 'pointer';
                    cell.addEventListener('click', () => {
                        if (confirm('Отметить задание как выполненное?')) {
                            updateCellStatus(cell, i.toString(), 'completed');
                        }
                    });
                }
                
                calendar.appendChild(cell);
            }
        }
        
        // Запускаем проверку статусов каждую минуту
        function startAutoUpdate() {
            // Проверяем каждую минуту
            setInterval(() => {
                updateAllCells();
            }, 60000);
            
            // Дополнительная проверка в полночь (каждый час)
            setInterval(() => {
                const now = new Date();
                if (now.getHours() === 0 && now.getMinutes() === 0) {
                    updateAllCells();
                }
            }, 60000);
        }
        
        // Инициализация при загрузке
        document.addEventListener('DOMContentLoaded', () => {
            createCalendar();
            startAutoUpdate();
            
            // Выводим информацию в консоль для отладки
            console.log('Календарь создан. Первая ячейка (№1) откроется:', new Date(START_DATE).toLocaleDateString('ru-RU'));
            console.log('Текущая дата:', new Date().toLocaleDateString('ru-RU'));
        });
    </script>
Подпись автора

https://i.imgur.com/5o0dxGP.png
♥️
поле чудес х rich bitch x капсула х  капсула'23
«good morning, reasons why I drink.»