拒绝摆烂!自律神器小组件!

你是否也曾在新立Flag时信誓旦旦,却在几天后不了了之?你是否也厌倦了冰冷、枯燥的待办清单,渴望一份能真正激发内在动力的自律伙伴?

今天,我们为你带来了一款全新上架的小组件,开源自律日历 —— 「熊二的自律日历」。它不只是日历,更是一个集任务管理、目标追踪、即时激励于一体的个人成长可视化生态系统。它的开源属性,意味着你可以自由探索、修改、分享,让它真正属于你。

现在,就让我们一一揭开它的“爆火”功能面纱:

🌟 一、核心:可视化任务与成就系统

  1. 智能日历,一目了然
    • 不仅是日历,更是你的“坚持地图”。已完成的天数会以醒目的绿色“✓”标记,今日日期高亮显示。
    • 点击任意日期,立即知晓距离今天还有几天/已经过去几天,让时间感触手可及。
    • 新品亮点:月份导航与“回到今天”按钮,让你随时聚焦当下,回顾过去,展望未来。
  2. 灵活的任务规划器
    • 自定义字段:不只是“任务”和“预计时间”,你可以添加任何你需要的字段(如优先级、类别、能量消耗等),打造专属任务模板。
    • 便捷录入:支持逐条添加,更支持批量导入文本,从笔记或清单中一键搬运,效率拉满。
    • 即时反馈:勾选任务,完成效果立即生效(划线),并自动统计当日任务完成情况。
    • 一键完成:当所有任务都搞定时,“一键全部完成”按钮让你享受瞬间清空的快感。
  3. 数据驱动的激励统计
    • 本月完成天数、历史最长连续天数、当前连续天数——三大数据直观展示你的自律曲线。
    • 新品亮点:这些数字不只是冷冰冰的统计,它们是你一步步成长的勋章,激励你保持“连胜”,挑战新的记录。

🎯 二、升级:跨日目标与里程碑管理

  1. 长期目标追踪器
    • 设定跨天、跨月、甚至跨年的目标,指定精确的开始与结束时间。
    • 目标卡片实时显示动态倒计时(精确到秒)和完成进度条,让遥远的目标变得具体且紧迫。
    • 支持多个目标并行,让你的成长不再单一。
  2. 目标到达仪式感
    • 当设定目标时间一到,系统会弹出完成确认弹窗,并伴随你自定义的庆祝动画或视频!
    • 你可以选择:播放小卡片飘落动画+音乐,或直接全屏播放你提前准备好的成功庆祝视频。
    • 根据你的反馈,将目标标记为“完成”或“未完成”,形成完整的目标生命周期闭环。

✨ 三、创新:沉浸式即时激励体验

  1. 每日庆祝功能
    • 完成今日所有任务后,点击“完成今日任务!🎉”按钮,即可触发庆祝环节!
    • 你可以自定义庆祝方式:播放一段振奋人心的音频,或播放一个搞笑/感人的视频,并随机显示你精心准备的语录。让坚持的终点充满快乐。
  2. 疲惫时的能量加油站
    • 全新“累了就来这里”按钮:在你意志力薄弱、想要放弃时,点击它!
    • 同样支持自定义:选择播放治愈系小卡片飘落动画+音乐,或播放一段励志视频。
    • 新品亮点:这个功能就像一个懂你的朋友,在你最需要的时候,给你一个暖心的拥抱和继续前行的力量。

⏰ 四、贴心:全方位时间与提醒守护

  1. 智能闹钟系统
    • 支持设置精确到秒的日期与时间闹钟。
    • 可添加备注,如“该学习啦!”、“喝水时间”。
    • 提醒方式可选:醒目的弹窗+音频,或直接播放你指定的视频(如健身教程、冥想引导)。
  2. 实时网络同步时钟
    • 内置大字体实时时钟,显示当前日期、星期。
    • 新品亮点:支持“🔄”按钮一键同步网络时间,确保你的日程安排精准无误。

🔒 五、保障:隐私安全与开源自由

  1. 完全本地化存储:所有数据(任务、目标、统计、媒体文件)均存储于本地浏览器(IndexedDB),无需登录,隐私绝对安全。
  2. 开源免费:源代码开放!你可以:
    • 学习其实现逻辑,甚至贡献代码。
    • 根据个人喜好修改界面颜色、动画效果。
    • 搭建属于自己的、独一无二的自励工具。
  3. 恢复出厂设置:提供谨慎的“清除所有数据”功能,给你重新开始的勇气和机会。

总结一下,「熊二的自律日历」不仅是一个强大的任务管理工具,更是一个充满人文关怀、能提供即时情绪价值、并且完全受你掌控的成长伙伴。

它的新品光环,源于其将自律过程中的“记录”、“追踪”、“坚持”与“奖励”、“鼓励”、“庆祝”无缝融合的创新设计。它的开源属性,则赋予了它无限的潜力和生命力,等待着社区共同丰富它、完善它。

