spaxel/dashboard/css/sleep.css
jedarden 6bf1e0394a feat(explainability): detection explainability overlay with per-link contributions, Fresnel zones, and BLE identity
Implements the full explainability overlay for understanding why a blob was detected:
- ExplainabilitySnapshot generation with per-link contribution tracking and zone decay
- Fresnel zone ellipsoid geometry computation and 3D wireframe rendering
- WebSocket request_explain / blob_explain flow for on-demand snapshots
- Right-click, long-press, click, and hover tooltip activation paths
- X-ray overlay dims non-contributing elements, highlights contributing links
- Sidebar panel with confidence gauge, links table, sparklines, BLE match card
- Escape key and backdrop click to exit, restoring scene state

Also includes: simple mode removal, CSS cleanup, fleet page enhancements, sidebar timeline fixes.

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-04-24 19:23:55 -04:00

313 lines
7.3 KiB
CSS

/* Sleep Quality Monitoring UI */
/* ── Morning Summary Card ────────────────────────────────────────────────── */
.sleep-summary-card {
position: fixed;
top: var(--space-4);
right: var(--space-4);
z-index: 1000;
background: var(--bg-card, var(--bg-card));
border: 1px solid var(--border-color, var(--slate-5));
border-radius: var(--radius-card);
padding: var(--space-4);
max-width: 380px;
width: 100%;
box-shadow: 0 8px 32px var(--shadow-lg);
animation: sleep-slide-in 0.3s ease-out;
color: var(--text-color, var(--slate-11));
}
@keyframes sleep-slide-in {
from { transform: translateY(-20px); opacity: 0; }
to { transform: translateY(0); opacity: 1; }
}
.sleep-summary-card.hidden {
display: none;
}
.sleep-summary-header {
display: flex;
align-items: center;
gap: var(--space-2);
margin-bottom: var(--space-3);
padding-bottom: var(--space-2);
border-bottom: 1px solid var(--border-color, var(--slate-5));
}
.sleep-summary-icon {
color: var(--blue-10);
display: flex;
align-items: center;
}
.sleep-summary-title {
font-weight: 600;
font-size: var(--text-sm);
flex: 1;
}
.sleep-summary-dismiss {
background: none;
border: none;
color: var(--text-muted, var(--text-muted));
font-size: var(--text-xl);
cursor: pointer;
padding: var(--space-half) var(--space-150);
line-height: 1;
border-radius: var(--radius-control);
}
.sleep-summary-dismiss:hover {
background: var(--bg-hover, var(--slate-5));
color: var(--text-color, var(--slate-11));
}
.sleep-summary-body {
display: flex;
flex-direction: column;
gap: var(--space-2);
}
.sleep-summary-body > div {
font-size: var(--text-sm);
line-height: var(--lh-body);
}
.sleep-summary-duration {
font-weight: 600;
font-size: var(--text-xl);
margin-bottom: var(--space-1);
}
.sleep-efficiency-dot {
display: inline-block;
width: 8px;
height: 8px;
border-radius: 50%;
margin-right: var(--space-1);
vertical-align: middle;
}
.sleep-efficiency-dot.green { background: var(--ok); }
.sleep-efficiency-dot.amber { background: var(--warn); }
.sleep-efficiency-dot.red { background: var(--alert); }
.sleep-anomaly-warning {
color: var(--warn);
font-weight: 500;
}
.sleep-summary-details-btn {
margin-top: var(--space-2);
padding: 6px var(--space-3);
background: var(--bg-hover);
border: 1px solid var(--border-color, var(--slate-6));
border-radius: var(--radius-control);
color: var(--text-color, var(--slate-11));
font-size: var(--text-xs);
cursor: pointer;
text-align: center;
}
.sleep-summary-details-btn:hover {
background: var(--bg-active);
}
.sleep-summary-details-btn.hidden {
display: none;
}
.sleep-summary-anomaly.hidden {
display: none;
}
/* ── Sleep Panel ──────────────────────────────────────────────────────────── */
.sleep-panel {
position: fixed;
top: 0;
right: 0;
width: 360px;
height: 100%;
background: var(--bg-panel, var(--bg-card));
border-left: 1px solid var(--border-color, var(--slate-5));
z-index: 900;
display: flex;
flex-direction: column;
box-shadow: -4px 0 24px var(--shadow);
overflow: hidden;
color: var(--text-color, var(--slate-11));
}
.sleep-panel.hidden {
display: none;
}
.sleep-panel-header {
display: flex;
align-items: center;
justify-content: space-between;
padding: var(--space-4);
border-bottom: 1px solid var(--border-color, var(--slate-5));
flex-shrink: 0;
}
.sleep-panel-header h3 {
margin: 0;
font-size: var(--text-base);
font-weight: 600;
}
.sleep-panel-close {
background: none;
border: none;
color: var(--text-muted, var(--text-muted));
font-size: var(--text-lg);
cursor: pointer;
padding: var(--space-half) var(--space-150);
border-radius: var(--radius-control);
}
.sleep-panel-close:hover {
background: var(--bg-hover, var(--slate-5));
color: var(--text-color, var(--slate-11));
}
.sleep-panel-content {
flex: 1;
overflow-y: auto;
padding: var(--space-4);
}
.sleep-panel-section {
margin-bottom: var(--space-6);
}
.sleep-panel-section h4 {
font-size: var(--text-sm);
font-weight: 600;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--text-muted, var(--text-muted));
margin: var(--space-3);
}
/* ── Trends ───────────────────────────────────────────────────────────────── */
.sleep-trends-container {
display: flex;
flex-direction: column;
gap: var(--space-3);
}
.sleep-trend-row {
display: flex;
align-items: center;
gap: var(--space-2);
}
.sleep-trend-label {
font-size: var(--text-xs);
color: var(--text-muted, var(--text-muted));
min-width: 100px;
flex-shrink: 0;
}
.sleep-sparkline {
flex: 1;
height: 30px;
}
.sleep-sparkline-svg {
width: 100%;
height: 100%;
}
.sleep-trend-value {
font-size: var(--text-xs);
font-weight: 600;
min-width: 60px;
text-align: right;
flex-shrink: 0;
}
.sleep-week-comparison {
font-size: var(--text-xs);
color: var(--text-muted, var(--text-muted));
margin-top: var(--space-2);
padding: var(--space-2);
background: var(--bg-card, var(--bg-card));
border-radius: var(--radius-control);
line-height: var(--lh-body);
}
/* ── Breathing Stats ──────────────────────────────────────────────────────── */
.sleep-breathing-stats {
display: flex;
gap: var(--space-4);
}
.sleep-stat {
flex: 1;
background: var(--bg-card, var(--bg-card));
border-radius: var(--radius-card);
padding: var(--space-3);
text-align: center;
}
.sleep-stat-label {
display: block;
font-size: var(--text-2xs);
color: var(--text-muted, var(--text-muted));
margin-bottom: var(--space-1);
}
.sleep-stat-value {
display: block;
font-size: var(--text-lg);
font-weight: 700;
color: var(--blue-9);
}
/* ── History ──────────────────────────────────────────────────────────────── */
.sleep-history {
display: flex;
flex-direction: column;
gap: var(--space-1);
}
.sleep-history-row {
display: flex;
align-items: center;
gap: var(--space-3);
padding: var(--space-2) 10px;
background: var(--bg-card, var(--bg-card));
border-radius: var(--radius-control);
font-size: var(--text-sm);
}
.sleep-history-date {
min-width: 90px;
color: var(--text-muted, var(--text-muted));
}
.sleep-history-duration {
flex: 1;
font-weight: 500;
}
.sleep-history-breathing {
color: var(--blue-9);
font-size: var(--text-xs);
}
.sleep-history-empty {
text-align: center;
color: var(--text-muted, var(--text-muted));
font-size: var(--text-sm);
padding: 24px 0;
}