<?php
$pageTitle = '婚礼总管数字人';
require_once 'header.php';
?>

<main class="site-main">
    <section class="page-banner dh-banner">
        <div class="container">
            <h1>🧑‍💼 如意管家 - 婚礼总管数字人</h1>
            <p>AI智能管家「如意」—— 全程统筹婚礼流程，实时监控进度，智能预警提醒
                <a href="digital_human_manager_screen.php" target="_blank" style="display:inline-block;margin-left:16px;padding:6px 18px;background:rgba(212,168,83,0.2);border:1px solid rgba(212,168,83,0.5);border-radius:20px;color:#d4a853;font-size:13px;text-decoration:none;vertical-align:middle;">📺 大屏展示模式</a>
            </p>
        </div>
    </section>

    <section class="dh-section">
        <div class="container">
            <div class="video-center-stage">
                <div class="main-video-wrapper" id="mainVideoWrapper">
                    <video id="mainVideo" preload="metadata" playsinline>
                        <source id="mainVideoSource" type="video/mp4">
                    </video>
                    <div class="video-overlay" id="videoOverlay">
                        <div class="overlay-bg"></div>
                        <div class="overlay-curtain-left"></div>
                        <div class="overlay-curtain-right"></div>
                        <div class="overlay-light-rays"></div>
                        <div class="overlay-lantern-left">
                            <div class="overlay-lantern">
                                <div class="overlay-lantern-top"></div>
                                <div class="overlay-lantern-body"></div>
                                <div class="overlay-lantern-bottom"></div>
                            </div>
                            <div class="overlay-lantern" style="margin-top:5px;animation-delay:-1s;transform:scale(0.8);">
                                <div class="overlay-lantern-top"></div>
                                <div class="overlay-lantern-body"></div>
                                <div class="overlay-lantern-bottom"></div>
                            </div>
                        </div>
                        <div class="overlay-lantern-right">
                            <div class="overlay-lantern">
                                <div class="overlay-lantern-top"></div>
                                <div class="overlay-lantern-body"></div>
                                <div class="overlay-lantern-bottom"></div>
                            </div>
                            <div class="overlay-lantern" style="margin-top:5px;animation-delay:-1s;transform:scale(0.8);">
                                <div class="overlay-lantern-top"></div>
                                <div class="overlay-lantern-body"></div>
                                <div class="overlay-lantern-bottom"></div>
                            </div>
                        </div>
                        <div class="overlay-xi-center">
                            <div class="overlay-xi-main">囍</div>
                        </div>
                        <div class="overlay-bottom-banner">
                            <div class="overlay-banner-item">喜</div>
                            <div class="overlay-banner-item">结</div>
                            <div class="overlay-banner-item">良</div>
                            <div class="overlay-banner-item">缘</div>
                        </div>
                        <div class="overlay-top">
                            <div class="current-phase-badge" id="currentPhaseBadge">
                                <span class="phase-icon">🎯</span>
                                <span class="phase-text">整体统筹</span>
                            </div>
                            <div class="emotion-indicator-mini" id="emotionIndicatorMini">
                                <span class="emotion-dot"></span>
                                <span class="emotion-text">就绪</span>
                            </div>
                        </div>
                        <div class="overlay-center" id="overlayCenter">
                            <div class="welcome-state">
                                <div class="avatar-mini" id="hostAvatarMini">
                                    <div class="mini-face">
                                        <div class="mini-eyes">
                                            <span class="mini-eye"></span>
                                            <span class="mini-eye"></span>
                                        </div>
                                        <div class="mini-mouth" id="miniMouth"></div>
                                    </div>
                                </div>
                                <p class="welcome-text" id="welcomeText">点击左侧时间轴选择统筹环节</p>
                                <p class="welcome-sub" id="welcomeSub">或从视频库选择视频播放</p>
                            </div>
                        </div>
                        <div class="overlay-info-panel" id="overlayInfoPanel" style="display:none;">
                            <div class="info-panel-header">
                                <div class="info-phase-time" id="infoPhaseTime"></div>
                                <div class="info-phase-name" id="infoPhaseName"></div>
                            </div>
                            <div class="info-panel-body">
                                <div class="info-row">
                                    <div class="info-label">👥 负责人员</div>
                                    <div class="info-content" id="infoTeam"></div>
                                </div>
                                <div class="info-row">
                                    <div class="info-label">📦 必备物资</div>
                                    <div class="info-content" id="infoMaterials"></div>
                                </div>
                                <div class="info-row">
                                    <div class="info-label">📝 习俗备注</div>
                                    <div class="info-content" id="infoNotes"></div>
                                </div>
                                <div class="info-row">
                                    <div class="info-label">🎯 统筹指令</div>
                                    <div class="info-content" id="infoInstruction"></div>
                                </div>
                            </div>
                        </div>
                        <div class="video-loading-overlay" id="videoLoadingOverlay" style="display:none;">
                            <div class="video-loading-spinner"></div>
                            <p class="video-loading-text">视频加载中...</p>
                        </div>
                    </div>
                    <div class="video-controls-bar">
                        <button class="ctrl-btn ctrl-btn-prev" id="btnPrevVideo" title="上一个视频" disabled><i class="fas fa-step-backward"></i></button>
                        <button class="ctrl-btn ctrl-btn-pause" id="btnMainPause" title="暂停"><i class="fas fa-pause"></i></button>
                        <button class="ctrl-btn ctrl-btn-stop" id="btnMainStop" title="停止"><i class="fas fa-stop"></i></button>
                        <button class="ctrl-btn ctrl-btn-next" id="btnNextVideo" title="下一个视频" disabled><i class="fas fa-step-forward"></i></button>
                        <div class="progress-track" id="progressTrack">
                            <div class="phase-markers" id="phaseMarkers"></div>
                            <div class="progress-filled" id="progressFilled"></div>
                            <div class="progress-handle" id="progressHandle"></div>
                        </div>
                        <div class="time-display" id="timeDisplay">00:00 / 00:00</div>
                        <button class="ctrl-btn ctrl-btn-rewind" id="btnRewind" title="快退10秒"><i class="fas fa-backward"></i></button>
                        <button class="ctrl-btn ctrl-btn-forward" id="btnForward" title="快进10秒"><i class="fas fa-forward"></i></button>
                        <button class="ctrl-btn ctrl-btn-loop" id="btnLoop" title="循环播放"><i class="fas fa-redo"></i></button>
                        <div class="speed-control" id="speedControl">
                            <button class="ctrl-btn ctrl-btn-speed" id="btnSpeed" title="倍速">1x</button>
                            <div class="speed-menu" id="speedMenu">
                                <div class="speed-option" data-speed="0.5">0.5x</div>
                                <div class="speed-option" data-speed="1">1x</div>
                                <div class="speed-option" data-speed="1.5">1.5x</div>
                            </div>
                        </div>
                        <div class="volume-control" id="volumeControl">
                            <button class="ctrl-btn ctrl-btn-volume" id="btnMute" title="静音"><i class="fas fa-volume-up" id="volumeIcon"></i></button>
                            <div class="volume-slider-wrapper" id="volumeSliderWrapper">
                                <div class="volume-slider-track" id="volumeSliderTrack">
                                    <div class="volume-slider-filled" id="volumeSliderFilled"></div>
                                    <div class="volume-slider-handle" id="volumeSliderHandle"></div>
                                </div>
                            </div>
                            <div class="volume-indicator" id="volumeIndicator">
                                <div class="vol-bar vol-bar-1"></div>
                                <div class="vol-bar vol-bar-2"></div>
                                <div class="vol-bar vol-bar-3"></div>
                                <div class="vol-bar vol-bar-4"></div>
                                <div class="vol-bar vol-bar-5"></div>
                            </div>
                            <span class="volume-percent" id="volumePercent">100%</span>
                        </div>
                        <button class="ctrl-btn" id="btnBgMusic" title="背景音乐"><i class="fas fa-music" id="bgMusicIcon"></i></button>
                        <input type="file" id="bgMusicInput" multiple style="display:none;">
                        <div class="settings-control" id="settingsControl">
                            <button class="ctrl-btn ctrl-btn-settings" id="btnSettings" title="设置"><i class="fas fa-cog"></i></button>
                            <div class="settings-menu" id="settingsMenu">
                                <div class="settings-item" id="settingsMute"><i class="fas fa-volume-mute"></i> 静音</div>
                                <div class="settings-item" id="settingsQuality"><i class="fas fa-tv"></i> 画质</div>
                                <div class="settings-item" id="settingsSubtitle"><i class="fas fa-closed-captioning"></i> 字幕</div>
                            </div>
                        </div>
                        <button class="ctrl-btn" id="btnFullscreen" title="全屏"><i class="fas fa-expand"></i></button>
                    </div>
                </div>
            </div>

            <div class="control-dashboard">
                <div class="dashboard-left">
                    <div class="panel-card timeline-panel">
                        <div class="panel-header">
                            <h3><i class="fas fa-stream"></i> 统筹时间轴</h3>
                            <span class="panel-badge" id="timelineBadge">12个环节</span>
                        </div>
                        <div class="timeline-track" id="timelineTrack">
                            <div class="timeline-progress" id="timelineProgress"></div>
                            <div class="timeline-phases" id="timelinePhases"></div>
                        </div>
                    </div>

                    <div class="panel-card phase-videos-panel">
                        <div class="panel-header">
                            <h3><i class="fas fa-users"></i> 团队状态监控</h3>
                            <span class="panel-badge" id="phaseVideosBadge">8个团队</span>
                        </div>
                        <div class="phase-videos-grid" id="phaseVideosGrid"></div>
                    </div>

                    <div class="panel-card timeline-ctrl-panel">
                        <div class="panel-header">
                            <h3><i class="fas fa-clock"></i> 进度监控控制</h3>
                            <div style="display:flex;gap:6px;align-items:center;">
                                <span class="sync-status-dot" id="syncStatusDot" title="同步状态"></span>
                                <span class="panel-badge" id="timelineCtrlBadge">已停止</span>
                            </div>
                        </div>
                        <div class="timeline-ctrl-body">
                            <div class="timeline-time-row">
                                <span class="tl-label">已运行</span>
                                <span class="tl-value" id="tlElapsed">00:00:00</span>
                                <span class="tl-label">当前环节</span>
                                <span class="tl-value" id="tlCurrentPhase">--</span>
                                <span class="tl-label">同步偏差</span>
                                <span class="tl-value" id="tlSyncDrift">0.0s</span>
                            </div>
                            <div class="timeline-ctrl-btns">
                                <button class="tl-ctrl-btn tl-start" id="btnTimelineStart" title="启动监控"><i class="fas fa-play"></i> 启动</button>
                                <button class="tl-ctrl-btn tl-pause" id="btnTimelinePause" title="暂停监控" disabled><i class="fas fa-pause"></i> 暂停</button>
                                <button class="tl-ctrl-btn tl-stop" id="btnTimelineStop" title="停止监控" disabled><i class="fas fa-stop"></i> 停止</button>
                                <button class="tl-ctrl-btn tl-calibrate" id="btnTimelineCalibrate" title="手动校准"><i class="fas fa-crosshairs"></i> 校准</button>
                            </div>
                        </div>
                    </div>

                    <div class="panel-card video-library-panel">
                        <div class="panel-header">
                            <h3><i class="fas fa-film"></i> 统筹视频库</h3>
                            <div class="library-tabs">
                                <button class="lib-tab active" data-lib="coordination">📋 统筹安排</button>
                                <button class="lib-tab" data-lib="communication">💬 协调沟通</button>
                                <button class="lib-tab" data-lib="emergency">🔧 应急处置</button>
                                <button class="lib-tab" data-lib="image">📷 任务卡片</button>
                            </div>
                        </div>
                        <div class="library-content" id="libContentCoordination">
                            <div class="upload-row">
                                <input type="file" id="fileInputCoordination" accept="video/*" multiple style="display:none;">
                                <button class="upload-btn-small" id="btnUploadCoordination"><i class="fas fa-cloud-upload-alt"></i> 上传统筹视频 (支持多选)</button>
                            </div>
                            <div class="video-grid" id="coordinationVideoList"></div>
                        </div>
                        <div class="library-content" id="libContentCommunication" style="display:none;">
                            <div class="upload-row">
                                <input type="file" id="fileInputCommunication" accept="video/*" multiple style="display:none;">
                                <button class="upload-btn-small" id="btnUploadCommunication"><i class="fas fa-cloud-upload-alt"></i> 上传沟通视频 (支持多选)</button>
                            </div>
                            <div class="video-grid" id="communicationVideoList"></div>
                        </div>
                        <div class="library-content" id="libContentEmergency" style="display:none;">
                            <div class="upload-row">
                                <input type="file" id="fileInputEmergency" accept="video/*" multiple style="display:none;">
                                <button class="upload-btn-small" id="btnUploadEmergency"><i class="fas fa-cloud-upload-alt"></i> 上传应急视频 (支持多选)</button>
                            </div>
                            <div class="video-grid" id="emergencyVideoList"></div>
                            <div class="ending-config-panel" id="emergencyConfigPanel">
                                <h4><i class="fas fa-cog"></i> 应急播报控制</h4>
                                <div class="config-row">
                                    <label>应急通知语</label>
                                    <textarea id="emergencyText" rows="3" placeholder="请输入应急通知语...">请注意，前方出现异常情况，请各团队保持冷静，听从现场指挥。</textarea>
                                </div>
                                <div class="config-actions">
                                    <button class="preview-btn" id="btnPreviewEmergency" style="flex:1;"><i class="fas fa-play"></i> 播放应急播报</button>
                                </div>
                            </div>
                        </div>
                        <div class="library-content" id="libContentImage" style="display:none;">
                            <div class="upload-row">
                                <input type="file" id="fileInputImage" accept="image/jpeg,image/png,image/gif,image/webp" multiple style="display:none;">
                                <button class="upload-btn-small" id="btnUploadImage"><i class="fas fa-image"></i> 上传任务卡片 (支持多选)</button>
                            </div>
                            <div class="image-grid" id="imageList"></div>
                            <div class="image-lightbox" id="imageLightbox" style="display:none;">
                                <span class="lightbox-close" id="lightboxClose">&times;</span>
                                <img id="lightboxImg" alt="图片预览">
                            </div>
                        </div>
                    </div>
                </div>

                <div class="dashboard-right">
                    <div class="panel-card info-panel">
                        <div class="panel-header">
                            <h3><i class="fas fa-info-circle"></i> 当前环节</h3>
                        </div>
                        <div class="info-body" id="infoBody">
                            <div class="info-placeholder">
                                <i class="fas fa-hand-pointer"></i>
                                <p>点击左侧时间轴选择统筹环节</p>
                            </div>
                        </div>
                    </div>

                    <div class="panel-card">
                        <div class="panel-header">
                            <h3><i class="fas fa-tasks"></i> 任务管理</h3>
                            <div class="header-actions">
                                <button class="btn-add" id="btnAddTask"><i class="fas fa-plus"></i> 新建任务</button>
                                <button class="btn-auto" id="btnAutoAssign"><i class="fas fa-robot"></i> 智能分配</button>
                            </div>
                        </div>
                        <div class="tasks-list" id="tasksList">
                            <div class="no-tasks">暂无任务</div>
                        </div>
                    </div>

                    <div class="panel-card">
                        <div class="panel-header">
                            <h3><i class="fas fa-exclamation-triangle"></i> 预警中心</h3>
                            <span class="alert-badge" id="alertBadge">0</span>
                        </div>
                        <div class="alerts-list" id="alertsList">
                            <div class="no-alerts">暂无预警 ✅</div>
                        </div>
                    </div>

                    <div class="panel-card quick-actions-panel">
                        <div class="panel-header">
                            <h3><i class="fas fa-bolt"></i> 快捷操作</h3>
                        </div>
                        <div class="actions-body">
                            <button class="action-btn primary" id="btnSyncToScreen">
                                <i class="fas fa-desktop"></i> 同步到大屏
                            </button>
                            <button class="action-btn" id="btnClearSession">
                                <i class="fas fa-redo"></i> 重置会话
                            </button>
                        </div>
                    </div>

                    <div class="panel-card reminder-config-panel">
                        <div class="panel-header">
                            <h3><i class="fas fa-bell"></i> 卡点提醒设置</h3>
                            <span class="alert-badge" id="reminderBadge">开</span>
                        </div>
                        <div class="reminder-config-body">
                            <div class="config-row">
                                <label>提前提醒 <span class="config-hint">(距下一环节)</span></label>
                                <select id="reminderLeadTime">
                                    <option value="60">1 分钟</option>
                                    <option value="180" selected>3 分钟</option>
                                    <option value="300">5 分钟</option>
                                    <option value="600">10 分钟</option>
                                </select>
                            </div>
                            <div class="config-row">
                                <label>超时告警 <span class="config-hint">(超过计划结束)</span></label>
                                <select id="delayAlertThreshold">
                                    <option value="60">超 1 分钟</option>
                                    <option value="180" selected>超 3 分钟</option>
                                    <option value="300">超 5 分钟</option>
                                </select>
                            </div>
                            <div class="config-row">
                                <label>大屏弹窗</label>
                                <label class="switch">
                                    <input type="checkbox" id="reminderPopup" checked>
                                    <span class="slider"></span>
                                </label>
                            </div>
                            <div class="config-row">
                                <label>声音提醒</label>
                                <label class="switch">
                                    <input type="checkbox" id="reminderSound" checked>
                                    <span class="slider"></span>
                                </label>
                            </div>
                            <div class="config-row">
                                <label>数字人播报</label>
                                <label class="switch">
                                    <input type="checkbox" id="reminderVoice" checked>
                                    <span class="slider"></span>
                                </label>
                            </div>
                            <div class="config-actions-row">
                                <button class="test-reminder-btn" id="btnTestReminder">
                                    <i class="fas fa-play"></i> 测试提醒
                                </button>
                            </div>
                        </div>
                    </div>

                    <div class="panel-card">
                        <div class="panel-header">
                            <h3><i class="fas fa-history"></i> 提醒记录</h3>
                            <span class="alert-badge" id="reminderLogBadge">0</span>
                        </div>
                        <div class="reminder-log" id="reminderLog">
                            <div class="no-alerts">暂无提醒 ✅</div>
                        </div>
                    </div>
                </div>
            </div>
        </div>
    </section>

    <div class="modal-overlay" id="taskForm" style="display:none;">
        <div class="modal-content">
            <h3>新建任务</h3>
            <div class="form-group">
                <label>分配团队</label>
                <select id="taskTeam">
                    <option value="makeup">化妆组</option>
                    <option value="bridesmaid">伴郎伴娘</option>
                    <option value="car">车队</option>
                    <option value="reception">接待组</option>
                    <option value="mc">司仪组</option>
                    <option value="photo">摄影组</option>
                    <option value="etiquette">礼仪组</option>
                    <option value="manager">总管</option>
                </select>
            </div>
            <div class="form-group">
                <label>任务内容</label>
                <input type="text" id="taskName" placeholder="请输入任务内容">
            </div>
            <div class="form-group">
                <label>截止时间</label>
                <input type="time" id="taskDeadline">
            </div>
            <div class="form-group">
                <label>优先级</label>
                <select id="taskPriority">
                    <option value="high">高</option>
                    <option value="medium">中</option>
                    <option value="low">低</option>
                </select>
            </div>
            <div class="form-actions">
                <button id="btnCancelTask">取消</button>
                <button id="btnSubmitTask">提交</button>
            </div>
        </div>
    </div>

    <div class="modal-overlay" id="autoAssignForm" style="display:none;">
        <div class="modal-content">
            <h3><i class="fas fa-robot"></i> 智能任务分配</h3>
            <div class="form-group">
                <label>任务描述</label>
                <textarea id="autoTaskDesc" rows="3" placeholder="描述需要分配的任务内容，例如：准备接亲道具、检查音响设备等"></textarea>
            </div>
            <div class="form-group">
                <label>期望完成时间</label>
                <input type="time" id="autoTaskDeadline">
            </div>
            <div class="form-group">
                <label>优先级</label>
                <select id="autoTaskPriority">
                    <option value="high">高</option>
                    <option value="medium">中</option>
                    <option value="low">低</option>
                </select>
            </div>
            <div class="form-group">
                <label>可选团队（多选）</label>
                <div class="team-checkboxes">
                    <label><input type="checkbox" name="autoTeam" value="makeup"> 化妆组</label>
                    <label><input type="checkbox" name="autoTeam" value="bridesmaid"> 伴郎伴娘</label>
                    <label><input type="checkbox" name="autoTeam" value="car"> 车队</label>
                    <label><input type="checkbox" name="autoTeam" value="reception"> 接待组</label>
                    <label><input type="checkbox" name="autoTeam" value="mc"> 司仪组</label>
                    <label><input type="checkbox" name="autoTeam" value="photo"> 摄影组</label>
                    <label><input type="checkbox" name="autoTeam" value="etiquette"> 礼仪组</label>
                    <label><input type="checkbox" name="autoTeam" value="manager"> 总管</label>
                </div>
            </div>
            <div class="form-actions">
                <button id="btnCancelAuto">取消</button>
                <button id="btnSubmitAuto">智能分配</button>
            </div>
        </div>
    </div>
</main>

