| <!DOCTYPE html>
|
| <html lang="en">
|
|
|
| <head>
|
| <meta charset="UTF-8">
|
| <meta name="viewport" content="width=device-width, initial-scale=1.0">
|
| <title>Sentinel Live Pulse — Real-time Multimodal Analysis</title>
|
| <link rel="stylesheet" href="/css/styles.css">
|
| <link
|
| href="https://fonts.googleapis.com/css2?family=Space+Grotesk:wght@300;400;500;600;700;800&family=Inter:wght@300;400;500;600;700&display=swap"
|
| rel="stylesheet">
|
| <link href="https://fonts.googleapis.com/css2?family=Material+Symbols+Outlined:wght,FILL@100..700,0..1&display=swap"
|
| rel="stylesheet">
|
| <style>
|
| .live-grid {
|
| display: grid;
|
| grid-template-columns: 200px 1fr 320px;
|
| gap: 20px;
|
| height: calc(100vh - 64px);
|
| padding: 20px;
|
| }
|
|
|
| .source-panel {
|
| display: flex;
|
| flex-direction: column;
|
| gap: 16px;
|
| overflow-y: auto;
|
| }
|
|
|
| .center-panel {
|
| display: flex;
|
| flex-direction: column;
|
| gap: 16px;
|
| min-height: 0;
|
| }
|
|
|
| .analytics-panel {
|
| display: flex;
|
| flex-direction: column;
|
| gap: 16px;
|
| overflow-y: auto;
|
| }
|
|
|
| .video-container {
|
| position: relative;
|
| flex: 1;
|
| border-radius: 16px;
|
| overflow: hidden;
|
| border: 1px solid rgba(59, 73, 75, 0.15);
|
| background: #000;
|
| min-height: 380px;
|
| }
|
|
|
| #webcam-video {
|
| width: 100%;
|
| height: 100%;
|
| object-fit: cover;
|
| }
|
|
|
| #mesh-canvas {
|
| position: absolute;
|
| top: 0;
|
| left: 0;
|
| width: 100%;
|
| height: 100%;
|
| pointer-events: none;
|
| object-fit: cover;
|
| }
|
|
|
| .video-overlay-top {
|
| position: absolute;
|
| top: 16px;
|
| left: 16px;
|
| display: flex;
|
| gap: 12px;
|
| z-index: 5;
|
| }
|
|
|
| .video-overlay-bottom {
|
| position: absolute;
|
| bottom: 16px;
|
| right: 16px;
|
| z-index: 5;
|
| }
|
|
|
| .emotion-badge {
|
| padding: 8px 16px;
|
| border-radius: 12px;
|
| background: rgba(0, 0, 0, 0.6);
|
| backdrop-filter: blur(12px);
|
| border-left: 4px solid var(--primary-container);
|
| }
|
|
|
| .emotion-badge-label {
|
| font-size: 9px;
|
| text-transform: uppercase;
|
| letter-spacing: 0.05em;
|
| color: rgba(0, 240, 255, 0.7);
|
| }
|
|
|
| .emotion-badge-value {
|
| font-family: var(--font-headline);
|
| font-size: 1.25rem;
|
| font-weight: 700;
|
| color: var(--primary);
|
| }
|
|
|
| .source-btn {
|
| display: flex;
|
| flex-direction: column;
|
| align-items: flex-start;
|
| padding: 16px;
|
| border-radius: 12px;
|
| border: 1px solid rgba(59, 73, 75, 0.15);
|
| background: var(--surface-container-low);
|
| cursor: pointer;
|
| transition: all 0.3s;
|
| position: relative;
|
| overflow: hidden;
|
| }
|
|
|
| .source-btn:hover {
|
| background: var(--surface-container);
|
| }
|
|
|
| .source-btn.active {
|
| border-color: rgba(0, 240, 255, 0.3);
|
| }
|
|
|
| .source-btn .bar {
|
| position: absolute;
|
| bottom: 0;
|
| left: 0;
|
| height: 3px;
|
| transition: width 0.5s;
|
| }
|
|
|
| .source-btn.active .bar {
|
| width: 100% !important;
|
| }
|
|
|
| .source-label {
|
| font-size: 10px;
|
| text-transform: uppercase;
|
| letter-spacing: 0.08em;
|
| color: var(--outline);
|
| margin-top: 4px;
|
| }
|
|
|
| .source-name {
|
| font-family: var(--font-headline);
|
| font-size: 12px;
|
| font-weight: 700;
|
| margin-top: 2px;
|
| }
|
|
|
|
|
| .audio-viz-container {
|
| height: 80px;
|
| display: flex;
|
| align-items: flex-end;
|
| gap: 2px;
|
| padding: 8px;
|
| }
|
|
|
| .audio-bar {
|
| flex: 1;
|
| border-radius: 3px 3px 0 0;
|
| transition: height 0.1s ease-out;
|
| min-height: 2px;
|
| }
|
|
|
|
|
| .tech-log {
|
| height: 120px;
|
| border-radius: 12px;
|
| padding: 12px;
|
| font-family: 'JetBrains Mono', 'Cascadia Code', monospace;
|
| font-size: 10px;
|
| overflow-y: auto;
|
| }
|
|
|
| .tech-log .log-line {
|
| margin-bottom: 2px;
|
| color: #64748b;
|
| }
|
|
|
|
|
| .prosody-bars {
|
| display: flex;
|
| align-items: flex-end;
|
| gap: 3px;
|
| height: 72px;
|
| }
|
|
|
| .prosody-bar {
|
| flex: 1;
|
| border-radius: 3px 3px 0 0;
|
| transition: height 0.3s ease-out;
|
| }
|
|
|
|
|
| .controls-bar {
|
| display: flex;
|
| align-items: center;
|
| gap: 12px;
|
| padding: 12px 16px;
|
| border-radius: 12px;
|
| background: rgba(26, 31, 47, 0.7);
|
| backdrop-filter: blur(16px);
|
| border: 1px solid rgba(59, 73, 75, 0.1);
|
| }
|
|
|
| .control-btn {
|
| width: 40px;
|
| height: 40px;
|
| border-radius: 50%;
|
| border: none;
|
| display: flex;
|
| align-items: center;
|
| justify-content: center;
|
| cursor: pointer;
|
| transition: all 0.3s;
|
| background: var(--surface-container);
|
| color: var(--on-surface-variant);
|
| }
|
|
|
| .control-btn:hover {
|
| background: var(--surface-container-high);
|
| color: var(--primary-container);
|
| }
|
|
|
| .control-btn.active {
|
| background: rgba(0, 240, 255, 0.15);
|
| color: var(--primary-container);
|
| }
|
|
|
| .control-btn.recording {
|
| background: rgba(255, 59, 48, 0.15);
|
| color: #ff3b30;
|
| animation: pulse-glow 1.5s infinite;
|
| }
|
|
|
|
|
| .btn-record-audio {
|
| background: rgba(255, 59, 48, 0.15);
|
| border: 1px solid rgba(255, 59, 48, 0.4);
|
| color: #ff3b30;
|
| padding: 10px 24px;
|
| border-radius: 999px;
|
| font-family: var(--font-headline);
|
| font-size: 14px;
|
| font-weight: 600;
|
| cursor: pointer;
|
| display: flex;
|
| align-items: center;
|
| gap: 8px;
|
| transition: all 0.3s;
|
| margin: 0 auto;
|
| }
|
|
|
| .btn-record-audio:hover {
|
| background: rgba(255, 59, 48, 0.3);
|
| box-shadow: 0 0 15px rgba(255, 59, 48, 0.4);
|
| }
|
|
|
| .btn-record-audio.active {
|
| animation: pulse-glow 1.5s infinite;
|
| background: rgba(255, 59, 48, 0.4);
|
| }
|
| </style>
|
|
|
|
|
| <script src="https://cdn.jsdelivr.net/npm/@mediapipe/camera_utils/camera_utils.js" crossorigin="anonymous"></script>
|
| <script src="https://cdn.jsdelivr.net/npm/@mediapipe/face_mesh/face_mesh.js" crossorigin="anonymous"></script>
|
| <script src="https://cdn.jsdelivr.net/npm/@mediapipe/drawing_utils/drawing_utils.js"
|
| crossorigin="anonymous"></script>
|
| </head>
|
|
|
| <body>
|
|
|
| <aside class="sidebar">
|
| <div class="sidebar-logo">S</div>
|
| <nav class="sidebar-nav">
|
| <a href="/" class="sidebar-link"><span class="material-symbols-outlined">dashboard</span><span
|
| class="label">Home</span></a>
|
| <a href="/live" class="sidebar-link active"><span class="material-symbols-outlined"
|
| style="font-variation-settings:'FILL' 1;">sensors</span><span class="label">Live</span></a>
|
| <a href="/scan" class="sidebar-link"><span class="material-symbols-outlined">analytics</span><span
|
| class="label">Scan</span></a>
|
| <a href="/stats" class="sidebar-link"><span class="material-symbols-outlined">school</span><span
|
| class="label">Stats</span></a>
|
| </nav>
|
| </aside>
|
|
|
|
|
| <header class="topbar">
|
| <div style="display:flex;align-items:center;gap:16px;">
|
| <h1 class="topbar-title gradient-text">Sentinel Live Pulse</h1>
|
| <div class="live-indicator" id="live-badge" style="display:none;">
|
| <div class="dot"></div>LIVE
|
| </div>
|
| <div class="status-pill" id="connection-status">
|
| <span class="status-dot" style="background:var(--tertiary-fixed-dim);"></span>
|
| <span class="status-text" style="color:var(--tertiary-fixed-dim);">Standby</span>
|
| </div>
|
| </div>
|
| <div style="display:flex;align-items:center;gap:12px;">
|
| <button class="btn-primary" id="btn-start-stop">
|
| <span class="material-symbols-outlined" style="font-size:18px;">play_arrow</span>
|
| Start Monitoring
|
| </button>
|
| </div>
|
| </header>
|
|
|
|
|
| <main class="main-content">
|
| <div class="live-grid">
|
|
|
| <section class="source-panel">
|
| <div
|
| style="font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--outline);font-weight:600;">
|
| System Sources</div>
|
|
|
| <div class="source-btn active" id="source-face">
|
| <span class="material-symbols-outlined"
|
| style="color:var(--primary-container);margin-bottom:8px;">videocam</span>
|
| <span class="source-name" style="color:var(--primary);">Live Face Feed</span>
|
| <span class="source-label" id="face-status">Standby</span>
|
| <div class="bar"
|
| style="background:var(--primary-container);box-shadow:0 0 10px var(--primary-container);width:100%;">
|
| </div>
|
| </div>
|
|
|
| <div class="source-btn" id="source-audio">
|
| <span class="material-symbols-outlined"
|
| style="color:var(--secondary);margin-bottom:8px;">graphic_eq</span>
|
| <span class="source-name" style="color:var(--secondary);">Audio Spectrum</span>
|
| <span class="source-label" id="audio-status">Standby</span>
|
| <div class="bar" style="background:var(--secondary);box-shadow:0 0 10px var(--secondary);width:0%;">
|
| </div>
|
| </div>
|
|
|
| <div class="source-btn" id="source-text">
|
| <span class="material-symbols-outlined"
|
| style="color:var(--tertiary-fixed-dim);margin-bottom:8px;">segment</span>
|
| <span class="source-name" style="color:var(--tertiary-fixed-dim);">Text Sentiment</span>
|
| <span class="source-label" id="text-status">Standby</span>
|
| <div class="bar"
|
| style="background:var(--tertiary-fixed-dim);box-shadow:0 0 10px var(--tertiary-fixed-dim);width:0%;">
|
| </div>
|
| </div>
|
|
|
|
|
| <div style="margin-top:auto;" class="glass-card" style="padding:16px;">
|
| <div style="padding:16px;">
|
| <div style="display:flex;align-items:center;gap:6px;margin-bottom:8px;">
|
| <span
|
| style="width:6px;height:6px;border-radius:50%;background:var(--primary-container);box-shadow:0 0 5px var(--primary-container);"></span>
|
| <span
|
| style="font-size:10px;text-transform:uppercase;letter-spacing:0.1em;font-weight:700;">AI
|
| Engine</span>
|
| </div>
|
| <div style="font-size:12px;color:var(--on-surface-variant);font-weight:600;" id="model-name">
|
| Sentinel-CNN-v1</div>
|
| <div style="font-size:9px;color:var(--outline);text-transform:uppercase;margin-top:4px;"
|
| id="model-latency">Latency: —</div>
|
| </div>
|
| </div>
|
| </section>
|
|
|
|
|
| <section class="center-panel">
|
| <div class="video-container" id="video-container">
|
| <video id="webcam-video" autoplay playsinline muted></video>
|
| <canvas id="mesh-canvas"></canvas>
|
|
|
| <div id="mesh-dot-overlay"
|
| style="position:absolute;inset:0;pointer-events:none;background-image:radial-gradient(circle,rgba(0,255,0,0.2) 1px,transparent 1px);background-size:20px 20px;opacity:0.2;">
|
| </div>
|
|
|
| <div class="video-overlay-top">
|
| <div class="emotion-badge">
|
| <div class="emotion-badge-label">Detected Emotion</div>
|
| <div class="emotion-badge-value" id="face-emotion-display">— —</div>
|
| </div>
|
| </div>
|
| <div class="video-overlay-bottom">
|
| <div
|
| style="display:flex;align-items:center;gap:16px;background:rgba(0,0,0,0.4);backdrop-filter:blur(12px);padding:8px 16px;border-radius:999px;border:1px solid rgba(255,255,255,0.1);">
|
| <div style="text-align:center;"><span
|
| style="font-size:8px;text-transform:uppercase;color:var(--outline);display:block;">Blink
|
| Rate</span><span style="font-size:12px;font-weight:700;" id="blink-rate">—</span>
|
| </div>
|
| <div style="width:1px;height:24px;background:rgba(255,255,255,0.1);"></div>
|
| <div style="text-align:center;"><span
|
| style="font-size:8px;text-transform:uppercase;color:var(--outline);display:block;">Head
|
| Pose</span><span style="font-size:12px;font-weight:700;" id="head-pose">—</span>
|
| </div>
|
| <div style="width:1px;height:24px;background:rgba(255,255,255,0.1);"></div>
|
| <div style="text-align:center;"><span
|
| style="font-size:8px;text-transform:uppercase;color:var(--outline);display:block;">Landmarks</span><span
|
| style="font-size:12px;font-weight:700;" id="landmark-count">0</span></div>
|
| </div>
|
| </div>
|
|
|
| <div id="scan-line"
|
| style="display:none;position:absolute;left:0;width:100%;height:2px;background:linear-gradient(90deg,transparent,#00ff00,transparent);animation:scan-line 3s linear infinite;opacity:0.4;">
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="glass-card" id="text-panel"
|
| style="display:none; flex: 1; min-height: 300px; padding: 24px; flex-direction:column;">
|
| <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;">
|
| <div>
|
| <div
|
| style="font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--outline);font-weight:600;">
|
| System NLP Engine</div>
|
| <div
|
| style="font-family:var(--font-headline);font-size:1.4rem;font-weight:700;color:var(--tertiary-fixed-dim);">
|
| Text Sentiment Analysis</div>
|
| </div>
|
| <span class="material-symbols-outlined"
|
| style="color:var(--tertiary-fixed-dim);font-size:32px;">segment</span>
|
| </div>
|
| <div id="text-sentiment-history"
|
| style="flex:1; overflow-y:auto; background:rgba(0,0,0,0.2); border-radius:12px; padding:16px; font-family: 'JetBrains Mono', monospace; font-size: 12px; color: var(--on-surface-variant);">
|
| <div style="color:var(--outline); text-align:center; margin-top:20px;">Analysis stream empty.
|
| Type something below to begin.</div>
|
| </div>
|
|
|
|
|
| <div
|
| style="margin-top:16px; position:relative; display:flex; align-items:center; background:rgba(255,255,255,0.03); border-radius:8px 8px 0 0; border-bottom: 2px solid rgba(0, 255, 255, 0.5); box-shadow: 0 4px 12px -4px rgba(0, 255, 255, 0.4);">
|
| <input type="text" id="live-text-input" placeholder="Enter text for deep semantic analysis..."
|
| style="flex:1; background:transparent; border:none; padding:14px 50px 14px 16px; color:#fff; outline:none; font-size:14px; letter-spacing:0.5px;">
|
| <button id="ctrl-text-send" title="Analyze Sentiment"
|
| style="position:absolute; right:12px; background:transparent; border:none; color:cyan; cursor:pointer; display:flex; align-items:center; justify-content:center; transition: all 0.3s ease;"
|
| onmouseover="this.style.transform='scale(1.1)'; this.style.filter='drop-shadow(0 0 5px cyan)';"
|
| onmouseout="this.style.transform='scale(1)'; this.style.filter='none';">
|
| <span class="material-symbols-outlined" style="font-size:24px;">send</span>
|
| </button>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="glass-card" id="audio-panel"
|
| style="display:none; flex: 1; min-height: 300px; padding: 24px; flex-direction:column;">
|
| <div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:16px;">
|
| <div>
|
| <div
|
| style="font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--outline);font-weight:600;">
|
| System Acoustic Engine</div>
|
| <div
|
| style="font-family:var(--font-headline);font-size:1.4rem;font-weight:700;color:var(--secondary);">
|
| Audio Spectrum Visualizer</div>
|
| </div>
|
| <span class="material-symbols-outlined"
|
| style="color:var(--secondary);font-size:32px;">graphic_eq</span>
|
| </div>
|
| <div style="flex:1; display:flex; align-items:flex-end; gap:4px; padding:20px; background:rgba(0,0,0,0.2); border-radius:12px; position:relative;"
|
| id="big-audio-viz">
|
|
|
| </div>
|
|
|
| <div style="margin-top:20px; text-align:center;">
|
| <button class="btn-record-audio" id="btn-record-audio" style="display:none;">
|
| <span class="material-symbols-outlined">mic</span>
|
| Record Live Audio
|
| </button>
|
| </div>
|
|
|
| <div style="margin-top:16px; text-align:center; display:none; flex-direction:column; gap:12px; align-items:center;"
|
| id="audio-preview-section">
|
| <audio id="audio-previewer" controls
|
| style="height:36px; border-radius:999px; outline:none; max-width:80%;"></audio>
|
| <button class="btn-record-audio" id="btn-analyze-audio"
|
| style="background:var(--primary-container); color:#000; border:none; padding:8px 24px;">
|
| <span class="material-symbols-outlined">analytics</span>
|
| Analyze Preview
|
| </button>
|
| </div>
|
|
|
| <div
|
| style="margin-top:16px; text-align:center; position:relative; min-height:40px; display:flex; justify-content:center; align-items:center;">
|
| <span id="speech-emotion-display-big"
|
| style="font-family:var(--font-headline);font-size:1.5rem;font-weight:700;color:var(--secondary);">Standby</span>
|
| <button id="btn-toggle-transcript"
|
| style="position:absolute; right:0; background:rgba(255,255,255,0.05); border:1px solid rgba(255,255,255,0.1); border-radius:30px; padding:5px 12px; display:flex; align-items:center; gap:6px; color:var(--on-surface); cursor:pointer; transition: all 0.3s cubic-bezier(0.4, 0, 0.2, 1); font-size:11px; backdrop-filter: blur(4px);"
|
| onmouseover="this.style.background='rgba(255,255,255,0.15)';this.style.borderColor='var(--primary-container)'"
|
| onmouseout="this.style.background='rgba(255,255,255,0.05)';this.style.borderColor='rgba(255,255,255,0.1)'">
|
| <span class="material-symbols-outlined" style="font-size:16px;"
|
| id="icon-transcript-toggle">visibility</span>
|
| <span id="text-transcript-toggle" style="font-weight:600; letter-spacing:0.5px;">SHOW
|
| TRANSCRIPT</span>
|
| </button>
|
| </div>
|
| </div>
|
|
|
|
|
|
|
|
|
| <div class="tech-log glass-card" id="tech-log">
|
| <div
|
| style="display:flex;justify-content:space-between;align-items:center;margin-bottom:6px;border-bottom:1px solid rgba(59,73,75,0.1);padding-bottom:4px;">
|
| <span
|
| style="text-transform:uppercase;letter-spacing:0.08em;color:var(--outline);font-weight:600;">Technical
|
| Data Stream</span>
|
| <span style="color:var(--primary-container);" id="log-status">STANDBY</span>
|
| </div>
|
| <div id="log-content" style="overflow-y:auto;max-height:72px;">
|
| <p class="log-line"><span class="tag-face">[SYSTEM]</span> Sentinel Live Pulse initialized.
|
| Ready for monitoring.</p>
|
| </div>
|
| </div>
|
| </section>
|
|
|
|
|
| <section class="analytics-panel">
|
|
|
| <div class="glass-card" style="padding:20px;">
|
| <div style="display:flex;justify-content:space-between;align-items:flex-start;">
|
| <div>
|
| <div
|
| style="font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--outline);font-weight:600;">
|
| Speech Prosody</div>
|
| <div style="font-family:var(--font-headline);font-size:1.1rem;font-weight:700;">Pitch & Tone
|
| </div>
|
| </div>
|
| <span class="material-symbols-outlined" style="color:var(--secondary);">waves</span>
|
| </div>
|
| <div class="prosody-bars" id="prosody-bars">
|
| <div class="prosody-bar" style="background:rgba(209,188,255,0.2);height:40%;"></div>
|
| <div class="prosody-bar" style="background:rgba(209,188,255,0.4);height:60%;"></div>
|
| <div class="prosody-bar"
|
| style="background:var(--secondary);height:90%;box-shadow:0 0 10px rgba(209,188,255,0.5);">
|
| </div>
|
| <div class="prosody-bar" style="background:rgba(209,188,255,0.6);height:70%;"></div>
|
| <div class="prosody-bar" style="background:rgba(209,188,255,0.3);height:50%;"></div>
|
| <div class="prosody-bar" style="background:rgba(209,188,255,0.8);height:85%;"></div>
|
| <div class="prosody-bar" style="background:rgba(209,188,255,0.4);height:30%;"></div>
|
| </div>
|
| <div style="margin-top:8px;font-size:11px;color:var(--on-surface-variant);"
|
| id="speech-emotion-display">Emotion: —</div>
|
| </div>
|
|
|
|
|
| <div class="glass-card" style="padding:20px;">
|
| <div style="display:flex;justify-content:space-between;align-items:flex-start;">
|
| <div>
|
| <div
|
| style="font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--outline);font-weight:600;">
|
| Sentiment Score</div>
|
| <div style="font-family:var(--font-headline);font-size:1.1rem;font-weight:700;">Text
|
| Analysis</div>
|
| </div>
|
| <span class="material-symbols-outlined"
|
| style="color:var(--tertiary-fixed-dim);">query_stats</span>
|
| </div>
|
| <div style="margin-top:16px;">
|
| <div class="progress-track">
|
| <div class="progress-fill" id="sentiment-bar"
|
| style="width:50%;background:linear-gradient(90deg,var(--error),var(--tertiary-fixed-dim),var(--primary-container));">
|
| </div>
|
| </div>
|
| <div
|
| style="display:flex;justify-content:space-between;margin-top:8px;font-size:9px;text-transform:uppercase;font-weight:700;color:var(--outline);">
|
| <span>Negative</span>
|
| <span style="color:var(--primary-container);" id="sentiment-score-display">—</span>
|
| </div>
|
| </div>
|
| <div style="margin-top:12px;font-size:11px;color:var(--on-surface-variant);"
|
| id="text-sentiment-label">Sentiment: —</div>
|
| </div>
|
|
|
|
|
| <div class="glass-card" style="padding:20px;flex:1;display:flex;flex-direction:column;">
|
| <div style="display:flex;justify-content:space-between;align-items:flex-start;">
|
| <div>
|
| <div
|
| style="font-size:10px;text-transform:uppercase;letter-spacing:0.08em;color:var(--outline);font-weight:600;">
|
| Engagement Trend</div>
|
| <div style="font-family:var(--font-headline);font-size:1.1rem;font-weight:700;">Session
|
| Lifecycle</div>
|
| </div>
|
| <span class="material-symbols-outlined"
|
| style="color:var(--primary-container);">trending_up</span>
|
| </div>
|
| <div style="flex:1;position:relative;margin-top:12px;min-height:120px;">
|
| <canvas id="engagement-chart"
|
| style="position:absolute;top:0;left:0;width:100%;height:100%;"></canvas>
|
| </div>
|
| <div style="display:grid;grid-template-columns:1fr 1fr;gap:8px;margin-top:12px;">
|
| <div class="stat-card" style="padding:10px;">
|
| <div class="stat-label" style="font-size:8px;">Peak</div>
|
| <div style="font-family:var(--font-headline);font-size:1rem;font-weight:700;color:var(--primary-container);"
|
| id="peak-engagement">—</div>
|
| </div>
|
| <div class="stat-card" style="padding:10px;">
|
| <div class="stat-label" style="font-size:8px;">Average</div>
|
| <div style="font-family:var(--font-headline);font-size:1rem;font-weight:700;color:var(--secondary);"
|
| id="avg-engagement">—</div>
|
| </div>
|
| </div>
|
| </div>
|
|
|
|
|
| <div class="glass-card" style="padding:20px;text-align:center;">
|
| <div
|
| style="font-size:10px;text-transform:uppercase;letter-spacing:0.1em;color:var(--outline);font-weight:600;margin-bottom:8px;">
|
| Overall Engagement</div>
|
| <div class="engagement-ring" style="margin:0 auto;">
|
| <svg viewBox="0 0 120 120">
|
| <circle class="ring-track" cx="60" cy="60" r="52"></circle>
|
| <circle class="ring-fill" cx="60" cy="60" r="52" stroke-dasharray="326.73"
|
| stroke-dashoffset="326.73" id="engagement-ring-fill"></circle>
|
| </svg>
|
| <span class="ring-value" id="engagement-value">0%</span>
|
| </div>
|
| <div style="margin-top:8px;font-size:12px;font-weight:600;color:var(--on-surface-variant);"
|
| id="engagement-level">Unknown</div>
|
| </div>
|
| </section>
|
| </div>
|
| </main>
|
|
|
| <script src="/js/live.js?v=24"></script>
|
| </body>
|
|
|
| </html> |