<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>加油!</title>
    <style>
        * {
            box-sizing: border-box;
            margin: 0;
            padding: 0;
        }

        body {
            font-family: "Microsoft YaHei", "Segoe UI", Arial, sans-serif;
            background: linear-gradient(135deg, #f5f7fa 0%, #e4e8f0 100%);
            margin: 0;
            padding: 20px;
            min-height: 100vh;
            display: flex;
            gap: 30px;
            flex-wrap: wrap;
            justify-content: center;
            color: #333;
        }

        /* 整体布局 */
        .main-content {
            flex: 1;
            min-width: 700px;
            max-width: 900px;
            position: relative;
        }

        .sidebar-left {
            width: 380px;
            background: white;
            border-radius: 20px;
            padding: 25px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
            height: fit-content;
        }

        .sidebar-right {
            width: 380px;
            background: white;
            border-radius: 20px;
            padding: 25px;
            box-shadow: 0 10px 30px rgba(0, 0, 0, 0.08);
            height: fit-content;
        }

        @media (max-width: 1600px) {
            body {
                flex-direction: column;
                align-items: center;
            }

            .main-content,
            .sidebar-left,
            .sidebar-right {
                width: 95%;
                max-width: 900px;
                min-width: unset;
            }
        }
h1 {
    text-align: center;
    padding-left: 240px;
    background: linear-gradient(135deg, #e74c3c 0%, #c0392b 100%);
    -webkit-background-clip: text;
    -webkit-text-fill-color: transparent; 
    
    font-size: 32px;
    font-weight: 700; 
}

        .today-info {
            text-align: center;
            font-size: 18px;
            margin-bottom: 25px;
            color: #7f8c8d;
            font-weight: 500;
        }

   /* ===== 功能按钮布局 - 两行排列 ===== */
.daily-task-btn, .long-term-btn, .encourage-settings-btn, .settings-btn,
.alarm-btn, .reset-btn {
    position: absolute;
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: white;
    border: none;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    font-size: 24px;
    cursor: pointer;
    box-shadow: 0 6px 20px rgba(102, 126, 234, 0.4);
    transition: all 0.3s ease;
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
}

/* 第一行按钮 */
.daily-task-btn { left: 0; top: 0; }
.long-term-btn { left: 60px; top: 0; }
.encourage-settings-btn { left: 120px; top: 0; }
.settings-btn { left: 180px; top: 0; }

/* 第二行按钮(在第一行下方) */
.alarm-btn { left: 0; top: 60px; }
.reset-btn { left: 60px; top: 60px; }

.daily-task-btn:hover, .long-term-btn:hover, .encourage-settings-btn:hover, 
.settings-btn:hover, .alarm-btn:hover, .reset-btn:hover {
    transform: translateY(-5px) scale(1.1);
    box-shadow: 0 12px 30px rgba(102, 126, 234, 0.6);
}
        /* 导航栏 */
        .nav {
            display: flex;
            justify-content: center;
            align-items: center;
            margin-bottom: 25px;
            gap: 20px;
        }

        .nav button {
            background: linear-gradient(135deg, #0066ff, #00a8ff);
            color: white;
            border: none;
            padding: 12px 24px;
            border-radius: 12px;
            cursor: pointer;
            font-size: 16px;
            font-weight: 600;
            box-shadow: 0 6px 15px rgba(0, 102, 255, 0.2);
            transition: all 0.3s ease;
            min-width: 120px;
        }

        .nav button:hover {
            transform: translateY(-3px);
            box-shadow: 0 10px 25px rgba(0, 102, 255, 0.3);
        }

        #today-btn {
            background: white;
            box-shadow: 0 6px 15px rgba(0, 0, 0, 0.1);
            color: #2c3e50;
            border: 2px solid #e0e0e0;
        }

        #today-btn:hover {
            box-shadow: 0 10px 25px rgba(0, 0, 0, 0.15);
            border-color: #ccc;
        }

        .nav span {
            font-size: 28px;
            font-weight: bold;
            min-width: 200px;
            text-align: center;
            color: #2c3e50;
        }

        /* 庆祝按钮 */
        .celebrate-section {
            text-align: center;
            margin: 25px 0;
        }

        #celebrate-btn {
            background: linear-gradient(45deg, #ff6b6b, #ffa500);
            color: white;
            border: none;
            padding: 20px 50px;
            border-radius: 50px;
            font-size: 24px;
            font-weight: bold;
            cursor: pointer;
            box-shadow: 0 12px 35px rgba(255, 107, 107, 0.4);
            transition: all 0.3s ease;
            letter-spacing: 1px;
        }

        #celebrate-btn:hover:not(:disabled) {
            transform: translateY(-5px) scale(1.05);
            box-shadow: 0 18px 45px rgba(255, 107, 107, 0.5);
        }

        #celebrate-btn:disabled {
            background: #ccc;
            cursor: not-allowed;
            transform: none;
            box-shadow: none;
        }

        /* 日历区域 */
        .weekday-header {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            background: linear-gradient(135deg, #0066ff, #00c8ff);
            color: white;
            font-weight: bold;
            border-radius: 16px 16px 0 0;
            overflow: hidden;
            box-shadow: 0 6px 20px rgba(0, 102, 255, 0.2);
        }

        .weekday-header div {
            padding: 18px 10px;
            text-align: center;
            font-size: 16px;
            letter-spacing: 1px;
        }

        .calendar-grid {
            display: grid;
            grid-template-columns: repeat(7, 1fr);
            gap: 12px;
            padding: 20px;
            background: #fff;
            border-radius: 0 0 16px 16px;
            box-shadow: 0 8px 30px rgba(0, 0, 0, 0.08);
        }

        .day {
            height: 140px;
            padding: 15px;
            box-sizing: border-box;
            background: #ffffff;
            border-radius: 16px;
            box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05);
            display: flex;
            flex-direction: column;
            justify-content: space-between;
            font-size: 18px;
            color: #333;
            cursor: pointer;
            transition: all 0.3s ease;
            user-select: none;
            position: relative;
            border: 2px solid transparent;
        }

        .day:hover {
            transform: translateY(-5px);
            box-shadow: 0 12px 25px rgba(0, 0, 0, 0.15);
            border-color: #e0e0e0;
        }

        .day.other-month {
            background: #f8f9fa;
            color: #bbb;
        }

        .day.today {
            background: linear-gradient(135deg, #0066ff, #00c8ff) !important;
            color: white !important;
            font-weight: bold;
            box-shadow: 0 8px 25px rgba(0, 102, 255, 0.3);
            border-color: #0066ff;
        }

        .day.selected {
            background: linear-gradient(135deg, #ff8800, #ffbb33) !important;
            color: white !important;
            font-weight: bold;
            box-shadow: 0 8px 25px rgba(255, 136, 0, 0.3);
            border-color: #ff8800;
        }

        .day-number {
            align-self: flex-end;
            font-weight: bold;
            font-size: 22px;
        }

        .completed-mark {
            position: absolute;
            top: 12px;
            right: 12px;
            font-size: 30px;
            color: #4caf50;
            text-shadow: 0 2px 8px rgba(76, 175, 80, 0.3);
        }

        /* 日期信息 */
        .date-info {
            text-align: center;
            font-size: 20px;
            margin-top: 30px;
            padding: 25px;
            background: white;
            border-radius: 16px;
            box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
            color: #555;
            font-weight: 500;
        }

        /* 左侧今日任务 */
        .today-tasks {
            margin-bottom: 30px;
        }

        .today-tasks h3 {
            text-align: center;
            margin-bottom: 25px;
            color: #2c3e50;
            font-size: 24px;
            font-weight: 700;
            position: relative;
            padding-bottom: 10px;
        }

        .today-tasks h3::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 50%;
            transform: translateX(-50%);
            width: 60px;
            height: 4px;
            background: linear-gradient(90deg, #667eea, #764ba2);
            border-radius: 2px;
        }

        .today-task-table {
            width: 100%;
            border-collapse: collapse;
            background: #f9f9f9;
            border-radius: 12px;
            overflow: hidden;
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.05);
        }

        .today-task-table th, .today-task-table td {
            padding: 14px 16px;
            text-align: left;
            border-bottom: 1px solid #eee;
        }

        .today-task-table th {
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
            font-weight: bold;
            font-size: 16px;
        }

        .today-task-table tbody tr {
            transition: all 0.3s ease;
        }

        .today-task-table tbody tr:hover {
            background-color: #f0f2ff;
        }

        .today-task-row.completed {
            opacity: 0.7;
            text-decoration: line-through;
            background: #f0f0f0;
        }

        .today-task-table td:last-child {
            text-align: center;
            width: 80px;
        }

        /* 新增:全部完成按钮样式 */
        .all-complete-display-btn {
            margin-top: 15px;
            text-align: center;
        }

        .all-complete-display-btn button {
            background: linear-gradient(135deg, #ffc107, #e0a800);
            color: white;
            border: none;
            padding: 12px 30px;
            border-radius: 12px;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            box-shadow: 0 6px 15px rgba(255, 193, 7, 0.3);
            transition: all 0.3s ease;
        }

        .all-complete-display-btn button:hover {
            transform: translateY(-3px);
            box-shadow: 0 10px 25px rgba(255, 193, 7, 0.4);
        }

        /* 右侧统计 */
        .stats {
            margin-bottom: 35px;
            text-align: center;
            padding: 30px 25px;
            background: linear-gradient(135deg, #a8edea 0%, #fed6e3 100%);
            border-radius: 16px;
            color: #333;
            box-shadow: 0 8px 25px rgba(0, 0, 0, 0.08);
        }

        .stats h3 {
            margin: 0 0 25px 0;
            font-size: 26px;
            color: #2c3e50;
            font-weight: 700;
        }

        .stats p {
            margin: 18px 0;
            font-size: 20px;
            font-weight: 500;
        }

        .stats strong {
            font-size: 28px;
            color: #0066ff;
            margin: 0 5px;
        }

        /* 跨日目标 */
        .long-term-goals h3 {
            text-align: center;
            margin-bottom: 25px;
            color: #2c3e50;
            font-size: 24px;
            font-weight: 700;
            position: relative;
            padding-bottom: 10px;
        }

        .long-term-goals h3::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 50%;
            transform: translateX(-50%);
            width: 60px;
            height: 4px;
            background: linear-gradient(90deg, #0066ff, #00c8ff);
            border-radius: 2px;
        }

        .goal-item {
            background: linear-gradient(135deg, #f9f9f9, #f0f0f0);
            padding: 20px;
            border-radius: 16px;
            margin-bottom: 18px;
            border-left: 6px solid #0066ff;
            box-shadow: 0 6px 20px rgba(0, 0, 0, 0.08);
            transition: all 0.3s ease;
            position: relative;
            overflow: hidden;
        }

        .goal-item::before {
            content: '';
            position: absolute;
            top: 0;
            left: 0;
            width: 100%;
            height: 100%;
            background: linear-gradient(135deg, rgba(0, 102, 255, 0.05), rgba(0, 200, 255, 0.05));
            z-index: 1;
            opacity: 0;
            transition: opacity 0.3s ease;
        }

        .goal-item:hover {
            transform: translateY(-5px);
            box-shadow: 0 12px 30px rgba(0, 0, 0, 0.12);
        }

        .goal-item:hover::before {
            opacity: 1;
        }

        .goal-title {
            font-weight: bold;
            font-size: 20px;
            margin-bottom: 10px;
            color: #2c3e50;
            position: relative;
            z-index: 2;
        }

        .goal-dates {
            font-size: 16px;
            color: #666;
            margin-bottom: 15px;
            position: relative;
            z-index: 2;
        }

        .countdown {
            font-size: 24px;
            font-weight: bold;
            color: #ff6b6b;
            margin-bottom: 15px;
            position: relative;
            z-index: 2;
        }

        .progress-bar {
            height: 14px;
            background: #e0e0e0;
            border-radius: 7px;
            overflow: hidden;
            position: relative;
            z-index: 2;
        }

        .progress-fill {
            height: 100%;
            background: linear-gradient(90deg, #0066ff, #00c8ff);
            border-radius: 7px;
            transition: width 0.8s ease;
        }

        /* 我不想干了按钮 - 红色 */
        .give-up-section {
            margin-top: 25px;
            text-align: center;
        }

        .give-up-btn {
            background: linear-gradient(135deg, #e74c3c, #c0392b);
            color: white;
            border: none;
            padding: 14px 28px;
            border-radius: 25px;
            font-size: 16px;
            font-weight: 600;
            cursor: pointer;
            box-shadow: 0 6px 20px rgba(231, 76, 60, 0.3);
            transition: all 0.3s ease;
            position: relative;
            overflow: hidden;
        }

        .give-up-btn::before {
            content: '';
            position: absolute;
            top: 0;
            left: -100%;
            width: 100%;
            height: 100%;
            background: linear-gradient(90deg, transparent, rgba(255,255,255,0.2), transparent);
            transition: left 0.5s ease;
        }

        .give-up-btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 10px 30px rgba(231, 76, 60, 0.4);
            background: linear-gradient(135deg, #c0392b, #a93226);
        }

        .give-up-btn:hover::before {
            left: 100%;
        }

        /* 鼓励模态框 */
        .encourage-modal {
            display: none;
            position: fixed;
            z-index: 2000;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.85);
            align-items: center;
            justify-content: center;
            backdrop-filter: blur(8px);
        }

        .encourage-content {
            background: linear-gradient(135deg, #e74c3c, #c0392b);
            color: white;
            padding: 60px 80px;
            border-radius: 30px;
            text-align: center;
            box-shadow: 0 25px 70px rgba(0, 0, 0, 0.5);
            max-width: 700px;
            animation: shakeIn 0.6s ease-out;
            position: relative;
            overflow: hidden;
        }

        .encourage-content::before {
            content: '';
            position: absolute;
            top: -50%;
            left: -50%;
            width: 200%;
            height: 200%;
            background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 1px, transparent 1px);
            background-size: 25px 25px;
            z-index: 1;
            animation: rotate 30s linear infinite;
        }

        @keyframes shakeIn {
            0% { transform: scale(0.5) rotate(-5deg); opacity: 0; }
            50% { transform: scale(1.1) rotate(3deg); }
            70% { transform: scale(0.95) rotate(-2deg); }
            100% { transform: scale(1) rotate(0); opacity: 1; }
        }

        @keyframes rotate {
            from { transform: rotate(0deg); }
            to { transform: rotate(360deg); }
        }

        .encourage-content h2 {
            font-size: 42px;
            margin-bottom: 30px;
            text-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
            position: relative;
            z-index: 2;
        }

        .encourage-content h2::before {
            content: '';
            display: block;
            font-size: 60px;
            margin-bottom: 15px;
        }

        .encourage-quote {
            font-size: 26px;
            line-height: 1.8;
            margin: 30px 0;
            text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
            position: relative;
            z-index: 2;
            font-weight: 500;
        }

        .encourage-close {
            margin-top: 40px;
            padding: 16px 40px;
            background: rgba(255, 255, 255, 0.2);
            border: 3px solid white;
            color: white;
            border-radius: 50px;
            cursor: pointer;
            font-size: 20px;
            font-weight: bold;
            transition: all 0.3s ease;
            position: relative;
            z-index: 2;
            letter-spacing: 1px;
        }

        .encourage-close:hover {
            background: rgba(255, 255, 255, 0.3);
            transform: scale(1.08);
            box-shadow: 0 8px 25px rgba(255, 255, 255, 0.2);
        }

        /* 庆祝模态框 */
        .celebrate-modal {
            display: none;
            position: fixed;
            z-index: 2000;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.85);
            align-items: center;
            justify-content: center;
            backdrop-filter: blur(5px);
        }

        .celebrate-content {
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
            padding: 70px 90px;
            border-radius: 30px;
            text-align: center;
            box-shadow: 0 25px 70px rgba(0, 0, 0, 0.5);
            max-width: 650px;
            animation: zoomIn 0.8s ease-out;
            position: relative;
            overflow: hidden;
        }

        .celebrate-content::before {
            content: '';
            position: absolute;
            top: -50%;
            left: -50%;
            width: 200%;
            height: 200%;
            background: radial-gradient(circle, rgba(255, 255, 255, 0.1) 1px, transparent 1px);
            background-size: 30px 30px;
            z-index: 1;
            animation: sparkle 20s linear infinite;
        }

        .celebrate-content h2 {
            font-size: 52px;
            margin-bottom: 40px;
            text-shadow: 0 4px 15px rgba(0, 0, 0, 0.3);
            position: relative;
            z-index: 2;
        }

        .celebrate-quote {
            font-size: 30px;
            font-style: italic;
            line-height: 1.6;
            margin: 40px 0;
            text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
            position: relative;
            z-index: 2;
        }

        .celebrate-close {
            margin-top: 50px;
            padding: 18px 45px;
            background: rgba(255, 255, 255, 0.2);
            border: 3px solid white;
            color: white;
            border-radius: 50px;
            cursor: pointer;
            font-size: 22px;
            font-weight: bold;
            transition: all 0.3s ease;
            position: relative;
            z-index: 2;
            letter-spacing: 1px;
        }

        .celebrate-close:hover {
            background: rgba(255, 255, 255, 0.3);
            transform: scale(1.08);
            box-shadow: 0 8px 25px rgba(255, 255, 255, 0.2);
        }

        @keyframes zoomIn {
            from {
                transform: scale(0.3);
                opacity: 0;
            }
            to {
                transform: scale(1);
                opacity: 1;
            }
        }

        @keyframes sparkle {
            0% {
                transform: rotate(0deg);
            }
            100% {
                transform: rotate(360deg);
            }
        }

        /* 模态框通用样式 */
        .modal, .daily-task-modal, .settings-modal, .long-term-modal, .encourage-settings-modal {
            display: none;
            position: fixed;
            z-index: 1500;
            left: 0;
            top: 0;
            width: 100%;
            height: 100%;
            background-color: rgba(0, 0, 0, 0.6);
            align-items: center;
            justify-content: center;
            backdrop-filter: blur(5px);
        }

        .modal-content {
            background: white;
            padding: 45px;
            border-radius: 24px;
            width: 850px;
            max-width: 95%;
            max-height: 85vh;
            overflow-y: auto;
            box-shadow: 0 20px 60px rgba(0, 0, 0, 0.25);
            animation: modalAppear 0.4s ease-out;
        }

        @keyframes modalAppear {
            from {
                opacity: 0;
                transform: translateY(-30px);
            }
            to {
                opacity: 1;
                transform: translateY(0);
            }
        }

        .modal-header {
            font-size: 32px;
            margin-bottom: 35px;
            text-align: center;
            font-weight: bold;
            color: #2c3e50;
            position: relative;
            padding-bottom: 15px;
        }

        .modal-header::after {
            content: '';
            position: absolute;
            bottom: 0;
            left: 50%;
            transform: translateX(-50%);
            width: 80px;
            height: 5px;
            background: linear-gradient(90deg, #667eea, #764ba2);
            border-radius: 3px;
        }

        /* 按钮样式 */
        .add-field-btn, .add-row-btn {
            background: linear-gradient(135deg, #17a2b8, #138496);
            color: white;
            border: none;
            padding: 14px 24px;
            border-radius: 12px;
            cursor: pointer;
            margin-right: 12px;
            margin-bottom: 20px;
            font-size: 16px;
            font-weight: 600;
            box-shadow: 0 6px 15px rgba(23, 162, 184, 0.3);
            transition: all 0.3s ease;
        }

        .add-field-btn:hover, .add-row-btn:hover {
            transform: translateY(-3px);
            box-shadow: 0 10px 25px rgba(23, 162, 184, 0.4);
        }

        .delete-field {
            background: none;
            border: none;
            color: #ff4444;
            cursor: pointer;
            font-size: 22px;
            margin-left: 10px;
            visibility: hidden;
            transition: all 0.3s;
            font-weight: bold;
        }

        th:hover .delete-field {
            visibility: visible;
        }

        .modal-buttons {
            display: flex;
            justify-content: flex-end;
            margin-top: 40px;
            gap: 20px;
        }

        .modal-buttons button {
            padding: 14px 32px;
            border: none;
            border-radius: 12px;
            cursor: pointer;
            font-size: 18px;
            font-weight: 600;
            transition: all 0.3s ease;
            min-width: 140px;
        }

        #daily-task-save, #long-term-save, #settings-save, #encourage-settings-save {
            background: linear-gradient(135deg, #667eea, #764ba2);
            color: white;
            box-shadow: 0 6px 20px rgba(102, 126, 234, 0.3);
        }

        #daily-task-cancel, #long-term-cancel, #settings-cancel, #encourage-settings-cancel {
            background: #e0e0e0;
            color: #666;
        }

        #daily-task-save:hover, #long-term-save:hover, #settings-save:hover, #encourage-settings-save:hover {
            transform: translateY(-3px);
            box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
        }

        #daily-task-cancel:hover, #long-term-cancel:hover, #settings-cancel:hover, #encourage-settings-cancel:hover {
            background: #d0d0d0;
            transform: translateY(-2px);
        }

        /* 表格样式 */
        table {
            width: 100%;
            border-collapse: collapse;
            margin-top: 20px;
        }

        th, td {
            padding: 14px 16px;
            text-align: left;
            border-bottom: 1px solid #eee;
        }

        th {
            background-color: #f8f9fa;
            font-weight: bold;
            color: #444;
        }

        tbody tr:hover {
            background-color: #f5f7ff;
        }

        input[type="text"], input[type="date"], textarea {
            width: 100%;
            padding: 12px 16px;
            border: 2px solid #e0e0e0;
            border-radius: 10px;
            font-size: 16px;
            transition: all 0.3s;
        }

        input[type="text"]:focus, input[type="date"]:focus, textarea:focus {
            border-color: #667eea;
            box-shadow: 0 0 0 3px rgba(102, 126, 234, 0.2);
            outline: none;
        }

        textarea {
            resize: vertical;
            min-height: 150px;
        }

        .form-group {
            margin-bottom: 25px;
        }

        .form-group label {
            display: block;
            margin-bottom: 10px;
            font-weight: 600;
            color: #444;
            font-size: 17px;
        }

        /* 自定义语录 */
        #quotes-list, #encourage-quotes-list {
            margin-top: 15px;
        }

        .quote-item {
            display: flex;
            justify-content: space-between;
            align-items: center;
            padding: 12px 16px;
            background-color: #f8f9fa;
            border-radius: 10px;
            margin-bottom: 10px;
            border-left: 4px solid #667eea;
        }

        .quote-delete {
            background: none;
            border: none;
            color: #ff4444;
            cursor: pointer;
            font-size: 20px;
            font-weight: bold;
            padding: 0 8px;
        }

        /* 任务完成复选框 */
        input[type="checkbox"] {
            width: 22px;
            height: 22px;
            cursor: pointer;
            accent-color: #4caf50;
        }

        /* 空状态提示 */
        .empty-state {
            text-align: center;
            color: #999;
            padding: 40px 20px;
            font-size: 17px;
            line-height: 1.6;
        }

        /* 本地文件选择样式 - 优化版 */
        .file-input-wrapper {
            position: relative;
            display: inline-block;
            width: 100%;
        }

        .file-input {
            position: absolute;
            opacity: 0;
            width: 100%;
            height: 100%;
            cursor: pointer;
        }

        .file-input-label {
            display: block;
            width: 100%;
            padding: 16px 20px;
            border: 2px dashed #667eea;
            border-radius: 12px;
            font-size: 16px;
            background: linear-gradient(135deg, #f5f7ff, #fff);
            cursor: pointer;
            transition: all 0.3s;
            text-align: center;
            color: #667eea;
            font-weight: 500;
        }

        .file-input-label:hover {
            border-color: #764ba2;
            background: linear-gradient(135deg, #f0f2ff, #f8f5ff);
            transform: translateY(-2px);
            box-shadow: 0 6px 20px rgba(102, 126, 234, 0.15);
        }

        .file-name {
            margin-top: 12px;
            font-size: 14px;
            color: #666;
            padding: 12px 16px;
            background: linear-gradient(135deg, #e8f5e9, #f1f8e9);
            border-radius: 10px;
            border-left: 4px solid #4caf50;
            display: flex;
            justify-content: space-between;
            align-items: center;
        }

        .file-name .file-size {
            color: #888;
            font-size: 13px;
        }

        .file-name .delete-file-btn {
            background: none;
            border: none;
            color: #ff4444;
            cursor: pointer;
            font-size: 18px;
            padding: 0 5px;
            transition: transform 0.2s;
        }

        .file-name .delete-file-btn:hover {
            transform: scale(1.2);
        }

        /* 上传进度条 */
        .upload-progress {
            margin-top: 10px;
            display: none;
        }

        .upload-progress-bar {
            height: 8px;
            background: #e0e0e0;
            border-radius: 4px;
            overflow: hidden;
        }

        .upload-progress-fill {
            height: 100%;
            background: linear-gradient(90deg, #667eea, #764ba2);
            border-radius: 4px;
            width: 0%;
            transition: width 0.3s ease;
        }

        .upload-progress-text {
            text-align: center;
            font-size: 13px;
            color: #666;
            margin-top: 5px;
        }

        /* 文件大小提示 */
        .file-size-hint {
            font-size: 13px;
            color: #888;
            margin-top: 8px;
            display: flex;
            align-items: center;
            gap: 5px;
        }

        .file-size-hint .hint-icon {
            color: #17a2b8;
        }

/* ===== 实时时钟样式 ===== */
.realtime-clock {
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 15px;
    padding: 20px;
    background: linear-gradient(135deg, #667eea, #764ba2);
    border-radius: 16px;
    margin-bottom: 25px;
    box-shadow: 0 8px 25px rgba(102, 126, 234, 0.3);
    color: white;
}

.clock-icon {
    font-size: 36px;
    animation: clockPulse 1s ease-in-out infinite;
}

@keyframes clockPulse {
    0%, 100% { transform: scale(1); }
    50% { transform: scale(1.1); }
}

.clock-display {
    text-align: center;
}

.clock-time {
    font-size: 32px;
    font-weight: bold;
    font-family: 'Courier New', monospace;
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.2);
}

.clock-date {
    font-size: 14px;
    opacity: 0.9;
    margin-top: 5px;
}

.clock-refresh {
    background: rgba(255, 255, 255, 0.2);
    border: none;
    width: 40px;
    height: 40px;
    border-radius: 50%;
    font-size: 20px;
    cursor: pointer;
    transition: all 0.3s ease;
}

.clock-refresh:hover {
    background: rgba(255, 255, 255, 0.3);
    transform: rotate(180deg);
}

/* ===== 署名样式 ===== */
.signature {
    text-align: center;
    margin-top: 20px;
    padding: 15px;
    font-size: 16px;
    color: #888;
    font-style: italic;
    background: linear-gradient(135deg, #f8f9fa, #e9ecef);
    border-radius: 12px;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
}

/* ===== 闹钟模态框样式 ===== */
.alarm-modal {
    display: none;
    position: fixed;
    z-index: 1500;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.6);
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(5px);
}

.alarm-list {
    margin-top: 20px;
    max-height: 300px;
    overflow-y: auto;
}

.alarm-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 15px 20px;
    background: linear-gradient(135deg, #f8f9fa, #e9ecef);
    border-radius: 12px;
    margin-bottom: 12px;
    border-left: 5px solid #f39c12;
    transition: all 0.3s ease;
}

.alarm-item:hover {
    transform: translateX(5px);
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.1);
}

.alarm-item-info {
    flex: 1;
}

.alarm-item-time {
    font-size: 18px;
    font-weight: bold;
    color: #2c3e50;
    margin-bottom: 5px;
}

.alarm-item-note {
    font-size: 14px;
    color: #666;
}

.alarm-item-delete {
    background: none;
    border: none;
    color: #e74c3c;
    font-size: 22px;
    cursor: pointer;
    padding: 5px 10px;
    transition: transform 0.2s;
}

.alarm-item-delete:hover {
    transform: scale(1.2);
}

.alarm-input-group {
    display: flex;
    gap: 15px;
    flex-wrap: wrap;
    margin-bottom: 15px;
}

.alarm-input-group input {
    flex: 1;
    min-width: 120px;
}

.alarm-input-wrapper {
    display: flex;
    flex-direction: column;
    flex: 1;
}

.alarm-input-wrapper label {
    font-size: 13px;
    color: #666;
    margin-bottom: 5px;
}

.radio-group {
    display: flex;
    gap: 20px;
    flex-wrap: wrap;
}

.radio-group label {
    display: flex;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    padding: 10px 15px;
    background: #f8f9fa;
    border-radius: 10px;
    transition: all 0.3s ease;
}

.radio-group label:hover {
    background: #e9ecef;
}

.radio-group input[type="radio"] {
    width: 18px;
    height: 18px;
}

/* ===== 闹钟提醒模态框 ===== */
.alarm-alert-modal {
    display: none;
    position: fixed;
    z-index: 3000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.85);
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(8px);
}

.alarm-alert-content {
    background: linear-gradient(135deg, #f39c12, #e67e22);
    color: white;
    padding: 60px 80px;
    border-radius: 30px;
    text-align: center;
    box-shadow: 0 25px 70px rgba(0, 0, 0, 0.5);
    max-width: 600px;
    animation: alarmPulse 0.5s ease-out infinite alternate;
    position: relative;
}

@keyframes alarmPulse {
    0% { transform: scale(1); box-shadow: 0 25px 70px rgba(0, 0, 0, 0.5); }
    100% { transform: scale(1.02); box-shadow: 0 30px 80px rgba(243, 156, 18, 0.6); }
}

.alarm-alert-content h2 {
    font-size: 48px;
    margin-bottom: 20px;
}

.alarm-alert-time {
    font-size: 36px;
    font-weight: bold;
    margin-bottom: 20px;
    text-shadow: 0 2px 10px rgba(0, 0, 0, 0.3);
}

.alarm-alert-note {
    font-size: 24px;
    margin-bottom: 30px;
    padding: 20px;
    background: rgba(255, 255, 255, 0.15);
    border-radius: 15px;
}

.alarm-alert-close {
    padding: 16px 50px;
    background: rgba(255, 255, 255, 0.2);
    border: 3px solid white;
    color: white;
    border-radius: 50px;
    cursor: pointer;
    font-size: 20px;
    font-weight: bold;
    transition: all 0.3s ease;
}

.alarm-alert-close:hover {
    background: rgba(255, 255, 255, 0.3);
    transform: scale(1.05);
}

/* ===== 恢复出厂设置确认模态框 ===== */
.reset-confirm-modal {
    display: none;
    position: fixed;
    z-index: 2500;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.85);
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(8px);
}

.reset-confirm-content {
    background: linear-gradient(135deg, #2c3e50, #34495e);
    color: white;
    padding: 50px 70px;
    border-radius: 25px;
    text-align: center;
    box-shadow: 0 25px 70px rgba(0, 0, 0, 0.5);
    max-width: 550px;
    animation: modalAppear 0.4s ease-out;
}

.reset-confirm-content h2 {
    font-size: 32px;
    margin-bottom: 30px;
    color: #f39c12;
}

.reset-confirm-content p {
    font-size: 22px;
    line-height: 1.8;
    margin-bottom: 40px;
}

.reset-confirm-buttons {
    display: flex;
    gap: 20px;
    justify-content: center;
    flex-wrap: wrap;
}

.reset-confirm-buttons button {
    padding: 16px 35px;
    border: none;
    border-radius: 50px;
    font-size: 18px;
    font-weight: bold;
    cursor: pointer;
    transition: all 0.3s ease;
}

.btn-keep-going {
    background: linear-gradient(135deg, #27ae60, #2ecc71);
    color: white;
    box-shadow: 0 6px 20px rgba(39, 174, 96, 0.4);
}

.btn-keep-going:hover {
    transform: translateY(-3px) scale(1.05);
    box-shadow: 0 10px 30px rgba(39, 174, 96, 0.5);
}

.btn-give-up {
    background: linear-gradient(135deg, #95a5a6, #7f8c8d);
    color: white;
    box-shadow: 0 6px 20px rgba(149, 165, 166, 0.4);
}

.btn-give-up:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 30px rgba(149, 165, 166, 0.5);
}

/* ===== 小卡片动画模态框 ===== */
.cards-animation-modal {
    display: none;
    position: fixed;
    z-index: 2000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background: linear-gradient(135deg, 
        #fff0f3 0%, 
        #ffe4ec 25%, 
        #ffd6e0 50%, 
        #ffccd5 75%, 
        #ffb3c1 100%);
}

.cards-board {
    position: relative;
    width: 100%;
    height: 100%;
    overflow: hidden;
}

.cards-close-btn {
    position: fixed;
    top: 20px;
    right: 20px;
    z-index: 2100;
    background: rgba(255, 255, 255, 0.9);
    border: none;
    width: 50px;
    height: 50px;
    border-radius: 50%;
    font-size: 20px;
    cursor: pointer;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.2);
    transition: all 0.3s ease;
}

.cards-close-btn:hover {
    transform: scale(1.1);
    background: white;
}

/* ===== 视频播放模态框 ===== */
.video-modal {
    display: none;
    position: fixed;
    z-index: 3000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.95);
    align-items: center;
    justify-content: center;
}

.video-modal-content {
    position: relative;
    max-width: 90%;
    max-height: 90%;
}

.video-modal-content video {
    max-width: 100%;
    max-height: 85vh;
    border-radius: 15px;
    box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5);
}

.video-close-btn {
    position: absolute;
    top: -50px;
    right: 0;
    background: rgba(255, 255, 255, 0.2);
    border: 2px solid white;
    color: white;
    padding: 10px 25px;
    border-radius: 25px;
    font-size: 16px;
    cursor: pointer;
    transition: all 0.3s ease;
}

.video-close-btn:hover {
    background: rgba(255, 255, 255, 0.3);
}

/* ===== 小卡片样式 ===== */
.card {
    position: absolute;
    left: 0;
    top: 0;
    border-radius: 14px;
    opacity: 0;
    cursor: grab;
    user-select: none;
    will-change: transform, opacity;
    backface-visibility: hidden;
}

.card.show { opacity: 1; }

.card.color-pink {
    background: linear-gradient(135deg, #ff9a9e 0%, #fecfef 100%);
    border: 2px solid rgba(255,255,255,0.7);
    box-shadow: 0 4px 20px rgba(255, 154, 158, 0.35);
}
.card.color-pink .card-body { color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.1); }

.card.color-purple {
    background: linear-gradient(135deg, #a18cd1 0%, #fbc2eb 100%);
    border: 2px solid rgba(255,255,255,0.7);
    box-shadow: 0 4px 20px rgba(161, 140, 209, 0.35);
}
.card.color-purple .card-body { color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.1); }

.card.color-blue {
    background: linear-gradient(135deg, #89c4f4 0%, #c5e1f5 100%);
    border: 2px solid rgba(255,255,255,0.7);
    box-shadow: 0 4px 20px rgba(137, 196, 244, 0.35);
}
.card.color-blue .card-body { color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.1); }

.card.color-mint {
    background: linear-gradient(135deg, #80deea 0%, #b2ebf2 100%);
    border: 2px solid rgba(255,255,255,0.7);
    box-shadow: 0 4px 20px rgba(128, 222, 234, 0.35);
}
.card.color-mint .card-body { color: #4a9ea8; text-shadow: 0 1px 0 rgba(255,255,255,0.5); }

.card.color-yellow {
    background: linear-gradient(135deg, #ffeaa7 0%, #fff3b0 100%);
    border: 2px solid rgba(255,255,255,0.8);
    box-shadow: 0 4px 20px rgba(255, 234, 167, 0.4);
}
.card.color-yellow .card-body { color: #b8860b; text-shadow: 0 1px 0 rgba(255,255,255,0.5); }

.card.color-orange {
    background: linear-gradient(135deg, #ffecd2 0%, #fcb69f 100%);
    border: 2px solid rgba(255,255,255,0.7);
    box-shadow: 0 4px 20px rgba(252, 182, 159, 0.35);
}
.card.color-orange .card-body { color: #d35400; text-shadow: 0 1px 0 rgba(255,255,255,0.3); }

.card.color-green {
    background: linear-gradient(135deg, #a8e6cf 0%, #dcedc1 100%);
    border: 2px solid rgba(255,255,255,0.7);
    box-shadow: 0 4px 20px rgba(168, 230, 207, 0.35);
}
.card.color-green .card-body { color: #27ae60; text-shadow: 0 1px 0 rgba(255,255,255,0.5); }

.card.color-coral {
    background: linear-gradient(135deg, #ff7675 0%, #fab1a0 100%);
    border: 2px solid rgba(255,255,255,0.7);
    box-shadow: 0 4px 20px rgba(255, 118, 117, 0.35);
}
.card.color-coral .card-body { color: #fff; text-shadow: 0 1px 2px rgba(0,0,0,0.15); }

.card.color-lavender {
    background: linear-gradient(135deg, #dda0dd 0%, #e6e6fa 100%);
    border: 2px solid rgba(255,255,255,0.7);
    box-shadow: 0 4px 20px rgba(221, 160, 221, 0.35);
}
.card.color-lavender .card-body { color: #8b008b; text-shadow: 0 1px 0 rgba(255,255,255,0.4); }

.card.color-white {
    background: linear-gradient(135deg, #ffffff 0%, #f8f9fa 100%);
    border: 2px solid rgba(255,200,210,0.5);
    box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08);
}
.card.color-white .card-body { color: #e84393; }

.card.float-in {
    animation: floatIn 0.6s cubic-bezier(0.25, 0.46, 0.45, 0.94) forwards;
    animation-delay: var(--delay, 0s);
}

@keyframes floatIn {
    0% {
        opacity: 0;
        transform: var(--base-transform) translateY(var(--float-y, -40px)) rotate(calc(var(--rotation) + var(--float-r, 25deg))) scale(0.5);
    }
    60% {
        opacity: 1;
        transform: var(--base-transform) translateY(5px) rotate(calc(var(--rotation) - 3deg)) scale(1.03);
    }
    100% {
        opacity: 1;
        transform: var(--base-transform) rotate(var(--rotation)) scale(1);
    }
}

.card.dragging {
    cursor: grabbing;
    box-shadow: 0 20px 50px rgba(0, 0, 0, 0.2) !important;
    z-index: 999999 !important;
}

.card-body {
    padding: 14px 12px;
    font-size: 17px;
    line-height: 1.35;
    font-weight: 600;
    text-align: center;
    height: 100%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
}

/* ===== 美化设置模态框 ===== */
.mode-selector {
    display: flex;
    gap: 15px;
    flex-wrap: wrap;
}

.mode-option {
    flex: 1;
    min-width: 200px;
    cursor: pointer;
}

.mode-option input[type="radio"] {
    display: none;
}

.mode-card {
    display: flex;
    flex-direction: column;
    align-items: center;
    padding: 20px 15px;
    background: linear-gradient(135deg, #f8f9fa, #e9ecef);
    border: 3px solid transparent;
    border-radius: 16px;
    transition: all 0.3s ease;
    text-align: center;
}

.mode-option input[type="radio"]:checked + .mode-card {
    background: linear-gradient(135deg, #667eea15, #764ba215);
    border-color: #667eea;
    box-shadow: 0 8px 25px rgba(102, 126, 234, 0.2);
}

.mode-card:hover {
    transform: translateY(-3px);
    box-shadow: 0 8px 20px rgba(0, 0, 0, 0.1);
}

.mode-icon {
    font-size: 36px;
    margin-bottom: 10px;
}

.mode-title {
    font-size: 16px;
    font-weight: bold;
    color: #2c3e50;
    margin-bottom: 5px;
}

.mode-desc {
    font-size: 12px;
    color: #888;
}

/* 文件上传美化 */
.file-upload-box {
    position: relative;
    border: 3px dashed #667eea;
    border-radius: 16px;
    background: linear-gradient(135deg, #f8f9ff, #fff);
    overflow: hidden;
    transition: all 0.3s ease;
}

.file-upload-box:hover {
    border-color: #764ba2;
    background: linear-gradient(135deg, #f0f2ff, #f8f5ff);
    transform: translateY(-2px);
    box-shadow: 0 8px 25px rgba(102, 126, 234, 0.15);
}

.file-upload-box .file-input {
    position: absolute;
    width: 100%;
    height: 100%;
    opacity: 0;
    cursor: pointer;
    z-index: 2;
}

.file-upload-label {
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    padding: 30px 20px;
    cursor: pointer;
}

.upload-icon {
    font-size: 48px;
    margin-bottom: 15px;
}

.upload-text {
    font-size: 16px;
    font-weight: 600;
    color: #667eea;
    margin-bottom: 8px;
}

.upload-hint {
    font-size: 12px;
    color: #999;
}

.selected-file {
    margin-top: 12px;
    padding: 15px 20px;
    background: linear-gradient(135deg, #d4edda, #c3e6cb);
    border-radius: 12px;
    border-left: 5px solid #28a745;
    display: flex;
    justify-content: space-between;
    align-items: center;
    animation: slideIn 0.3s ease;
}

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

.selected-file .file-info {
    display: flex;
    align-items: center;
    gap: 10px;
}

.selected-file .file-icon {
    font-size: 24px;
}

.selected-file .file-details {
    display: flex;
    flex-direction: column;
}

.selected-file .file-name-text {
    font-weight: 600;
    color: #155724;
}

.selected-file .file-size-text {
    font-size: 12px;
    color: #666;
}

.selected-file .delete-btn {
    background: #dc3545;
    color: white;
    border: none;
    width: 30px;
    height: 30px;
    border-radius: 50%;
    font-size: 18px;
    cursor: pointer;
    transition: all 0.2s ease;
}

.selected-file .delete-btn:hover {
    transform: scale(1.1);
    background: #c82333;
}

.input-hint {
    font-size: 12px;
    color: #888;
    margin-top: 8px;
    padding-left: 5px;
}

/* 按钮美化 */
.modal-buttons .btn-cancel {
    background: linear-gradient(135deg, #e0e0e0, #d0d0d0);
    color: #555;
    border: none;
    padding: 14px 32px;
    border-radius: 12px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    transition: all 0.3s ease;
}

.modal-buttons .btn-cancel:hover {
    background: linear-gradient(135deg, #d0d0d0, #c0c0c0);
    transform: translateY(-2px);
}

.modal-buttons .btn-save {
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: white;
    border: none;
    padding: 14px 32px;
    border-radius: 12px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    box-shadow: 0 6px 20px rgba(102, 126, 234, 0.3);
    transition: all 0.3s ease;
}

.modal-buttons .btn-save:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
}

/* 模态框内容防溢出 */
.modal-content {
    max-height: 90vh;
    overflow-y: auto;
    overflow-x: hidden;
}

.modal-content::-webkit-scrollbar {
    width: 8px;
}

.modal-content::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 4px;
}

.modal-content::-webkit-scrollbar-thumb {
    background: linear-gradient(135deg, #667eea, #764ba2);
    border-radius: 4px;
}

.modal-content::-webkit-scrollbar-thumb:hover {
    background: linear-gradient(135deg, #5a6fd6, #6a4190);
}

/* 表单组间距优化 */
.form-group {
    margin-bottom: 25px;
}

.form-group label {
    display: block;
    margin-bottom: 12px;
    font-weight: 600;
    color: #2c3e50;
    font-size: 16px;
}

.form-group textarea {
    width: 100%;
    padding: 15px;
    border: 2px solid #e0e0e0;
    border-radius: 12px;
    font-size: 15px;
    line-height: 1.6;
    resize: vertical;
    transition: all 0.3s ease;
    font-family: inherit;
}

.form-group textarea:focus {
    border-color: #667eea;
    box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.15);
    outline: none;
}

.form-group textarea::placeholder {
    color: #aaa;
}

/* ===== 颜色选择器美化 ===== */
.color-picker-box {
    display: flex;
    align-items: center;
    gap: 20px;
}

.color-picker-box input[type="color"] {
    width: 80px;
    height: 50px;
    border: none;
    border-radius: 12px;
    cursor: pointer;
    padding: 0;
    overflow: hidden;
}

.color-picker-box input[type="color"]::-webkit-color-swatch-wrapper {
    padding: 0;
}

.color-picker-box input[type="color"]::-webkit-color-swatch {
    border: none;
    border-radius: 12px;
}

.color-preview {
    flex: 1;
    height: 50px;
    border-radius: 12px;
    display: flex;
    align-items: center;
    justify-content: center;
    color: #666;
    font-size: 14px;
    border: 2px dashed #ddd;
    transition: all 0.3s ease;
}

/* ===== 日期时间选择器美化 ===== */
.datetime-picker {
    display: flex;
    gap: 20px;
    flex-wrap: wrap;
}

.datetime-input-wrapper {
    flex: 1;
    min-width: 180px;
    display: flex;
    flex-direction: column;
    gap: 8px;
}

.datetime-label {
    font-size: 13px;
    color: #666;
    font-weight: 500;
}

.datetime-input-wrapper input {
    padding: 15px;
    border: 2px solid #e0e0e0;
    border-radius: 12px;
    font-size: 16px;
    transition: all 0.3s ease;
}

.datetime-input-wrapper input:focus {
    border-color: #667eea;
    box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.15);
    outline: none;
}

/* ===== 添加闹钟区域 ===== */
.add-alarm-section {
    background: linear-gradient(135deg, #f8f9ff, #fff);
    border-radius: 16px;
    padding: 25px;
    margin-bottom: 25px;
    border: 2px solid #e8ecf5;
}

.section-title {
    font-size: 18px;
    color: #2c3e50;
    margin: 0 0 20px 0;
    padding-bottom: 12px;
    border-bottom: 2px solid #e8ecf5;
}

.btn-add-alarm {
    width: 100%;
    padding: 16px;
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: white;
    border: none;
    border-radius: 12px;
    font-size: 18px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    box-shadow: 0 6px 20px rgba(102, 126, 234, 0.3);
    transition: all 0.3s ease;
    margin-top: 20px;
}

.btn-add-alarm:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
}

.btn-add-alarm span {
    font-size: 20px;
}

/* ===== 闹钟列表区域 ===== */
.alarm-list-section {
    background: #fff;
    border-radius: 16px;
    padding: 20px;
    border: 2px solid #e8ecf5;
}

.alarm-list {
    max-height: 250px;
    overflow-y: auto;
    padding-right: 5px;
}

.alarm-list::-webkit-scrollbar {
    width: 6px;
}

.alarm-list::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 3px;
}

.alarm-list::-webkit-scrollbar-thumb {
    background: linear-gradient(135deg, #667eea, #764ba2);
    border-radius: 3px;
}

.empty-alarm {
    text-align: center;
    color: #999;
    padding: 30px;
    font-size: 15px;
}

.alarm-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 18px 20px;
    background: linear-gradient(135deg, #f8f9fa, #fff);
    border-radius: 14px;
    margin-bottom: 12px;
    border-left: 5px solid #667eea;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
    transition: all 0.3s ease;
}

.alarm-item:hover {
    transform: translateX(5px);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);
}

.alarm-item:last-child {
    margin-bottom: 0;
}

.alarm-item-info {
    flex: 1;
}

.alarm-item-time {
    font-size: 20px;
    font-weight: bold;
    color: #2c3e50;
    margin-bottom: 6px;
    display: flex;
    align-items: center;
    gap: 10px;
}

.alarm-item-time::before {
    content: '⏰';
    font-size: 18px;
}

.alarm-item-note {
    font-size: 14px;
    color: #666;
    display: flex;
    align-items: center;
    gap: 8px;
}

.alarm-mode-tag {
    display: inline-block;
    padding: 3px 10px;
    background: linear-gradient(135deg, #667eea20, #764ba220);
    color: #667eea;
    border-radius: 20px;
    font-size: 12px;
    font-weight: 600;
}

.alarm-item-delete {
    background: linear-gradient(135deg, #ff6b6b, #ee5a5a);
    border: none;
    color: white;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    font-size: 18px;
    cursor: pointer;
    transition: all 0.3s ease;
    display: flex;
    align-items: center;
    justify-content: center;
}

.alarm-item-delete:hover {
    transform: scale(1.15);
    box-shadow: 0 4px 15px rgba(255, 107, 107, 0.4);
}

/* ===== 通用输入框美化 ===== */
.form-group input[type="text"] {
    width: 100%;
    padding: 15px;
    border: 2px solid #e0e0e0;
    border-radius: 12px;
    font-size: 16px;
    transition: all 0.3s ease;
}

.form-group input[type="text"]:focus {
    border-color: #667eea;
    box-shadow: 0 0 0 4px rgba(102, 126, 234, 0.15);
    outline: none;
}

.form-group input[type="text"]::placeholder {
    color: #aaa;
}

/* ===== 跨日目标模态框美化 ===== */
.add-goal-section {
    background: linear-gradient(135deg, #f8f9ff, #fff);
    border-radius: 16px;
    padding: 25px;
    margin-bottom: 25px;
    border: 2px solid #e8ecf5;
}

.btn-add-goal {
    width: 100%;
    padding: 16px;
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: white;
    border: none;
    border-radius: 12px;
    font-size: 18px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    box-shadow: 0 6px 20px rgba(102, 126, 234, 0.3);
    transition: all 0.3s ease;
    margin-top: 20px;
}

.btn-add-goal:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 30px rgba(102, 126, 234, 0.4);
}

.btn-add-goal span {
    font-size: 20px;
}

.goal-list-section {
    background: #fff;
    border-radius: 16px;
    padding: 20px;
    border: 2px solid #e8ecf5;
}

.goal-list-container {
    max-height: 300px;
    overflow-y: auto;
    padding-right: 5px;
}

.goal-list-container::-webkit-scrollbar {
    width: 6px;
}

.goal-list-container::-webkit-scrollbar-track {
    background: #f1f1f1;
    border-radius: 3px;
}

.goal-list-container::-webkit-scrollbar-thumb {
    background: linear-gradient(135deg, #667eea, #764ba2);
    border-radius: 3px;
}

.empty-goal {
    text-align: center;
    color: #999;
    padding: 30px;
    font-size: 15px;
}

.goal-list-item {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 18px 20px;
    background: linear-gradient(135deg, #f8f9fa, #fff);
    border-radius: 14px;
    margin-bottom: 12px;
    border-left: 5px solid #667eea;
    box-shadow: 0 4px 15px rgba(0, 0, 0, 0.05);
    transition: all 0.3s ease;
}

.goal-list-item:hover {
    transform: translateX(5px);
    box-shadow: 0 6px 20px rgba(0, 0, 0, 0.1);
}

.goal-list-item:last-child {
    margin-bottom: 0;
}

.goal-list-item.completed {
    border-left-color: #27ae60;
    background: linear-gradient(135deg, #d4edda, #c3e6cb);
}

.goal-list-item.failed {
    border-left-color: #e74c3c;
    background: linear-gradient(135deg, #f8d7da, #f5c6cb);
    opacity: 0.8;
}

.goal-item-info {
    flex: 1;
}

.goal-item-name {
    font-size: 18px;
    font-weight: bold;
    color: #2c3e50;
    margin-bottom: 8px;
    display: flex;
    align-items: center;
    gap: 10px;
}

.goal-item-name::before {
    content: '🎯';
    font-size: 16px;
}

.goal-item-dates {
    font-size: 13px;
    color: #666;
    margin-bottom: 6px;
}

.goal-item-countdown {
    font-size: 14px;
    font-weight: 600;
    color: #667eea;
}

.goal-status-tag {
    display: inline-block;
    padding: 4px 12px;
    border-radius: 20px;
    font-size: 12px;
    font-weight: 600;
    margin-left: 10px;
}

.goal-status-tag.running {
    background: linear-gradient(135deg, #667eea20, #764ba220);
    color: #667eea;
}

.goal-status-tag.completed {
    background: linear-gradient(135deg, #27ae6020, #2ecc7120);
    color: #27ae60;
}

.goal-status-tag.failed {
    background: linear-gradient(135deg, #e74c3c20, #c0392b20);
    color: #e74c3c;
}

.goal-item-delete {
    background: linear-gradient(135deg, #ff6b6b, #ee5a5a);
    border: none;
    color: white;
    width: 36px;
    height: 36px;
    border-radius: 50%;
    font-size: 18px;
    cursor: pointer;
    transition: all 0.3s ease;
    display: flex;
    align-items: center;
    justify-content: center;
}

.goal-item-delete:hover {
    transform: scale(1.15);
    box-shadow: 0 4px 15px rgba(255, 107, 107, 0.4);
}

/* ===== 目标完成确认模态框 ===== */
.goal-complete-modal {
    display: none;
    position: fixed;
    z-index: 3000;
    left: 0;
    top: 0;
    width: 100%;
    height: 100%;
    background-color: rgba(0, 0, 0, 0.85);
    align-items: center;
    justify-content: center;
    backdrop-filter: blur(8px);
}

.goal-complete-content {
    background: linear-gradient(135deg, #667eea, #764ba2);
    color: white;
    padding: 50px 70px;
    border-radius: 30px;
    text-align: center;
    box-shadow: 0 25px 70px rgba(0, 0, 0, 0.5);
    max-width: 500px;
    animation: goalPulse 0.5s ease-out;
}

@keyframes goalPulse {
    0% { transform: scale(0.8); opacity: 0; }
    50% { transform: scale(1.05); }
    100% { transform: scale(1); opacity: 1; }
}

.goal-complete-content h2 {
    font-size: 36px;
    margin-bottom: 20px;
}

.goal-complete-name {
    font-size: 24px;
    font-weight: bold;
    margin-bottom: 25px;
    padding: 15px 25px;
    background: rgba(255, 255, 255, 0.15);
    border-radius: 15px;
}

.goal-complete-text {
    font-size: 28px;
    margin-bottom: 35px;
    line-height: 1.6;
}

.goal-complete-buttons {
    display: flex;
    gap: 20px;
    justify-content: center;
    flex-wrap: wrap;
}

.goal-complete-buttons button {
    padding: 16px 40px;
    border: none;
    border-radius: 50px;
    font-size: 18px;
    font-weight: bold;
    cursor: pointer;
    transition: all 0.3s ease;
}

.btn-not-complete {
    background: rgba(255, 255, 255, 0.2);
    color: white;
    border: 3px solid rgba(255, 255, 255, 0.5) !important;
}

.btn-not-complete:hover {
    background: rgba(255, 255, 255, 0.3);
    transform: scale(1.05);
}

.btn-complete {
    background: linear-gradient(135deg, #27ae60, #2ecc71);
    color: white;
    box-shadow: 0 6px 20px rgba(39, 174, 96, 0.4);
}

.btn-complete:hover {
    transform: translateY(-3px) scale(1.05);
    box-shadow: 0 10px 30px rgba(39, 174, 96, 0.5);
}

.btn-confirm {
    background: rgba(255, 255, 255, 0.2);
    color: white;
    border: 3px solid white !important;
    padding: 16px 60px !important;
}

.btn-confirm:hover {
    background: rgba(255, 255, 255, 0.3);
    transform: scale(1.05);
}

/* ===== 跨日目标媒体设置区域 ===== */
.goal-media-section {
    background: linear-gradient(135deg, #e8f5e9, #f1f8e9);
    border-radius: 16px;
    padding: 25px;
    margin-bottom: 25px;
    border: 2px solid #c8e6c9;
}

.goal-media-section .section-title {
    color: #2e7d32;
    border-bottom-color: #c8e6c9;
}

.btn-save-media {
    width: 100%;
    padding: 14px;
    background: linear-gradient(135deg, #27ae60, #2ecc71);
    color: white;
    border: none;
    border-radius: 12px;
    font-size: 16px;
    font-weight: 600;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 10px;
    box-shadow: 0 6px 20px rgba(39, 174, 96, 0.3);
    transition: all 0.3s ease;
    margin-top: 15px;
}

.btn-save-media:hover {
    transform: translateY(-3px);
    box-shadow: 0 10px 30px rgba(39, 174, 96, 0.4);
}

.btn-save-media span {
    font-size: 18px;
}

    </style>
</head>
<body>
    <!-- 左侧边栏:今日任务 -->
 <div class="sidebar-left">
    <!-- 实时时钟显示 -->
    <div class="realtime-clock">
        <div class="clock-icon">🕐</div>
        <div class="clock-display">
            <div class="clock-time" id="realtime-clock">--:--:--</div>
            <div class="clock-date" id="realtime-date">----年--月--日 星期-</div>
        </div>
        <button class="clock-refresh" id="sync-time-btn" title="同步网络时间">🔄</button>
    </div>
    
    <div class="today-tasks">
        <h3>今日任务</h3>
            <table class="today-task-table" id="today-task-display">
                <tbody>
                    <tr><td colspan="3" style="text-align:center;color:#999;padding:30px;">点击 📝 设置今日任务</td></tr>
                </tbody>
            </table>
            <!-- 新增:一键全部完成按钮 -->
            <div class="all-complete-display-btn" id="all-complete-display-wrapper" style="display:none;">
                <button id="all-complete-display">一键全部完成 ✅</button>
            </div>
        </div>
    </div>

    <!-- 中间主内容区 -->
    <div class="main-content">
      <!-- 功能按钮 -->
<div class="daily-task-btn" title="设置今日任务">📝</div>
<div class="alarm-btn" title="设置闹钟">⏰</div>
<div class="long-term-btn" title="管理跨日目标">🎯</div>
<div class="reset-btn" title="清除所有数据">🗑️</div>
<div class="encourage-settings-btn" title="自定义鼓励语">💪</div>
<div class="settings-btn" title="自定义庆祝内容">✨</div>

        <h1>雄关漫道真如铁,而今迈步从头越!</h1>

        <!-- 月份导航 -->
        <div class="nav">
            <button id="today-btn">回到今天</button>
            <button id="prev">&lt; 上个月</button>
            <span id="month-year">2025年12月</span>
            <button id="next">下个月 &gt;</button>
        </div>

        <!-- 庆祝按钮 -->
        <div class="celebrate-section">
            <button id="celebrate-btn">完成今日任务!🎉</button>
        </div>

        <!-- 星期标题 -->
        <div class="weekday-header">
            <div>星期日</div>
            <div>星期一</div>
            <div>星期二</div>
            <div>星期三</div>
            <div>星期四</div>
            <div>星期五</div>
            <div>星期六</div>
        </div>

        <!-- 日历网格 -->
        <div class="calendar-grid" id="calendar"></div>

      <!-- 日期信息 -->
<div class="date-info" id="date-info">单击查看距离今天的时间</div>
<!-- 署名 -->
<div class="signature">@天方夜谭熊二</div>
    </div>

    <!-- 右侧边栏:统计和跨日目标 -->
    <div class="sidebar-right">
        <!-- 本月统计 -->
        <div class="stats">
            <h3>本月坚持痕迹</h3>
            <p id="month-completed">本月已完成 <strong>0</strong> 天</p>
            <p id="longest-streak">最长连续完成 <strong>0</strong> 天</p>
            <p id="current-streak">当前连续 <strong>0</strong> 天</p>
        </div>

        <!-- 跨日目标 -->
        <div class="long-term-goals">
            <h3>跨日目标</h3>
            <div id="goals-list">
                <p class="empty-state">暂无跨日目标<br>点击左上角 🎯 添加</p>
            </div>
        </div>

     <!-- 鼓励动画按钮 -->
<div class="give-up-section">
    <button class="give-up-btn" id="give-up-btn">累了就来这里 💕</button>
</div>
    </div>

    <!-- 音频元素 -->
    <audio id="celebrate-audio" preload="auto"></audio>
    <audio id="encourage-audio" preload="auto"></audio>

    <!-- 庆祝模态框 -->
    <div class="celebrate-modal" id="celebrate-modal">
        <div class="celebrate-content">
            <h2>太棒了!</h2>
            <div class="celebrate-quote" id="celebrate-quote"></div>
            <button class="celebrate-close" id="celebrate-close">明天见~</button>
        </div>
    </div>

    <!-- 鼓励模态框 -->
    <div class="encourage-modal" id="encourage-modal">
        <div class="encourage-content">
            <h2>少年,振作起来!</h2>
            <div class="encourage-quote" id="encourage-quote"></div>
            <button class="encourage-close" id="encourage-close">坚持下去!</button>
        </div>
    </div>

    <!-- 今日任务模态框 -->
    <div class="daily-task-modal" id="daily-task-modal">
        <div class="modal-content">
            <div class="modal-header">今日任务规划</div>
            <button class="add-field-btn" id="add-task-field">+ 添加字段</button>
            <button class="add-row-btn" id="add-task-row">+ 添加任务</button>
            <button class="add-row-btn" id="import-text" style="background:#28a745;">导入文本</button>
            <table id="task-table" style="margin-top:20px;">
                <thead id="task-head"></thead>
                <tbody id="task-rows"></tbody>
            </table>
            <div class="modal-buttons">
                <button id="daily-task-cancel">取消</button>
                <button id="daily-task-save">保存并显示</button>
            </div>
        </div>
    </div>

 <!-- 设置模态框 -->
<div class="settings-modal" id="settings-modal">
    <div class="modal-content" style="max-width:600px;">
        <div class="modal-header">✨ 自定义庆祝内容</div>
        
        <!-- 播放模式选择 -->
        <div class="form-group">
            <label>🎬 播放模式</label>
            <div class="mode-selector">
                <label class="mode-option">
                    <input type="radio" name="celebrate-mode" value="audio" checked>
                    <div class="mode-card">
                        <span class="mode-icon">🎵</span>
                        <span class="mode-title">音频 + 语录</span>
                        <span class="mode-desc">播放音乐并显示庆祝弹窗</span>
                    </div>
                </label>
                <label class="mode-option">
                    <input type="radio" name="celebrate-mode" value="video">
                    <div class="mode-card">
                        <span class="mode-icon">🎥</span>
                        <span class="mode-title">仅播放视频</span>
                        <span class="mode-desc">全屏播放视频,不显示弹窗</span>
                    </div>
                </label>
            </div>
        </div>
        
        <!-- 文件选择 -->
        <div class="form-group">
            <label>🎵 音频/视频文件</label>
            <div class="file-upload-box">
                <input type="file" id="local-celebrate-file" accept="audio/*,video/*" class="file-input">
                <label for="local-celebrate-file" class="file-upload-label">
                    <span class="upload-icon">📂</span>
                    <span class="upload-text">点击或拖拽选择文件</span>
                    <span class="upload-hint">支持 MP3、MP4、WAV 等格式,最大 100MB</span>
                </label>
            </div>
            <div id="selected-file-name" class="selected-file" style="display:none;"></div>
        </div>
        
        <!-- 语录设置 -->
        <div class="form-group">
            <label>📝 庆祝语录</label>
            <textarea id="custom-quotes" rows="6" placeholder="输入庆祝语,每行一句
例如:
太棒了!你做到了!
坚持就是胜利!
今天的努力是明天的收获!"></textarea>
            <div class="input-hint">每行一句,随机显示</div>
        </div>
        
        <div class="modal-buttons">
            <button id="settings-cancel" class="btn-cancel">取消</button>
            <button id="settings-save" class="btn-save">💾 保存设置</button>
        </div>
    </div>
</div>

 <!-- 鼓励/小卡片设置模态框 -->
<div class="encourage-settings-modal" id="encourage-settings-modal">
    <div class="modal-content" style="max-width:650px;">
        <div class="modal-header">💪 自定义鼓励动画</div>
        
        <!-- 播放模式选择 -->
        <div class="form-group">
            <label>🎬 播放模式</label>
            <div class="mode-selector">
                <label class="mode-option">
                    <input type="radio" name="encourage-mode" value="animation" checked>
                    <div class="mode-card">
                        <span class="mode-icon">🎴</span>
                        <span class="mode-title">动画 + 音频</span>
                        <span class="mode-desc">播放小卡片飘落动画和音乐</span>
                    </div>
                </label>
                <label class="mode-option">
                    <input type="radio" name="encourage-mode" value="video">
                    <div class="mode-card">
                        <span class="mode-icon">🎥</span>
                        <span class="mode-title">仅播放视频</span>
                        <span class="mode-desc">全屏播放视频,不显示动画</span>
                    </div>
                </label>
            </div>
        </div>
        
        <!-- 文件选择 -->
        <div class="form-group">
            <label>🎵 音频/视频文件</label>
            <div class="file-upload-box">
                <input type="file" id="local-encourage-file" accept="audio/*,video/*" class="file-input">
                <label for="local-encourage-file" class="file-upload-label">
                    <span class="upload-icon">📂</span>
                    <span class="upload-text">点击或拖拽选择文件</span>
                    <span class="upload-hint">支持 MP3、MP4、WAV 等格式,最大 100MB</span>
                </label>
            </div>
            <div id="selected-encourage-file-name" class="selected-file" style="display:none;"></div>
        </div>
        
        <!-- 背景颜色 -->
        <div class="form-group">
            <label>🎨 动画背景颜色</label>
            <div class="color-picker-box">
                <input type="color" id="encourage-bg-color" value="#fff0f3">
                <div class="color-preview" id="color-preview">
                    <span>当前颜色预览</span>
                </div>
            </div>
        </div>
        
        <!-- 小卡片语录 -->
        <div class="form-group">
            <label>📝 小卡片语录</label>
            <textarea id="custom-encourage-quotes" rows="5" placeholder="输入鼓励语,每行一句
例如:
少年,振作起来!
你可以的!
坚持就是胜利!"></textarea>
            <div class="input-hint">每行一句,随机显示在小卡片上</div>
        </div>
        
        <!-- 小卡片Emoji -->
        <div class="form-group">
            <label>😊 小卡片 Emoji</label>
            <input type="text" id="encourage-emojis" placeholder="💕,💗,💖,✨,🌸,🦋,⭐,🥰" style="padding:15px;font-size:18px;">
            <div class="input-hint">用逗号分隔,随机显示在小卡片上</div>
        </div>
        
        <div class="modal-buttons">
            <button id="encourage-settings-cancel" class="btn-cancel">取消</button>
            <button id="encourage-settings-save" class="btn-save">💾 保存设置</button>
        </div>
    </div>
</div>
<!-- 跨日目标模态框 -->
<div class="long-term-modal" id="long-term-modal">
    <div class="modal-content" style="max-width:750px;">
        <div class="modal-header">🎯 跨日目标管理</div>
        
<!-- 小卡片动画自定义区 -->
<div class="section">
    <h3>🎴 小卡片动画自定义</h3>
    <div class="form-group">
        <label>📝 小卡片语录(每行一句)</label>
        <textarea id="goal-cards-quotes" rows="8" placeholder="每行输入一句语录
例如:
坚持就是胜利!
你超棒的!"></textarea>
    </div>
    <div class="form-group">
        <label>😊 小卡片 Emoji(用空格分隔)</label>
        <input type="text" id="goal-cards-emojis" placeholder="🎉 ✨ 🔥 💪 ❤️ 🚀">
    </div>
</div>

        <!-- 完成提醒设置区域 -->
        <div class="goal-media-section">
            <h4 class="section-title">🎉 完成提醒设置</h4>
            
            <!-- 播放模式选择 -->
            <div class="form-group">
                <label>🎬 播放模式</label>
                <div class="mode-selector">
                    <label class="mode-option">
                        <input type="radio" name="goal-mode" value="animation" checked>
                        <div class="mode-card">
                            <span class="mode-icon">🎴</span>
                            <span class="mode-title">动画 + 音频</span>
                            <span class="mode-desc">播放小卡片飘落动画和音乐</span>
                        </div>
                    </label>
                    <label class="mode-option">
                        <input type="radio" name="goal-mode" value="video">
                        <div class="mode-card">
                            <span class="mode-icon">🎥</span>
                            <span class="mode-title">仅播放视频</span>
                            <span class="mode-desc">全屏播放视频,不显示动画</span>
                        </div>
                    </label>
                </div>
            </div>
            
            <!-- 文件选择 -->
            <div class="form-group">
                <label>🎵 音频/视频文件</label>
                <div class="file-upload-box">
                    <input type="file" id="goal-media-file" accept="audio/*,video/*" class="file-input">
                    <label for="goal-media-file" class="file-upload-label">
                        <span class="upload-icon">📂</span>
                        <span class="upload-text">点击或拖拽选择文件</span>
                        <span class="upload-hint">支持 MP3、MP4、WAV 等格式,最大 100MB</span>
                    </label>
                </div>
                <div id="goal-media-file-name" class="selected-file" style="display:none;"></div>
            </div>
            
            <button class="btn-save-media" id="btn-save-goal-media">
                <span>💾</span> 保存提醒设置
            </button>
        </div>
        
        <!-- 添加新目标区域 -->
        <div class="add-goal-section">
            <h4 class="section-title">➕ 添加新目标</h4>
            
            <div class="form-group">
                <label>📌 目标名称</label>
                <input type="text" id="new-goal-name" placeholder="例如:完成项目报告">
            </div>
            
            <div class="form-group">
                <label>📅 时间范围</label>
                <div class="datetime-picker">
                    <div class="datetime-input-wrapper">
                        <span class="datetime-label">开始时间</span>
                        <input type="datetime-local" id="new-goal-start" step="1">
                    </div>
                    <div class="datetime-input-wrapper">
                        <span class="datetime-label">结束时间</span>
                        <input type="datetime-local" id="new-goal-end" step="1">
                    </div>
                </div>
            </div>
            
            <button class="btn-add-goal" id="btn-add-goal">
                <span>➕</span> 添加目标
            </button>
        </div>
        
        <!-- 目标列表 -->
        <div class="goal-list-section">
            <h4 class="section-title">📋 我的目标</h4>
            <div class="goal-list-container" id="goal-list-container">
                <p class="empty-goal">暂无目标,点击上方添加</p>
            </div>
        </div>
        
        <div class="modal-buttons">
            <button id="long-term-cancel" class="btn-cancel">关闭</button>
        </div>
    </div>
</div>
<!-- 闹钟设置模态框 -->
<div class="alarm-modal" id="alarm-modal">
    <div class="modal-content" style="max-width:650px;">
        <div class="modal-header">⏰ 闹钟设置</div>
        
        <!-- 添加新闹钟区域 -->
        <div class="add-alarm-section">
            <h4 class="section-title">➕ 添加新闹钟</h4>
            
            <!-- 日期时间选择 -->
            <div class="form-group">
                <label>📅 选择日期和时间</label>
                <div class="datetime-picker">
                    <div class="datetime-input-wrapper">
                        <span class="datetime-label">日期</span>
                        <input type="date" id="alarm-date">
                    </div>
                    <div class="datetime-input-wrapper">
                        <span class="datetime-label">时间</span>
                        <input type="time" id="alarm-time" step="1">
                    </div>
                </div>
            </div>
            
            <!-- 备注 -->
            <div class="form-group">
                <label>📝 备注</label>
                <input type="text" id="alarm-note" placeholder="例如:该学习啦!" style="padding:15px;">
            </div>
            
            <!-- 播放模式选择 -->
            <div class="form-group">
                <label>🎬 提醒方式</label>
                <div class="mode-selector">
                    <label class="mode-option">
                        <input type="radio" name="alarm-mode" value="audio" checked>
                        <div class="mode-card">
                            <span class="mode-icon">🔔</span>
                            <span class="mode-title">弹窗 + 音频</span>
                            <span class="mode-desc">显示提醒弹窗并播放音乐</span>
                        </div>
                    </label>
                    <label class="mode-option">
                        <input type="radio" name="alarm-mode" value="video">
                        <div class="mode-card">
                            <span class="mode-icon">🎥</span>
                            <span class="mode-title">播放视频</span>
                            <span class="mode-desc">直接播放视频,不显示弹窗</span>
                        </div>
                    </label>
                </div>
            </div>
            
            <!-- 文件选择 -->
            <div class="form-group">
                <label>🎵 提醒音频/视频</label>
                <div class="file-upload-box">
                    <input type="file" id="alarm-audio-file" accept="audio/*,video/*" class="file-input">
                    <label for="alarm-audio-file" class="file-upload-label">
                        <span class="upload-icon">📂</span>
                        <span class="upload-text">点击选择提醒铃声</span>
                        <span class="upload-hint">支持 MP3、MP4 等格式</span>
                    </label>
                </div>
                <div id="alarm-file-name" class="selected-file" style="display:none;"></div>
            </div>
            
            <button class="btn-add-alarm" id="add-alarm-btn">
                <span>➕</span> 添加闹钟
            </button>
        </div>
        
        <!-- 闹钟列表 -->
        <div class="alarm-list-section">
            <h4 class="section-title">📋 已设置的闹钟</h4>
            <div class="alarm-list" id="alarm-list">
                <p class="empty-alarm">暂无闹钟</p>
            </div>
        </div>
        
        <div class="modal-buttons">
            <button id="alarm-cancel" class="btn-cancel">关闭</button>
        </div>
    </div>
</div>
<!-- 闹钟提醒模态框 -->
<div class="alarm-alert-modal" id="alarm-alert-modal">
    <div class="alarm-alert-content">
        <h2>⏰ 时间到!</h2>
        <div class="alarm-alert-time" id="alarm-alert-time"></div>
        <div class="alarm-alert-note" id="alarm-alert-note"></div>
        <button class="alarm-alert-close" id="alarm-alert-close">我知道了</button>
    </div>
</div>

<!-- 闹钟提醒模态框 -->
<div class="alarm-alert-modal" id="alarm-alert-modal">
    <div class="alarm-alert-content">
        <h2>⏰ 时间到!</h2>
        <div class="alarm-alert-time" id="alarm-alert-time"></div>
        <div class="alarm-alert-note" id="alarm-alert-note"></div>
        <button class="alarm-alert-close" id="alarm-alert-close">我知道了</button>
    </div>
</div>

<!-- 跨日目标视频播放模态框 -->
<div class="video-modal" id="goal-video-modal">
    <div class="video-modal-content">
        <video id="goal-video-player" controls autoplay></video>
        <button class="video-close-btn" id="goal-video-close">关闭</button>
    </div>
</div>

<!-- 跨日目标完成确认模态框 -->
<div class="goal-complete-modal" id="goal-complete-modal">
    <div class="goal-complete-content">
        <h2 id="goal-complete-title">⏰ 目标时间到!</h2>
        <div class="goal-complete-name" id="goal-complete-name"></div>
        <div class="goal-complete-text" id="goal-complete-text">是否完成?</div>
        <div class="goal-complete-buttons" id="goal-complete-buttons">
            <button class="btn-not-complete" id="btn-not-complete">未完成 😔</button>
            <button class="btn-complete" id="btn-complete">完成 🎉</button>
        </div>
    </div>
</div>

<!-- 闹钟视频播放模态框 -->
<div class="video-modal" id="alarm-video-modal">
    <div class="video-modal-content">
        <video id="alarm-video-player" controls autoplay></video>
        <button class="video-close-btn" id="alarm-video-close">关闭</button>
    </div>
</div>

<!-- 恢复出厂设置确认模态框 -->
<div class="reset-confirm-modal" id="reset-confirm-modal">
    <div class="reset-confirm-content">
        <h2>⚠️ 警告</h2>
        <p>少年,难道你要就此止步吗?</p>
        <div class="reset-confirm-buttons">
            <button class="btn-keep-going" id="btn-keep-going">我不会放弃 💪</button>
            <button class="btn-give-up" id="btn-give-up-confirm">我做不到 😔</button>
        </div>
    </div>
</div>

<!-- 小卡片动画模态框 -->
<div class="cards-animation-modal" id="cards-animation-modal">
    <div class="cards-board" id="cards-board"></div>
    <button class="cards-close-btn" id="cards-close-btn">✕ 关闭</button>
</div>

<!-- 庆祝视频播放模态框 -->
<div class="video-modal" id="celebrate-video-modal">
    <div class="video-modal-content">
        <video id="celebrate-video-player" controls autoplay></video>
        <button class="video-close-btn" id="celebrate-video-close">关闭</button>
    </div>
</div>

<!-- 鼓励视频播放模态框 -->
<div class="video-modal" id="encourage-video-modal">
    <div class="video-modal-content">
        <video id="encourage-video-player" controls autoplay></video>
        <button class="video-close-btn" id="encourage-video-close">关闭</button>
    </div>
</div>

<!-- 闹钟音频元素 -->
<audio id="alarm-audio" preload="auto"></audio>
<!-- 鼓励动画音频元素 -->
<audio id="cards-audio" preload="auto"></audio>

    <script>
     // ==================== IndexedDB 操作封装 ====================
const DB_NAME = 'CelebrateAppDB';
const DB_VERSION = 2;
const STORE_NAME = 'mediaFiles';
const MAX_FILE_SIZE = 100 * 1024 * 1024;

function openDB() {
    return new Promise((resolve, reject) => {
        const request = indexedDB.open(DB_NAME, DB_VERSION);
        request.onerror = () => reject(request.error);
        request.onsuccess = () => resolve(request.result);
        request.onupgradeneeded = (event) => {
            const db = event.target.result;
            if (!db.objectStoreNames.contains(STORE_NAME)) {
                db.createObjectStore(STORE_NAME, { keyPath: 'id' });
            }
        };
    });
}

async function saveMediaFile(id, file, onProgress) {
    const db = await openDB();
    return new Promise((resolve, reject) => {
        const reader = new FileReader();
        reader.onprogress = (e) => {
            if (e.lengthComputable && onProgress) {
                onProgress(Math.round((e.loaded / e.total) * 100));
            }
        };
        reader.onload = () => {
            const transaction = db.transaction([STORE_NAME], 'readwrite');
            const store = transaction.objectStore(STORE_NAME);
            const data = {
                id: id,
                arrayBuffer: reader.result,
                name: file.name,
                type: file.type,
                size: file.size,
                timestamp: Date.now()
            };
            const request = store.put(data);
            request.onsuccess = () => resolve();
            request.onerror = () => reject(request.error);
        };
        reader.onerror = () => reject(reader.error);
        reader.readAsArrayBuffer(file);
    });
}

async function getMediaFile(id) {
    try {
        const db = await openDB();
        return new Promise((resolve, reject) => {
            const transaction = db.transaction([STORE_NAME], 'readonly');
            const store = transaction.objectStore(STORE_NAME);
            const request = store.get(id);
            request.onsuccess = () => resolve(request.result);
            request.onerror = () => reject(request.error);
        });
    } catch (err) {
        console.error('获取媒体文件失败:', err);
        return null;
    }
}

async function deleteMediaFile(id) {
    try {
        const db = await openDB();
        return new Promise((resolve, reject) => {
            const transaction = db.transaction([STORE_NAME], 'readwrite');
            const store = transaction.objectStore(STORE_NAME);
            const request = store.delete(id);
            request.onsuccess = () => resolve();
            request.onerror = () => reject(request.error);
        });
    } catch (err) {
        console.error('删除媒体文件失败:', err);
    }
}

function createBlobURL(arrayBuffer, mimeType) {
    const blob = new Blob([arrayBuffer], { type: mimeType });
    return URL.createObjectURL(blob);
}

function formatFileSize(bytes) {
    if (bytes < 1024) return bytes + ' B';
    if (bytes < 1024 * 1024) return (bytes / 1024).toFixed(1) + ' KB';
    return (bytes / (1024 * 1024)).toFixed(2) + ' MB';
}

// ==================== 网络时间同步 ====================
let networkTimeOffset = 0;

async function syncNetworkTime() {
    try {
        const response = await fetch('https://worldtimeapi.org/api/ip');
        const data = await response.json();
        const serverTime = new Date(data.datetime);
        const localTime = new Date();
        networkTimeOffset = serverTime - localTime;
        console.log('网络时间同步成功,偏移量:', networkTimeOffset, 'ms');
        return true;
    } catch (err) {
        console.log('网络时间同步失败,使用本地时间');
        networkTimeOffset = 0;
        return false;
    }
}

function getCurrentTime() {
    return new Date(Date.now() + networkTimeOffset);
}

// ==================== 全局变量定义 ====================
let today = getCurrentTime();
let currentYear = today.getFullYear();
let currentMonth = today.getMonth();

let celebrateBlobURL = null;
let encourageBlobURL = null;
let alarmBlobURLs = {};
let cardsBlobURL = null;

// DOM元素
const calendarGrid = document.getElementById('calendar');
const monthYearDisplay = document.getElementById('month-year');
const dateInfo = document.getElementById('date-info');
const celebrateBtn = document.getElementById('celebrate-btn');
const audio = document.getElementById('celebrate-audio');
const encourageAudio = document.getElementById('encourage-audio');
const celebrateModal = document.getElementById('celebrate-modal');
const celebrateQuote = document.getElementById('celebrate-quote');
const celebrateClose = document.getElementById('celebrate-close');
const monthCompleted = document.getElementById('month-completed');
const longestStreak = document.getElementById('longest-streak');
const currentStreak = document.getElementById('current-streak');
const goalsList = document.getElementById('goals-list');
const todayTaskDisplay = document.getElementById('today-task-display');
const allCompleteDisplayWrapper = document.getElementById('all-complete-display-wrapper');
const giveUpBtn = document.getElementById('give-up-btn');

// 闹钟相关
const alarmModal = document.getElementById('alarm-modal');
const alarmList = document.getElementById('alarm-list');
const alarmAlertModal = document.getElementById('alarm-alert-modal');
const alarmAlertTime = document.getElementById('alarm-alert-time');
const alarmAlertNote = document.getElementById('alarm-alert-note');
const alarmAudio = document.getElementById('alarm-audio');
const alarmVideoModal = document.getElementById('alarm-video-modal');
const alarmVideoPlayer = document.getElementById('alarm-video-player');

// 恢复出厂设置
const resetConfirmModal = document.getElementById('reset-confirm-modal');

// 小卡片动画
const cardsAnimationModal = document.getElementById('cards-animation-modal');
const cardsBoard = document.getElementById('cards-board');
const cardsAudio = document.getElementById('cards-audio');

// 视频模态框
const celebrateVideoModal = document.getElementById('celebrate-video-modal');
const celebrateVideoPlayer = document.getElementById('celebrate-video-player');
const encourageVideoModal = document.getElementById('encourage-video-modal');
const encourageVideoPlayer = document.getElementById('encourage-video-player');

// 模态框
const dailyTaskModal = document.getElementById('daily-task-modal');
const taskHead = document.getElementById('task-head');
const taskRows = document.getElementById('task-rows');
const settingsModal = document.getElementById('settings-modal');
const localCelebrateFile = document.getElementById('local-celebrate-file');
const selectedFileName = document.getElementById('selected-file-name');
const customQuotesTextarea = document.getElementById('custom-quotes');
const quotesList = document.getElementById('quotes-list');
const longTermModal = document.getElementById('long-term-modal');
const goalHead = document.getElementById('goal-head');
const goalRows = document.getElementById('goal-rows');
const encourageSettingsModal = document.getElementById('encourage-settings-modal');

// 本地存储数据
let dailyTaskData = JSON.parse(localStorage.getItem('dailyTaskData') || '{"fields":["任务","预计时间"],"rows":[]}');
let currentTaskFields = [...dailyTaskData.fields];
let currentTaskRows = dailyTaskData.rows.map(r => ({...r}));
let completedDates = JSON.parse(localStorage.getItem('completedDates') || '[]');
let longTermGoals = JSON.parse(localStorage.getItem('longTermGoals') || '{"rows":[]}');

// 兼容旧数据格式
if (longTermGoals.fields) {
    // 转换旧格式到新格式
    const newRows = longTermGoals.rows.map(row => ({
        name: row["目标名称"] || '',
        startDate: row["开始日期"] || '',
        endDate: row["结束日期"] || '',
        status: 'running',
        notified: false
    }));
    longTermGoals = { rows: newRows };
    localStorage.setItem('longTermGoals', JSON.stringify(longTermGoals));
}
let quotes = JSON.parse(localStorage.getItem('celebrateQuotes') || '["太棒了!你做到了!","坚持就是胜利!","今天的努力是明天的收获!"]');
let alarms = JSON.parse(localStorage.getItem('alarms') || '[]');

// 庆祝设置
let celebrateSettings = JSON.parse(localStorage.getItem('celebrateSettings') || '{"mode":"audio"}');

// 跨日目标完成提醒设置
let goalMediaSettings = JSON.parse(localStorage.getItem('goalMediaSettings') || JSON.stringify({
    mode: "animation"
}));
let goalBlobURL = null;

// 鼓励/小卡片设置
let encourageSettings = JSON.parse(localStorage.getItem('encourageSettings') || JSON.stringify({
    mode: "animation",
    bgColor: "#fff0f3",
    messages: ["少年,振作起来!", "你可以的!", "加油!"],
    emojis: ["💕", "💗", "💖", "💝", "💓", "✨", "🌸", "🦋"]
}));

let currentGoalFields = [];
let currentGoalRows = [];
let pendingCelebrateFile = null;
let pendingEncourageFile = null;
let pendingAlarmFile = null;
let pendingCardsFile = null;

// ==================== 实时时钟 ====================
function updateRealtimeClock() {
    const now = getCurrentTime();
    const clockEl = document.getElementById('realtime-clock');
    const dateEl = document.getElementById('realtime-date');
    
    if (clockEl) {
        clockEl.textContent = now.toLocaleTimeString('zh-CN', { hour12: false });
    }
    if (dateEl) {
        const weekdays = ['星期日', '星期一', '星期二', '星期三', '星期四', '星期五', '星期六'];
        dateEl.textContent = `${now.getFullYear()}年${now.getMonth() + 1}月${now.getDate()}日 ${weekdays[now.getDay()]}`;
    }
    
    // 更新today
    today = now;
}

// 同步时间按钮
document.getElementById('sync-time-btn')?.addEventListener('click', async () => {
    const btn = document.getElementById('sync-time-btn');
    btn.textContent = '⏳';
    btn.disabled = true;
    
    const success = await syncNetworkTime();
    
    btn.textContent = success ? '✅' : '❌';
    setTimeout(() => {
        btn.textContent = '🔄';
        btn.disabled = false;
    }, 2000);
    
    updateRealtimeClock();
    renderCalendar(currentYear, currentMonth);
});

// 启动时钟
setInterval(updateRealtimeClock, 1000);

// ==================== 闹钟功能 ====================
function renderAlarmList() {
    alarmList.innerHTML = '';
    if (alarms.length === 0) {
        alarmList.innerHTML = '<p class="empty-alarm">暂无闹钟,点击上方添加</p>';
        return;
    }
    
    alarms.forEach((alarm, index) => {
        const div = document.createElement('div');
        div.className = 'alarm-item';
        const modeText = alarm.mode === 'video' ? '🎥 视频' : '🔔 弹窗';
        div.innerHTML = `
            <div class="alarm-item-info">
                <div class="alarm-item-time">${alarm.datetime}</div>
                <div class="alarm-item-note">
                    ${alarm.note || '无备注'}
                    <span class="alarm-mode-tag">${modeText}</span>
                </div>
            </div>
            <button class="alarm-item-delete" data-index="${index}">×</button>
        `;
        alarmList.appendChild(div);
    });
    
    alarmList.querySelectorAll('.alarm-item-delete').forEach(btn => {
        btn.onclick = async () => {
            const idx = parseInt(btn.dataset.index);
            const alarmId = `alarm_${alarms[idx].id}`;
            await deleteMediaFile(alarmId);
            alarms.splice(idx, 1);
            localStorage.setItem('alarms', JSON.stringify(alarms));
            renderAlarmList();
        };
    });
}

document.querySelector('.alarm-btn')?.addEventListener('click', () => {
    renderAlarmList();
    alarmModal.style.display = 'flex';
});

document.getElementById('alarm-cancel')?.addEventListener('click', () => {
    alarmModal.style.display = 'none';
});

document.getElementById('add-alarm-btn')?.addEventListener('click', async () => {
    const dateInput = document.getElementById('alarm-date');
    const timeInput = document.getElementById('alarm-time');
    const noteInput = document.getElementById('alarm-note');
    const modeInputs = document.querySelectorAll('input[name="alarm-mode"]');
    const fileInput = document.getElementById('alarm-audio-file');
    
    if (!dateInput.value || !timeInput.value) {
        alert('请选择日期和时间!');
        return;
    }
    
    let mode = 'audio';
    modeInputs.forEach(input => {
        if (input.checked) mode = input.value;
    });
    
    const alarmId = Date.now();
    const alarm = {
        id: alarmId,
        datetime: `${dateInput.value} ${timeInput.value}`,
        note: noteInput.value,
        mode: mode,
        triggered: false
    };
    
    // 保存音频文件
    if (fileInput.files[0]) {
        try {
            await saveMediaFile(`alarm_${alarmId}`, fileInput.files[0]);
        } catch (err) {
            console.error('保存闹钟音频失败:', err);
        }
    }
    
    alarms.push(alarm);
    localStorage.setItem('alarms', JSON.stringify(alarms));
    
    // 清空输入
    dateInput.value = '';
    timeInput.value = '';
    noteInput.value = '';
    fileInput.value = '';
    document.getElementById('alarm-file-name').style.display = 'none';
    
    renderAlarmList();
    alert('闹钟已添加!');
});

// 闹钟检查
async function checkAlarms() {
    const now = getCurrentTime();
    const nowStr = `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, '0')}-${String(now.getDate()).padStart(2, '0')} ${String(now.getHours()).padStart(2, '0')}:${String(now.getMinutes()).padStart(2, '0')}:${String(now.getSeconds()).padStart(2, '0')}`;
    
    for (let i = 0; i < alarms.length; i++) {
        const alarm = alarms[i];
        if (alarm.triggered) continue;
        
        // 比较时间(精确到秒)
        const alarmTime = alarm.datetime.includes(':') && alarm.datetime.split(':').length === 3 
            ? alarm.datetime 
            : alarm.datetime + ':00';
        
        if (alarmTime <= nowStr) {
            alarm.triggered = true;
            localStorage.setItem('alarms', JSON.stringify(alarms));
            
            // 获取音频
            const mediaData = await getMediaFile(`alarm_${alarm.id}`);
            
            if (alarm.mode === 'video' && mediaData && mediaData.type.startsWith('video')) {
                // 视频模式
                const blobURL = createBlobURL(mediaData.arrayBuffer, mediaData.type);
                alarmVideoPlayer.src = blobURL;
                alarmVideoModal.style.display = 'flex';
                alarmVideoPlayer.play();
            } else {
                // 音频模式
                if (mediaData) {
                    const blobURL = createBlobURL(mediaData.arrayBuffer, mediaData.type);
                    alarmAudio.src = blobURL;
                }
                alarmAlertTime.textContent = alarm.datetime;
                alarmAlertNote.textContent = alarm.note || '时间到了!';
                alarmAlertModal.style.display = 'flex';
                alarmAudio.play().catch(err => console.log('闹钟音频播放失败'));
            }
            
            break;
        }
    }
}

setInterval(checkAlarms, 1000);

document.getElementById('alarm-alert-close')?.addEventListener('click', () => {
    alarmAlertModal.style.display = 'none';
    alarmAudio.pause();
    alarmAudio.currentTime = 0;
});

document.getElementById('alarm-video-close')?.addEventListener('click', () => {
    alarmVideoModal.style.display = 'none';
    alarmVideoPlayer.pause();
    alarmVideoPlayer.src = '';
});

// 闹钟文件选择显示
function updateFileDisplay(type, fileName, fileSize) {
    const container = type === 'celebrate' ? selectedFileName : 
                      type === 'cards' ? document.getElementById('selected-encourage-file-name') :
                      document.getElementById('selected-encourage-file-name');
    if (!container) return;
    
    if (fileName) {
        const isVideo = fileName.match(/\.(mp4|webm|mov|avi)$/i);
        const icon = isVideo ? '🎥' : '🎵';
        container.innerHTML = `
            <div class="file-info">
                <span class="file-icon">${icon}</span>
                <div class="file-details">
                    <span class="file-name-text">${fileName}</span>
                    <span class="file-size-text">${formatFileSize(fileSize)}</span>
                </div>
            </div>
            <button class="delete-btn" onclick="deleteFile('${type}')">×</button>
        `;
        container.style.display = 'flex';
    } else {
        container.style.display = 'none';
    }
}
// ==================== 恢复出厂设置 ====================
document.querySelector('.reset-btn')?.addEventListener('click', () => {
    resetConfirmModal.style.display = 'flex';
});

document.getElementById('btn-keep-going')?.addEventListener('click', () => {
    resetConfirmModal.style.display = 'none';
});

document.getElementById('btn-give-up-confirm')?.addEventListener('click', async () => {
    // 清除所有localStorage
    localStorage.clear();
    
    // 清除IndexedDB
    const db = await openDB();
    const transaction = db.transaction([STORE_NAME], 'readwrite');
    const store = transaction.objectStore(STORE_NAME);
    store.clear();
    
    alert('所有数据已清除,页面即将刷新...');
    location.reload();
});

// ==================== 小卡片动画功能 ====================
const cardColorStyles = [
    'color-pink', 'color-purple', 'color-blue', 'color-mint',
    'color-yellow', 'color-orange', 'color-green', 'color-coral',
    'color-lavender', 'color-white'
];

function randomFrom(arr) {
    return arr[Math.floor(Math.random() * arr.length)];
}

function randomRange(min, max) {
    return min + Math.random() * (max - min);
}

function createCard(board, x, y, content, layer) {
    const card = document.createElement('div');
    const rotation = randomRange(-18, 18);
    const scale = randomRange(0.9, 1.1);
    const colorStyle = randomFrom(cardColorStyles);
    
    card.className = `card ${colorStyle} float-in`;
    
    const isMobile = window.innerWidth <= 768;
    const cardWidth = Math.round((isMobile ? 75 : 105) * 1.265);
    const cardHeight = Math.round((isMobile ? 48 : 65) * 1.265);
    
    const baseTransform = `translate(${x}px, ${y}px)`;
    const floatY = randomRange(-60, 60);
    const floatR = randomRange(-30, 30);
    const delay = randomRange(0, 0.5);
    
    card.style.cssText = `
        width: ${cardWidth}px;
        height: ${cardHeight}px;
        transform: ${baseTransform} rotate(${rotation}deg) scale(${scale});
        --base-transform: ${baseTransform};
        --rotation: ${rotation}deg;
        --delay: ${delay}s;
        --float-y: ${floatY}px;
        --float-r: ${floatR}deg;
        z-index: ${layer};
    `;
    
    card.innerHTML = `<div class="card-body">${content}</div>`;
    board.appendChild(card);
    
    return card;
}

async function runCardsAnimation() {
    cardsBoard.innerHTML = '';
    
const quotes = goalCardsSettings.quotes.length > 0 ? goalCardsSettings.quotes : ["目标达成!🎉", "你太棒了!💪", "坚持就是胜利!🔥"];
const emojis = goalCardsSettings.emojis.length > 0 ? goalCardsSettings.emojis : ["🎉", "✨", "🔥", "💪", "❤️", "🚀"];
    
    // 设置背景颜色
    if (encourageSettings.bgColor) {
        cardsAnimationModal.style.background = encourageSettings.bgColor;
    }
    
    const isMobile = window.innerWidth <= 768;
    const cardWidth = Math.round((isMobile ? 75 : 105) * 1.265);
    const cardHeight = Math.round((isMobile ? 48 : 65) * 1.265);
    
    const screenArea = window.innerWidth * window.innerHeight;
    const cardsCount = Math.ceil(screenArea / (cardWidth * cardHeight * 1.1));
    
    for (let i = 0; i < cardsCount; i++) {
        setTimeout(() => {
            const x = randomRange(0, window.innerWidth - cardWidth);
            const y = randomRange(0, window.innerHeight - cardHeight);
            const useEmoji = Math.random() > 0.5;
            const content = useEmoji ? randomFrom(emojis) : randomFrom(messages);
            createCard(cardsBoard, x, y, content, 100 + i);
        }, i * 30);
    }
}

// 累了就来这里按钮
giveUpBtn?.addEventListener('click', async () => {
    if (encourageSettings.mode === 'video') {
        // 视频模式
        const mediaData = await getMediaFile('cards');
        if (mediaData && mediaData.type.startsWith('video')) {
            const blobURL = createBlobURL(mediaData.arrayBuffer, mediaData.type);
            encourageVideoPlayer.src = blobURL;
            encourageVideoModal.style.display = 'flex';
            encourageVideoPlayer.play();
        } else {
            alert('未设置视频文件,请在💪设置中上传视频');
        }
    } else {
        // 动画模式
        cardsAnimationModal.style.display = 'block';
        
        // 播放音频
        const mediaData = await getMediaFile('cards');
        if (mediaData) {
            if (cardsBlobURL) URL.revokeObjectURL(cardsBlobURL);
            cardsBlobURL = createBlobURL(mediaData.arrayBuffer, mediaData.type);
            cardsAudio.src = cardsBlobURL;
            cardsAudio.play().catch(err => console.log('小卡片音频播放失败'));
        }
        
        runCardsAnimation();
    }
});

document.getElementById('cards-close-btn')?.addEventListener('click', () => {
    cardsAnimationModal.style.display = 'none';
    cardsAudio.pause();
    cardsAudio.currentTime = 0;
    cardsBoard.innerHTML = '';
});

// 跨日目标视频关闭
document.getElementById('goal-video-close')?.addEventListener('click', () => {
    const goalVideoModal = document.getElementById('goal-video-modal');
    const goalVideoPlayer = document.getElementById('goal-video-player');
    if (goalVideoModal) goalVideoModal.style.display = 'none';
    if (goalVideoPlayer) {
        goalVideoPlayer.pause();
        goalVideoPlayer.src = '';
    }
    // 显示确认弹窗
    showGoalConfirmButtons();
});

// ==================== 鼓励设置(💪按钮) ====================
document.querySelector('.encourage-settings-btn')?.addEventListener('click', async () => {
    // 填充当前设置
    document.getElementById('custom-encourage-quotes').value = (encourageSettings.messages || []).join('\n');
    document.getElementById('encourage-emojis').value = (encourageSettings.emojis || []).join(',');
    document.getElementById('encourage-bg-color').value = encourageSettings.bgColor || '#fff0f3';
    
    const modeRadios = document.querySelectorAll('input[name="encourage-mode"]');
    modeRadios.forEach(radio => {
        radio.checked = radio.value === encourageSettings.mode;
    });
    
    // 显示已选择的文件
    const mediaData = await getMediaFile('cards');
    if (mediaData) {
        document.getElementById('selected-encourage-file-name').innerHTML = `✅ ${mediaData.name} (${formatFileSize(mediaData.size)})`;
        document.getElementById('selected-encourage-file-name').style.display = 'block';
    } else {
        document.getElementById('selected-encourage-file-name').style.display = 'none';
    }
    
    encourageSettingsModal.style.display = 'flex';
});

document.getElementById('encourage-settings-save')?.addEventListener('click', async () => {
    const file = document.getElementById('local-encourage-file').files[0];
    if (file) {
        try {
            await saveMediaFile('cards', file);
        } catch (err) {
            console.error('保存文件失败:', err);
        }
    }
    
    // 保存设置
    const messagesText = document.getElementById('custom-encourage-quotes').value;
    const emojisText = document.getElementById('encourage-emojis')?.value || '';
    const bgColor = document.getElementById('encourage-bg-color')?.value || '#fff0f3';
    
    let mode = 'animation';
    document.querySelectorAll('input[name="encourage-mode"]').forEach(radio => {
        if (radio.checked) mode = radio.value;
    });
    
    encourageSettings = {
        mode: mode,
        bgColor: bgColor,
        messages: messagesText.split('\n').map(s => s.trim()).filter(s => s),
        emojis: emojisText.split(/[,,\n]/).map(s => s.trim()).filter(s => s)
    };
    
    localStorage.setItem('encourageSettings', JSON.stringify(encourageSettings));
    alert('鼓励设置已保存!');
    encourageSettingsModal.style.display = 'none';
});

document.getElementById('encourage-settings-cancel')?.addEventListener('click', () => {
    encourageSettingsModal.style.display = 'none';
});

// ==================== 庆祝功能 ====================
celebrateBtn?.addEventListener('click', async () => {
    const dateStr = today.toISOString().split('T')[0];
    if (!completedDates.includes(dateStr)) {
        completedDates.push(dateStr);
        localStorage.setItem('completedDates', JSON.stringify(completedDates));
    }
    renderCalendar(currentYear, currentMonth);
    
    if (celebrateSettings.mode === 'video') {
        // 视频模式
        const mediaData = await getMediaFile('celebrate');
        if (mediaData && mediaData.type.startsWith('video')) {
            const blobURL = createBlobURL(mediaData.arrayBuffer, mediaData.type);
            celebrateVideoPlayer.src = blobURL;
            celebrateVideoModal.style.display = 'flex';
            celebrateVideoPlayer.play();
        } else {
            alert('未设置视频文件,请在✨设置中上传视频');
        }
    } else {
        // 音频模式
        audio.currentTime = 0;
        audio.play().catch(err => console.log('音频播放失败'));
        
        const randomQuote = quotes[Math.floor(Math.random() * quotes.length)];
        celebrateQuote.textContent = randomQuote;
        celebrateModal.style.display = 'flex';
    }
});

celebrateClose?.addEventListener('click', () => {
    celebrateModal.style.display = 'none';
    audio.pause();
    audio.currentTime = 0;
});

document.getElementById('celebrate-video-close')?.addEventListener('click', () => {
    celebrateVideoModal.style.display = 'none';
    celebrateVideoPlayer.pause();
    celebrateVideoPlayer.src = '';
});

// ==================== 庆祝设置(✨按钮) ====================
document.querySelector('.settings-btn')?.addEventListener('click', async () => {
    localCelebrateFile.value = '';
    
    const mediaData = await getMediaFile('celebrate');
    if (mediaData) {
        selectedFileName.innerHTML = `✅ ${mediaData.name} (${formatFileSize(mediaData.size)})`;
        selectedFileName.style.display = 'block';
    } else {
        selectedFileName.style.display = 'none';
    }
    
    customQuotesTextarea.value = quotes.join('\n');
    
    // 设置播放模式
    const modeRadios = document.querySelectorAll('input[name="celebrate-mode"]');
    modeRadios.forEach(radio => {
        radio.checked = radio.value === celebrateSettings.mode;
    });
    
    settingsModal.style.display = 'flex';
});

document.getElementById('settings-save')?.addEventListener('click', async () => {
    const file = localCelebrateFile.files[0];
    if (file) {
        try {
            await saveMediaFile('celebrate', file);
            await initCelebrateMedia();
        } catch (err) {
            console.error('保存文件失败:', err);
        }
    }
    
    const newQuotes = customQuotesTextarea.value.split('\n').map(q => q.trim()).filter(q => q);
    if (newQuotes.length > 0) {
        quotes = newQuotes;
        localStorage.setItem('celebrateQuotes', JSON.stringify(quotes));
    }
    
    // 保存播放模式
    let mode = 'audio';
    document.querySelectorAll('input[name="celebrate-mode"]').forEach(radio => {
        if (radio.checked) mode = radio.value;
    });
    celebrateSettings.mode = mode;
    localStorage.setItem('celebrateSettings', JSON.stringify(celebrateSettings));
    
    alert('庆祝设置已保存!');
    settingsModal.style.display = 'none';
});

document.getElementById('settings-cancel')?.addEventListener('click', () => {
    settingsModal.style.display = 'none';
});

// ==================== 初始化媒体文件 ====================
async function initCelebrateMedia() {
    const mediaData = await getMediaFile('celebrate');
    if (mediaData) {
        if (celebrateBlobURL) URL.revokeObjectURL(celebrateBlobURL);
        celebrateBlobURL = createBlobURL(mediaData.arrayBuffer, mediaData.type);
        audio.src = celebrateBlobURL;
    }
}

// ==================== 日历相关功能 ====================
function getDaysDifference(selectedDate) {  
    // 去除时间部分,只比较日期  
    const selected = new Date(selectedDate.getFullYear(), selectedDate.getMonth(), selectedDate.getDate());  
    const now = new Date(today.getFullYear(), today.getMonth(), today.getDate());  
    const diffTime = selected - now;  
    const diffDays = Math.floor(diffTime / (1000 * 60 * 60 * 24));  
    if (diffDays === 0) return "今天";  
    return diffDays > 0 ? `还有 ${diffDays} 天` : `已经过去 ${-diffDays} 天`;  
}  

function calculateStats() {
    const year = currentYear;
    const month = currentMonth;
    const daysInMonth = new Date(year, month + 1, 0).getDate();
    let monthCount = 0;
    let current = 0;
    let longest = 0;
    let temp = 0;
    for (let d = 1; d <= daysInMonth; d++) {
        const dateStr = `${year}-${String(month + 1).padStart(2, '0')}-${String(d).padStart(2, '0')}`;
        if (completedDates.includes(dateStr)) {
            monthCount++;
            temp++;
            longest = Math.max(longest, temp);
            if (new Date(year, month, d) <= today) {
                current = temp;
            }
        } else {
            temp = 0;
        }
    }
    monthCompleted.innerHTML = `本月已完成 <strong>${monthCount}</strong> 天`;
    longestStreak.innerHTML = `最长连续完成 <strong>${longest}</strong> 天`;
    currentStreak.innerHTML = `当前连续 <strong>${current}</strong> 天`;
}

function formatCountdown(ms) {
    if (ms <= 0) return '已结束';
    let totalSeconds = Math.floor(ms / 1000);
    const years = Math.floor(totalSeconds / (365 * 24 * 60 * 60));
    totalSeconds -= years * 365 * 24 * 60 * 60;
    const months = Math.floor(totalSeconds / (30 * 24 * 60 * 60));
    totalSeconds -= months * 30 * 24 * 60 * 60;
    const days = Math.floor(totalSeconds / (24 * 60 * 60));
    totalSeconds -= days * 24 * 60 * 60;
    const hours = Math.floor(totalSeconds / (60 * 60));
    totalSeconds -= hours * 60 * 60;
    const minutes = Math.floor(totalSeconds / 60);
    const seconds = totalSeconds % 60;

    let result = '';
    if (years > 0) result += `${years}年`;
    if (months > 0) result += `${months}月`;
    if (days > 0) result += `${days}日`;
    if (hours > 0) result += `${hours}时`;
    if (minutes > 0) result += `${minutes}分`;
    result += `${seconds}秒`;

    return `还剩${result}`;
}

function renderLongTermGoals() {
    goalsList.innerHTML = '';
    if (longTermGoals.rows.length === 0) {
        goalsList.innerHTML = '<p class="empty-state">暂无跨日目标<br>点击左上角 🎯 添加</p>';
        return;
    }

    if (window.countdownTimer) clearInterval(window.countdownTimer);

    const goalElements = [];
    longTermGoals.rows.forEach((goal, index) => {
        const start = new Date(goal["开始日期"]);
        const end = new Date(goal["结束日期"]);
        if (isNaN(start) || isNaN(end)) return;

        const div = document.createElement('div');
        div.className = 'goal-item';

        const totalMs = end - start;
        const currentMs = Math.max(0, Math.min(totalMs, new Date() - start));
        const progressPercent = totalMs > 0 ? Math.min(100, (currentMs / totalMs) * 100) : 0;

        div.innerHTML = `
            <div class="goal-title">${goal["目标名称"] || '未命名目标'}</div>
            <div class="goal-dates">${goal["开始日期"]} ~ ${goal["结束日期"]}</div>
            <div class="countdown" id="countdown-${index}">${formatCountdown(end - new Date())}</div>
            <div class="progress-bar"><div class="progress-fill" style="width:${progressPercent}%"></div></div>
        `;
        goalsList.appendChild(div);
        goalElements.push({
            element: document.getElementById(`countdown-${index}`),
            endDate: end
        });
    });

    window.countdownTimer = setInterval(() => {
        goalElements.forEach(item => {
            if (item.element) {
                item.element.textContent = formatCountdown(item.endDate - new Date());
            }
        });
    }, 1000);
}

function renderCalendar(year, month) {
    calendarGrid.innerHTML = '';
    monthYearDisplay.textContent = `${year}年${month + 1}月`;
    const firstDay = new Date(year, month, 1).getDay();
    const daysInMonth = new Date(year, month + 1, 0).getDate();
    const daysInPrevMonth = new Date(year, month, 0).getDate();
    
    for (let i = firstDay - 1; i >= 0; i--) {
        const dayNum = daysInPrevMonth - i;
        const actualDate = new Date(year, month - 1, dayNum);
        createDayElement(dayNum, actualDate, true);
    }
    
    for (let day = 1; day <= daysInMonth; day++) {
        const actualDate = new Date(year, month, day);
        createDayElement(day, actualDate, false);
    }
    
    const totalCells = calendarGrid.children.length;
    const remaining = 42 - totalCells;
    for (let i = 1; i <= remaining; i++) {
        const actualDate = new Date(year, month + 1, i);
        createDayElement(i, actualDate, true);
    }
    calculateStats();
    renderLongTermGoals();
    updateCelebrateBtn();
}

function createDayElement(displayNum, actualDate, isOtherMonth) {
    const dayEl = document.createElement('div');
    dayEl.classList.add('day');
    if (isOtherMonth) dayEl.classList.add('other-month');
    const numSpan = document.createElement('span');
    numSpan.className = 'day-number';
    numSpan.textContent = displayNum;
    dayEl.appendChild(numSpan);
    const dateStr = actualDate.toISOString().split('T')[0];
    if (completedDates.includes(dateStr)) {
        const mark = document.createElement('div');
        mark.className = 'completed-mark';
        mark.textContent = '✓';
        dayEl.appendChild(mark);
    }
    if (actualDate.toDateString() === today.toDateString()) {
        dayEl.classList.add('today');
    }
    dayEl.addEventListener('click', (e) => {
        e.stopPropagation();
        document.querySelectorAll('.day.selected').forEach(el => el.classList.remove('selected'));
        if (!dayEl.classList.contains('today')) dayEl.classList.add('selected');
        const formatted = actualDate.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' });
        const diff = getDaysDifference(actualDate);
        dateInfo.textContent = `${formatted} —— ${diff}`;
    });
    calendarGrid.appendChild(dayEl);
}

function updateCelebrateBtn() {
    const isCurrentMonth = currentYear === today.getFullYear() && currentMonth === today.getMonth();
    const dateStr = today.toISOString().split('T')[0];
    const isCompleted = completedDates.includes(dateStr);
    celebrateBtn.disabled = !isCurrentMonth || isCompleted;
    celebrateBtn.textContent = isCompleted ? '今日已完成!✨' : (isCurrentMonth ? '完成今日任务!🎉' : '请切换到本月');
}

// ==================== 今日任务功能 ====================
document.querySelector('.daily-task-btn')?.addEventListener('click', () => {
    currentTaskFields = [...dailyTaskData.fields];
    currentTaskRows = dailyTaskData.rows.map(r => ({...r}));
    renderDailyTaskTable();
    dailyTaskModal.style.display = 'flex';
});

function renderDailyTaskTable() {
    taskHead.innerHTML = '';
    taskRows.innerHTML = '';
    const tr = document.createElement('tr');
    currentTaskFields.forEach(field => {
        const th = document.createElement('th');
        th.textContent = field;
        const del = document.createElement('button');
        del.textContent = '×';
        del.className = 'delete-field';
        del.onclick = () => {
            if (confirm(`删除字段 "${field}"?`)) {
                const idx = currentTaskFields.indexOf(field);
                currentTaskFields.splice(idx, 1);
                currentTaskRows.forEach(row => delete row[field]);
                renderDailyTaskTable();
            }
        };
        th.appendChild(del);
        tr.appendChild(th);
    });
    const thAction = document.createElement('th');
    thAction.textContent = '操作';
    tr.appendChild(thAction);
    taskHead.appendChild(tr);
    currentTaskRows.forEach(row => addDailyTaskRow(row));
    if (currentTaskRows.length === 0) addDailyTaskRow({});
}

function addDailyTaskRow(row = {}) {
    const tr = document.createElement('tr');
    currentTaskFields.forEach(field => {
        const td = document.createElement('td');
        const input = document.createElement('input');
        input.type = 'text';
        input.value = row[field] || '';
        input.placeholder = field;
        td.appendChild(input);
        tr.appendChild(td);
    });
    const delTd = document.createElement('td');
    const delBtn = document.createElement('button');
    delBtn.textContent = '×';
    delBtn.style = 'background:none;border:none;color:#ff4444;cursor:pointer;font-size:22px;font-weight:bold;padding:0 8px;';
    delBtn.onclick = () => tr.remove();
    delTd.appendChild(delBtn);
    tr.appendChild(delTd);
    taskRows.appendChild(tr);
}

document.getElementById('add-task-field')?.addEventListener('click', () => {
    const name = prompt('新字段名称:');
    if (name && !currentTaskFields.includes(name)) {
        currentTaskFields.push(name);
        renderDailyTaskTable();
    }
});

document.getElementById('add-task-row')?.addEventListener('click', () => addDailyTaskRow({}));

document.getElementById('import-text')?.addEventListener('click', () => {
    const text = prompt('粘贴文本(每行一个任务,用空格或制表符分隔字段):', '');
    if (text) {
        const lines = text.split('\n');
        lines.forEach(line => {
            const parts = line.trim().split(/\s+/);
            if (parts.length > 0) {
                const row = {};
                parts.forEach((part, i) => {
                    const field = currentTaskFields[i] || `字段${i+1}`;
                    row[field] = part;
                });
                currentTaskRows.push(row);
            }
        });
        renderDailyTaskTable();
    }
});

document.getElementById('daily-task-save')?.addEventListener('click', () => {
    const newRows = [];
    taskRows.querySelectorAll('tr').forEach(tr => {
        const inputs = tr.querySelectorAll('input[type="text"]');
        const row = {};
        currentTaskFields.forEach((f, i) => {
            const val = inputs[i]?.value.trim();
            if (val) row[f] = val;
        });
        if (Object.keys(row).length > 0) newRows.push(row);
    });
    dailyTaskData = { fields: currentTaskFields, rows: newRows };
    localStorage.setItem('dailyTaskData', JSON.stringify(dailyTaskData));
    renderTodayTaskDisplay();
    dailyTaskModal.style.display = 'none';
});

document.getElementById('daily-task-cancel')?.addEventListener('click', () => {
    dailyTaskModal.style.display = 'none';
});

function renderTodayTaskDisplay() {
    todayTaskDisplay.innerHTML = '';
    if (dailyTaskData.rows.length === 0) {
        todayTaskDisplay.innerHTML = '<tr><td colspan="3" style="text-align:center;color:#999;padding:30px;">点击 📝 设置今日任务</td></tr>';
        allCompleteDisplayWrapper.style.display = 'none';
        return;
    }
    const thead = document.createElement('thead');
    const trHead = document.createElement('tr');
    dailyTaskData.fields.forEach(f => {
        const th = document.createElement('th');
        th.textContent = f;
        trHead.appendChild(th);
    });
    const thCheck = document.createElement('th');
    thCheck.textContent = '完成';
    trHead.appendChild(thCheck);
    thead.appendChild(trHead);
    todayTaskDisplay.appendChild(thead);
    const tbody = document.createElement('tbody');
    dailyTaskData.rows.forEach((row, index) => {
        const tr = document.createElement('tr');
        if (row.completed) tr.classList.add('completed');
        dailyTaskData.fields.forEach(f => {
            const td = document.createElement('td');
            td.textContent = row[f] || '';
            tr.appendChild(td);
        });
        const tdCheck = document.createElement('td');
        const checkbox = document.createElement('input');
        checkbox.type = 'checkbox';
        checkbox.checked = row.completed || false;
        checkbox.onchange = () => {
            dailyTaskData.rows[index].completed = checkbox.checked;
            localStorage.setItem('dailyTaskData', JSON.stringify(dailyTaskData));
            if (checkbox.checked) tr.classList.add('completed');
            else tr.classList.remove('completed');
            checkAllCompleted();
        };
        tdCheck.appendChild(checkbox);
        tr.appendChild(tdCheck);
        tbody.appendChild(tr);
    });
    todayTaskDisplay.appendChild(tbody);
    allCompleteDisplayWrapper.style.display = 'block';
    checkAllCompleted();
}

function checkAllCompleted() {
    const allCompleted = dailyTaskData.rows.length > 0 && dailyTaskData.rows.every(r => r.completed);
    celebrateBtn.disabled = !allCompleted;
    celebrateBtn.textContent = allCompleted ? '完成今日任务!🎉' : '请完成所有任务后再庆祝';
}

document.getElementById('all-complete-display')?.addEventListener('click', () => {
    dailyTaskData.rows.forEach((row, index) => {
        row.completed = true;
        const checkbox = todayTaskDisplay.querySelectorAll('input[type="checkbox"]')[index];
        if (checkbox) checkbox.checked = true;
        const tr = checkbox?.closest('tr');
        if (tr) tr.classList.add('completed');
    });
    localStorage.setItem('dailyTaskData', JSON.stringify(dailyTaskData));
    checkAllCompleted();
});

// ==================== 跨日目标功能 ====================
const goalCompleteModal = document.getElementById('goal-complete-modal');
const goalCompleteName = document.getElementById('goal-complete-name');
const goalCompleteText = document.getElementById('goal-complete-text');
const goalCompleteButtons = document.getElementById('goal-complete-buttons');
let currentCompletingGoalIndex = -1;

// 格式化日期时间显示
function formatDateTime(dateTimeStr) {
    if (!dateTimeStr) return '';
    const date = new Date(dateTimeStr);
    if (isNaN(date)) return dateTimeStr;
    
    const year = date.getFullYear();
    const month = date.getMonth() + 1;
    const day = date.getDate();
    const hours = String(date.getHours()).padStart(2, '0');
    const minutes = String(date.getMinutes()).padStart(2, '0');
    const seconds = String(date.getSeconds()).padStart(2, '0');
    
    return `${year}年${month}月${day}日 ${hours}:${minutes}:${seconds}`;
}

// 渲染目标列表(在模态框内)
function renderGoalListInModal() {
    const container = document.getElementById('goal-list-container');
    if (!container) return;
    
    container.innerHTML = '';
    
    if (longTermGoals.rows.length === 0) {
        container.innerHTML = '<p class="empty-goal">暂无目标,点击上方添加</p>';
        return;
    }
    
    longTermGoals.rows.forEach((goal, index) => {
        const div = document.createElement('div');
        div.className = 'goal-list-item';
        
        // 添加状态样式
        if (goal.status === 'completed') {
            div.classList.add('completed');
        } else if (goal.status === 'failed') {
            div.classList.add('failed');
        }
        
        const startStr = formatDateTime(goal.startDate);
        const endStr = formatDateTime(goal.endDate);
        
        let statusTag = '';
        if (goal.status === 'completed') {
            statusTag = '<span class="goal-status-tag completed">✓ 已完成</span>';
        } else if (goal.status === 'failed') {
            statusTag = '<span class="goal-status-tag failed">✗ 未完成</span>';
        } else {
            statusTag = '<span class="goal-status-tag running">进行中</span>';
        }
        
        div.innerHTML = `
            <div class="goal-item-info">
                <div class="goal-item-name">${goal.name || '未命名目标'} ${statusTag}</div>
                <div class="goal-item-dates">📅 ${startStr} → ${endStr}</div>
            </div>
            <button class="goal-item-delete" data-index="${index}">×</button>
        `;
        container.appendChild(div);
    });
    
    // 绑定删除事件
    container.querySelectorAll('.goal-item-delete').forEach(btn => {
        btn.onclick = () => {
            const idx = parseInt(btn.dataset.index);
            if (confirm('确定删除这个目标吗?')) {
                longTermGoals.rows.splice(idx, 1);
                localStorage.setItem('longTermGoals', JSON.stringify(longTermGoals));
                renderGoalListInModal();
                renderLongTermGoals();
            }
        };
    });
}

// 打开跨日目标模态框
document.querySelector('.long-term-btn')?.addEventListener('click', async () => {
    await initGoalMediaDisplay();
    renderGoalListInModal();
    longTermModal.style.display = 'flex';
});

// 添加新目标
document.getElementById('btn-add-goal')?.addEventListener('click', () => {
    const nameInput = document.getElementById('new-goal-name');
    const startInput = document.getElementById('new-goal-start');
    const endInput = document.getElementById('new-goal-end');
    
    if (!nameInput.value.trim()) {
        alert('请输入目标名称!');
        return;
    }
    if (!startInput.value || !endInput.value) {
        alert('请选择开始和结束时间!');
        return;
    }
    
    const newGoal = {
        name: nameInput.value.trim(),
        startDate: startInput.value,
        endDate: endInput.value,
        status: 'running',
        notified: false
    };
    
    longTermGoals.rows.push(newGoal);
    localStorage.setItem('longTermGoals', JSON.stringify(longTermGoals));
    
    // 清空输入
    nameInput.value = '';
    startInput.value = '';
    endInput.value = '';
    
    renderGoalListInModal();
    renderLongTermGoals();
    alert('目标已添加!');
});

// 关闭模态框
document.getElementById('long-term-cancel')?.addEventListener('click', () => {
    longTermModal.style.display = 'none';
});

longTermModal?.addEventListener('click', (e) => {
    if (e.target === longTermModal) {
        longTermModal.style.display = 'none';
    }
});

// 渲染右侧跨日目标显示
function renderLongTermGoals() {
    goalsList.innerHTML = '';
    
    const activeGoals = longTermGoals.rows.filter(g => g.status === 'running');
    
    if (activeGoals.length === 0) {
        goalsList.innerHTML = '<p class="empty-state">暂无进行中的目标<br>点击左上角 🎯 添加</p>';
        return;
    }

    if (window.countdownTimer) clearInterval(window.countdownTimer);

    const goalElements = [];
    activeGoals.forEach((goal, index) => {
        const start = new Date(goal.startDate);
        const end = new Date(goal.endDate);
        if (isNaN(start) || isNaN(end)) return;

        const div = document.createElement('div');
        div.className = 'goal-item';

        const now = getCurrentTime();
        const totalMs = end - start;
        const elapsedMs = Math.max(0, Math.min(totalMs, now - start));
        const progressPercent = totalMs > 0 ? Math.min(100, (elapsedMs / totalMs) * 100) : 0;
        const remainingMs = end - now;

        div.innerHTML = `
            <div class="goal-title">${goal.name || '未命名目标'}</div>
            <div class="goal-dates">${formatDateTime(goal.startDate)} ~ ${formatDateTime(goal.endDate)}</div>
            <div class="countdown" id="goal-countdown-${index}">${formatCountdown(remainingMs)}</div>
            <div class="progress-bar"><div class="progress-fill" style="width:${progressPercent}%"></div></div>
        `;
        goalsList.appendChild(div);
        
        goalElements.push({
            element: document.getElementById(`goal-countdown-${index}`),
            endDate: end,
            goal: goal,
            originalIndex: longTermGoals.rows.indexOf(goal)
        });
    });

    // 倒计时更新和目标完成检测
    window.countdownTimer = setInterval(() => {
        const now = getCurrentTime();
        
        goalElements.forEach(item => {
            if (item.element) {
                const remaining = item.endDate - now;
                item.element.textContent = formatCountdown(remaining);
                
                // 检测是否到期
                if (remaining <= 0 && !item.goal.notified && item.goal.status === 'running') {
                    item.goal.notified = true;
                    localStorage.setItem('longTermGoals', JSON.stringify(longTermGoals));
                    showGoalCompleteModal(item.goal, item.originalIndex);
                }
            }
        });
    }, 1000);
}

// 显示目标完成确认模态框
async function showGoalCompleteModal(goal, index) {
    currentCompletingGoalIndex = index;
    goalCompleteName.textContent = goal.name || '未命名目标';
    goalCompleteText.textContent = '是否完成?';
    
    // 根据设置播放媒体
    const mediaData = await getMediaFile('goalComplete');
    
    if (goalMediaSettings.mode === 'video' && mediaData && mediaData.type.startsWith('video')) {
        // 视频模式 - 播放视频
        if (goalBlobURL) URL.revokeObjectURL(goalBlobURL);
        goalBlobURL = createBlobURL(mediaData.arrayBuffer, mediaData.type);
        
        const goalVideoModal = document.getElementById('goal-video-modal');
        const goalVideoPlayer = document.getElementById('goal-video-player');
        
        if (goalVideoModal && goalVideoPlayer) {
            goalVideoPlayer.src = goalBlobURL;
            goalVideoModal.style.display = 'flex';
            goalVideoPlayer.play().catch(err => console.log('视频播放失败'));
            
            // 视频结束后显示确认弹窗
            goalVideoPlayer.onended = () => {
                goalVideoModal.style.display = 'none';
                showGoalConfirmButtons();
            };
        }
    } else if (goalMediaSettings.mode === 'animation') {
        // 动画模式 - 播放小卡片动画
        cardsAnimationModal.style.display = 'block';
        
        if (mediaData) {
            if (cardsBlobURL) URL.revokeObjectURL(cardsBlobURL);
            cardsBlobURL = createBlobURL(mediaData.arrayBuffer, mediaData.type);
            cardsAudio.src = cardsBlobURL;
            cardsAudio.play().catch(err => console.log('音频播放失败'));
        }
        
        runCardsAnimation();
        
        // 3秒后显示确认弹窗
        setTimeout(() => {
            showGoalConfirmButtons();
        }, 3000);
    } else {
        // 无媒体设置,直接显示确认弹窗
        showGoalConfirmButtons();
    }
}

// 显示目标确认按钮
function showGoalConfirmButtons() {
    goalCompleteButtons.innerHTML = `
        <button class="btn-not-complete" id="btn-not-complete">未完成 😔</button>
        <button class="btn-complete" id="btn-complete">完成 🎉</button>
    `;
    
    goalCompleteModal.style.display = 'flex';
    
    // 绑定按钮事件
    document.getElementById('btn-not-complete').onclick = () => {
        // 关闭动画
        cardsAnimationModal.style.display = 'none';
        cardsAudio.pause();
        cardsAudio.currentTime = 0;
        cardsBoard.innerHTML = '';
        
        goalCompleteText.textContent = '下次加油!💪';
        goalCompleteButtons.innerHTML = `
            <button class="btn-confirm" id="btn-confirm">确定</button>
        `;
        document.getElementById('btn-confirm').onclick = () => {
            longTermGoals.rows[currentCompletingGoalIndex].status = 'failed';
            localStorage.setItem('longTermGoals', JSON.stringify(longTermGoals));
            goalCompleteModal.style.display = 'none';
            renderLongTermGoals();
            renderGoalListInModal();
        };
    };
    
    document.getElementById('btn-complete').onclick = () => {
        // 关闭动画
        cardsAnimationModal.style.display = 'none';
        cardsAudio.pause();
        cardsAudio.currentTime = 0;
        cardsBoard.innerHTML = '';
        
        goalCompleteText.textContent = '少年,你做到了!🎉';
        goalCompleteButtons.innerHTML = `
            <button class="btn-confirm" id="btn-confirm">确定</button>
        `;
        document.getElementById('btn-confirm').onclick = () => {
            longTermGoals.rows[currentCompletingGoalIndex].status = 'completed';
            localStorage.setItem('longTermGoals', JSON.stringify(longTermGoals));
            goalCompleteModal.style.display = 'none';
            renderLongTermGoals();
            renderGoalListInModal();
        };
    };
}

// 检查是否有到期的目标(页面加载时)
function checkExpiredGoals() {
    const now = getCurrentTime();
    
    longTermGoals.rows.forEach((goal, index) => {
        if (goal.status !== 'running') return;
        
        const end = new Date(goal.endDate);
        if (isNaN(end)) return;
        
        if (now >= end && !goal.notified) {
            goal.notified = true;
            localStorage.setItem('longTermGoals', JSON.stringify(longTermGoals));
            
            // 延迟显示,避免页面加载时立即弹出
            setTimeout(() => {
                showGoalCompleteModal(goal, index);
            }, 1000);
        }
    });
}

let goalCardsSettings = {
    quotes: ["目标达成!🎉", "你太棒了!💪", "坚持就是胜利!🔥"],
    emojis: ["🎉", "✨", "🔥", "💪", "❤️", "🚀"]
};
try {
    const saved = localStorage.getItem('goalCardsSettings');
    if (saved) goalCardsSettings = JSON.parse(saved);
} catch(e) {}

// ==================== 跨日目标媒体设置 ====================
// 文件选择显示
document.getElementById('goal-media-file')?.addEventListener('change', (e) => {
    const file = e.target.files[0];
    const nameEl = document.getElementById('goal-media-file-name');
    if (file && nameEl) {
        const isVideo = file.name.match(/\.(mp4|webm|mov|avi)$/i);
        const icon = isVideo ? '🎥' : '🎵';
        nameEl.innerHTML = `
            <div class="file-info">
                <span class="file-icon">${icon}</span>
                <div class="file-details">
                    <span class="file-name-text">${file.name}</span>
                    <span class="file-size-text">${formatFileSize(file.size)}</span>
                </div>
            </div>
            <button class="delete-btn" onclick="this.parentElement.style.display='none';document.getElementById('goal-media-file').value='';">×</button>
        `;
        nameEl.style.display = 'flex';
    } else if (nameEl) {
        nameEl.style.display = 'none';
    }
});

// 保存跨日目标媒体设置
document.getElementById('btn-save-goal-media')?.addEventListener('click', async () => {
    const fileInput = document.getElementById('goal-media-file');
    const file = fileInput?.files[0];
    // 保存小卡片设置
const quotesText = document.getElementById('goal-cards-quotes').value.trim();
const emojisText = document.getElementById('goal-cards-emojis').value.trim();

if (quotesText) {
    goalCardsSettings.quotes = quotesText.split('\n').map(q => q.trim()).filter(q => q);
}
if (emojisText) {
    goalCardsSettings.emojis = emojisText.split(/\s+/).filter(e => e);
}

localStorage.setItem('goalCardsSettings', JSON.stringify(goalCardsSettings));
    // 保存文件
    if (file) {
        try {
            await saveMediaFile('goalComplete', file);
            console.log('跨日目标媒体文件已保存');
        } catch (err) {
            console.error('保存文件失败:', err);
            alert('保存文件失败,请重试!');
            return;
        }
    }
    
    // 保存播放模式
    let mode = 'animation';
    document.querySelectorAll('input[name="goal-mode"]').forEach(radio => {
        if (radio.checked) mode = radio.value;
    });
    
    goalMediaSettings.mode = mode;
    localStorage.setItem('goalMediaSettings', JSON.stringify(goalMediaSettings));
    
    alert('提醒设置已保存!🎉');
});

// 初始化跨日目标媒体设置显示
async function initGoalMediaDisplay() {
document.getElementById('goal-cards-quotes').value = goalCardsSettings.quotes.join('\n');
document.getElementById('goal-cards-emojis').value = goalCardsSettings.emojis.join(' ');
    // 设置播放模式
    document.querySelectorAll('input[name="goal-mode"]').forEach(radio => {
        radio.checked = radio.value === goalMediaSettings.mode;
    });
    
    // 显示已保存的文件
    const mediaData = await getMediaFile('goalComplete');
    const nameEl = document.getElementById('goal-media-file-name');
    if (mediaData && nameEl) {
        const isVideo = mediaData.type.startsWith('video');
        const icon = isVideo ? '🎥' : '🎵';
        nameEl.innerHTML = `
            <div class="file-info">
                <span class="file-icon">${icon}</span>
                <div class="file-details">
                    <span class="file-name-text">${mediaData.name}</span>
                    <span class="file-size-text">${formatFileSize(mediaData.size)}</span>
                </div>
            </div>
            <button class="delete-btn" onclick="deleteGoalMedia()">×</button>
        `;
        nameEl.style.display = 'flex';
    }
}

// 删除跨日目标媒体文件
async function deleteGoalMedia() {
    await deleteMediaFile('goalComplete');
    const nameEl = document.getElementById('goal-media-file-name');
    if (nameEl) nameEl.style.display = 'none';
    document.getElementById('goal-media-file').value = '';
}

// ==================== 颜色选择器实时预览 ====================
document.getElementById('encourage-bg-color')?.addEventListener('input', (e) => {
    const preview = document.getElementById('color-preview');
    if (preview) {
        preview.style.background = e.target.value;
        preview.style.borderStyle = 'solid';
        preview.style.borderColor = e.target.value;
        // 根据背景色调整文字颜色
        const hex = e.target.value.replace('#', '');
        const r = parseInt(hex.substr(0, 2), 16);
        const g = parseInt(hex.substr(2, 2), 16);
        const b = parseInt(hex.substr(4, 2), 16);
        const brightness = (r * 299 + g * 587 + b * 114) / 1000;
        preview.style.color = brightness > 128 ? '#333' : '#fff';
    }
});

// ==================== 闹钟文件选择显示(美化版) ====================
document.getElementById('alarm-audio-file')?.addEventListener('change', (e) => {
    const file = e.target.files[0];
    const nameEl = document.getElementById('alarm-file-name');
    if (file && nameEl) {
        const isVideo = file.name.match(/\.(mp4|webm|mov|avi)$/i);
        const icon = isVideo ? '🎥' : '🎵';
        nameEl.innerHTML = `
            <div class="file-info">
                <span class="file-icon">${icon}</span>
                <div class="file-details">
                    <span class="file-name-text">${file.name}</span>
                    <span class="file-size-text">${formatFileSize(file.size)}</span>
                </div>
            </div>
            <button class="delete-btn" onclick="this.parentElement.style.display='none';document.getElementById('alarm-audio-file').value='';">×</button>
        `;
        nameEl.style.display = 'flex';
    } else if (nameEl) {
        nameEl.style.display = 'none';
    }
});

// ==================== 初始化 ====================
// 立即渲染日历(使用本地时间,不等待网络)
function immediateRender() {
    today = new Date();
    currentYear = today.getFullYear();
    currentMonth = today.getMonth();
    
    updateRealtimeClock();
    renderCalendar(currentYear, currentMonth);
    renderTodayTaskDisplay();
    
    const formattedToday = today.toLocaleDateString('zh-CN', { year: 'numeric', month: 'long', day: 'numeric', weekday: 'long' });
    dateInfo.textContent = `${formattedToday} —— 今天`;
}

// 立即执行渲染
immediateRender();

// 检查到期目标
setTimeout(checkExpiredGoals, 2000);

// 后台异步初始化(不阻塞页面显示)
async function asyncInit() {
    // 后台同步网络时间
    const synced = await syncNetworkTime();
    if (synced) {
        today = getCurrentTime();
        currentYear = today.getFullYear();
        currentMonth = today.getMonth();
        renderCalendar(currentYear, currentMonth);
        updateRealtimeClock();
    }
    
    // 后台加载媒体文件
    await initCelebrateMedia();
}

// 延迟执行异步初始化,不阻塞页面
setTimeout(asyncInit, 100);
document.getElementById('encourage-video-close')?.addEventListener('click', () => {  
    document.getElementById('encourage-video-modal').style.display = 'none';  
    document.getElementById('encourage-video-player').pause();  
});
window.addEventListener('beforeunload', () => {
    if (window.countdownTimer) clearInterval(window.countdownTimer);
    if (celebrateBlobURL) URL.revokeObjectURL(celebrateBlobURL);
    if (encourageBlobURL) URL.revokeObjectURL(encourageBlobURL);
    if (cardsBlobURL) URL.revokeObjectURL(cardsBlobURL);
});
    </script>
</body>
</html>

如果你渴望一种更科学、更有趣、更具可持续性的自律方式,如果你是一名喜欢折腾、追求极致个性化的开发者或极客,那么,请不要错过这款在创意工坊刚刚上架的宝藏应用。

立即体验,用「熊二的自律日历」,开启你独一无二的可视化自律之旅,让每一天的坚持,都闪闪发光!

© 版权声明
THE END
喜欢就支持一下吧
点赞3 分享
评论 共1条

请登录后发表评论