<style>
.dh-banner { background: linear-gradient(135deg, #1a1a2e 0%, #16213e 50%, #0f3460 100%); color: #fff; }
.dh-section { padding: 24px 0 60px; }

.video-center-stage { margin-bottom: 24px; }
.main-video-wrapper {
    position: relative;
    width: 100%;
    aspect-ratio: 16 / 9;
    background: linear-gradient(180deg, #2a0a0a 0%, #1a0505 50%, #0f0202 100%);
    border-radius: 16px;
    overflow: hidden;
    box-shadow: 0 8px 32px rgba(0,0,0,0.3);
}
.main-video-wrapper video {
    width: 100%;
    height: 100%;
    object-fit: contain;
    display: block;
}

.video-overlay {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    display: flex;
    flex-direction: column;
    justify-content: space-between;
    pointer-events: none;
    z-index: 2;
}
.overlay-bg {
    position: absolute;
    inset: 0;
    background: 
        radial-gradient(ellipse at 50% 25%, rgba(255,220,120,0.5) 0%, rgba(255,180,80,0.3) 20%, transparent 45%),
        radial-gradient(ellipse at 50% 60%, rgba(200,30,30,0.3) 0%, rgba(150,15,15,0.5) 50%, rgba(100,10,10,0.8) 80%),
        linear-gradient(180deg, #3a0505 0%, #5a0a0a 30%, #7a1010 50%, #5a0a0a 70%, #2a0202 100%);
    pointer-events: none;
}
.overlay-bg::before {
    content: '';
    position: absolute;
    inset: 0;
    background:
        radial-gradient(circle at 20% 20%, rgba(255,200,100,0.25) 0%, transparent 15%),
        radial-gradient(circle at 80% 25%, rgba(255,200,100,0.2) 0%, transparent 12%),
        radial-gradient(circle at 30% 50%, rgba(255,180,80,0.15) 0%, transparent 10%),
        radial-gradient(circle at 70% 45%, rgba(255,200,100,0.18) 0%, transparent 12%),
        radial-gradient(circle at 50% 70%, rgba(255,160,60,0.12) 0%, transparent 15%),
        radial-gradient(circle at 15% 65%, rgba(255,180,80,0.1) 0%, transparent 10%),
        radial-gradient(circle at 85% 60%, rgba(255,200,100,0.15) 0%, transparent 10%),
        radial-gradient(circle at 40% 30%, rgba(255,220,120,0.08) 0%, transparent 8%),
        radial-gradient(circle at 60% 35%, rgba(255,200,100,0.1) 0%, transparent 8%);
    pointer-events: none;
}
.overlay-curtain-left, .overlay-curtain-right {
    position: absolute;
    top: 0;
    width: 18%;
    height: 100%;
    pointer-events: none;
    z-index: 3;
}
.overlay-curtain-left {
    left: 0;
    background: 
        linear-gradient(90deg, rgba(120,5,5,0.95) 0%, rgba(150,15,15,0.9) 40%, rgba(180,20,20,0.7) 70%, transparent 100%),
        repeating-linear-gradient(90deg, 
            transparent 0px, 
            rgba(0,0,0,0.15) 20px, 
            transparent 40px);
    border-right: 3px solid rgba(212,168,83,0.6);
    box-shadow: 8px 0 30px rgba(0,0,0,0.4);
}
.overlay-curtain-right {
    right: 0;
    background: 
        linear-gradient(-90deg, rgba(120,5,5,0.95) 0%, rgba(150,15,15,0.9) 40%, rgba(180,20,20,0.7) 70%, transparent 100%),
        repeating-linear-gradient(-90deg, 
            transparent 0px, 
            rgba(0,0,0,0.15) 20px, 
            transparent 40px);
    border-left: 3px solid rgba(212,168,83,0.6);
    box-shadow: -8px 0 30px rgba(0,0,0,0.4);
}
.overlay-xi-center {
    position: absolute;
    top: 50%;
    left: 50%;
    transform: translate(-50%, -55%);
    z-index: 4;
    pointer-events: none;
    text-align: center;
}
.overlay-xi-main {
    font-size: 180px;
    font-weight: 900;
    color: rgba(255,200,80,0.85);
    font-family: 'SimSun', 'STSong', serif;
    line-height: 1;
    text-shadow: 
        0 0 40px rgba(255,180,60,0.6),
        0 0 80px rgba(255,150,40,0.4),
        0 0 120px rgba(255,120,20,0.3),
        2px 2px 0 rgba(180,30,30,0.8);
    letter-spacing: 0;
    animation: xiGlow 3s ease-in-out infinite alternate;
}
@keyframes xiGlow {
    0% { 
        text-shadow: 
            0 0 40px rgba(255,180,60,0.6),
            0 0 80px rgba(255,150,40,0.4),
            0 0 120px rgba(255,120,20,0.3),
            2px 2px 0 rgba(180,30,30,0.8);
    }
    100% { 
        text-shadow: 
            0 0 60px rgba(255,200,80,0.8),
            0 0 100px rgba(255,180,60,0.6),
            0 0 150px rgba(255,150,40,0.4),
            2px 2px 0 rgba(180,30,30,0.8);
    }
}
.overlay-xi-dragon {
    position: absolute;
    top: -30px;
    left: 50%;
    transform: translateX(-50%);
    width: 280px;
    height: 60px;
    display: flex;
    justify-content: center;
    align-items: center;
    font-size: 40px;
    opacity: 0.8;
}
.overlay-lantern-left, .overlay-lantern-right {
    position: absolute;
    top: 10px;
    width: 70px;
    z-index: 5;
    pointer-events: none;
    display: flex;
    flex-direction: column;
    align-items: center;
}
.overlay-lantern-left { left: 25px; }
.overlay-lantern-right { right: 25px; }
.overlay-lantern {
    width: 70px;
    height: 80px;
    position: relative;
    animation: lanternSway 4s ease-in-out infinite;
}
.overlay-lantern-right .overlay-lantern { animation-delay: -2s; }
.overlay-lantern-top {
    width: 22px;
    height: 8px;
    background: linear-gradient(180deg, #b8860b 0%, #8b6914 100%);
    margin: 0 auto;
    border-radius: 3px 3px 0 0;
}
.overlay-lantern-body {
    width: 70px;
    height: 55px;
    background: radial-gradient(ellipse at 30% 30%, #ff4444 0%, #e62020 35%, #b80000 70%, #8b0000 100%);
    border-radius: 50%;
    position: relative;
    display: flex;
    align-items: center;
    justify-content: center;
    box-shadow: 
        0 0 25px rgba(255,80,80,0.6),
        inset 0 -10px 20px rgba(0,0,0,0.3);
}
.overlay-lantern-body::before {
    content: '囍';
    font-size: 28px;
    color: #ffd700;
    font-family: 'SimSun', serif;
    font-weight: bold;
    text-shadow: 0 0 8px rgba(255,215,0,0.8);
}
.overlay-lantern-bottom {
    width: 14px;
    height: 30px;
    background: linear-gradient(180deg, #d4a853 0%, #b8860b 50%, #8b6914 100%);
    margin: 0 auto;
    border-radius: 0 0 4px 4px;
    position: relative;
}
.overlay-lantern-bottom::after {
    content: '';
    position: absolute;
    bottom: -18px;
    left: 50%;
    transform: translateX(-50%);
    width: 3px;
    height: 22px;
    background: linear-gradient(180deg, #ffd700 0%, #d4a853 100%);
    border-radius: 2px;
    box-shadow: 0 0 6px rgba(255,215,0,0.6);
}
@keyframes lanternSway {
    0%, 100% { transform: rotate(-4deg); }
    50% { transform: rotate(4deg); }
}
.overlay-bottom-banner {
    position: absolute;
    bottom: 0;
    left: 50%;
    transform: translateX(-50%);
    z-index: 6;
    pointer-events: none;
    display: flex;
    gap: 8px;
    padding-bottom: 8px;
}
.overlay-banner-item {
    width: 50px;
    height: 60px;
    background: radial-gradient(ellipse at 50% 40%, #ffd700 0%, #d4a853 40%, #b8860b 70%, #8b6914 100%);
    border-radius: 50% 50% 45% 45%;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 22px;
    color: #8b0000;
    font-family: 'SimSun', serif;
    font-weight: bold;
    box-shadow: 
        0 0 15px rgba(255,215,0,0.5),
        inset 0 -8px 15px rgba(0,0,0,0.2);
}
.overlay-light-rays {
    position: absolute;
    top: 0;
    left: 50%;
    transform: translateX(-50%);
    width: 120%;
    height: 75%;
    pointer-events: none;
    z-index: 2;
    opacity: 0.5;
    background: 
        repeating-conic-gradient(from 180deg at 50% 0%, 
            transparent 0deg, 
            rgba(255,220,120,0.18) 1.5deg, 
            transparent 3deg, 
            transparent 15deg);
    animation: rayRotate 80s linear infinite;
}
@keyframes rayRotate {
    0% { transform: translateX(-50%) rotate(0deg); }
    100% { transform: translateX(-50%) rotate(360deg); }
}
.overlay-top {
    display: flex;
    justify-content: space-between;
    align-items: flex-start;
    padding: 16px 20px;
}
.current-phase-badge {
    display: inline-flex;
    align-items: center;
    gap: 6px;
    padding: 6px 16px;
    background: rgba(212,168,83,0.9);
    color: #fff;
    border-radius: 20px;
    font-size: 14px;
    font-weight: 500;
    backdrop-filter: blur(4px);
}
.emotion-indicator-mini {
    display: inline-flex;
    align-items: center;
    gap: 5px;
    padding: 4px 12px;
    background: rgba(0,0,0,0.5);
    border-radius: 20px;
    font-size: 12px;
    color: #fff;
    backdrop-filter: blur(4px);
}
.emotion-indicator-mini .emotion-dot {
    width: 7px; height: 7px;
    border-radius: 50%;
    background: #27ae60;
}

.overlay-center {
    display: flex;
    align-items: center;
    justify-content: center;
    flex: 1;
    transition: opacity 0.3s;
}
.welcome-state {
    text-align: center;
    color: #fff;
}
.overlay-info-panel {
    position: absolute;
    bottom: 80px;
    left: 30px;
    right: 30px;
    background: rgba(100, 20, 20, 0.9);
    border: 1px solid rgba(212, 168, 83, 0.5);
    border-radius: 12px;
    padding: 12px 18px;
    backdrop-filter: blur(10px);
    pointer-events: none;
    max-height: 45%;
    overflow-y: auto;
    box-shadow: 0 -5px 30px rgba(180, 30, 30, 0.3);
    z-index: 10;
}
.overlay-info-panel::-webkit-scrollbar {
    width: 4px;
}
.overlay-info-panel::-webkit-scrollbar-track {
    background: transparent;
}
.overlay-info-panel::-webkit-scrollbar-thumb {
    background: rgba(212, 168, 83, 0.5);
    border-radius: 2px;
}

.video-loading-overlay {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    display: flex;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    background: rgba(0, 0, 0, 0.7);
    z-index: 30;
    pointer-events: none;
}
.video-loading-spinner {
    width: 60px;
    height: 60px;
    border: 4px solid rgba(212, 168, 83, 0.2);
    border-top-color: #d4a853;
    border-radius: 50%;
    animation: spinFade 0.8s linear infinite;
}
@keyframes spinFade {
    0% { transform: rotate(0deg); }
    100% { transform: rotate(360deg); }
}
.video-loading-text {
    color: #d4a853;
    font-size: 14px;
    margin-top: 16px;
    text-shadow: 0 0 10px rgba(212, 168, 83, 0.5);
    letter-spacing: 2px;
}

.video-overlay.mode-library .overlay-bg,
.video-overlay.mode-library .overlay-curtain-left,
.video-overlay.mode-library .overlay-curtain-right,
.video-overlay.mode-library .overlay-light-rays,
.video-overlay.mode-library .overlay-lantern-left,
.video-overlay.mode-library .overlay-lantern-right,
.video-overlay.mode-library .overlay-xi-center,
.video-overlay.mode-library .overlay-bottom-banner,
.video-overlay.mode-library .overlay-top,
.video-overlay.mode-library .overlay-info-panel {
    display: none !important;
}
.info-panel-header {
    text-align: center;
    margin-bottom: 12px;
    padding-bottom: 10px;
    border-bottom: 1px solid rgba(212, 168, 83, 0.2);
}
.info-phase-time {
    font-size: 12px;
    color: #f0d68a;
    letter-spacing: 4px;
    margin-bottom: 4px;
}
.info-phase-name {
    font-size: 20px;
    color: #d4a853;
    font-weight: 700;
    letter-spacing: 6px;
    text-shadow: 0 0 20px rgba(212, 168, 83, 0.5);
}
.info-panel-body {
    display: grid;
    grid-template-columns: 1fr 1fr;
    gap: 10px;
}
.info-row {
    background: rgba(0, 0, 0, 0.2);
    border-radius: 8px;
    padding: 8px 12px;
}
.info-label {
    font-size: 11px;
    color: #d4a853;
    font-weight: 500;
    margin-bottom: 4px;
    letter-spacing: 2px;
}
.info-content {
    font-size: 11px;
    color: #f0e6d3;
    line-height: 1.6;
    white-space: pre-wrap;
    word-break: break-word;
}
.avatar-mini {
    width: 80px; height: 100px;
    margin: 0 auto 16px;
    position: relative;
}
.mini-face {
    width: 50px; height: 50px;
    background: #ffdbac;
    border-radius: 50%;
    margin: 0 auto;
    position: relative;
}
.mini-eyes {
    display: flex;
    justify-content: center;
    gap: 12px;
    padding-top: 18px;
}
.mini-eye {
    width: 5px; height: 5px;
    background: #333;
    border-radius: 50%;
    display: block;
}
.mini-mouth {
    width: 14px; height: 7px;
    border-bottom: 2px solid #c0392b;
    border-radius: 0 0 50% 50%;
    margin: 8px auto 0;
}
.avatar-mini.speaking .mini-mouth {
    animation: miniSpeak 0.3s infinite alternate;
}
@keyframes miniSpeak {
    0% { height: 4px; }
    100% { height: 10px; }
}
.welcome-text { font-size: 18px; font-weight: 500; margin-bottom: 6px; opacity: 0.9; }
.welcome-sub { font-size: 13px; opacity: 0.6; }

.video-controls-bar {
    position: absolute;
    bottom: 0; left: 0; right: 0;
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 16px;
    background: linear-gradient(transparent, rgba(0,0,0,0.85));
    z-index: 3;
    pointer-events: auto;
}
.ctrl-btn {
    width: 36px; height: 36px;
    border: none;
    background: rgba(255,255,255,0.15);
    color: #fff;
    border-radius: 50%;
    cursor: pointer;
    transition: all 0.2s;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 13px;
}
.ctrl-btn:hover { background: rgba(212,168,83,0.8); transform: scale(1.1); }
.ctrl-btn .pulsing {
    animation: musicPulse 1.2s ease-in-out infinite;
}
@keyframes musicPulse {
    0%, 100% { transform: scale(1); opacity: 1; }
    50% { transform: scale(1.3); opacity: 0.7; }
}
.ctrl-btn-pause {
    background: rgba(52,152,219,0.25);
    border: 1px solid rgba(52,152,219,0.4);
}
.ctrl-btn-pause:hover {
    background: rgba(52,152,219,0.8) !important;
    border-color: rgba(52,152,219,0.9);
}
.ctrl-btn-pause.is-resume {
    background: rgba(39,174,96,0.25);
    border: 1px solid rgba(39,174,96,0.4);
}
.ctrl-btn-pause.is-resume:hover {
    background: rgba(39,174,96,0.8) !important;
    border-color: rgba(39,174,96,0.9);
}
.ctrl-btn-stop {
    background: rgba(231,76,60,0.25);
    border: 1px solid rgba(231,76,60,0.4);
}
.ctrl-btn-stop:hover {
    background: rgba(231,76,60,0.8) !important;
    border-color: rgba(231,76,60,0.9);
}
.ctrl-btn-prev, .ctrl-btn-next {
    background: rgba(155,89,182,0.25);
    border: 1px solid rgba(155,89,182,0.4);
}
.ctrl-btn-prev:hover, .ctrl-btn-next:hover {
    background: rgba(155,89,182,0.8) !important;
    border-color: rgba(155,89,182,0.9);
}
.ctrl-btn:disabled {
    opacity: 0.3;
    cursor: not-allowed;
    transform: none !important;
}
.ctrl-btn-rewind, .ctrl-btn-forward {
    background: rgba(52,152,219,0.25);
    border: 1px solid rgba(52,152,219,0.4);
}
.ctrl-btn-rewind:hover, .ctrl-btn-forward:hover {
    background: rgba(52,152,219,0.8) !important;
    border-color: rgba(52,152,219,0.9);
}
.ctrl-btn-loop {
    background: rgba(243,156,18,0.25);
    border: 1px solid rgba(243,156,18,0.4);
}
.ctrl-btn-loop:hover {
    background: rgba(243,156,18,0.8) !important;
    border-color: rgba(243,156,18,0.9);
}
.ctrl-btn-loop.active {
    background: rgba(243,156,18,0.6);
    border-color: rgba(243,156,18,0.8);
    box-shadow: 0 0 8px rgba(243,156,18,0.4);
}
.ctrl-btn-speed {
    background: rgba(46,204,113,0.25);
    border: 1px solid rgba(46,204,113,0.4);
    width: 44px;
    font-size: 12px;
    font-weight: 500;
}
.ctrl-btn-speed:hover {
    background: rgba(46,204,113,0.8) !important;
    border-color: rgba(46,204,113,0.9);
}
.ctrl-btn-settings {
    background: rgba(149,165,166,0.25);
    border: 1px solid rgba(149,165,166,0.4);
}
.ctrl-btn-settings:hover {
    background: rgba(149,165,166,0.8) !important;
    border-color: rgba(149,165,166,0.9);
}
.speed-control, .settings-control {
    position: relative;
}
.speed-menu, .settings-menu {
    position: absolute;
    bottom: 100%;
    right: 0;
    margin-bottom: 8px;
    background: rgba(0,0,0,0.9);
    border-radius: 8px;
    padding: 4px;
    display: none;
    z-index: 100;
    min-width: 80px;
    border: 1px solid rgba(255,255,255,0.1);
}
.speed-control:hover .speed-menu, .settings-control:hover .settings-menu {
    display: block;
}
.speed-option {
    padding: 6px 12px;
    color: #fff;
    font-size: 12px;
    cursor: pointer;
    border-radius: 4px;
    text-align: center;
}
.speed-option:hover {
    background: rgba(46,204,113,0.3);
}
.speed-option.active {
    background: rgba(46,204,113,0.5);
}
.settings-item {
    padding: 8px 12px;
    color: #fff;
    font-size: 12px;
    cursor: pointer;
    border-radius: 4px;
    display: flex;
    align-items: center;
    gap: 8px;
}
.settings-item:hover {
    background: rgba(255,255,255,0.1);
}
.progress-track {
    flex: 1;
    position: relative;
    height: 6px;
    background: rgba(255,255,255,0.2);
    border-radius: 3px;
    cursor: pointer;
}
.phase-markers {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    pointer-events: none;
}
.phase-marker {
    position: absolute;
    top: -4px;
    width: 3px;
    height: 14px;
    background: #d4a853;
    border-radius: 2px;
    transform: translateX(-50%);
}
.phase-marker::after {
    content: attr(data-name);
    position: absolute;
    bottom: 18px;
    left: 50%;
    transform: translateX(-50%);
    font-size: 10px;
    color: #d4a853;
    white-space: nowrap;
    background: rgba(0,0,0,0.6);
    padding: 2px 6px;
    border-radius: 4px;
    opacity: 0;
    transition: opacity 0.2s;
}
.progress-track:hover .phase-marker::after { opacity: 1; }
.progress-filled {
    position: absolute;
    top: 0; left: 0;
    height: 100%;
    background: #d4a853;
    border-radius: 3px;
    transition: width 0.1s;
}
.progress-handle {
    position: absolute;
    top: 50%;
    width: 14px; height: 14px;
    background: #d4a853;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    opacity: 0;
    transition: opacity 0.2s;
}
.progress-track:hover .progress-handle { opacity: 1; }
.time-display {
    color: #fff;
    font-size: 12px;
    white-space: nowrap;
    font-variant-numeric: tabular-nums;
    min-width: 90px;
    text-align: center;
}

.volume-control {
    display: flex;
    align-items: center;
    gap: 6px;
    position: relative;
}
.ctrl-btn-volume {
    background: rgba(255,255,255,0.15) !important;
    border: 1px solid rgba(255,255,255,0.2) !important;
}
.ctrl-btn-volume:hover {
    background: rgba(212,168,83,0.8) !important;
}
.ctrl-btn-volume.is-muted {
    background: rgba(231,76,60,0.25) !important;
    border: 1px solid rgba(231,76,60,0.4) !important;
}
.ctrl-btn-volume.is-muted:hover {
    background: rgba(231,76,60,0.8) !important;
}
.volume-slider-wrapper {
    width: 80px;
    height: 24px;
    display: flex;
    align-items: center;
    cursor: pointer;
    position: relative;
}
.volume-slider-track {
    width: 100%;
    height: 4px;
    background: rgba(255,255,255,0.2);
    border-radius: 2px;
    position: relative;
}
.volume-slider-filled {
    position: absolute;
    top: 0;
    left: 0;
    height: 100%;
    background: #d4a853;
    border-radius: 2px;
    transition: width 0.05s;
}
.volume-slider-handle {
    position: absolute;
    top: 50%;
    width: 12px;
    height: 12px;
    background: #d4a853;
    border-radius: 50%;
    transform: translate(-50%, -50%);
    opacity: 0;
    transition: opacity 0.2s;
    box-shadow: 0 0 4px rgba(0,0,0,0.3);
}
.volume-slider-wrapper:hover .volume-slider-handle { opacity: 1; }
.volume-indicator {
    display: flex;
    align-items: flex-end;
    gap: 2px;
    height: 16px;
}
.vol-bar {
    width: 3px;
    background: rgba(255,255,255,0.2);
    border-radius: 1px;
    transition: all 0.15s;
}
.vol-bar-1 { height: 4px; }
.vol-bar-2 { height: 7px; }
.vol-bar-3 { height: 10px; }
.vol-bar-4 { height: 13px; }
.vol-bar-5 { height: 16px; }
.vol-bar.active { background: #d4a853; }
.vol-bar.muted { background: rgba(231,76,60,0.5); }
.volume-percent {
    color: rgba(255,255,255,0.7);
    font-size: 11px;
    min-width: 32px;
    text-align: center;
    font-variant-numeric: tabular-nums;
}

.control-dashboard {
    display: grid;
    grid-template-columns: 1fr 320px;
    gap: 20px;
    max-height: calc(100vh - 420px);
    overflow-y: auto;
}
.dashboard-left {
    overflow-y: auto;
}
.dashboard-left::-webkit-scrollbar {
    width: 6px;
}
.dashboard-left::-webkit-scrollbar-track {
    background: #f5f5f5;
    border-radius: 3px;
}
.dashboard-left::-webkit-scrollbar-thumb {
    background: #ddd;
    border-radius: 3px;
}
.dashboard-left::-webkit-scrollbar-thumb:hover {
    background: #ccc;
}

.panel-card {
    background: #fff;
    border-radius: 16px;
    box-shadow: 0 2px 12px rgba(0,0,0,0.06);
    overflow: hidden;
    margin-bottom: 20px;
}
.panel-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    padding: 14px 18px;
    border-bottom: 1px solid #f0f0f0;
}
.panel-header h3 {
    font-size: 14px;
    color: #333;
    margin: 0;
    font-weight: 600;
}
.panel-badge {
    font-size: 11px;
    padding: 2px 8px;
    background: #f0f0f0;
    border-radius: 10px;
    color: #888;
}

.timeline-panel { margin-bottom: 20px; }
.timeline-track {
    position: relative;
    padding: 20px 18px;
}
.timeline-progress {
    position: absolute;
    top: 32px;
    left: 18px; right: 18px;
    height: 4px;
    background: #eee;
    border-radius: 2px;
}
.timeline-progress::after {
    content: '';
    position: absolute;
    top: 0; left: 0;
    height: 100%;
    width: var(--progress, 0%);
    background: #b64a2a;
    border-radius: 2px;
    transition: width 0.3s;
}
.timeline-phases {
    display: flex;
    justify-content: space-between;
    position: relative;
    z-index: 1;
}
.timeline-phase {
    display: flex;
    flex-direction: column;
    align-items: center;
    gap: 8px;
    cursor: pointer;
    transition: all 0.2s;
}
.timeline-phase-dot {
    width: 32px; height: 32px;
    border-radius: 50%;
    background: #fff;
    border: 2px solid #ddd;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 14px;
    transition: all 0.3s;
    position: relative;
}
.timeline-phase-dot .dot-icon {
    position: relative;
    z-index: 2;
}
.timeline-phase-dot .dot-progress-ring {
    position: absolute;
    top: -4px; left: -4px;
    width: calc(100% + 8px);
    height: calc(100% + 8px);
    border-radius: 50%;
    background: conic-gradient(#3498db var(--progress, 0%), transparent var(--progress, 0%));
    opacity: 0;
    transition: all 0.3s;
    z-index: 1;
}
.timeline-phase.active .timeline-phase-dot .dot-progress-ring {
    opacity: 1;
    box-shadow: 0 0 8px rgba(52, 152, 219, 0.5);
}
.timeline-phase.completed .timeline-phase-dot .dot-progress-ring {
    background: conic-gradient(#27ae60 100%, transparent 100%);
    opacity: 1;
    box-shadow: 0 0 8px rgba(39, 174, 96, 0.5);
}
.timeline-phase:hover .timeline-phase-dot { transform: scale(1.15); border-color: #b64a2a; }
.timeline-phase.active .timeline-phase-dot {
    background: #b64a2a;
    border-color: #b64a2a;
    color: #fff;
    box-shadow: 0 0 0 4px rgba(182,74,42,0.15);
}
.timeline-phase.completed .timeline-phase-dot {
    background: #27ae60;
    border-color: #27ae60;
    color: #fff;
}
.timeline-phase-name {
    font-size: 11px;
    color: #666;
    text-align: center;
    max-width: 60px;
    line-height: 1.3;
}
.timeline-phase.active .timeline-phase-name { color: #b64a2a; font-weight: 500; }
.timeline-phase.completed .timeline-phase-name { color: #27ae60; }
.timeline-phase .bind-indicator {
    width: 6px;
    height: 6px;
    border-radius: 50%;
    background: #ccc;
    margin-top: 2px;
}
.timeline-phase.has-video .bind-indicator { background: #3498db; }
.timeline-phase.active .bind-indicator { background: #fff; }

.phase-videos-panel { margin-bottom: 20px; }
.phase-videos-grid {
    display: grid;
    grid-template-columns: repeat(4, 1fr);
    gap: 10px;
    padding: 14px 18px;
}
.phase-video-window {
    position: relative;
    aspect-ratio: 16 / 9;
    background: #0a0a1a;
    border-radius: 8px;
    overflow: hidden;
    cursor: pointer;
    border: 2px solid transparent;
    transition: all 0.3s ease;
}
.phase-video-window:hover {
    border-color: rgba(212,168,83,0.5);
    transform: scale(1.02);
}
.phase-video-window.active {
    border-color: #d4a853;
    box-shadow: 0 0 12px rgba(212,168,83,0.4);
}
.phase-video-window.completed {
    border-color: #27ae60;
}
.phase-video-window video {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.phase-video-window .window-overlay {
    position: absolute;
    inset: 0;
    background: linear-gradient(transparent 40%, rgba(0,0,0,0.8));
    display: flex;
    flex-direction: column;
    justify-content: flex-end;
    padding: 6px 8px;
    transition: background 0.3s;
}
.phase-video-window.active .window-overlay {
    background: linear-gradient(transparent 30%, rgba(212,168,83,0.3));
}
.phase-video-window .window-label {
    display: flex;
    align-items: center;
    gap: 4px;
    font-size: 11px;
    color: #fff;
    font-weight: 500;
}
.phase-video-window .window-icon {
    font-size: 13px;
}
.phase-video-window .window-status {
    position: absolute;
    top: 4px;
    right: 6px;
    width: 8px;
    height: 8px;
    border-radius: 50%;
    background: rgba(255,255,255,0.3);
    transition: all 0.3s;
}
.phase-video-window.pending .window-status {
    background: rgba(255,255,255,0.3);
}
.phase-video-window.active .window-status {
    background: #d4a853;
    box-shadow: 0 0 6px rgba(212,168,83,0.6);
    animation: statusPulse 1.5s infinite;
}
.phase-video-window.completed .window-status {
    background: #27ae60;
    box-shadow: 0 0 6px rgba(39,174,96,0.6);
}
.phase-video-window .window-placeholder {
    position: absolute;
    inset: 0;
    display: flex;
    align-items: center;
    justify-content: center;
    color: rgba(255,255,255,0.3);
    font-size: 24px;
}
.phase-video-window .window-progress {
    position: absolute;
    bottom: 0;
    left: 0;
    right: 0;
    height: 3px;
    background: rgba(255,255,255,0.1);
}
.phase-video-window .window-progress-bar {
    height: 100%;
    background: #d4a853;
    transition: width 0.2s;
    width: 0%;
}
@keyframes statusPulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

.timeline-ctrl-panel { margin-bottom: 20px; }
.timeline-ctrl-body { padding: 14px 18px; }
.timeline-time-row {
    display: flex;
    align-items: center;
    gap: 12px;
    margin-bottom: 14px;
    flex-wrap: wrap;
}
.tl-label {
    font-size: 11px;
    color: #999;
}
.tl-value {
    font-size: 14px;
    font-weight: 600;
    color: #333;
    font-variant-numeric: tabular-nums;
    min-width: 60px;
}
.tl-value.drift-ok { color: #27ae60; }
.tl-value.drift-warn { color: #f39c12; }
.tl-value.drift-error { color: #e74c3c; }
.timeline-ctrl-btns {
    display: flex;
    gap: 8px;
}
.tl-ctrl-btn {
    padding: 8px 16px;
    border: 1px solid #eee;
    border-radius: 8px;
    background: #fff;
    cursor: pointer;
    font-size: 12px;
    color: #666;
    transition: all 0.2s;
    display: flex;
    align-items: center;
    gap: 5px;
}
.tl-ctrl-btn:disabled {
    opacity: 0.4;
    cursor: not-allowed;
}
.tl-ctrl-btn:not(:disabled):hover { background: #f5f5f5; }
.tl-start:not(:disabled) { background: #27ae60; color: #fff; border-color: #27ae60; }
.tl-start:not(:disabled):hover { background: #219a52; }
.tl-pause:not(:disabled) { background: #f39c12; color: #fff; border-color: #f39c12; }
.tl-pause:not(:disabled):hover { background: #d68910; }
.tl-stop:not(:disabled) { background: #e74c3c; color: #fff; border-color: #e74c3c; }
.tl-stop:not(:disabled):hover { background: #c0392b; }
.tl-calibrate:not(:disabled) { background: #3498db; color: #fff; border-color: #3498db; }
.tl-calibrate:not(:disabled):hover { background: #2980b9; }
.sync-status-dot {
    width: 8px; height: 8px;
    border-radius: 50%;
    background: #ccc;
    display: inline-block;
}
.sync-status-dot.synced { background: #27ae60; animation: syncPulse 2s infinite; }
.sync-status-dot.drifting { background: #f39c12; animation: syncPulse 0.8s infinite; }
.sync-status-dot.error { background: #e74c3c; animation: syncPulse 0.4s infinite; }
@keyframes syncPulse {
    0%, 100% { opacity: 1; }
    50% { opacity: 0.4; }
}

.video-library-panel { margin-bottom: 20px; }
.library-tabs {
    display: flex;
    gap: 4px;
}
.lib-tab {
    padding: 5px 10px;
    border: 1px solid #eee;
    border-radius: 6px;
    background: #fff;
    cursor: pointer;
    font-size: 12px;
    transition: all 0.2s;
}
.lib-tab:hover { border-color: #b64a2a; color: #b64a2a; }
.lib-tab.active { background: #b64a2a; color: #fff; border-color: #b64a2a; }

.library-content { padding: 14px 18px; }
.upload-row { margin-bottom: 12px; }
.upload-btn-small {
    padding: 8px 14px;
    border: 1px dashed #ccc;
    border-radius: 8px;
    background: #fafafa;
    cursor: pointer;
    font-size: 12px;
    color: #666;
    transition: all 0.2s;
    width: 100%;
}
.upload-btn-small:hover { border-color: #3498db; color: #3498db; background: #f0f8ff; }

.video-grid {
    display: flex;
    flex-direction: column;
    gap: 8px;
    max-height: 260px;
    overflow-y: auto;
}
.image-grid {
    display: grid;
    grid-template-columns: repeat(3, 1fr);
    gap: 8px;
    max-height: 260px;
    overflow-y: auto;
    padding: 4px;
}
.image-card {
    position: relative;
    aspect-ratio: 1 / 1;
    border-radius: 8px;
    overflow: hidden;
    cursor: pointer;
    background: #f0f0f0;
    border: 1px solid #eee;
    transition: all 0.2s;
}
.image-card:hover { border-color: #b64a2a; transform: scale(1.03); }
.image-card img {
    width: 100%;
    height: 100%;
    object-fit: cover;
    display: block;
}
.image-card .image-delete {
    position: absolute;
    top: 4px;
    right: 4px;
    width: 22px;
    height: 22px;
    border: none;
    border-radius: 50%;
    background: rgba(0,0,0,0.6);
    color: #fff;
    font-size: 11px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    opacity: 0;
    transition: opacity 0.2s;
}
.image-card:hover .image-delete { opacity: 1; }
.image-card .image-delete:hover { background: rgba(231,76,60,0.9); }
.image-lightbox {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0,0,0,0.85);
    z-index: 9999;
    display: flex;
    align-items: center;
    justify-content: center;
    cursor: zoom-out;
}
.image-lightbox img {
    max-width: 90%;
    max-height: 90%;
    border-radius: 8px;
    box-shadow: 0 8px 40px rgba(0,0,0,0.6);
}
.image-lightbox .lightbox-close {
    position: absolute;
    top: 16px;
    right: 24px;
    color: #fff;
    font-size: 36px;
    cursor: pointer;
    line-height: 1;
}
.image-lightbox .lightbox-close:hover { color: #d4a853; }
.video-card {
    display: flex;
    align-items: center;
    gap: 10px;
    padding: 10px 12px;
    background: #f9f9f9;
    border-radius: 10px;
    border: 1px solid transparent;
    cursor: pointer;
    transition: all 0.2s;
}
.video-card:hover { background: #f0f0f0; border-color: #ddd; }
.video-card.active { background: #fdf2f0; border-color: #b64a2a; }
.video-card .thumb {
    width: 48px; height: 36px;
    background: #ddd;
    border-radius: 6px;
    display: flex;
    align-items: center;
    justify-content: center;
    font-size: 18px;
    flex-shrink: 0;
}
.video-card .info { flex: 1; min-width: 0; }
.video-card .name {
    font-size: 13px;
    color: #333;
    white-space: nowrap;
    overflow: hidden;
    text-overflow: ellipsis;
}
.video-card .meta {
    font-size: 11px;
    color: #999;
    margin-top: 2px;
}
.video-card .actions {
    display: flex;
    gap: 6px;
    opacity: 0;
    transition: opacity 0.2s;
}
.video-card:hover .actions { opacity: 1; }
.video-card .actions button {
    width: 28px; height: 28px;
    border: none;
    background: #f0f0f0;
    border-radius: 6px;
    cursor: pointer;
    color: #666;
    font-size: 11px;
    transition: all 0.2s;
}
.video-card .actions .select-btn {
    background: rgba(52,152,219,0.1);
    color: #3498db;
    border: 1px solid rgba(52,152,219,0.3);
}
.video-card .actions .select-btn:hover {
    background: #3498db;
    color: #fff;
    border-color: #3498db;
}
.video-card .actions .delete-btn {
    background: rgba(231,76,60,0.1);
    color: #e74c3c;
    border: 1px solid rgba(231,76,60,0.3);
}
.video-card .actions .delete-btn:hover {
    background: #e74c3c;
    color: #fff;
    border-color: #e74c3c;
}

.info-panel { margin-bottom: 16px; }
.info-body {
    padding: 16px 18px;
    min-height: 120px;
}
.info-placeholder {
    text-align: center;
    color: #bbb;
    padding: 20px 0;
}
.info-placeholder i { font-size: 24px; margin-bottom: 8px; display: block; }
.info-placeholder p { margin: 0; font-size: 13px; }
.info-content { line-height: 1.6; }
.info-content .info-row {
    display: flex;
    justify-content: space-between;
    padding: 8px 0;
    border-bottom: 1px solid #f5f5f5;
    font-size: 13px;
}
.info-content .info-row:last-child { border-bottom: none; }
.info-content .info-label { color: #888; }
.info-content .info-value { color: #333; font-weight: 500; }

.ending-config-panel {
    margin-top: 16px;
    padding: 16px;
    background: rgba(0,0,0,0.1);
    border-radius: 8px;
    border: 1px solid rgba(212,168,83,0.2);
}
.ending-config-panel h4 {
    margin: 0 0 12px 0;
    font-size: 14px;
    color: #d4a853;
    display: flex;
    align-items: center;
    gap: 6px;
}
.config-row {
    display: flex;
    align-items: flex-start;
    gap: 10px;
    margin-bottom: 10px;
}
.config-row label {
    width: 70px;
    font-size: 12px;
    color: #999;
    flex-shrink: 0;
    padding-top: 4px;
}
.config-row input[type="text"],
.config-row input[type="number"],
.config-row input[type="date"],
.config-row select,
.config-row textarea {
    flex: 1;
    padding: 6px 8px;
    border: 1px solid rgba(255,255,255,0.1);
    border-radius: 4px;
    background: rgba(0,0,0,0.2);
    color: #fff;
    font-size: 12px;
    outline: none;
}
.config-row textarea {
    resize: vertical;
    min-height: 60px;
}
.config-row input:focus,
.config-row select:focus,
.config-row textarea:focus {
    border-color: #d4a853;
}
.toggle-switch {
    position: relative;
    display: inline-block;
    width: 40px;
    height: 22px;
}
.toggle-switch input {
    opacity: 0;
    width: 0;
    height: 0;
}
.toggle-slider {
    position: absolute;
    cursor: pointer;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background-color: #444;
    transition: 0.3s;
    border-radius: 22px;
}
.toggle-slider:before {
    position: absolute;
    content: "";
    height: 18px;
    width: 18px;
    left: 2px;
    bottom: 2px;
    background-color: #fff;
    transition: 0.3s;
    border-radius: 50%;
}
.toggle-switch input:checked + .toggle-slider {
    background-color: #d4a853;
}
.toggle-switch input:checked + .toggle-slider:before {
    transform: translateX(18px);
}
.config-actions {
    display: flex;
    gap: 8px;
    margin-top: 12px;
}
.save-btn, .preview-btn {
    flex: 1;
    padding: 8px 12px;
    border: none;
    border-radius: 4px;
    font-size: 12px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 4px;
    transition: all 0.2s;
}
.save-btn {
    background: #27ae60;
    color: #fff;
}
.save-btn:hover {
    background: #2ecc71;
}
.preview-btn {
    background: #3498db;
    color: #fff;
}
.preview-btn:hover {
    background: #2980b9;
}

.ending-overlay {
    position: absolute;
    top: 0;
    left: 0;
    right: 0;
    bottom: 0;
    background: rgba(0,0,0,0.85);
    display: none;
    flex-direction: column;
    align-items: center;
    justify-content: center;
    z-index: 20;
    opacity: 0;
    transition: opacity 1s ease;
}
.ending-overlay.show {
    display: flex;
    opacity: 1;
    pointer-events: auto;
}
.ending-content {
    text-align: center;
    max-width: 80%;
}
.ending-text {
    font-size: 32px;
    font-weight: 300;
    color: #fff;
    text-shadow: 0 2px 10px rgba(0,0,0,0.5);
    margin-bottom: 30px;
    line-height: 1.6;
}
.ending-text.fade-in {
    animation: endingFadeIn 2s ease-out forwards;
}
.ending-text.slide-in {
    animation: endingSlideIn 1.5s ease-out forwards;
}
.ending-text.scale-in {
    animation: endingScaleIn 1.5s ease-out forwards;
}
.ending-close-btn {
    position: absolute;
    top: 20px;
    right: 20px;
    width: 40px;
    height: 40px;
    background: rgba(255,255,255,0.1);
    border: 1px solid rgba(255,255,255,0.2);
    border-radius: 50%;
    color: rgba(255,255,255,0.8);
    font-size: 18px;
    cursor: pointer;
    display: flex;
    align-items: center;
    justify-content: center;
    transition: all 0.3s;
    z-index: 30;
}
.ending-close-btn:hover {
    background: rgba(255,255,255,0.2);
    border-color: rgba(255,255,255,0.4);
    color: #fff;
}
@keyframes endingFadeIn {
    from { opacity: 0; }
    to { opacity: 1; }
}
@keyframes endingSlideIn {
    from { opacity: 0; transform: translateY(30px); }
    to { opacity: 1; transform: translateY(0); }
}
@keyframes endingScaleIn {
    from { opacity: 0; transform: scale(0.8); }
    to { opacity: 1; transform: scale(1); }
}

.tasks-list { padding: 14px 18px; }
.no-tasks {
    text-align: center;
    padding: 30px 0;
    color: #999;
    font-size: 13px;
}
.task-item {
    background: #f8f9fa;
    border-radius: 8px;
    padding: 12px;
    margin-bottom: 10px;
    border-left: 3px solid #ddd;
}
.task-item.high { border-left-color: #e74c3c; }
.task-item.medium { border-left-color: #f39c12; }
.task-item.low { border-left-color: #3498db; }
.task-item.completed { opacity: 0.6; }
.task-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 6px;
}
.task-name {
    font-size: 13px;
    font-weight: 600;
    color: #333;
}
.task-priority {
    font-size: 10px;
    padding: 2px 8px;
    border-radius: 4px;
    color: #fff;
}
.task-priority.high { background: #e74c3c; }
.task-priority.medium { background: #f39c12; }
.task-priority.low { background: #3498db; }
.task-meta {
    display: flex;
    justify-content: space-between;
    font-size: 11px;
    color: #999;
}
.task-team { display: flex; align-items: center; gap: 4px; }
.task-team::before { content: '👥'; }
.task-deadline { display: flex; align-items: center; gap: 4px; }
.task-deadline::before { content: '⏰'; }
.task-actions {
    display: flex;
    gap: 6px;
    margin-top: 8px;
}
.task-action-btn {
    padding: 4px 10px;
    border: none;
    border-radius: 4px;
    font-size: 10px;
    cursor: pointer;
    transition: all 0.2s;
}
.task-action-btn.complete { background: #27ae60; color: #fff; }
.task-action-btn.complete:hover { background: #2ecc71; }
.task-action-btn.delay { background: #f39c12; color: #fff; }
.task-action-btn.delay:hover { background: #f1c40f; }
.task-action-btn.delete { background: #e74c3c; color: #fff; }
.task-action-btn.delete:hover { background: #ec7063; }

.alerts-list { padding: 14px 18px; }
.no-alerts {
    text-align: center;
    padding: 20px 0;
    color: #27ae60;
    font-size: 13px;
}
.alert-item {
    background: #fff5f5;
    border-radius: 8px;
    padding: 10px;
    margin-bottom: 8px;
    border-left: 3px solid #e74c3c;
}
.alert-item.warning {
    background: #fffbf0;
    border-left-color: #f39c12;
}
.alert-item.info {
    background: #f0f8ff;
    border-left-color: #3498db;
}
.alert-item.success {
    background: #f0fff4;
    border-left-color: #27ae60;
}
.alert-header {
    display: flex;
    justify-content: space-between;
    align-items: center;
    margin-bottom: 4px;
}
.alert-title {
    font-size: 12px;
    font-weight: 600;
    color: #333;
}
.alert-time {
    font-size: 10px;
    color: #999;
}
.alert-desc {
    font-size: 11px;
    color: #666;
    line-height: 1.4;
}

.quick-actions-panel { margin-bottom: 20px; }
.actions-body { padding: 14px 18px; display: flex; flex-direction: column; gap: 10px; }
.action-btn {
    padding: 10px 14px;
    border: 1px solid #eee;
    border-radius: 10px;
    background: #fff;
    cursor: pointer;
    font-size: 13px;
    color: #666;
    transition: all 0.2s;
    display: flex;
    align-items: center;
    justify-content: center;
    gap: 6px;
}
.action-btn:hover { background: #f5f5f5; }
.action-btn.primary {
    background: #b64a2a;
    color: #fff;
    border-color: #b64a2a;
}
.action-btn.primary:hover { background: #a04020; }

.modal-overlay {
    position: fixed;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0,0,0,0.6);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 1000;
}
.modal-content {
    background: #fff;
    border-radius: 16px;
    padding: 24px;
    width: 400px;
    max-width: 90%;
}
.modal-content h3 {
    margin: 0 0 20px;
    font-size: 18px;
    color: #333;
}
.form-group { margin-bottom: 16px; }
.form-group label {
    display: block;
    font-size: 13px;
    color: #666;
    margin-bottom: 6px;
    font-weight: 500;
}
.form-group input, .form-group select, .form-group textarea {
    width: 100%;
    padding: 10px;
    border: 1px solid #ddd;
    border-radius: 8px;
    font-size: 14px;
    box-sizing: border-box;
}
.form-group textarea { resize: vertical; }
.team-checkboxes {
    display: grid;
    grid-template-columns: repeat(2, 1fr);
    gap: 8px;
}
.team-checkboxes label {
    font-size: 12px;
    display: flex;
    align-items: center;
    gap: 6px;
    cursor: pointer;
}
.form-actions {
    display: flex;
    justify-content: flex-end;
    gap: 10px;
    margin-top: 24px;
}
.form-actions button {
    padding: 10px 20px;
    border: none;
    border-radius: 8px;
    font-size: 13px;
    font-weight: 500;
    cursor: pointer;
    transition: all 0.2s;
}
.form-actions button:first-child {
    background: #f0f0f0;
    color: #666;
}
.form-actions button:first-child:hover { background: #e0e0e0; }
.form-actions button:last-child {
    background: #d4a853;
    color: #fff;
}
.form-actions button:last-child:hover { background: #e6b800; }

.alert-badge {
    padding: 2px 8px;
    background: #e74c3c;
    color: #fff;
    border-radius: 10px;
    font-size: 11px;
    font-weight: 600;
}

.pause-overlay {
    position: absolute;
    top: 0; left: 0; right: 0; bottom: 0;
    background: rgba(0,0,0,0.6);
    display: flex;
    align-items: center;
    justify-content: center;
    z-index: 10;
    pointer-events: none;
}
.pause-content {
    text-align: center;
    animation: fadeInScale 0.3s ease-out;
}
.pause-icon {
    font-size: 48px;
    margin-bottom: 16px;
    animation: pulse 1.5s infinite;
}
.pause-text {
    font-size: 28px;
    font-weight: 600;
    color: #d4a853;
    text-shadow: 0 2px 4px rgba(0,0,0,0.5);
    margin-bottom: 8px;
}
.pause-hint {
    font-size: 14px;
    color: rgba(255,255,255,0.7);
}
@keyframes fadeInScale {
    from { opacity: 0; transform: scale(0.9); }
    to { opacity: 1; transform: scale(1); }
}
@keyframes pulse {
    0%, 100% { opacity: 1; transform: scale(1); }
    50% { opacity: 0.7; transform: scale(1.1); }
}

.btn-add, .btn-auto {
    padding: 6px 12px;
    border: none;
    border-radius: 6px;
    font-size: 11px;
    cursor: pointer;
    transition: all 0.2s;
    display: flex;
    align-items: center;
    gap: 4px;
}
.btn-add {
    background: #3498db;
    color: #fff;
}
.btn-add:hover { background: #2980b9; }
.btn-auto {
    background: #9b59b6;
    color: #fff;
    margin-left: 6px;
}
.btn-auto:hover { background: #8e44ad; }

@media (max-width: 1024px) {
    .control-dashboard { grid-template-columns: 1fr; }
    .dashboard-right { display: grid; grid-template-columns: 1fr 1fr; gap: 16px; }
    .phase-videos-grid { grid-template-columns: repeat(4, 1fr); }
}
@media (max-width: 768px) {
    .main-video-wrapper { border-radius: 12px; }
    .dashboard-right { grid-template-columns: 1fr; }
    .timeline-phases { gap: 8px; flex-wrap: wrap; justify-content: center; }
    .overlay-top { padding: 10px 12px; }
    .phase-videos-grid { grid-template-columns: repeat(2, 1fr); }
    .volume-slider-wrapper { width: 60px; }
    .volume-indicator { display: none; }
    .volume-percent { display: none; }
    .timeline-time-row { flex-wrap: wrap; }
    .timeline-ctrl-btns { flex-wrap: wrap; }
}
@media (max-width: 480px) {
    .video-controls-bar { gap: 6px; padding: 8px 10px; }
    .time-display { font-size: 11px; min-width: 70px; }
    .ctrl-btn { width: 32px; height: 32px; font-size: 12px; }
    .phase-videos-grid { grid-template-columns: repeat(2, 1fr); gap: 6px; }
    .volume-slider-wrapper { width: 50px; }
}

/* 过渡环节样式 */
.timeline-phase.transition-phase { position: relative; }
.timeline-phase.transition-phase .timeline-phase-dot {
    width: 24px; height: 24px;
    border-color: #9b59b6;
    background: linear-gradient(135deg, #9b59b6 0%, #8e44ad 100%);
    animation: transitionGlow 2s infinite;
}
.timeline-phase.transition-phase:hover .timeline-phase-dot { transform: scale(1.2); border-color: #9b59b6; }
.timeline-phase.transition-phase.active .timeline-phase-dot {
    background: #9b59b6; border-color: #9b59b6;
    box-shadow: 0 0 0 4px rgba(155,89,182,0.2);
}
.timeline-phase.transition-phase .timeline-phase-name { color: #9b59b6; font-size: 10px; }
.timeline-phase.transition-phase.active .timeline-phase-name { color: #9b59b6; }
.timeline-phase.transition-phase.completed .timeline-phase-name { color: #9b59b6; }
.timeline-phase.transition-phase.completed .timeline-phase-dot { background: #9b59b6; border-color: #9b59b6; }
.timeline-phase.transition-phase.active .timeline-phase-dot .dot-progress-ring {
    background: conic-gradient(#9b59b6 var(--progress, 0%), transparent var(--progress, 0%));
}
.timeline-phase.transition-phase.completed .timeline-phase-dot .dot-progress-ring {
    background: conic-gradient(#9b59b6 100%, transparent 100%);
}
@keyframes transitionGlow {
    0%, 100% { box-shadow: 0 0 6px rgba(155,89,182,0.4); }
    50% { box-shadow: 0 0 12px rgba(155,89,182,0.8); }
}

.phase-video-window.transition-window { border-color: rgba(155,89,182,0.3); }
.phase-video-window.transition-window:hover { border-color: #9b59b6; }
.phase-video-window.transition-window.active {
    border-color: #9b59b6;
    box-shadow: 0 0 12px rgba(155,89,182,0.4);
}
.phase-video-window.transition-window.active .window-overlay {
    background: linear-gradient(transparent 30%, rgba(155,89,182,0.3));
}
.phase-video-window.transition-window.active .window-status {
    background: #9b59b6;
    box-shadow: 0 0 6px rgba(155,89,182,0.6);
}
</style>

<script>
(function() {
    // ==================== 状态变量 ====================
    var currentPhase = null;
    var currentStatus = 'ready';
    var isLoading = false;
    var statusLabels = {
        ready: '就绪', running: '执行中', warning: '预警', urgent: '紧急'
    };
    var statusColors = {
        ready: '#27ae60', running: '#3498db', warning: '#f39c12', urgent: '#e74c3c'
    };
    var phaseIcons = {
        pre_wedding: '📋', setup: '👔', groom_prep: '🤵', car_prep: '🚗', depart: '🚀', arrive_bride: '🏠',
        enter_home: '🎉', ceremony_home: '🙏', ceremony_hotel: '🎤', dinner: '🍽️',
        see_off: '👋', final_settlement: '✅', home_return: '🏮'
    };
    var phaseNames = {
        pre_wedding: '婚前1天·前置筹备', setup: '男方全员上岗', groom_prep: '新郎梳妆更衣', car_prep: '婚车扎花整队',
        depart: '吉时出发娶亲', arrive_bride: '抵达新娘家', enter_home: '吉时进门',
        ceremony_home: '院内拜天地', ceremony_hotel: '酒店开仪式', dinner: '正餐开席',
        see_off: '送客返程', final_settlement: '礼金对账', home_return: '婚后回门宴'
    };

    var currentVolume = 1.0;
    var previousVolume = 1.0;
    var isMuted = false;
    var isVolumeDragging = false;
    var phaseVideoElements = {};
    var lastSyncPhase = null;

    function escapeHtml(str) {
        if (!str) return '';
        var div = document.createElement('div');
        div.textContent = str;
        return div.innerHTML;
    }

    function getTeamName(code) {
        var team = teamStatuses.find(function(t) { return t.code === code; });
        return team ? team.name : code;
    }

    // ==================== DOM 引用 ====================
    var mainVideo = document.getElementById('mainVideo');
    var mainVideoSource = document.getElementById('mainVideoSource');
    var videoOverlay = document.getElementById('videoOverlay');
    var overlayCenter = document.getElementById('overlayCenter');
    var videoLoadingOverlay = document.getElementById('videoLoadingOverlay');
    var videoMode = 'timeline';
    var currentPhaseBadge = document.getElementById('currentPhaseBadge');
    var emotionIndicatorMini = document.getElementById('emotionIndicatorMini');
    var timelineProgress = document.getElementById('timelineProgress');
    var timelinePhases = document.getElementById('timelinePhases');
    var progressFilled = document.getElementById('progressFilled');
    var progressHandle = document.getElementById('progressHandle');
    var phaseMarkers = document.getElementById('phaseMarkers');
    var timeDisplay = document.getElementById('timeDisplay');
    var infoBody = document.getElementById('infoBody');
    var phaseVideosGrid = document.getElementById('phaseVideosGrid');
    var btnMute = document.getElementById('btnMute');
    var volumeIcon = document.getElementById('volumeIcon');
    var volumeSliderWrapper = document.getElementById('volumeSliderWrapper');
    var volumeSliderTrack = document.getElementById('volumeSliderTrack');
    var volumeSliderFilled = document.getElementById('volumeSliderFilled');
    var volumeSliderHandle = document.getElementById('volumeSliderHandle');
    var volumeIndicator = document.getElementById('volumeIndicator');
    var volumePercent = document.getElementById('volumePercent');

    // ==================== 时间线管理系统 ====================
    var TimelineManager = {
        startTime: null,
        pausedElapsed: 0,
        isRunning: false,
        isPaused: false,
        totalDuration: 0,
        phases: [],
        phaseVideoMap: {},
        syncDrift: 0,
        lastCalibrationTime: 0,
        calibrationInterval: 5000,
        maxDrift: 0.5,
        tickRAF: null,

        init: function(phases) {
            this.phases = phases;
            this.totalDuration = 0;
            var self = this;
            phases.forEach(function(p) {
                p.duration = p.duration || 300;
                p.startTime = self.totalDuration;
                p.endTime = self.totalDuration + p.duration;
                self.totalDuration += p.duration;
            });
            this.updateUI();
            this.updateBadges();
        },

        updateBadges: function() {
            var totalPhases = this.phases.length;
            var mainPhases = this.phases.filter(function(p) { return !p.isTransition; }).length;
            var transitionPhases = this.phases.filter(function(p) { return p.isTransition; }).length;
            document.getElementById('timelineBadge').textContent = totalPhases + '个环节 (' + mainPhases + '主+' + transitionPhases + '过渡)';
            document.getElementById('phaseVideosBadge').textContent = '8个团队';
        },

        start: function() {
            if (this.isRunning && !this.isPaused) return;
            if (this.isPaused) {
                this.startTime = Date.now() - this.pausedElapsed * 1000;
                this.isPaused = false;
            } else {
                this.startTime = Date.now();
                this.pausedElapsed = 0;
            }
            this.isRunning = true;
            this.isPaused = false;
            this.lastCalibrationTime = Date.now();
            this.startTick();
            this.updateControlButtons();
            document.getElementById('timelineCtrlBadge').textContent = '运行中';
            document.getElementById('syncStatusDot').className = 'sync-status-dot synced';
        },

        pause: function() {
            if (!this.isRunning || this.isPaused) return;
            this.pausedElapsed = (Date.now() - this.startTime) / 1000;
            this.isPaused = true;
            this.stopTick();
            this.updateControlButtons();
            document.getElementById('timelineCtrlBadge').textContent = '已暂停';
            document.getElementById('syncStatusDot').className = 'sync-status-dot drifting';
        },

        stop: function() {
            this.isRunning = false;
            this.isPaused = false;
            this.startTime = null;
            this.pausedElapsed = 0;
            this.syncDrift = 0;
            this.stopTick();
            this.updateControlButtons();
            document.getElementById('timelineCtrlBadge').textContent = '已停止';
            document.getElementById('syncStatusDot').className = 'sync-status-dot';
            document.getElementById('tlElapsed').textContent = '00:00:00';
            document.getElementById('tlCurrentPhase').textContent = '--';
            document.getElementById('tlSyncDrift').textContent = '0.0s';
            document.getElementById('tlSyncDrift').className = 'tl-value drift-ok';
            currentPhase = null;
            alertedPhases = {};
            renderTimeline();
            if (typeof CheckpointReminder !== 'undefined') {
                CheckpointReminder.reset();
            }
            if (typeof EmergencyManager !== 'undefined') {
                EmergencyManager._emergencyTriggered = false;
                EmergencyManager.stop();
            }
        },

        reset: function() {
            this.stop();
            this.phaseVideoMap = {};
            var self = this;
            this.totalDuration = 0;
            this.phases.forEach(function(p) {
                p.startTime = self.totalDuration;
                p.endTime = self.totalDuration + p.duration;
                self.totalDuration += p.duration;
            });
            this.updateUI();
            this.updateBadges();
            alertedPhases = {};
            if (typeof CheckpointReminder !== 'undefined') {
                CheckpointReminder.reset();
            }
        },

        getElapsed: function() {
            if (!this.isRunning) return 0;
            if (this.isPaused) return this.pausedElapsed;
            return (Date.now() - this.startTime) / 1000;
        },

        getPhaseAtTime: function(elapsed) {
            for (var i = 0; i < this.phases.length; i++) {
                var p = this.phases[i];
                if (elapsed >= p.startTime && elapsed < p.endTime) {
                    return p;
                }
            }
            if (elapsed >= this.totalDuration) {
                return this.phases[this.phases.length - 1];
            }
            return this.phases[0];
        },

        getPhaseProgress: function(phaseCode) {
            var elapsed = this.getElapsed();
            for (var i = 0; i < this.phases.length; i++) {
                var p = this.phases[i];
                if (p.code === phaseCode) {
                    if (elapsed < p.startTime) return 0;
                    if (elapsed >= p.endTime) return 100;
                    return ((elapsed - p.startTime) / p.duration) * 100;
                }
            }
            return 0;
        },

        getOverallProgress: function() {
            var elapsed = this.getElapsed();
            return Math.min((elapsed / this.totalDuration) * 100, 100);
        },

        jumpToPhase: function(phaseCode) {
            var phase = null;
            for (var i = 0; i < this.phases.length; i++) {
                if (this.phases[i].code === phaseCode) {
                    phase = this.phases[i];
                    break;
                }
            }
            if (!phase) return;
            var targetElapsed = phase.startTime;
            this.startTime = Date.now() - targetElapsed * 1000;
            this.pausedElapsed = targetElapsed;
            this.syncDrift = 0;
            lastSyncPhase = null;
            this.onPhaseChange(phaseCode);
            this.syncVideoToTimeline();
        },

        bindVideo: function(phaseCode, videoUrl, videoId) {
            this.phaseVideoMap[phaseCode] = { url: videoUrl, videoId: videoId };
            this.updateTeamWindow(phaseCode);
        },

        unbindVideo: function(phaseCode) {
            delete this.phaseVideoMap[phaseCode];
            this.updateTeamWindow(phaseCode);
        },

        syncVideoToTimeline: function() {
            var elapsed = this.getElapsed();
            var phase = this.getPhaseAtTime(elapsed);
            if (!phase) return;
            var boundVideo = this.phaseVideoMap[phase.code];
            if (boundVideo && boundVideo.url) {
                if (managerVideoUrl !== boundVideo.url) {
                    loadVideoToPlayer(boundVideo.url, 'coordination');
                }
                var phaseElapsed = elapsed - phase.startTime;
                var videoDuration = mainVideo.duration || 0;
                var videoTime;
                if (videoDuration > 0 && phaseElapsed > videoDuration) {
                    videoTime = phaseElapsed % videoDuration;
                } else {
                    videoTime = phaseElapsed;
                }
                if (Math.abs(mainVideo.currentTime - videoTime) > this.maxDrift) {
                    mainVideo.currentTime = videoTime;
                }
            }
        },

        calibrate: function() {
            this.syncDrift = 0;
            this.lastCalibrationTime = Date.now();
            this.syncVideoToTimeline();
            document.getElementById('syncStatusDot').className = 'sync-status-dot synced';
        },

        checkSync: function() {
            if (!this.isRunning || this.isPaused) return;
            var elapsed = this.getElapsed();
            var phase = this.getPhaseAtTime(elapsed);
            if (!phase || !mainVideo.duration) return;
            var boundVideo = this.phaseVideoMap[phase.code];
            var expectedVideoTime;
            if (boundVideo) {
                expectedVideoTime = elapsed - phase.startTime;
            } else {
                expectedVideoTime = (elapsed / this.totalDuration) * mainVideo.duration;
            }
            this.syncDrift = Math.abs(mainVideo.currentTime - expectedVideoTime);
            var driftEl = document.getElementById('tlSyncDrift');
            var dotEl = document.getElementById('syncStatusDot');
            if (!driftEl || !dotEl) return;
            if (this.syncDrift <= 0.3) {
                driftEl.textContent = this.syncDrift.toFixed(1) + 's';
                driftEl.className = 'tl-value drift-ok';
                dotEl.className = 'sync-status-dot synced';
            } else if (this.syncDrift <= this.maxDrift) {
                driftEl.textContent = this.syncDrift.toFixed(1) + 's';
                driftEl.className = 'tl-value drift-warn';
                dotEl.className = 'sync-status-dot drifting';
            } else {
                driftEl.textContent = this.syncDrift.toFixed(1) + 's';
                driftEl.className = 'tl-value drift-error';
                dotEl.className = 'sync-status-dot error';
                this.syncVideoToTimeline();
            }
            if (Date.now() - this.lastCalibrationTime > this.calibrationInterval) {
                if (this.syncDrift > 0.2) {
                    this.syncVideoToTimeline();
                }
                this.lastCalibrationTime = Date.now();
            }
        },

        onPhaseChange: function(phaseCode) {
            if (currentPhase === phaseCode) return;
            currentPhase = phaseCode;
            var phase = managerPhases.find(function(p) { return p.code === phaseCode; });
            if (!phase) return;
            setVideoMode('timeline');
            renderTimeline();
            updateOverlayPhase(phase);
            updateStatusIndicator(getPhaseDynamicStatus(phaseCode));
            updateInfoPanel(phase);
            updateWelcomeState(phase);
            updateTeamWindows(phaseCode);
            var boundVideo = this.phaseVideoMap[phaseCode];
            if (boundVideo && boundVideo.url) {
                if (managerVideoUrl !== boundVideo.url) {
                    loadVideoToPlayer(boundVideo.url, 'coordination');
                }
            }
            document.getElementById('tlCurrentPhase').textContent = phase.name;
            checkAndGenerateAlerts(phase);
            CheckpointReminder.onPhaseSwitched(phase);
            syncPhaseToScreen(phase);
        },

        startTick: function() {
            if (this.tickRAF) cancelAnimationFrame(this.tickRAF);
            var self = this;
            function tick() {
                if (!self.isRunning || self.isPaused) return;
                var elapsed = self.getElapsed();
                if (elapsed >= self.totalDuration) {
                    self.onTick();
                    self.stop();
                    return;
                }
                self.onTick();
                self.tickRAF = requestAnimationFrame(tick);
            }
            this.tickRAF = requestAnimationFrame(tick);
        },

        stopTick: function() {
            if (this.tickRAF) {
                cancelAnimationFrame(this.tickRAF);
                this.tickRAF = null;
            }
        },

        onTick: function() {
            var elapsed = this.getElapsed();
            var hours = Math.floor(elapsed / 3600);
            var mins = Math.floor((elapsed % 3600) / 60);
            var secs = Math.floor(elapsed % 60);
            document.getElementById('tlElapsed').textContent =
                String(hours).padStart(2, '0') + ':' + String(mins).padStart(2, '0') + ':' + String(secs).padStart(2, '0');

            var phase = this.getPhaseAtTime(elapsed);
            if (phase && phase.code !== currentPhase) {
                this.onPhaseChange(phase.code);
            }

            var overallProgress = this.getOverallProgress();
            timelineProgress.style.setProperty('--progress', overallProgress + '%');

            managerPhases.forEach(function(p) {
                var progress = TimelineManager.getPhaseProgress(p.code);
                updateTimelinePhaseProgress(p.code, progress);
            });

            if (phase) {
                var currentProgress = this.getPhaseProgress(phase.code);
                var teams = phaseTeamMap[phase.code] || [];
                teams.forEach(function(teamCode) {
                    updateTeamWindowProgress(teamCode, currentProgress);
                });
                if (currentProgress > 0) {
                    checkAndGenerateAlerts(phase);
                }
            }

            CheckpointReminder.check(elapsed);

            this.checkSync();
        },

        updateControlButtons: function() {
            var btnStart = document.getElementById('btnTimelineStart');
            var btnPause = document.getElementById('btnTimelinePause');
            var btnStop = document.getElementById('btnTimelineStop');
            var btnCalibrate = document.getElementById('btnTimelineCalibrate');
            btnStart.disabled = (this.isRunning && !this.isPaused);
            btnPause.disabled = (!this.isRunning || this.isPaused);
            btnStop.disabled = !this.isRunning;
            btnCalibrate.disabled = !this.isRunning;
            if (this.isPaused) {
                btnStart.innerHTML = '<i class="fas fa-play"></i> 继续';
            } else {
                btnStart.innerHTML = '<i class="fas fa-play"></i> 启动';
            }
        },

        updateTeamWindow: function(phaseCode) {
            var boundVideo = this.phaseVideoMap[phaseCode];
            var teams = phaseTeamMap[phaseCode] || [];
            teams.forEach(function(teamCode) {
                var el = phaseVideoElements[teamCode];
                if (!el || !el.window || !el.video) return;
                var video = el.video;
                var placeholder = el.window.querySelector('.window-placeholder');
                if (boundVideo && boundVideo.url) {
                    video.src = boundVideo.url;
                    video.muted = true;
                    video.style.display = 'block';
                    video.load();
                    if (placeholder) placeholder.style.display = 'none';
                } else {
                    video.src = '';
                    video.style.display = 'none';
                    if (placeholder) placeholder.style.display = '';
                }
            });
        },

        updateUI: function() {
            this.updateControlButtons();
        }
    };

    // ==================== API 工具 ====================
    function apiCall(method, path, params, callback) {
        var xhr = new XMLHttpRequest();
        var url = 'api/api_router.php?path=' + path;
        if (method === 'GET' && params) {
            var qs = Object.keys(params).map(function(k) { return k + '=' + encodeURIComponent(params[k]); }).join('&');
            url += '&' + qs;
        }
        xhr.open(method, url, true);
        xhr.timeout = 30000;
        xhr.onload = function() {
            if (xhr.status === 200) {
                try { callback(null, JSON.parse(xhr.responseText)); }
                catch(e) { callback(e); }
            } else { callback(new Error('HTTP ' + xhr.status)); }
        };
        xhr.onerror = function() { callback(new Error('网络错误')); };
        xhr.ontimeout = function() { callback(new Error('请求超时')); };
        if (method === 'POST' && params && !(params instanceof FormData)) {
            xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
            xhr.send(Object.keys(params).map(function(k) { return k + '=' + encodeURIComponent(params[k]); }).join('&'));
        } else if ((method === 'DELETE' || method === 'PUT') && params) {
            xhr.setRequestHeader('Content-Type', 'application/json');
            xhr.send(JSON.stringify(params));
        } else { xhr.send(); }
    }

    function setLoading(loading) {
        isLoading = loading;
    }

    // ==================== 音量控制 ====================
    function initVolumeControl() {
        mainVideo.volume = currentVolume;
        updateVolumeUI(currentVolume);
        btnMute.addEventListener('click', function() {
            if (isMuted) {
                isMuted = false;
                mainVideo.volume = previousVolume;
                currentVolume = previousVolume;
            } else {
                isMuted = true;
                previousVolume = currentVolume > 0 ? currentVolume : 0.5;
                mainVideo.volume = 0;
                currentVolume = 0;
            }
            updateVolumeUI(currentVolume);
        });
        volumeSliderWrapper.addEventListener('mousedown', onVolumeSliderStart);
        volumeSliderWrapper.addEventListener('touchstart', onVolumeSliderStart, { passive: false });
        document.addEventListener('mousemove', onVolumeSliderMove);
        document.addEventListener('touchmove', onVolumeSliderMove, { passive: false });
        document.addEventListener('mouseup', onVolumeSliderEnd);
        document.addEventListener('touchend', onVolumeSliderEnd);
    }

    function onVolumeSliderStart(e) {
        e.preventDefault();
        isVolumeDragging = true;
        updateVolumeFromEvent(e);
    }

    function onVolumeSliderMove(e) {
        if (!isVolumeDragging) return;
        e.preventDefault();
        updateVolumeFromEvent(e);
    }

    function onVolumeSliderEnd() {
        if (!isVolumeDragging) return;
        isVolumeDragging = false;
    }

    function updateVolumeFromEvent(e) {
        var rect = volumeSliderTrack.getBoundingClientRect();
        var clientX = e.touches ? e.touches[0].clientX : e.clientX;
        var percent = (clientX - rect.left) / rect.width;
        percent = Math.max(0, Math.min(1, percent));
        currentVolume = percent;
        isMuted = percent === 0;
        if (percent > 0) previousVolume = percent;
        mainVideo.volume = percent;
        updateVolumeUI(percent);
    }

    function updateVolumeUI(volume) {
        var percent = Math.round(volume * 100);
        volumeSliderFilled.style.width = (volume * 100) + '%';
        volumeSliderHandle.style.left = (volume * 100) + '%';
        volumePercent.textContent = percent + '%';
        if (isMuted || volume === 0) {
            volumeIcon.className = 'fas fa-volume-mute';
            btnMute.classList.add('is-muted');
            btnMute.title = '取消静音';
        } else if (volume < 0.5) {
            volumeIcon.className = 'fas fa-volume-down';
            btnMute.classList.remove('is-muted');
            btnMute.title = '静音';
        } else {
            volumeIcon.className = 'fas fa-volume-up';
            btnMute.classList.remove('is-muted');
            btnMute.title = '静音';
        }
        var bars = volumeIndicator.querySelectorAll('.vol-bar');
        var activeBars = 0;
        if (volume === 0 || isMuted) { activeBars = 0; }
        else if (volume <= 0.2) { activeBars = 1; }
        else if (volume <= 0.4) { activeBars = 2; }
        else if (volume <= 0.6) { activeBars = 3; }
        else if (volume <= 0.8) { activeBars = 4; }
        else { activeBars = 5; }
        bars.forEach(function(bar, index) {
            bar.classList.remove('active', 'muted');
            if (isMuted || volume === 0) { bar.classList.add('muted'); }
            else if (index < activeBars) { bar.classList.add('active'); }
        });
    }

    // ==================== 统筹时间轴 ====================
    var managerPhases = [];
    var managerVideoUrl = null;
    var managerUserId = 'manager_' + Date.now();
    var currentVideoId = null;
    var currentVideoTab = 'coordination';
    var managerVideoType = 'coordination';
    
    // ==================== 视频播放列表和轮播 ====================
    var currentVideoList = [];
    var currentVideoIndex = -1;
    var autoPlayEnabled = true;
    var lastInteractionTime = 0;
    var resumeAutoPlayTimer = null;
    var AUTO_PLAY_RESUME_DELAY = 30000;

    var teamStatuses = [
        { code: 'manager', name: '总管', status: 'pending', icon: '👔', desc: '全场统筹协调' },
        { code: 'bridesmaid', name: '伴娘团', status: 'pending', icon: '👗', desc: '全程陪伴新娘' },
        { code: 'groomsman', name: '伴郎团', status: 'pending', icon: '🤵', desc: '全程陪伴新郎' },
        { code: 'mc', name: '司仪组', status: 'pending', icon: '🎤', desc: '主持与音响控制' },
        { code: 'reception', name: '接待引位组', status: 'pending', icon: '👋', desc: '宾客接待与引位' },
        { code: 'cash_register', name: '礼金登记组', status: 'pending', icon: '💰', desc: '礼金登记与保管' },
        { code: 'car', name: '婚车司机组', status: 'pending', icon: '🚗', desc: '婚车调度与驾驶' },
        { code: 'item_manager', name: '物品管理组', status: 'pending', icon: '📦', desc: '物资清点与保管' },
        { code: 'photo', name: '摄影服务组', status: 'pending', icon: '📸', desc: '摄影摄像记录' },
        { code: 'sound_light', name: '灯光音效组', status: 'pending', icon: '🎵', desc: '灯光音响控制' },
        { code: 'bridal_pickup', name: '接亲团', status: 'pending', icon: '🎊', desc: '娶亲迎亲队伍' },
        { code: 'bride_liaison', name: '女方对接专员', status: 'pending', icon: '🤝', desc: '与女方家沟通对接' }
    ];

    var phaseTeamMap = {
        pre_wedding: ['manager', 'cash_register', 'item_manager', 'car', 'reception'],
        setup: ['manager', 'reception', 'cash_register', 'item_manager'],
        groom_prep: ['groomsman', 'bridesmaid', 'photo'],
        car_prep: ['car', 'item_manager', 'manager'],
        depart: ['car', 'groomsman', 'bridal_pickup', 'manager'],
        arrive_bride: ['car', 'bride_liaison', 'groomsman', 'bridal_pickup'],
        enter_home: ['bridesmaid', 'bride_liaison', 'sound_light', 'photo'],
        ceremony_home: ['mc', 'sound_light', 'photo', 'reception', 'item_manager'],
        ceremony_hotel: ['mc', 'sound_light', 'photo', 'reception', 'manager'],
        dinner: ['reception', 'manager', 'photo', 'bridesmaid', 'groomsman'],
        see_off: ['reception', 'car', 'item_manager', 'manager'],
        final_settlement: ['manager', 'cash_register', 'item_manager', 'reception'],
        home_return: ['manager', 'bride_liaison', 'photo', 'reception', 'cash_register']
    };

    function initTimeline() {
        var phases = [
            { code: 'pre_wedding', name: '婚前1天·前置筹备（18:00前完成）', status: 'ready', desc: '1.新房布置：全屋贴喜字、拉花、红毯，新床由全福人铺好撒干果；2.物资清点：分装红包、清点娶亲礼品、核对仪式道具、整理酒水烟糖；3.人员交底：召集帮忙人员开短会，明确分工、时间节点、民俗禁忌；4.车队确认：确认车辆数量、行车路线、扎花时间、司机集合地点；5.酒店对接：确认桌数、舞台、音响、迎宾区布置、上菜时间', instruction: '各位工作人员，婚礼将于明日举行！请在今天18:00前完成全部前置筹备工作：新房布置、物资清点、人员交底、车队确认、酒店对接。', team: '男方总管2人+全福妇女2人；总管+账房2人+物资看管1人；车管1人；酒店对接人', materials: '喜字、胶带、红绳、拉花、红毯、新被褥、红枣/花生/桂圆/莲子、压床红包；各类红包、离娘肉、喜馍、烟酒、彩礼礼盒、喜糖、胸花、手捧花；分工表、流程表、联系方式清单；行车路线图、司机红包、喜烟喜糖；桌签、席位图、酒水、烟糖、伴手礼', notes: '铺床人需父母双全、夫妻健在、儿女齐全；孕妇/戴孝人员禁止参与；所有礼品红包备双份；娶亲队伍里不能有新郎姑姑；车辆总数必须双数；预留2桌备用，主桌优先安排娘家送亲大客', duration: 21600, isTransition: false },
            { code: 'setup', name: '04:40–05:40 男方全员上岗', status: 'ready', desc: '1.男方全员到岗，总管分工；2.账房就位、布置收礼台；3.全福人铺新床、撒子孙干果；4.院内布置喜场、贴喜字、红毯；5.清点娶亲全套礼品、红包分类', instruction: '各位工作人员早上好！请各团队迅速就位，总管分工、账房就位、全福人铺新床、布置院内喜场、清点娶亲全套礼品、红包分类。', team: '总负责人：男方总管2人；账房2人、娶亲婆2人；铺床全福人2名、车管1人；搬礼人员4人', materials: '喜字、胶带、红绳、新床品、子孙干果（枣/花生/桂圆/莲子）、娶亲礼品、红包、分装信封、记账本、笔', notes: '铺床需全福人；新床当天禁止外人随意坐；当天不扫地、不倒垃圾', duration: 3600, isTransition: false },
            { code: 'groom_prep', name: '05:40–06:30 新郎梳妆更衣', status: 'ready', desc: '1.新郎梳妆更衣、父母披红；2.简单祭祖、拜拜祖先；3.伴郎集合、领取娶亲道具、红包；4.核对戒指、手捧花、胸花', instruction: '新郎梳妆更衣、父母披红、简单祭祖；伴郎集合领取道具、红包、戒指手捧花。', team: '新郎本人、父母；伴郎6人（双数）、娶亲婆2人', materials: '新郎礼服、红腰带、披红布、祭祖用品、手捧花、胸花、婚戒、红包、娶亲道具', notes: '伴郎必须双数；忌单数人员参与娶亲', duration: 3000, isTransition: false },
            { code: 'car_prep', name: '06:30–07:50 婚车扎花整队', status: 'ready', desc: '1.婚车扎花、车队整队、检查双数车辆；2.车管核对车队数量、司机联系方式；3.娶亲婆再次核对离娘肉、喜馍、彩礼、回礼物资；4.压车娃到位、准备出发', instruction: '婚车扎花、车队整队、检查双数车辆；娶亲婆再次核对离娘肉、喜馍、彩礼、回礼物资。', team: '车管1人、总管2人；娶亲婆2人、伴郎2人', materials: '婚车扎花道具、彩带、礼炮、离娘肉礼盒、喜馍、彩礼、回礼礼盒、司机红包、压车娃红包', notes: '车队必须双数；离娘肉、喜馍必须带双数；压车娃坐头车', duration: 4800, isTransition: false },
            { code: 'depart', name: '08:08 吉时出发娶亲', status: 'ready', desc: '1.全员集合、鸣炮发车；2.车队按顺序出发、压车娃坐头车；3.前往新娘家娶亲', instruction: '吉时已到！鸣炮、车队出发、压车娃坐头车，注意行车安全。', team: '男方总管2人、车管1人；娶亲婆2人、伴郎6人；所有娶亲人员', materials: '礼炮、彩带、娶亲全套礼品、红包、手捧花、胸花', notes: '出发吉时严格遵选日课；车队途中忌走回头路', duration: 600, isTransition: false },
            { code: 'arrive_bride', name: '09:00左右 抵达新娘家', status: 'ready', desc: '1.抵达新娘家，娶亲婆与送亲婆对接；2.清点礼品、办理交接礼数；3.等候接亲完成、准备返程', instruction: '抵达新娘家，对接礼数、等候接亲完成，请保持秩序。', team: '娶亲婆2人、男方总管1人；伴郎2人、车管1人', materials: '礼盒收纳袋、红包、纸笔、登记本', notes: '对接时先递礼品，再给压车娃红包；全程礼数周全', duration: 4800, isTransition: false },
            { code: 'enter_home', name: '10:28 吉时进门', status: 'ready', desc: '1.新娘下车、红伞护顶；2.跨火盆、踩干草、不踩门槛；3.入新房、坐床、翻喜被', instruction: '吉时已到！新娘下车、红伞护顶、跨火盆、踩干草、不踩门槛入新房坐床。', team: '新娘新郎、送亲婆2人；娶亲婆2人、伴娘2人；男方父母', materials: '红伞、火盆、干草、门槛红纸、喜被、红枣、花生', notes: '进门吉时严格遵选日课；跨火盆寓意红火，踩干草寓意富贵', duration: 600, isTransition: false },
            { code: 'ceremony_home', name: '10:30–11:20 院内拜天地', status: 'ready', desc: '1.院内拜天地、拜高堂、夫妻对拜；2.新娘向公婆改口敬茶、给长辈行礼；3.礼遇送亲大客、安排落座、上茶', instruction: '院内拜天地、拜高堂、夫妻对拜；新娘向公婆改口敬茶、给长辈行礼；礼遇送亲大客。', team: '新郎新娘、男方父母；送亲大客、娶亲婆2人；送亲婆2人、总管2人；摄影1名', materials: '天地桌、香烛、贡品、茶杯、热水、改口红包、长辈红包、喜糖、瓜子', notes: '拜天地顺序：一拜天地、二拜高堂、夫妻对拜；改口红包必须双数', duration: 3000, isTransition: false },
            { code: 'ceremony_hotel', name: '11:58 酒店开仪式', status: 'ready', desc: '1.新人入场、父亲交接；2.宣誓、交换戒指、亲吻；3.父母致辞、新人致辞；4.全家合影、抛手捧花', instruction: '酒店仪式开始！入场、交接、宣誓、交换戒指、父母致辞、合影留念。', team: '新郎新娘、双方父母；主持人、摄影摄像；伴郎伴娘、所有亲友', materials: '手捧花、婚戒、誓词卡、话筒、音乐设备、合影道具', notes: '仪式吉时严格遵选日课；提前与酒店、主持人核对流程', duration: 1320, isTransition: false },
            { code: 'dinner', name: '12:20–13:40 正餐开席', status: 'ready', desc: '1.正餐开席、新人逐桌敬酒；2.优先敬娘家送亲大客主桌；3.全场照应、引导亲友用餐', instruction: '正餐开席，请逐桌敬酒，优先娘家大客主桌，全场照应宾客需求。', team: '新郎新娘、伴郎伴娘；男方总管2人、娶亲婆2人', materials: '敬酒酒杯、喜糖、红包、纸巾、矿泉水', notes: '敬酒顺序：先娘家主桌，再按辈分依次敬酒；每桌敬双杯', duration: 4800, isTransition: false },
            { code: 'see_off', name: '14:30前 送客返程', status: 'ready', desc: '1.送客、送亲亲友返程；2.酒店收尾、结清酒店费用；3.物资清点、回收', instruction: '请有序送客，安排送亲亲友返程，完成酒店收尾工作。', team: '男方总管2人、账房2人；车管1人、所有帮忙人员', materials: '剩余喜糖、红包、礼盒、酒店结算单、礼金收纳箱', notes: '送亲亲友必须安排车辆返程；酒店剩余物资全部回收', duration: 2400, isTransition: false },
            { code: 'final_settlement', name: '16:00前 礼金对账', status: 'ready', desc: '1.礼金对账、清点全部红包；2.发放帮忙人员红包；3.全屋收尾、清理场地；4.剩余物资收纳、归档', instruction: '礼金对账、物资清点、发放帮忙红包、全屋收尾整理，确保万无一失。', team: '账房2人、男方总管2人；所有帮忙人员', materials: '记账本、礼金收纳箱、剩余红包、结清红包、收纳箱', notes: '所有帮忙人员红包当天结清；剩余礼金、物资全部清点入库', duration: 3600, isTransition: false },
            { code: 'home_return', name: '婚后第1天·回门宴', status: 'ready', desc: '1.09:30 新人带四色礼到达娘家，新郎改口敬父母、给改口红包、拍全家福；2.10:30 出发前往酒店；3.11:00 新人+女方父母在酒店门口迎宾；4.11:28 吉时开场仪式（约10分钟）：主持人开场→邀请女方父母上台→新人牵手入场→家长简短致辞→新人感谢父母→全家共同举杯→宣布开席；5.11:40 正式开席，12:20 新人逐桌敬酒；6.13:30 宴席结束送客，14:00 返回娘家小憩；7.17:00前离开娘家返回新房（不留宿）', instruction: '婚后回门请注意：新人必须同行，礼品必须双数，日落前必须离开娘家，不在娘家过夜。酒店回门宴必须中午举办，不办晚宴。', team: '新郎新娘、女方父母；女方总管2人、司仪1人；摄影1人、接待2人；账房1人', materials: '四色礼（烟、酒、糕点、水果，双数）、牛奶、新郎改口红包、回门新衣（不穿婚纱/秀禾）、敬酒用品（酒、杯子、纸巾）、签到本、笔', notes: '回门宴必须中午办，不办晚上；新人必须同行，新娘不可单独回门；礼品必须双数，忌单数；日落前必须离开娘家，新婚第一回门不在娘家过夜', duration: 14400, isTransition: false }
        ];
        managerPhases = phases;
        TimelineManager.init(phases);
        renderTimeline();
        initTeamWindows();
    }

    function renderTimeline() {
        var html = '';
        managerPhases.forEach(function(phase, index) {
            var isActive = currentPhase === phase.code;
            var hasVideo = !!TimelineManager.phaseVideoMap[phase.code];
            var isTransition = phase.isTransition || false;
            var progress = TimelineManager.getPhaseProgress(phase.code);
            var isCompleted = progress >= 100;
            html += '<div class="timeline-phase' + (isActive ? ' active' : '') + (hasVideo ? ' has-video' : '') + (isTransition ? ' transition-phase' : '') + (isCompleted ? ' completed' : '') + '" data-phase="' + phase.code + '">' +
                '<div class="timeline-phase-dot" data-progress="' + progress + '">' +
                '<span class="dot-icon">' + phaseIcons[phase.code] + '</span>' +
                '<div class="dot-progress-ring" style="--progress:' + progress + '%"></div>' +
                '</div>' +
                '<div class="timeline-phase-name">' + phase.name + '</div>' +
                '<div class="bind-indicator" title="' + (hasVideo ? '已绑定视频' : '未绑定视频') + '"></div>' +
                '</div>';
        });
        timelinePhases.innerHTML = html;

        timelinePhases.querySelectorAll('.timeline-phase').forEach(function(item) {
            item.addEventListener('click', function() {
                var phaseCode = this.dataset.phase;
                activatePhase(phaseCode);
            });
        });
    }

    // ==================== 团队状态监控窗口 ====================
    function initTeamWindows() {
        var html = '';
        teamStatuses.forEach(function(team, index) {
            var isActive = false;
            if (currentPhase) {
                var activeTeams = phaseTeamMap[currentPhase] || [];
                isActive = activeTeams.indexOf(team.code) !== -1;
            }
            var statusClass = '';
            if (team.status === 'active') statusClass = ' active';
            else if (team.status === 'completed') statusClass = ' completed';
            html += '<div class="phase-video-window' + (isActive ? ' active' : '') + statusClass + '" id="teamWindow_' + team.code + '" data-team="' + team.code + '">' +
                '<div class="window-placeholder">' + team.icon + '</div>' +
                '<video id="teamVideo_' + team.code + '" preload="metadata" muted playsinline style="display:none;"></video>' +
                '<div class="window-overlay">' +
                '<div class="window-label"><span class="window-icon">' + team.icon + '</span> ' + team.name + '</div>' +
                '</div>' +
                '<div class="window-status"></div>' +
                '<div class="window-progress"><div class="window-progress-bar" id="teamWindowProgress_' + team.code + '"></div></div>' +
                '</div>';
        });
        phaseVideosGrid.innerHTML = html;

        teamStatuses.forEach(function(team) {
            phaseVideoElements[team.code] = {
                window: document.getElementById('teamWindow_' + team.code),
                video: document.getElementById('teamVideo_' + team.code),
                progressBar: document.getElementById('teamWindowProgress_' + team.code)
            };
            
            var win = document.getElementById('teamWindow_' + team.code);
            if (win) {
                win.addEventListener('click', function() {
                    toggleTeamStatus(team.code);
                });
            }
        });
    }
    
    function toggleTeamStatus(teamCode) {
        var team = teamStatuses.find(function(t) { return t.code === teamCode; });
        if (!team) return;
        
        if (team.status === 'pending') {
            team.status = 'active';
        } else if (team.status === 'active') {
            team.status = 'completed';
        } else {
            team.status = 'pending';
        }
        
        var el = phaseVideoElements[teamCode];
        if (el && el.window) {
            el.window.classList.remove('pending', 'active', 'completed');
            el.window.classList.add(team.status);
        }
        
        addAlert('info', '团队状态', team.name + ' 状态已切换为: ' + getStatusText(team.status));
    }
    
    function getStatusText(status) {
        var texts = { pending: '待启动', active: '进行中', completed: '已完成' };
        return texts[status] || status;
    }

    function updateTeamWindows(phaseCode) {
        var activeTeams = phaseTeamMap[phaseCode] || [];
        var phase = managerPhases.find(function(p) { return p.code === phaseCode; });
        var progress = phase ? TimelineManager.getPhaseProgress(phaseCode) : 0;
        
        teamStatuses.forEach(function(team) {
            var el = phaseVideoElements[team.code];
            if (!el || !el.window) return;
            
            el.window.classList.remove('active');
            
            if (activeTeams.indexOf(team.code) !== -1) {
                el.window.classList.add('active');
            }
            
            if (progress >= 100) {
                el.window.classList.add('completed');
            }
            
            if (el.progressBar) {
                if (activeTeams.indexOf(team.code) !== -1) {
                    el.progressBar.style.width = progress + '%';
                } else {
                    el.progressBar.style.width = '0%';
                }
            }
        });
    }

    function updateTeamWindowProgress(teamCode, percent) {
        var el = phaseVideoElements[teamCode];
        if (!el || !el.progressBar) return;
        el.progressBar.style.width = percent + '%';
    }

    function updateTimelinePhaseProgress(phaseCode, percent) {
        var dotEl = document.querySelector('.timeline-phase[data-phase="' + phaseCode + '"] .timeline-phase-dot');
        if (!dotEl) return;
        var progressRing = dotEl.querySelector('.dot-progress-ring');
        if (progressRing) {
            progressRing.style.setProperty('--progress', percent + '%');
        }
        var phaseEl = document.querySelector('.timeline-phase[data-phase="' + phaseCode + '"]');
        if (phaseEl) {
            if (percent >= 100) {
                phaseEl.classList.add('completed');
                phaseEl.classList.remove('active');
            } else if (phaseCode === currentPhase) {
                phaseEl.classList.add('active');
                phaseEl.classList.remove('completed');
            }
        }
    }

    function activatePhase(phaseCode) {
        if (isLoading) return;
        if (TimelineManager.isRunning) {
            TimelineManager.jumpToPhase(phaseCode);
            var phase = managerPhases.find(function(p) { return p.code === phaseCode; });
            if (phase) syncPhaseToScreen(phase);
            return;
        }
        currentPhase = phaseCode;
        var phase = managerPhases.find(function(p) { return p.code === phaseCode; });
        if (!phase) return;
        setVideoMode('timeline');
        renderTimeline();
        updateOverlayPhase(phase);
        updateStatusIndicator(getPhaseDynamicStatus(phaseCode));
        updateInfoPanel(phase);
        updateWelcomeState(phase);
        updateTeamWindows(phaseCode);
        var boundVideo = TimelineManager.phaseVideoMap[phaseCode];
        if (boundVideo && boundVideo.url) {
            loadVideoToPlayer(boundVideo.url, 'coordination');
        }
        checkAndGenerateAlerts(phase);
        syncPhaseToScreen(phase);
    }

    function syncPhaseToScreen(phase) {
        console.log('syncPhaseToScreen called:', phase.name);
        var phaseData = {
            code: phase.code,
            name: phase.name,
            desc: phase.desc,
            team: phase.team,
            materials: phase.materials,
            notes: phase.notes,
            instruction: phase.instruction,
            timestamp: Date.now(),
            elapsed: TimelineManager.getElapsed(),
            totalDuration: TimelineManager.totalDuration,
            phaseProgress: TimelineManager.getPhaseProgress(phase.code),
            isRunning: TimelineManager.isRunning
        };
        localStorage.setItem('managerPhaseData', JSON.stringify(phaseData));
        console.log('syncPhaseToScreen saved to localStorage');
        
        if (screenWindow && !screenWindow.closed) {
            try {
                screenWindow.postMessage({
                    type: 'managerPhaseUpdate',
                    payload: phaseData
                }, '*');
                console.log('syncPhaseToScreen sent via postMessage');
            } catch(e) {
                console.error('postMessage failed:', e);
            }
        }
    }

    function showVideoLoading() {
        if (videoLoadingOverlay) videoLoadingOverlay.style.display = 'flex';
    }
    function hideVideoLoading() {
        if (videoLoadingOverlay) videoLoadingOverlay.style.display = 'none';
    }
    function setVideoMode(mode) {
        videoMode = mode;
        if (mode === 'library') {
            videoOverlay.classList.add('mode-library');
            overlayCenter.style.display = 'none';
        } else {
            videoOverlay.classList.remove('mode-library');
        }
    }

    function loadVideoToPlayer(url, videoType, source) {
        managerVideoUrl = url;
        managerVideoType = videoType || 'coordination';
        if (source === 'library') {
            setVideoMode('library');
        }
        showVideoLoading();
        mainVideoSource.src = url;
        mainVideo.volume = currentVolume;
        mainVideo.load();
        overlayCenter.style.display = 'none';
        mainVideo.play().then(function() {
            hideVideoLoading();
        }).catch(function() {
            hideVideoLoading();
            if (videoMode === 'library') {
                setVideoMode('timeline');
                overlayCenter.style.display = '';
                overlayCenter.style.opacity = '1';
                addAlert('warning', '视频播放', '视频播放失败，请检查视频格式或网络');
            } else {
                overlayCenter.style.display = '';
                overlayCenter.style.opacity = '1';
            }
        });
    }
    
    function updateWelcomeState(phase) {
        var welcomeText = document.getElementById('welcomeText');
        var welcomeSub = document.getElementById('welcomeSub');
        var overlayCenter = document.getElementById('overlayCenter');
        var infoPanel = document.getElementById('overlayInfoPanel');
        
        if (welcomeText) welcomeText.textContent = phase.name;
        if (welcomeSub) welcomeSub.textContent = phase.instruction || phase.desc;
        
        overlayCenter.style.display = 'none';
        infoPanel.style.display = 'block';
        
        var timePart = phase.name.substring(0, phase.name.indexOf(' '));
        var namePart = phase.name.substring(phase.name.indexOf(' ') + 1);
        
        document.getElementById('infoPhaseTime').textContent = timePart;
        document.getElementById('infoPhaseName').textContent = namePart;
        document.getElementById('infoTeam').textContent = phase.team || '暂无信息';
        document.getElementById('infoMaterials').textContent = phase.materials || '暂无信息';
        document.getElementById('infoNotes').textContent = phase.notes || '暂无信息';
        document.getElementById('infoInstruction').textContent = phase.instruction || '暂无信息';
    }

    function updateOverlayPhase(phase) {
        currentPhaseBadge.innerHTML = '<span class="phase-icon">' + phaseIcons[phase.code] + '</span><span class="phase-text">' + escapeHtml(phase.name) + '</span>';
    }

    function getPhaseDynamicStatus(phaseCode) {
        var progress = TimelineManager.getPhaseProgress(phaseCode);
        if (!TimelineManager.isRunning) return 'ready';
        if (progress >= 100) return 'ready';
        if (progress > 0) return 'running';
        return 'ready';
    }

    function updateStatusIndicator(status) {
        currentStatus = status || 'ready';
        emotionIndicatorMini.querySelector('.emotion-dot').style.background = statusColors[currentStatus] || '#27ae60';
        emotionIndicatorMini.querySelector('.emotion-text').textContent = statusLabels[currentStatus] || currentStatus;
    }

    function updateInfoPanel(phase) {
        var boundVideo = TimelineManager.phaseVideoMap[phase.code];
        var hasVideo = !!boundVideo;
        var durationMin = Math.floor(phase.duration / 60);
        var durationSec = phase.duration % 60;
        var durationStr = durationMin + '分' + (durationSec > 0 ? durationSec + '秒' : '');
        var html = '<div class="info-content">' +
            '<div class="info-row"><span class="info-label">环节名称</span><span class="info-value">' + escapeHtml(phase.name) + '</span></div>' +
            '<div class="info-row"><span class="info-label">当前状态</span><span class="info-value">' + escapeHtml(statusLabels[phase.status]) + '</span></div>' +
            '<div class="info-row"><span class="info-label">环节时长</span><span class="info-value">' + durationStr + '</span></div>' +
            '<div class="info-row"><span class="info-label">时间区间</span><span class="info-value">' + formatTime(phase.startTime) + ' - ' + formatTime(phase.endTime) + '</span></div>' +
            '<div class="info-row"><span class="info-label">负责人员</span><span class="info-value" style="font-size:12px;line-height:1.5;">' + escapeHtml(phase.team || '-') + '</span></div>' +
            '<div class="info-row"><span class="info-label">必备物资</span><span class="info-value" style="font-size:12px;line-height:1.5;">' + escapeHtml(phase.materials || '-') + '</span></div>' +
            '<div class="info-row"><span class="info-label">习俗备注</span><span class="info-value" style="font-size:12px;line-height:1.5;color:#d4a853;">' + escapeHtml(phase.notes || '-') + '</span></div>' +
            '<div class="info-row"><span class="info-label">统筹指令</span><span class="info-value" style="font-size:12px;line-height:1.5;">' + escapeHtml(phase.instruction) + '</span></div>' +
            '<div class="info-row"><span class="info-label">关联视频</span><span class="info-value">' + (hasVideo ? '<span style="color:#27ae60;">✓ 已绑定</span>' : '<span style="color:#999;">未绑定</span>') + '</span></div>' +
            '</div>';
        infoBody.innerHTML = html;
    }

    // ==================== 视频播放器控制 ====================
    function formatTime(seconds) {
        if (isNaN(seconds) || seconds < 0) seconds = 0;
        var mins = Math.floor(seconds / 60);
        var secs = Math.floor(seconds % 60);
        return String(mins).padStart(2, '0') + ':' + String(secs).padStart(2, '0');
    }

    function updateVideoProgress() {
        if (!mainVideo.duration) return;
        var percent = (mainVideo.currentTime / mainVideo.duration) * 100;
        progressFilled.style.width = percent + '%';
        progressHandle.style.left = percent + '%';
        timeDisplay.textContent = formatTime(mainVideo.currentTime) + ' / ' + formatTime(mainVideo.duration);
    }

    function showPauseBtn() {
        var btn = document.getElementById('btnMainPause');
        btn.innerHTML = '<i class="fas fa-pause"></i>';
        btn.title = '暂停';
        btn.classList.add('is-pause');
        btn.classList.remove('is-resume');
    }

    function showResumeBtn() {
        var btn = document.getElementById('btnMainPause');
        btn.innerHTML = '<i class="fas fa-play"></i>';
        btn.title = '继续';
        btn.classList.remove('is-pause');
        btn.classList.add('is-resume');
    }

    document.getElementById('btnMainPause').addEventListener('click', function() {
        recordInteraction();
        if (this.classList.contains('is-pause')) {
            mainVideo.pause();
        } else {
            if (!managerVideoUrl) return;
            mainVideo.play().catch(function() {});
        }
    });

    document.getElementById('btnMainStop').addEventListener('click', function() {
        recordInteraction();
        mainVideo.pause();
        mainVideo.currentTime = 0;
        showResumeBtn();
        setVideoMode('timeline');
        overlayCenter.style.opacity = '1';
        overlayCenter.style.display = '';
        progressFilled.style.width = '0%';
        progressHandle.style.left = '0%';
        timeDisplay.textContent = '00:00 / ' + formatTime(mainVideo.duration || 0);
        managerVideoUrl = null;
        document.querySelectorAll('.video-card').forEach(function(c) { c.classList.remove('active'); });
    });
    
    document.getElementById('btnPrevVideo').addEventListener('click', function() {
        playPrevVideo();
    });
    
    document.getElementById('btnNextVideo').addEventListener('click', function() {
        playNextVideo();
    });
    
    mainVideo.addEventListener('ended', function() {
        showResumeBtn();
        onVideoEnded();
    });
    
    document.getElementById('btnRewind').addEventListener('click', function() {
        recordInteraction();
        var skipTime = 10;
        var newTime = Math.max(0, mainVideo.currentTime - skipTime);
        mainVideo.currentTime = newTime;
        addAlert('info', '快退', '已快退 ' + skipTime + ' 秒');
    });
    
    document.getElementById('btnForward').addEventListener('click', function() {
        recordInteraction();
        var skipTime = 10;
        var newTime = Math.min(mainVideo.duration || 0, mainVideo.currentTime + skipTime);
        mainVideo.currentTime = newTime;
        addAlert('info', '快进', '已快进 ' + skipTime + ' 秒');
    });
    
    document.getElementById('btnLoop').addEventListener('click', function() {
        recordInteraction();
        mainVideo.loop = !mainVideo.loop;
        this.classList.toggle('active');
        if (mainVideo.loop) {
            addAlert('success', '循环播放', '已开启循环播放');
        } else {
            addAlert('info', '循环播放', '已关闭循环播放');
        }
    });
    
    var currentSpeed = 1;
    document.querySelectorAll('.speed-option').forEach(function(opt) {
        opt.addEventListener('click', function() {
            recordInteraction();
            currentSpeed = parseFloat(this.dataset.speed);
            mainVideo.playbackRate = currentSpeed;
            document.getElementById('btnSpeed').textContent = currentSpeed + 'x';
            document.querySelectorAll('.speed-option').forEach(function(o) { o.classList.remove('active'); });
            this.classList.add('active');
            addAlert('info', '播放速度', '已切换为 ' + currentSpeed + 'x');
        });
    });
    
    document.getElementById('settingsMute').addEventListener('click', function() {
        recordInteraction();
        mainVideo.muted = !mainVideo.muted;
        if (mainVideo.muted) {
            addAlert('info', '设置', '已静音');
        } else {
            addAlert('info', '设置', '已取消静音');
        }
    });
    
    document.getElementById('settingsQuality').addEventListener('click', function() {
        addAlert('info', '画质设置', '当前为自动画质');
    });
    
    document.getElementById('settingsSubtitle').addEventListener('click', function() {
        addAlert('info', '字幕设置', '暂无字幕文件');
    });

    document.getElementById('btnFullscreen').addEventListener('click', function() {
        var wrapper = document.getElementById('mainVideoWrapper');
        if (wrapper.requestFullscreen) wrapper.requestFullscreen();
        else if (wrapper.webkitRequestFullscreen) wrapper.webkitRequestFullscreen();
    });

    var bgMusicPlaylist = [];
    var bgMusicIndex = 0;
    var bgMusicAudio = null;
    var bgMusicPlaying = false;

    function loadBgMusicList() {
        var xhr = new XMLHttpRequest();
        xhr.open('GET', 'api/get_audio_list.php', true);
        xhr.onload = function() {
            if (xhr.status === 200) {
                try {
                    var resp = JSON.parse(xhr.responseText);
                    if (resp.success && resp.data.length > 0) {
                        bgMusicPlaylist = resp.data.map(function(item) { return item.storage_path; });
                        bgMusicIndex = 0;
                    }
                } catch(e) {}
            }
        };
        xhr.onerror = function() {};
        xhr.send();
    }
    loadBgMusicList();

    function playBgMusic() {
        if (bgMusicPlaylist.length === 0) return;
        if (bgMusicAudio) {
            bgMusicAudio.pause();
            bgMusicAudio = null;
        }
        bgMusicAudio = new Audio(bgMusicPlaylist[bgMusicIndex]);
        bgMusicAudio.volume = 0.4;
        bgMusicAudio.addEventListener('ended', function() {
            bgMusicIndex = (bgMusicIndex + 1) % bgMusicPlaylist.length;
            playBgMusic();
        });
        bgMusicAudio.play().catch(function() {});
    }

    document.getElementById('btnBgMusic').addEventListener('click', function() {
        if (bgMusicPlaylist.length === 0) {
            document.getElementById('bgMusicInput').click();
            return;
        }
        if (bgMusicPlaying) {
            if (bgMusicAudio) bgMusicAudio.pause();
            bgMusicPlaying = false;
            document.getElementById('bgMusicIcon').className = 'fas fa-music';
            this.style.color = '';
            addAlert('info', '背景音乐', '已暂停');
        } else {
            playBgMusic();
            bgMusicPlaying = true;
            document.getElementById('bgMusicIcon').className = 'fas fa-music pulsing';
            this.style.color = '#d4a853';
            addAlert('info', '背景音乐', '播放中 (' + bgMusicPlaylist.length + '首)');
        }
    });

    function uploadAudioFile(file, callback) {
        var formData = new FormData();
        formData.append('audio', file);
        formData.append('audio_name', file.name.replace(/\.[^/.]+$/, ''));
        var xhr = new XMLHttpRequest();
        xhr.open('POST', 'api/upload_audio.php', true);
        xhr.onload = function() {
            if (xhr.status === 200) {
                try {
                    var resp = JSON.parse(xhr.responseText);
                    if (resp.success) {
                        callback(null, resp.data.storage_path);
                    } else {
                        callback(resp.message);
                    }
                } catch(e) {
                    callback('响应格式错误');
                }
            } else {
                callback('上传失败，HTTP ' + xhr.status);
            }
        };
        xhr.onerror = function() { callback('网络错误'); };
        xhr.timeout = 60000;
        xhr.send(formData);
    }

    document.getElementById('bgMusicInput').addEventListener('change', function(e) {
        var files = e.target.files;
        if (!files || files.length === 0) return;
        bgMusicPlaylist = [];
        bgMusicIndex = 0;
        if (bgMusicAudio) {
            bgMusicAudio.pause();
            bgMusicAudio = null;
        }
        var audioFiles = [];
        var audioExtensions = ['.mp3', '.wav', '.ogg', '.m4a', '.aac', '.flac', '.wma'];
        for (var i = 0; i < files.length; i++) {
            var name = files[i].name.toLowerCase();
            if (files[i].type.startsWith('audio/') || audioExtensions.some(function(ext) { return name.endsWith(ext); })) {
                audioFiles.push(files[i]);
            }
        }
        if (audioFiles.length === 0) {
            addAlert('warning', '背景音乐', '未找到音频文件');
            return;
        }
        addAlert('info', '背景音乐', '正在上传 ' + audioFiles.length + ' 个文件...');
        var uploadedCount = 0;
        var btn = document.getElementById('btnBgMusic');
        audioFiles.forEach(function(file) {
            uploadAudioFile(file, function(err, path) {
                if (!err) {
                    bgMusicPlaylist.push(path);
                }
                uploadedCount++;
                if (uploadedCount === audioFiles.length) {
                    if (bgMusicPlaylist.length > 0) {
                        playBgMusic();
                        bgMusicPlaying = true;
                        document.getElementById('bgMusicIcon').className = 'fas fa-music pulsing';
                        btn.style.color = '#d4a853';
                        addAlert('success', '背景音乐', '成功上传 ' + bgMusicPlaylist.length + ' 首，循环播放中');
                    } else {
                        addAlert('warning', '背景音乐', '所有文件上传失败');
                    }
                }
            });
        });
        e.target.value = '';
    });

    mainVideo.addEventListener('play', function() {
        showPauseBtn();
        overlayCenter.style.opacity = '0';
    });
    mainVideo.addEventListener('pause', function() {
        showResumeBtn();
        if (videoMode !== 'library') {
            overlayCenter.style.opacity = '1';
            overlayCenter.style.display = '';
        }
    });
    mainVideo.addEventListener('timeupdate', updateVideoProgress);
    mainVideo.addEventListener('waiting', function() {
        showVideoLoading();
    });
    mainVideo.addEventListener('playing', function() {
        hideVideoLoading();
    });
    mainVideo.addEventListener('canplay', function() {
        hideVideoLoading();
    });
    mainVideo.addEventListener('error', function() {
        hideVideoLoading();
        addAlert('warning', '视频播放', '视频加载出错，请检查视频文件');
        if (videoMode === 'library') {
            setVideoMode('timeline');
            overlayCenter.style.display = '';
            overlayCenter.style.opacity = '1';
        }
    });
    mainVideo.addEventListener('ended', function() {
        if (TimelineManager.isRunning && !TimelineManager.isPaused) {
            var elapsed = TimelineManager.getElapsed();
            var phase = TimelineManager.getPhaseAtTime(elapsed);
            if (phase && TimelineManager.phaseVideoMap[phase.code]) {
                mainVideo.currentTime = 0;
                mainVideo.play().catch(function() {});
            } else {
                showResumeBtn();
                overlayCenter.style.opacity = '1';
                overlayCenter.style.display = '';
            }
        } else if (videoMode === 'library') {
            showResumeBtn();
            mainVideo.currentTime = 0;
        } else {
            showResumeBtn();
            overlayCenter.style.opacity = '1';
            overlayCenter.style.display = '';
        }
    });

    document.getElementById('progressTrack').addEventListener('click', function(e) {
        if (!mainVideo.duration) return;
        var rect = this.getBoundingClientRect();
        var percent = (e.clientX - rect.left) / rect.width;
        mainVideo.currentTime = percent * mainVideo.duration;
    });

    // ==================== 时间线控制按钮 ====================
    document.getElementById('btnTimelineStart').addEventListener('click', function() {
        TimelineManager.start();
    });
    document.getElementById('btnTimelinePause').addEventListener('click', function() {
        TimelineManager.pause();
    });
    document.getElementById('btnTimelineStop').addEventListener('click', function() {
        if (!confirm('确定要停止监控吗？当前进度将清空。')) return;
        TimelineManager.stop();
        mainVideo.pause();
        mainVideo.currentTime = 0;
        showResumeBtn();
        overlayCenter.style.opacity = '1';
        overlayCenter.style.display = '';
        progressFilled.style.width = '0%';
        progressHandle.style.left = '0%';
        timeDisplay.textContent = '00:00 / ' + formatTime(mainVideo.duration || 0);
        currentPhase = null;
        renderTimeline();
        updateTeamWindows(null);
        teamStatuses.forEach(function(team) {
            updateTeamWindowProgress(team.code, 0);
        });
        if (typeof EmergencyManager !== 'undefined') {
            EmergencyManager._emergencyTriggered = false;
            EmergencyManager.stop();
        }
    });
    document.getElementById('btnTimelineCalibrate').addEventListener('click', function() {
        TimelineManager.calibrate();
    });

    // ==================== 视频库管理 ====================

    function loadVideoList(type) {
        apiCall('GET', 'video/assets', { type: type, active_only: true }, function(err, resp) {
            var listId = type === 'coordination' ? 'coordinationVideoList' : (type === 'communication' ? 'communicationVideoList' : 'emergencyVideoList');
            var container = document.getElementById(listId);
            if (err || !resp.success) {
                container.innerHTML = '<p style="text-align:center;color:#999;font-size:12px;">加载失败</p>';
                return;
            }
            var videoData = resp.data;
            if (videoData && videoData.data) videoData = videoData.data;
            if (!videoData || videoData.length === 0) {
                container.innerHTML = '<p style="text-align:center;color:#999;font-size:12px;">暂无视频，点击上方按钮上传</p>';
                if (type === currentVideoTab) {
                    currentVideoList = [];
                    currentVideoIndex = -1;
                    updateNavButtons();
                }
                return;
            }
            if (type === currentVideoTab) {
                currentVideoList = videoData;
                if (currentVideoId) {
                    currentVideoIndex = currentVideoList.findIndex(function(v) { return v.video_id === currentVideoId; });
                }
                updateNavButtons();
            }
            var html = '';
            videoData.forEach(function(video) {
                var isSelected = currentVideoId === video.video_id ? ' active' : '';
                html += '<div class="video-card' + isSelected + '" data-video-id="' + escapeHtml(video.video_id) + '" data-video-type="' + escapeHtml(type) + '">' +
                    '<div class="thumb">🎬</div>' +
                    '<div class="info">' +
                    '<div class="name">' + escapeHtml(video.video_name) + '</div>' +
                    '<div class="meta">' + escapeHtml(video.duration) + '秒 | ' + (video.file_size ? (video.file_size/1024/1024).toFixed(1) + 'MB' : '') + '</div>' +
                    '</div>' +
                    '<div class="actions">' +
                    '<button class="select-btn" data-video-id="' + escapeHtml(video.video_id) + '" data-video-type="' + escapeHtml(type) + '" title="选择"><i class="fas fa-check"></i></button>' +
                    '<button class="bind-btn" data-video-id="' + escapeHtml(video.video_id) + '" data-video-type="' + escapeHtml(type) + '" title="绑定到当前环节" style="background:rgba(52,152,219,0.1);color:#3498db;border:1px solid rgba(52,152,219,0.3);width:28px;height:28px;border-radius:6px;cursor:pointer;font-size:11px;display:flex;align-items:center;justify-content:center;transition:all 0.2s;"><i class="fas fa-link"></i></button>' +
                    '<button class="delete-btn" data-video-id="' + escapeHtml(video.video_id) + '" title="删除"><i class="fas fa-trash"></i></button>' +
                    '</div>' +
                    '</div>';
            });
            container.innerHTML = html;
        });
    }

    function selectVideo(videoId, type) {
        if (!videoId) return;
        recordInteraction();
        currentVideoId = videoId;
        currentVideoTab = type;
        document.querySelectorAll('.video-card').forEach(function(c) { c.classList.remove('active'); });
        var card = document.querySelector('.video-card[data-video-id="' + videoId + '"]');
        if (card) card.classList.add('active');
        if (TimelineManager.isRunning) {
            TimelineManager.pause();
        }
        setVideoMode('library');
        showVideoLoading();
        apiCall('GET', 'video/play/' + videoId, null, function(err, resp) {
            if (err) {
                hideVideoLoading();
                setVideoMode('timeline');
                addAlert('warning', '视频加载失败', err.message);
                return;
            }
            var url = null;
            if (resp && resp.relative_url) {
                url = resp.relative_url;
            } else if (resp && resp.data && resp.data.url) {
                url = resp.data.url;
            } else if (resp && resp.url) {
                url = resp.url;
            }
            if (!resp.success || !url) {
                hideVideoLoading();
                setVideoMode('timeline');
                addAlert('warning', '视频加载失败', resp.message || '未获取到视频地址');
                return;
            }
            loadVideoToPlayer(url, type, 'library');
            if (currentVideoList.length > 0) {
                currentVideoIndex = currentVideoList.findIndex(function(v) { return v.video_id === videoId; });
                updateNavButtons();
            }
        });
    }
    
    function updateNavButtons() {
        var prevBtn = document.getElementById('btnPrevVideo');
        var nextBtn = document.getElementById('btnNextVideo');
        if (!prevBtn || !nextBtn) return;
        
        if (currentVideoList.length < 2) {
            prevBtn.disabled = true;
            nextBtn.disabled = true;
            return;
        }
        
        prevBtn.disabled = currentVideoIndex <= 0;
        nextBtn.disabled = currentVideoIndex >= currentVideoList.length - 1;
    }
    
    function playNextVideo() {
        if (currentVideoList.length < 2 || currentVideoIndex >= currentVideoList.length - 1) return;
        recordInteraction();
        var nextVideo = currentVideoList[currentVideoIndex + 1];
        selectVideo(nextVideo.video_id, currentVideoTab);
    }
    
    function playPrevVideo() {
        if (currentVideoList.length < 2 || currentVideoIndex <= 0) return;
        recordInteraction();
        var prevVideo = currentVideoList[currentVideoIndex - 1];
        selectVideo(prevVideo.video_id, currentVideoTab);
    }
    
    function onVideoEnded() {
        if (autoPlayEnabled && currentVideoList.length > 1) {
            playNextVideo();
        }
    }
    
    function recordInteraction() {
        lastInteractionTime = Date.now();
        autoPlayEnabled = false;
        if (resumeAutoPlayTimer) {
            clearTimeout(resumeAutoPlayTimer);
            resumeAutoPlayTimer = null;
        }
        scheduleResumeAutoPlay();
    }
    
    function scheduleResumeAutoPlay() {
        resumeAutoPlayTimer = setTimeout(function() {
            autoPlayEnabled = true;
            addAlert('info', '自动轮播', '已恢复自动轮播');
        }, AUTO_PLAY_RESUME_DELAY);
    }

    function bindVideoToPhase(videoId, phaseCode) {
        if (!phaseCode) { alert('请先选择一个统筹环节'); return; }
        apiCall('GET', 'video/play/' + videoId, null, function(err, resp) {
            var url = null;
            if (resp && resp.relative_url) {
                url = resp.relative_url;
            } else if (resp && resp.data && resp.data.url) {
                url = resp.data.url;
            } else if (resp && resp.url) {
                url = resp.url;
            }
            if (err || !resp.success || !url) { alert('获取视频播放地址失败'); return; }
            TimelineManager.bindVideo(phaseCode, url, videoId);
            renderTimeline();
            var phase = managerPhases.find(function(p) { return p.code === phaseCode; });
            if (phase) updateInfoPanel(phase);
            alert('已将视频绑定到环节: ' + (phase ? phase.name : phaseCode));
        });
    }

    function deleteVideo(videoId) {
        if (!confirm('确定要删除这个视频吗？')) return;
        apiCall('DELETE', 'video/asset/' + videoId, null, function(err, resp) {
            if (err) { alert('删除失败: ' + err.message); return; }
            var success = resp.success || (resp.data && resp.data.success);
            if (!success) { alert(resp.message || '删除失败'); return; }
            if (currentVideoId === videoId) { currentVideoId = null; managerVideoUrl = null; }
            Object.keys(TimelineManager.phaseVideoMap).forEach(function(key) {
                if (TimelineManager.phaseVideoMap[key] && TimelineManager.phaseVideoMap[key].videoId === videoId) {
                    TimelineManager.unbindVideo(key);
                }
            });
            renderTimeline();
            loadVideoList(currentVideoTab);
        });
    }

    document.addEventListener('click', function(e) {
        var selectBtn = e.target.closest('.select-btn');
        if (selectBtn) {
            var vid = selectBtn.getAttribute('data-video-id');
            var vtype = selectBtn.getAttribute('data-video-type');
            if (vid) selectVideo(vid, vtype);
            return;
        }
        var bindBtn = e.target.closest('.bind-btn');
        if (bindBtn) {
            var vid = bindBtn.getAttribute('data-video-id');
            if (vid && currentPhase) bindVideoToPhase(vid, currentPhase);
            else alert('请先在时间轴上选择一个统筹环节');
            return;
        }
        var card = e.target.closest('.video-card');
        if (card && !e.target.closest('.delete-btn') && !e.target.closest('.select-btn') && !e.target.closest('.bind-btn')) {
            var vid = card.getAttribute('data-video-id');
            var vtype = card.getAttribute('data-video-type') || currentVideoTab;
            if (vid) selectVideo(vid, vtype);
            return;
        }
        var delBtn = e.target.closest('.delete-btn');
        if (delBtn) {
            var vid = delBtn.getAttribute('data-video-id');
            if (vid) deleteVideo(vid);
        }
    });

    document.querySelectorAll('.lib-tab').forEach(function(btn) {
        btn.addEventListener('click', function() {
            document.querySelectorAll('.lib-tab').forEach(function(b) { b.classList.remove('active'); });
            document.querySelectorAll('.library-content').forEach(function(c) { c.style.display = 'none'; });
            this.classList.add('active');
            var lib = this.dataset.lib;
            currentVideoTab = lib;
            var libMap = { coordination: 'Coordination', communication: 'Communication', emergency: 'Emergency', image: 'Image' };
            document.getElementById('libContent' + libMap[lib]).style.display = '';
            if (lib === 'image') {
                loadImageList();
            } else {
                loadVideoList(lib);
            }
        });
    });

    function uploadVideo(type) {
        var inputId = type === 'coordination' ? 'fileInputCoordination' : (type === 'communication' ? 'fileInputCommunication' : 'fileInputEmergency');
        document.getElementById(inputId).click();
    }
    document.getElementById('btnUploadCoordination').addEventListener('click', function() { uploadVideo('coordination'); });
    document.getElementById('btnUploadCommunication').addEventListener('click', function() { uploadVideo('communication'); });
    document.getElementById('btnUploadEmergency').addEventListener('click', function() { uploadVideo('emergency'); });
    document.getElementById('fileInputCoordination').addEventListener('change', function(e) { handleFileUpload(e, 'coordination'); });
    document.getElementById('fileInputCommunication').addEventListener('change', function(e) { handleFileUpload(e, 'communication'); });
    document.getElementById('fileInputEmergency').addEventListener('change', function(e) { handleFileUpload(e, 'emergency'); });

    function handleFileUpload(event, type) {
        var files = event.target.files;
        if (!files || files.length === 0) return;
        
        var uploadedCount = 0;
        var failedCount = 0;
        var totalCount = files.length;
        var uploadResults = [];
        
        addAlert('info', '批量上传', '开始上传 ' + totalCount + ' 个视频文件...');
        
        function uploadNext(index) {
            if (index >= files.length) {
                var msg = '批量上传完成！成功: ' + uploadedCount + ' 个，失败: ' + failedCount + ' 个';
                if (uploadedCount > 0) {
                    addAlert('success', '批量上传', msg);
                    loadVideoList(type);
                } else {
                    addAlert('warning', '批量上传', msg);
                }
                event.target.value = '';
                return;
            }
            
            var file = files[index];
            var fileSizeMB = (file.size / (1024 * 1024)).toFixed(2);
            
            if (fileSizeMB > 500) {
                uploadResults.push({ name: file.name, status: 'fail', reason: '文件大小超过限制（最大500MB）' });
                failedCount++;
                uploadNext(index + 1);
                return;
            }
            
            var formData = new FormData();
            formData.append('video', file);
            formData.append('video_type', type);
            formData.append('video_name', file.name.replace(/\.[^/.]+$/, ''));
            
            var xhr = new XMLHttpRequest();
            xhr.open('POST', 'api/upload_video_php73.php', true);
            
            xhr.onload = function() {
                if (xhr.status === 200) {
                    try {
                        var resp = JSON.parse(xhr.responseText);
                        if (resp.success) {
                            uploadResults.push({ name: file.name, status: 'success' });
                            uploadedCount++;
                        } else {
                            uploadResults.push({ name: file.name, status: 'fail', reason: resp.message || '未知错误' });
                            failedCount++;
                        }
                    } catch(e) {
                        uploadResults.push({ name: file.name, status: 'fail', reason: '响应格式错误' });
                        failedCount++;
                    }
                } else {
                    uploadResults.push({ name: file.name, status: 'fail', reason: 'HTTP ' + xhr.status });
                    failedCount++;
                }
                uploadNext(index + 1);
            };
            
            xhr.onerror = function() {
                uploadResults.push({ name: file.name, status: 'fail', reason: '网络错误' });
                failedCount++;
                uploadNext(index + 1);
            };
            
            xhr.ontimeout = function() {
                uploadResults.push({ name: file.name, status: 'fail', reason: '上传超时' });
                failedCount++;
                uploadNext(index + 1);
            };
            
            xhr.timeout = 300000;
            xhr.send(formData);
        }
        
        uploadNext(0);
    }

    // ==================== 任务卡片管理 ====================
    function loadImageList() {
        apiCall('GET', 'image/assets', null, function(err, resp) {
            var container = document.getElementById('imageList');
            if (err || !resp.success) {
                container.innerHTML = '<p style="text-align:center;color:#999;font-size:12px;">加载失败</p>';
                return;
            }
            var images = resp.data;
            if (!images || images.length === 0) {
                container.innerHTML = '<p style="text-align:center;color:#999;font-size:12px;">暂无图片，点击上方按钮上传</p>';
                return;
            }
            var html = '';
            images.forEach(function(img) {
                html += '<div class="image-card" data-file="' + escapeHtml(img.file_name) + '" data-url="' + escapeHtml(img.url) + '" title="点击查看大图">' +
                    '<img src="' + escapeHtml(img.url) + '" alt="' + escapeHtml(img.file_name) + '" loading="lazy">' +
                    '<button class="image-delete" data-file="' + escapeHtml(img.file_name) + '" title="删除图片"><i class="fas fa-times"></i></button>' +
                    '</div>';
            });
            container.innerHTML = html;
        });
    }

    document.getElementById('btnUploadImage').addEventListener('click', function() {
        document.getElementById('fileInputImage').click();
    });

    document.getElementById('fileInputImage').addEventListener('change', function(e) {
        var files = e.target.files;
        if (!files || files.length === 0) return;

        var uploadedCount = 0;
        var failedCount = 0;
        var totalCount = files.length;

        addAlert('info', '图片上传', '开始上传 ' + totalCount + ' 张图片...');

        function uploadNext(index) {
            if (index >= files.length) {
                var msg = '图片上传完成！成功: ' + uploadedCount + ' 张，失败: ' + failedCount + ' 张';
                if (uploadedCount > 0) {
                    addAlert('success', '图片上传', msg);
                    loadImageList();
                } else {
                    addAlert('warning', '图片上传', msg);
                }
                e.target.value = '';
                return;
            }

            var file = files[index];
            var isImage = /^image\/(jpeg|png|gif|webp)$/.test(file.type);
            var fileSizeMB = (file.size / (1024 * 1024)).toFixed(2);

            if (!isImage) {
                failedCount++;
                addAlert('warning', '图片上传', file.name + ' 不是支持的图片格式');
                uploadNext(index + 1);
                return;
            }
            if (fileSizeMB > 10) {
                failedCount++;
                addAlert('warning', '图片上传', file.name + ' 超过10MB限制');
                uploadNext(index + 1);
                return;
            }

            var formData = new FormData();
            formData.append('file', file);

            var xhr = new XMLHttpRequest();
            xhr.open('POST', 'api/api_router.php?path=image/upload', true);
            xhr.onload = function() {
                if (xhr.status === 200) {
                    try {
                        var resp = JSON.parse(xhr.responseText);
                        if (resp.success) {
                            uploadedCount++;
                        } else {
                            failedCount++;
                            addAlert('warning', '图片上传', file.name + ' 上传失败: ' + (resp.message || '未知错误'));
                        }
                    } catch(err2) {
                        failedCount++;
                        addAlert('warning', '图片上传', file.name + ' 服务器响应异常');
                        console.error('图片上传JSON解析失败:', xhr.responseText.substring(0, 200), err2);
                    }
                } else {
                    failedCount++;
                    addAlert('warning', '图片上传', file.name + ' 请求失败 (HTTP ' + xhr.status + ')');
                    console.error('图片上传HTTP错误:', xhr.status, xhr.responseText.substring(0, 200));
                }
                uploadNext(index + 1);
            };
            xhr.onerror = function() {
                failedCount++;
                addAlert('warning', '图片上传', file.name + ' 网络请求失败，请检查网络连接');
                uploadNext(index + 1);
            };
            xhr.timeout = 60000;
            xhr.send(formData);
        }

        uploadNext(0);
    });

    document.getElementById('imageList').addEventListener('click', function(e) {
        var delBtn = e.target.closest('.image-delete');
        if (delBtn) {
            e.stopPropagation();
            var fileName = delBtn.getAttribute('data-file');
            if (!fileName) return;
            if (!confirm('确定要删除这张图片吗？此操作无法撤销。')) return;
            apiCall('DELETE', 'image/asset', { file: fileName }, function(err, resp) {
                if (err || !resp.success) {
                    alert('删除失败: ' + ((err && err.message) || (resp && resp.message) || '未知错误'));
                    return;
                }
                loadImageList();
                alert('图片删除成功');
            });
            return;
        }
        var card = e.target.closest('.image-card');
        if (card) {
            var url = card.getAttribute('data-url');
            if (!url) return;
            document.getElementById('lightboxImg').src = url;
            document.getElementById('imageLightbox').style.display = 'flex';
        }
    });

    document.getElementById('imageLightbox').addEventListener('click', function(e) {
        if (e.target === this || e.target.id === 'lightboxClose') {
            this.style.display = 'none';
        }
    });

    // ==================== 任务管理 ====================
    var taskList = [];
    var taskIdCounter = 0;

    document.getElementById('btnAddTask').addEventListener('click', function() {
        document.getElementById('taskForm').style.display = 'flex';
    });
    document.getElementById('btnCancelTask').addEventListener('click', function() {
        document.getElementById('taskForm').style.display = 'none';
    });
    document.getElementById('btnSubmitTask').addEventListener('click', function() {
        var team = document.getElementById('taskTeam').value;
        var name = document.getElementById('taskName').value.trim();
        var deadline = document.getElementById('taskDeadline').value;
        var priority = document.getElementById('taskPriority').value;
        if (!name) { alert('请输入任务内容'); return; }
        taskIdCounter++;
        taskList.push({
            id: taskIdCounter,
            team: team,
            name: name,
            deadline: deadline,
            priority: priority,
            completed: false,
            createdAt: new Date().toISOString()
        });
        document.getElementById('taskForm').style.display = 'none';
        document.getElementById('taskName').value = '';
        document.getElementById('taskDeadline').value = '';
        renderTaskList();
        addAlert('info', '新建任务', '已为' + team + '分配任务: ' + name);
    });

    document.getElementById('btnAutoAssign').addEventListener('click', function() {
        document.getElementById('autoAssignForm').style.display = 'flex';
    });
    document.getElementById('btnCancelAuto').addEventListener('click', function() {
        document.getElementById('autoAssignForm').style.display = 'none';
    });
    document.getElementById('btnSubmitAuto').addEventListener('click', function() {
        var desc = document.getElementById('autoTaskDesc').value.trim();
        var deadline = document.getElementById('autoTaskDeadline').value;
        var priority = document.getElementById('autoTaskPriority').value;
        if (!desc) { alert('请输入任务描述'); return; }
        var selectedTeams = [];
        document.querySelectorAll('input[name="autoTeam"]:checked').forEach(function(cb) {
            selectedTeams.push(cb.value);
        });
        if (selectedTeams.length === 0) { alert('请至少选择一个团队'); return; }
        var assignedTeam = selectedTeams[Math.floor(Math.random() * selectedTeams.length)];
        taskIdCounter++;
        taskList.push({
            id: taskIdCounter,
            team: assignedTeam,
            name: desc,
            deadline: deadline,
            priority: priority,
            completed: false,
            autoAssigned: true,
            createdAt: new Date().toISOString()
        });
        document.getElementById('autoAssignForm').style.display = 'none';
        document.getElementById('autoTaskDesc').value = '';
        document.getElementById('autoTaskDeadline').value = '';
        renderTaskList();
        addAlert('info', '智能分配', '已自动将任务分配给' + assignedTeam + ': ' + desc);
    });

    function renderTaskList() {
        var container = document.getElementById('tasksList');
        if (taskList.length === 0) {
            container.innerHTML = '<div class="no-tasks">暂无任务</div>';
            return;
        }
        var html = '';
        taskList.forEach(function(task) {
            var priorityLabel = task.priority === 'high' ? '高' : (task.priority === 'medium' ? '中' : '低');
            html += '<div class="task-item ' + task.priority + (task.completed ? ' completed' : '') + '">' +
                '<div class="task-header">' +
                '<span class="task-name">' + escapeHtml(task.name) + (task.autoAssigned ? ' <span style="font-size:10px;color:#9b59b6;">🤖自动</span>' : '') + (task.delayed ? ' <span style="font-size:10px;color:#e67e22;">⏰延迟</span>' : '') + '</span>' +
                '<span class="task-priority ' + task.priority + '">' + priorityLabel + '</span>' +
                '</div>' +
                '<div class="task-meta">' +
                '<span class="task-team">' + escapeHtml(getTeamName(task.team)) + '</span>' +
                '<span class="task-deadline">' + (task.deadline || '无截止时间') + '</span>' +
                '</div>';
            if (!task.completed) {
                html += '<div class="task-actions">' +
                    '<button class="task-action-btn complete" data-task-id="' + task.id + '">完成</button>' +
                    '<button class="task-action-btn delay" data-task-id="' + task.id + '">延迟</button>' +
                    '<button class="task-action-btn delete" data-task-id="' + task.id + '">删除</button>' +
                    '</div>';
            }
            html += '</div>';
        });
        container.innerHTML = html;
        container.querySelectorAll('.task-action-btn.complete').forEach(function(btn) {
            btn.addEventListener('click', function() {
                completeTask(parseInt(this.dataset.taskId));
            });
        });
        container.querySelectorAll('.task-action-btn.delay').forEach(function(btn) {
            btn.addEventListener('click', function() {
                delayTask(parseInt(this.dataset.taskId));
            });
        });
        container.querySelectorAll('.task-action-btn.delete').forEach(function(btn) {
            btn.addEventListener('click', function() {
                deleteTask(parseInt(this.dataset.taskId));
            });
        });
    }

    function completeTask(taskId) {
        var task = taskList.find(function(t) { return t.id === taskId; });
        if (task) {
            task.completed = true;
            renderTaskList();
            addAlert('info', '任务完成', task.team + '已完成: ' + task.name);
        }
    }

    function delayTask(taskId) {
        var task = taskList.find(function(t) { return t.id === taskId; });
        if (task) {
            task.delayed = true;
            task.delayedAt = new Date().toLocaleTimeString('zh-CN', { hour12: false });
            renderTaskList();
            addAlert('warning', '任务延迟', task.team + '的任务已延迟: ' + task.name);
        }
    }

    function deleteTask(taskId) {
        if (!confirm('确定要删除此任务吗？')) return;
        taskList = taskList.filter(function(t) { return t.id !== taskId; });
        renderTaskList();
    }

    // ==================== 预警中心 ====================
    var alerts = [];
    var alertIdCounter = 0;

    function addAlert(type, title, desc) {
        alertIdCounter++;
        alerts.unshift({ id: alertIdCounter, type: type, title: title, desc: desc, time: new Date().toLocaleTimeString() });
        if (alerts.length > 20) alerts.pop();
        renderAlerts();
    }

    var alertedPhases = {};

    function checkAndGenerateAlerts(phase) {
        if (phase.isTransition) return;
        var progress = TimelineManager.getPhaseProgress(phase.code);
        if (progress > 50 && progress < 55 && !alertedPhases[phase.code + '_50']) {
            alertedPhases[phase.code + '_50'] = true;
            addAlert('info', '进度提醒', phase.name + '已完成50%，请确认后续团队准备就绪。');
        }
        if (progress > 90 && !alertedPhases[phase.code + '_90']) {
            alertedPhases[phase.code + '_90'] = true;
            addAlert('warning', '即将完成', phase.name + '即将完成，请下一环节团队做好准备。');
        }
    }

    function renderAlerts() {
        var container = document.getElementById('alertsList');
        var badge = document.getElementById('alertBadge');
        var urgentAlerts = alerts.filter(function(a) { return a.type === 'warning'; });
        badge.textContent = urgentAlerts.length;

        if (alerts.length === 0) {
            container.innerHTML = '<div class="no-alerts">暂无预警 ✅</div>';
            return;
        }
        var html = '';
        alerts.forEach(function(alert) {
            html += '<div class="alert-item ' + alert.type + '">' +
                '<div class="alert-header">' +
                '<span class="alert-title">' + escapeHtml(alert.title) + '</span>' +
                '<span class="alert-time">' + alert.time + '</span>' +
                '</div>' +
                '<div class="alert-desc">' + escapeHtml(alert.desc) + '</div>' +
                '</div>';
        });
        container.innerHTML = html;
    }

    // ==================== 卡点提醒管理器 ====================
    var CheckpointReminder = {
        _remindedBefore: {},
        _remindedOverdue: {},
        _remindedSwitch: {},
        _log: [],
        _soundEnabled: true,
        _popupEnabled: true,
        _voiceEnabled: true,
        _leadTime: 180,
        _delayThreshold: 180,

        init: function() {
            var self = this;
            var leadSelect = document.getElementById('reminderLeadTime');
            var delaySelect = document.getElementById('delayAlertThreshold');
            var soundCheck = document.getElementById('reminderSound');
            var popupCheck = document.getElementById('reminderPopup');
            var voiceCheck = document.getElementById('reminderVoice');
            if (leadSelect) {
                leadSelect.value = localStorage.getItem('rmLeadTime') || 180;
                this._leadTime = parseInt(leadSelect.value);
                leadSelect.addEventListener('change', function() {
                    self._leadTime = parseInt(this.value);
                    localStorage.setItem('rmLeadTime', this.value);
                });
            }
            if (delaySelect) {
                delaySelect.value = localStorage.getItem('rmDelayThreshold') || 180;
                this._delayThreshold = parseInt(delaySelect.value);
                delaySelect.addEventListener('change', function() {
                    self._delayThreshold = parseInt(this.value);
                    localStorage.setItem('rmDelayThreshold', this.value);
                });
            }
            if (soundCheck) {
                soundCheck.checked = localStorage.getItem('rmSound') !== 'off';
                this._soundEnabled = soundCheck.checked;
                soundCheck.addEventListener('change', function() {
                    self._soundEnabled = this.checked;
                    localStorage.setItem('rmSound', this.checked ? 'on' : 'off');
                });
            }
            if (popupCheck) {
                popupCheck.checked = localStorage.getItem('rmPopup') !== 'off';
                this._popupEnabled = popupCheck.checked;
                popupCheck.addEventListener('change', function() {
                    self._popupEnabled = this.checked;
                    localStorage.setItem('rmPopup', this.checked ? 'on' : 'off');
                });
            }
            if (voiceCheck) {
                voiceCheck.checked = localStorage.getItem('rmVoice') !== 'off';
                this._voiceEnabled = voiceCheck.checked;
                voiceCheck.addEventListener('change', function() {
                    self._voiceEnabled = this.checked;
                    localStorage.setItem('rmVoice', this.checked ? 'on' : 'off');
                });
            }
            document.getElementById('btnTestReminder').addEventListener('click', function() {
                self.testReminder();
            });
        },

        testReminder: function() {
            if (!TimelineManager.phases || !TimelineManager.phases.length) {
                addAlert('info', '测试提醒', '请先启动时间线');
                return;
            }
            var next = null;
            var elapsed = TimelineManager.getElapsed();
            for (var i = 0; i < TimelineManager.phases.length; i++) {
                var p = TimelineManager.phases[i];
                if (p.startTime > elapsed && !p.isTransition) {
                    next = p;
                    break;
                }
            }
            if (!next) next = TimelineManager.phases[0];
            var phaseName = this._extractName(next.name);
            var voiceText = '测试提醒，' + phaseName + '即将开始，请各团队做好准备。';
            this._fire('before', next, '测试提醒 - 即将开始');
            addAlert('info', '⏰ 测试提醒', '测试: ' + next.name + ' 即将开始');
            var data = {
                type: 'checkpointReminder',
                payload: {
                    reminderType: 'before',
                    phaseName: next.name,
                    phaseCode: next.code,
                    message: voiceText,
                    requireVoice: true,
                    timestamp: Date.now(),
                    isTest: true
                }
            };
            localStorage.setItem('checkpointReminder', JSON.stringify(data.payload));
            if (screenWindow && !screenWindow.closed) {
                try { screenWindow.postMessage(data, '*'); } catch(e) {}
            }
            addAlert('success', '🎙️ 语音播报', '已向数字人发送播报: ' + voiceText);
        },

        check: function(elapsed) {
            if (!TimelineManager.isRunning || TimelineManager.isPaused) return;
            var phases = TimelineManager.phases;
            for (var i = 0; i < phases.length; i++) {
                var phase = phases[i];
                if (phase.isTransition) continue;
                var timeToStart = phase.startTime - elapsed;
                var key = 'before_' + phase.code;
                if (timeToStart > 0 && timeToStart <= this._leadTime && !this._remindedBefore[key]) {
                    this._remindedBefore[key] = true;
                    this._fire('before', phase, '即将开始');
                }
                if (phase.code === currentPhase) {
                    var overdue = elapsed - phase.endTime;
                    var overKey = 'overdue_' + phase.code;
                    if (overdue > this._delayThreshold && !this._remindedOverdue[overKey]) {
                        this._remindedOverdue[overKey] = true;
                        this._fire('overdue', phase, '已超时');
                    }
                }
            }
        },

        onPhaseSwitched: function(phase) {
            var key = 'switch_' + phase.code;
            if (this._remindedSwitch[key]) return;
            this._remindedSwitch[key] = true;
            this._fire('switch', phase, '开始执行');
        },

        _fire: function(type, phase, label) {
            var title = '';
            var icon = '';
            var voiceText = '';
            switch (type) {
                case 'before':
                    title = '⏰ ' + label;
                    icon = '⏰';
                    voiceText = '注意，' + this._extractName(phase.name) + '即将开始，请各团队做好准备。';
                    break;
                case 'overdue':
                    title = '⚠️ ' + label;
                    icon = '⚠️';
                    var overdueSec = Math.round(TimelineManager.getElapsed() - phase.endTime);
                    var overdueMin = Math.round(overdueSec / 60);
                    voiceText = '警告，' + this._extractName(phase.name) + '已超时' + overdueMin + '分钟，请加快进度。';
                    break;
                case 'switch':
                    title = '🔄 ' + label;
                    icon = '🔄';
                    voiceText = '现在开始，' + this._extractName(phase.name) + '，请各团队全力配合。';
                    break;
            }
            var desc = phase.name;
            this._addLog(icon, title, desc);
            if (this._soundEnabled) this._playSound(type);
            if (this._popupEnabled) this._showPopup(type, icon, title, desc);
            if (this._voiceEnabled) this._syncVoice(type, phase, voiceText);
            this._syncToScreen(type, phase, icon + ' ' + title + '：' + desc);
        },

        _extractName: function(name) {
            var idx = name.indexOf(' ');
            if (idx > 0 && idx < name.length - 1) {
                return name.substring(idx + 1);
            }
            return name;
        },

        _addLog: function(icon, title, desc) {
            this._log.unshift({ icon: icon, title: title, desc: desc, time: new Date().toLocaleTimeString('zh-CN', { hour12: false }) });
            if (this._log.length > 20) this._log.pop();
            this._renderLog();
        },

        _renderLog: function() {
            var container = document.getElementById('reminderLog');
            var badge = document.getElementById('reminderLogBadge');
            if (!container) return;
            badge.textContent = this._log.length;
            if (this._log.length === 0) {
                container.innerHTML = '<div class="no-alerts">暂无提醒 ✅</div>';
                return;
            }
            var html = '';
            for (var i = 0; i < this._log.length; i++) {
                var item = this._log[i];
                html += '<div class="reminder-log-item">' +
                    '<span class="reminder-log-icon">' + item.icon + '</span>' +
                    '<span class="reminder-log-text">' + escapeHtml(item.title) + '：' + escapeHtml(item.desc) + '</span>' +
                    '<span class="reminder-log-time">' + item.time + '</span>' +
                    '</div>';
            }
            container.innerHTML = html;
        },

        _showPopup: function(type, icon, title, desc) {
            var popup = document.createElement('div');
            popup.className = 'reminder-popup ' + type;
            popup.innerHTML = '<div class="reminder-popup-content">' +
                '<div class="reminder-icon">' + icon + '</div>' +
                '<div class="reminder-title">' + escapeHtml(title) + '</div>' +
                '<div class="reminder-desc">' + escapeHtml(desc) + '</div>' +
                '<div class="reminder-progress"></div>' +
                '</div>';
            document.body.appendChild(popup);
            requestAnimationFrame(function() { popup.classList.add('show'); });
            setTimeout(function() {
                popup.classList.remove('show');
                setTimeout(function() { if (popup.parentNode) popup.parentNode.removeChild(popup); }, 300);
            }, 4000);
        },

        _playSound: function(type) {
            try {
                var audioCtx = new (window.AudioContext || window.webkitAudioContext)();
                if (audioCtx.state === 'suspended') audioCtx.resume();
                var osc = audioCtx.createOscillator();
                var gain = audioCtx.createGain();
                osc.connect(gain);
                gain.connect(audioCtx.destination);
                gain.gain.value = 0.15;
                if (type === 'before') {
                    osc.frequency.value = 880;
                    osc.type = 'sine';
                    osc.start();
                    gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.3);
                    osc.stop(audioCtx.currentTime + 0.3);
                    setTimeout(function() {
                        var osc2 = audioCtx.createOscillator();
                        var gain2 = audioCtx.createGain();
                        osc2.connect(gain2);
                        gain2.connect(audioCtx.destination);
                        gain2.gain.value = 0.12;
                        osc2.frequency.value = 1100;
                        osc2.type = 'sine';
                        osc2.start();
                        gain2.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.2);
                        osc2.stop(audioCtx.currentTime + 0.2);
                    }, 350);
                } else if (type === 'switch') {
                    osc.frequency.value = 660;
                    osc.type = 'sine';
                    osc.start();
                    gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.4);
                    osc.stop(audioCtx.currentTime + 0.4);
                } else {
                    osc.frequency.value = 440;
                    osc.type = 'square';
                    osc.start();
                    gain.gain.value = 0.12;
                    gain.gain.exponentialRampToValueAtTime(0.001, audioCtx.currentTime + 0.5);
                    osc.stop(audioCtx.currentTime + 0.5);
                }
            } catch(e) {}
        },

        _syncVoice: function(type, phase, text) {
            var data = {
                type: 'checkpointReminder',
                payload: {
                    reminderType: type,
                    phaseName: phase.name,
                    phaseCode: phase.code,
                    message: text,
                    requireVoice: true,
                    timestamp: Date.now()
                }
            };
            localStorage.setItem('checkpointReminder', JSON.stringify(data.payload));
            if (screenWindow && !screenWindow.closed) {
                try { screenWindow.postMessage(data, '*'); } catch(e) {}
            }
        },

        _syncToScreen: function(type, phase, message) {
            var data = {
                type: 'checkpointReminder',
                payload: {
                    reminderType: type,
                    phaseName: phase.name,
                    phaseCode: phase.code,
                    message: message,
                    requireVoice: false,
                    timestamp: Date.now()
                }
            };
            localStorage.setItem('checkpointReminder', JSON.stringify(data.payload));
            if (screenWindow && !screenWindow.closed) {
                try { screenWindow.postMessage(data, '*'); } catch(e) {}
            }
        },

        reset: function() {
            this._remindedBefore = {};
            this._remindedOverdue = {};
            this._remindedSwitch = {};
        }
    };

    // ==================== 应急管理器 ====================
    var EmergencyManager = {
        _emergencyTriggered: false,
        _emergencyOverlayEl: null,
        _emergencyTimer: null,

        init: function() {
            this._emergencyOverlayEl = document.getElementById('emergencyOverlay');
            if (!this._emergencyOverlayEl) {
                this._emergencyOverlayEl = document.createElement('div');
                this._emergencyOverlayEl.id = 'emergencyOverlay';
                this._emergencyOverlayEl.className = 'ending-overlay';
                this._emergencyOverlayEl.innerHTML = '<div class="ending-content" id="emergencyContent"></div>' +
                    '<button class="ending-close-btn" id="emergencyCloseBtn"><i class="fas fa-times"></i></button>';
                document.getElementById('mainVideoWrapper').appendChild(this._emergencyOverlayEl);
            }
            var self = this;
            var closeBtn = document.getElementById('emergencyCloseBtn');
            if (closeBtn && !closeBtn._bound) {
                closeBtn._bound = true;
                closeBtn.addEventListener('click', function() {
                    self.stop();
                });
            }
        },

        trigger: function(text) {
            if (this._emergencyTriggered) return;
            this._emergencyTriggered = true;
            this.init();
            var overlay = this._emergencyOverlayEl;
            var content = document.getElementById('emergencyContent');

            content.innerHTML = '<div class="ending-text fade-in">' + escapeHtml(text) + '</div>';

            overlay.classList.add('show');

            addAlert('warning', '应急播报', '已触发应急播报: ' + text.substring(0, 20) + '...');

            var self = this;
            this._emergencyTimer = setTimeout(function() {
                self.stop();
            }, 15000);
        },

        stop: function() {
            if (this._emergencyTimer) {
                clearTimeout(this._emergencyTimer);
                this._emergencyTimer = null;
            }
            if (this._emergencyOverlayEl) {
                this._emergencyOverlayEl.classList.remove('show');
                setTimeout(function() {
                    if (EmergencyManager._emergencyOverlayEl && !EmergencyManager._emergencyTriggered) {
                        EmergencyManager._emergencyOverlayEl.style.display = 'none';
                    }
                }, 1000);
            }
            this._emergencyTriggered = false;
        }
    };

    // ==================== 应急配置面板事件 ====================
    document.getElementById('btnPreviewEmergency').addEventListener('click', function() {
        var text = document.getElementById('emergencyText').value || '请注意，前方出现异常情况，请各团队保持冷静，听从现场指挥。';
        EmergencyManager.trigger(text);
    });

    var screenWindow = null;

    // ==================== 快捷操作 ====================
    document.getElementById('btnSyncToScreen').addEventListener('click', function() {
        screenWindow = window.open('digital_human_manager_screen.php', '_blank');
        addAlert('info', '大屏同步', '已打开大屏展示模式');
    });

    document.getElementById('btnClearSession').addEventListener('click', function() {
        if (!confirm('确定要重置会话吗？这将清除所有任务、预警和绑定信息。')) return;
        taskList = [];
        alerts = [];
        taskIdCounter = 0;
        alertIdCounter = 0;
        TimelineManager.reset();
        currentPhase = null;
        managerVideoUrl = null;
        currentVideoId = null;
        mainVideo.pause();
        mainVideo.currentTime = 0;
        showResumeBtn();
        setVideoMode('timeline');
        overlayCenter.style.opacity = '1';
        overlayCenter.style.display = '';
        progressFilled.style.width = '0%';
        progressHandle.style.left = '0%';
        timeDisplay.textContent = '00:00 / 00:00';
        renderTimeline();
        updateTeamWindows(null);
        renderTaskList();
        renderAlerts();
        document.getElementById('emergencyText').value = '请注意，前方出现异常情况，请各团队保持冷静，听从现场指挥。';
        EmergencyManager._emergencyTriggered = false;
        EmergencyManager.stop();
        addAlert('info', '会话重置', '所有数据已清除，模块已恢复初始状态');
    });

    // ==================== 键盘快捷键 ====================
    document.addEventListener('keydown', function(e) {
        if (e.target.tagName === 'INPUT' || e.target.tagName === 'TEXTAREA' || e.target.tagName === 'SELECT') return;
        if (e.code === 'Space') {
            e.preventDefault();
            if (TimelineManager.isRunning && !TimelineManager.isPaused) {
                TimelineManager.pause();
            } else if (TimelineManager.isPaused) {
                TimelineManager.start();
            }
        }
    });

    // ==================== 模态框点击外部关闭 ====================
    document.getElementById('taskForm').addEventListener('click', function(e) {
        if (e.target === this) { this.style.display = 'none'; }
    });
    document.getElementById('autoAssignForm').addEventListener('click', function(e) {
        if (e.target === this) { this.style.display = 'none'; }
    });

    // ==================== 监听大屏/数字人相关消息 ====================
    window.addEventListener('storage', function(e) {
        if (e.key === 'checkpointReminderAck' && e.newValue) {
            try {
                var ack = JSON.parse(e.newValue);
                if (ack && ack.timestamp) {
                    localStorage.removeItem('checkpointReminderAck');
                }
            } catch(err) {}
        }
    });

    // ==================== 初始化 ====================
    function init() {
        initVolumeControl();
        initTimeline();
        loadVideoList('coordination');
        EmergencyManager.init();
        CheckpointReminder.init();
        document.getElementById('reminderBadge').textContent = 'ON';
        setTimeout(function() {
            if (managerPhases.length > 0) {
                syncTimelineToScreen();
                syncPhaseToScreen(managerPhases[0]);
            }
        }, 500);
    }

    function syncTimelineToScreen() {
        var timelineData = managerPhases.map(function(p) {
            return {
                code: p.code,
                name: p.name,
                duration: p.duration
            };
        });
        localStorage.setItem('managerTimelineData', JSON.stringify(timelineData));
        if (screenWindow && !screenWindow.closed) {
            try {
                screenWindow.postMessage({
                    type: 'managerTimelineUpdate',
                    payload: timelineData
                }, '*');
            } catch(e) {}
        }
    }

    if (document.readyState === 'loading') {
        document.addEventListener('DOMContentLoaded', init);
    } else {
        init();
    }

})();
</script>

<?php require_once 'footer.php'; ?>