blob: dc9c65bb19125e656945d79ac06a62ca43046a54 [file]
/* Otava Test Data Visualizer Styles */
:root {
--primary-color: #2563eb;
--primary-hover: #1d4ed8;
--secondary-color: #64748b;
--secondary-hover: #475569;
--success-color: #10b981;
--warning-color: #f59e0b;
--danger-color: #ef4444;
--background: #f8fafc;
--surface: #ffffff;
--text-primary: #1e293b;
--text-secondary: #64748b;
--border-color: #e2e8f0;
--chart-line: #3b82f6;
--chart-point: #ef4444;
--chart-area: rgba(59, 130, 246, 0.1);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
/* Removed overflow-x: hidden to debug layout issues */
body {
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Oxygen, Ubuntu, sans-serif;
background-color: var(--background);
color: var(--text-primary);
line-height: 1.6;
}
header {
background: url('/static/images/meteor.webp') center 65% / cover no-repeat;
color: white;
padding: 1.5rem 1rem;
position: relative;
}
header::before {
content: '';
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.3);
z-index: 0;
}
header > * {
position: relative;
z-index: 1;
}
.header-content {
display: flex;
justify-content: space-between;
align-items: center;
}
.header-left {
text-align: left;
}
header h1 {
font-size: 1.25rem;
margin-bottom: 0.15rem;
}
header .subtitle {
opacity: 0.9;
font-size: 0.8rem;
}
header .version {
text-align: left;
font-size: 0.65rem;
opacity: 0.7;
margin-top: 0.25rem;
}
.header-right {
display: flex;
align-items: center;
}
.settings-btn {
background: rgba(255, 255, 255, 0.15);
border: none;
border-radius: 6px;
padding: 0.5rem;
cursor: pointer;
color: white;
display: flex;
align-items: center;
justify-content: center;
transition: background 0.2s;
}
.settings-btn:hover {
background: rgba(255, 255, 255, 0.25);
}
/* Settings Dialog */
.settings-dialog {
position: fixed;
top: 0;
left: 0;
right: 0;
bottom: 0;
background: rgba(0, 0, 0, 0.5);
display: flex;
align-items: center;
justify-content: center;
z-index: 1000;
}
.settings-dialog.hidden {
display: none;
}
.settings-dialog-content {
background: var(--surface);
border-radius: 12px;
box-shadow: 0 20px 40px rgba(0, 0, 0, 0.2);
width: 90%;
max-width: 450px;
max-height: 90vh;
overflow-y: auto;
}
.settings-dialog-header {
display: flex;
justify-content: space-between;
align-items: center;
padding: 1rem 1.25rem;
border-bottom: 1px solid var(--border-color);
}
.settings-dialog-header h3 {
margin: 0;
font-size: 1.1rem;
color: var(--text-primary);
}
.settings-close-btn {
background: none;
border: none;
font-size: 1.5rem;
color: var(--text-secondary);
cursor: pointer;
padding: 0;
line-height: 1;
transition: color 0.2s;
}
.settings-close-btn:hover {
color: var(--text-primary);
}
.settings-dialog-body {
padding: 1.25rem;
}
.settings-group {
margin-bottom: 1.25rem;
}
.settings-group:last-child {
margin-bottom: 0;
}
.settings-group > label {
display: block;
font-weight: 600;
font-size: 0.85rem;
color: var(--text-secondary);
margin-bottom: 0.5rem;
}
.settings-group .slider-with-bounds {
display: flex;
align-items: center;
gap: 0.5rem;
}
.settings-group .seed-input {
width: 100%;
padding: 0.5rem;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 0.9rem;
}
main {
max-width: calc(100vw - 2rem);
margin: 0 auto;
padding: 0.75rem 1rem;
}
/* Generator Grid Section */
.generator-grid-section {
background: var(--surface);
border-radius: 8px;
padding: 0.75rem 1rem;
margin-bottom: 0.75rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.generator-grid-section .section-title {
margin: 0 0 0.5rem 0;
font-size: 0.9rem;
color: var(--text-secondary);
}
.generator-grid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
gap: 0.5rem;
}
.generator-tile {
background: var(--background);
border: 2px solid transparent;
border-radius: 8px;
padding: 0.5rem;
cursor: pointer;
transition: all 0.2s ease;
display: flex;
flex-direction: column;
align-items: center;
}
.generator-tile:hover {
border-color: var(--border-color);
transform: translateY(-2px);
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.1);
}
.generator-tile.selected {
background: linear-gradient(135deg, #1e3a5f, #1e293b);
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.2);
}
.generator-tile.selected .generator-tile-name {
color: white;
}
.generator-tile-preview {
width: 100%;
height: 50px;
margin-bottom: 0.35rem;
}
.generator-tile-preview canvas {
width: 100% !important;
height: 100% !important;
}
.generator-tile-name {
font-size: 0.75rem;
font-weight: 600;
color: var(--text-primary);
text-align: center;
line-height: 1.2;
}
.generator-grid-break {
flex-basis: 100%;
height: 0;
grid-column: 1 / -1;
}
/* Placeholder tile for alignment */
.generator-tile.placeholder {
background: transparent;
border: 2px dashed var(--border-color);
cursor: default;
opacity: 0.3;
}
.generator-tile.placeholder:hover {
transform: none;
box-shadow: none;
border-color: var(--border-color);
}
/* Controls Section */
.controls {
background: var(--surface);
border-radius: 8px;
padding: 0.75rem 1rem;
margin-bottom: 0.75rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
display: grid;
grid-template-columns: repeat(auto-fit, minmax(180px, 1fr));
gap: 0.75rem;
align-items: end;
}
.control-group {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.control-group label {
font-weight: 600;
font-size: 0.75rem;
color: var(--text-secondary);
}
.control-group select,
.control-group input[type="number"] {
padding: 0.4rem 0.5rem;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 0.9rem;
background: white;
transition: border-color 0.2s, box-shadow 0.2s;
}
input[type="number"] {
text-align: right;
}
.control-group select:focus,
.control-group input:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 3px rgba(37, 99, 235, 0.1);
}
.control-group input[type="range"] {
width: 100%;
height: 8px;
border-radius: 4px;
background: var(--border-color);
appearance: none;
cursor: pointer;
}
.control-group input[type="range"]::-webkit-slider-thumb {
appearance: none;
width: 20px;
height: 20px;
border-radius: 50%;
background: var(--primary-color);
cursor: pointer;
transition: background 0.2s;
}
.control-group input[type="range"]::-webkit-slider-thumb:hover {
background: var(--primary-hover);
}
/* Top Controls - Parameters section */
.top-controls {
display: flex;
flex-wrap: wrap;
gap: 1rem;
align-items: end;
}
.slider-row {
display: flex;
align-items: center;
gap: 0.5rem;
}
.slider-row input[type="range"] {
flex: 1;
min-width: 120px;
}
.slider-row span {
min-width: 4ch;
text-align: right;
font-weight: 600;
font-size: 0.9rem;
color: var(--primary-color);
}
.slider-row input[type="number"] {
width: 5em;
text-align: center;
flex-shrink: 0;
}
/* Slider with configurable bounds */
.slider-with-bounds {
display: flex;
align-items: center;
gap: 0.35rem;
}
.slider-with-bounds input[type="range"] {
flex: 1;
min-width: 100px;
}
.slider-with-bounds .bound-input {
width: 4.5em;
padding: 0.25rem 0.3rem;
font-size: 0.75rem;
text-align: center;
border: 1px solid var(--border-color);
border-radius: 4px;
color: var(--text-secondary);
background: var(--background);
}
.slider-with-bounds .bound-input:focus {
outline: none;
border-color: var(--primary-color);
color: var(--text-primary);
}
.slider-with-bounds .value-input {
width: 5em;
padding: 0.3rem 0.4rem;
font-size: 0.85rem;
text-align: center;
border: 1px solid var(--border-color);
border-radius: 4px;
font-weight: 600;
color: var(--primary-color);
}
.slider-with-bounds .value-input:focus {
outline: none;
border-color: var(--primary-color);
box-shadow: 0 0 0 2px rgba(37, 99, 235, 0.1);
}
/* Y-Axis slider groups in toolbar */
.analysis-toolbar .y-axis-group {
flex: 0 1 420px;
min-width: 330px;
}
.analysis-toolbar .y-axis-group .slider-with-bounds input[type="range"] {
min-width: 120px;
}
.seed-input {
width: 5em !important;
text-align: center;
}
/* Dynamic Parameters */
.dynamic-params {
flex-basis: 100%;
display: flex;
flex-wrap: wrap;
gap: 1rem;
padding-top: 0.5rem;
border-top: 1px solid var(--border-color);
}
.dynamic-params:empty {
display: none;
}
#params-section:has(.dynamic-params:empty) {
display: none;
}
.param-group {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.param-group label {
font-size: 0.8rem;
color: var(--text-secondary);
}
.param-group .label-with-help {
display: flex;
align-items: center;
gap: 0.25rem;
}
.param-group input {
padding: 0.5rem;
border: 1px solid var(--border-color);
border-radius: 6px;
font-size: 0.9rem;
}
/* Control Actions */
.control-actions {
display: flex;
gap: 0.5rem;
align-items: end;
}
.btn-primary,
.btn-secondary {
padding: 0.5rem 1rem;
border: none;
border-radius: 6px;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
transition: all 0.2s;
}
.btn-primary {
background: var(--primary-color);
color: white;
}
.btn-primary:hover {
background: var(--primary-hover);
transform: translateY(-1px);
}
.btn-secondary {
background: var(--surface);
color: var(--text-primary);
border: 1px solid var(--border-color);
}
.btn-secondary:hover {
background: var(--background);
border-color: var(--secondary-color);
}
/* Generator Info */
.generator-info {
background: var(--surface);
border-radius: 8px;
padding: 0.5rem 1rem;
margin-bottom: 0.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.generator-info-header {
display: flex;
align-items: center;
gap: 1rem;
flex-wrap: wrap;
}
.generator-info-main {
flex: 1;
min-width: 200px;
}
.generator-info h3 {
font-size: 1rem;
margin-bottom: 0.15rem;
}
.generator-info p {
color: var(--text-secondary);
font-size: 0.85rem;
}
.change-point-badge {
margin: 0;
}
.badge {
display: inline-block;
padding: 0.25rem 0.75rem;
background: rgba(239, 68, 68, 0.1);
color: var(--danger-color);
border-radius: 20px;
font-size: 0.8rem;
font-weight: 600;
}
/* Generator Help Button (? icon) */
.generator-help-btn {
width: 22px;
height: 22px;
border-radius: 50%;
border: 1px solid var(--border-color);
background: var(--surface);
color: var(--text-secondary);
font-size: 0.8rem;
font-weight: 700;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
flex-shrink: 0;
}
.generator-help-btn:hover {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
.generator-help-btn.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
/* Generator Tutorial Panel */
.tutorial-panel {
margin-top: 0.75rem;
padding: 1rem;
background: linear-gradient(135deg, #f0f9ff, #e0f2fe);
border-radius: 8px;
border-left: 3px solid var(--primary-color);
animation: slideDown 0.2s ease-out;
}
@keyframes slideDown {
from {
opacity: 0;
transform: translateY(-10px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.tutorial-section {
margin-bottom: 0.75rem;
}
.tutorial-section:last-child {
margin-bottom: 0;
}
.tutorial-section h4 {
font-size: 0.8rem;
font-weight: 600;
color: var(--primary-color);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 0.25rem;
}
.tutorial-section p {
font-size: 0.85rem;
color: var(--text-primary);
line-height: 1.5;
}
/* Method Help Button */
.method-help-btn {
width: 20px;
height: 20px;
border-radius: 50%;
border: 1px solid var(--border-color);
background: var(--surface);
color: var(--text-secondary);
font-size: 0.75rem;
font-weight: 700;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
margin-left: auto;
}
.method-help-btn:hover {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
.method-help-btn.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
/* Method Tutorial Panel */
.method-tutorial {
margin-top: 0.75rem;
padding: 0.75rem;
background: rgba(255, 255, 255, 0.8);
border-radius: 6px;
border-top: 1px solid var(--border-color);
animation: slideDown 0.2s ease-out;
}
.method-tutorial .method-explanation {
font-size: 0.8rem;
color: var(--text-primary);
line-height: 1.5;
margin-bottom: 0.5rem;
}
.method-tutorial .method-algorithm {
margin-bottom: 0.5rem;
}
.method-tutorial .method-algorithm strong,
.method-tutorial .method-best-for strong {
font-size: 0.75rem;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.3px;
}
.method-tutorial .method-algorithm pre {
font-size: 0.75rem;
font-family: 'SF Mono', 'Monaco', 'Consolas', monospace;
background: var(--background);
padding: 0.5rem;
border-radius: 4px;
margin-top: 0.25rem;
white-space: pre-wrap;
line-height: 1.4;
color: var(--text-primary);
}
.method-tutorial .method-best-for ul {
margin: 0.25rem 0 0 1rem;
padding: 0;
font-size: 0.8rem;
}
.method-tutorial .method-best-for li {
margin-bottom: 0.15rem;
color: var(--text-primary);
}
/* Parameter Label with Help Button */
.label-with-help {
display: flex;
align-items: center;
gap: 0.25rem;
}
.param-help-btn {
width: 14px;
height: 14px;
border-radius: 50%;
border: 1px solid var(--border-color);
background: var(--surface);
color: var(--text-secondary);
font-size: 0.6rem;
font-weight: 700;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
padding: 0;
flex-shrink: 0;
}
.param-help-btn:hover {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
/* Parameter Label Tooltip */
.param-label[data-tooltip] {
cursor: help;
border-bottom: 1px dotted var(--text-secondary);
}
.param-tooltip {
position: fixed;
z-index: 1001;
background: var(--text-primary);
color: white;
padding: 0.5rem 0.75rem;
border-radius: 6px;
font-size: 0.75rem;
max-width: 280px;
line-height: 1.4;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
animation: fadeIn 0.15s ease-out;
}
@keyframes fadeIn {
from {
opacity: 0;
transform: translateY(-3px);
}
to {
opacity: 1;
transform: translateY(0);
}
}
.param-tooltip::before {
content: '';
position: absolute;
top: -6px;
left: 15px;
border-width: 0 6px 6px 6px;
border-style: solid;
border-color: transparent transparent var(--text-primary) transparent;
}
/* Popup tooltip for param help buttons */
.param-tooltip-popup {
position: fixed;
z-index: 1001;
background: var(--text-primary);
color: white;
padding: 0.5rem 0.75rem;
border-radius: 6px;
font-size: 0.75rem;
max-width: 280px;
line-height: 1.4;
box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2);
animation: fadeIn 0.15s ease-out;
}
.param-help-btn.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
/* Input with Help Button Container */
.input-with-help {
display: flex;
align-items: center;
gap: 0.35rem;
}
.input-with-help input {
flex: 1;
}
.hidden {
display: none !important;
}
/* Chart Container */
.chart-container {
background: var(--surface);
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 1.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.chart-container canvas {
width: 100% !important;
height: 400px !important;
}
/* Stats Section */
.stats {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(90px, 1fr));
gap: 0.4rem;
margin-bottom: 0.5rem;
}
.stat-card {
background: var(--surface);
border-radius: 4px;
padding: 0.3rem 0.4rem;
text-align: center;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.stat-card h4 {
font-size: 0.6rem;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.3px;
margin-bottom: 0.15rem;
}
.stat-card span {
font-size: 1rem;
font-weight: 700;
color: var(--primary-color);
}
/* Change Points Detail */
.change-points-detail {
background: var(--surface);
border-radius: 12px;
padding: 1.5rem;
margin-bottom: 1.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.change-points-detail h3 {
margin-bottom: 1rem;
}
.change-points-detail table {
width: 100%;
border-collapse: collapse;
}
.change-points-detail th,
.change-points-detail td {
padding: 0.75rem;
text-align: left;
border-bottom: 1px solid var(--border-color);
}
.change-points-detail th {
font-weight: 600;
color: var(--text-secondary);
font-size: 0.85rem;
text-transform: uppercase;
letter-spacing: 0.5px;
}
.change-points-detail tr:last-child td {
border-bottom: none;
}
.change-points-detail .empty-message {
color: var(--text-secondary);
font-style: italic;
}
/* Multi-chart Container */
.multi-chart-container {
background: var(--surface);
border-radius: 12px;
padding: 1.5rem;
margin-top: 2rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.multi-chart-container h2 {
margin-bottom: 1.5rem;
}
.chart-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(350px, 1fr));
gap: 1.5rem;
}
.mini-chart {
background: var(--background);
border-radius: 8px;
padding: 1rem;
}
.mini-chart h4 {
font-size: 0.9rem;
margin-bottom: 0.5rem;
color: var(--text-primary);
}
.mini-chart p {
font-size: 0.8rem;
color: var(--text-secondary);
margin-bottom: 0.75rem;
}
.mini-chart canvas {
width: 100% !important;
height: 200px !important;
}
/* Footer */
footer {
text-align: center;
padding: 2rem;
color: var(--text-secondary);
border-top: 1px solid var(--border-color);
margin-top: 2rem;
}
footer a {
color: var(--primary-color);
text-decoration: none;
}
footer a:hover {
text-decoration: underline;
}
/* Loading State */
.loading {
opacity: 0.6;
pointer-events: none;
}
/* Analysis Wrapper */
.analysis-wrapper {
background: var(--surface);
border-radius: 8px;
padding: 0.75rem 1rem;
margin-bottom: 0.75rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.analysis-wrapper .section-title {
margin: 0 0 0.5rem 0;
font-size: 1rem;
color: var(--text-primary);
}
.analysis-toolbar {
display: flex;
align-items: end;
gap: 1rem;
margin-bottom: 0.75rem;
padding-bottom: 0.75rem;
border-bottom: 1px solid var(--border-color);
}
.analysis-toolbar .control-actions {
display: flex;
gap: 0.5rem;
}
.analysis-toolbar .control-group {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.analysis-panels {
display: flex;
gap: 1rem;
flex-wrap: wrap;
}
.analysis-panels .controls {
flex: 1;
min-width: 200px;
margin-bottom: 0;
box-shadow: none;
background: var(--background);
border-radius: 6px;
padding: 0.75rem;
display: flex;
flex-direction: column;
align-items: flex-start;
}
.analysis-panels .panel-header {
display: flex;
align-items: center;
gap: 0.4rem;
margin-bottom: 0.4rem;
}
.analysis-panels .panel-header input[type="checkbox"] {
width: 14px;
height: 14px;
cursor: pointer;
}
.analysis-panels .panel-title {
margin: 0;
font-size: 0.85rem;
font-weight: 600;
cursor: pointer;
}
.analysis-panels .panel-fields {
display: flex;
flex-direction: column;
gap: 0.25rem;
}
.analysis-panels .panel-fields .control-group {
display: flex;
flex-direction: row;
align-items: center;
gap: 0.5rem;
}
.analysis-panels .panel-fields .control-group label {
font-size: 0.75rem;
white-space: nowrap;
display: inline-block;
width: 100px;
text-align: left;
}
.analysis-panels .panel-fields .control-group input {
width: 70px;
padding: 0.25rem 0.4rem;
font-size: 0.85rem;
}
/* Wider input for p-value to accommodate small values like 0.00001 */
#max-pvalue-input {
width: 90px;
}
/* Otava Controls Section */
.otava-controls {
border-left: 3px solid var(--primary-color);
}
.otava-controls .section-title,
.otava-controls .panel-title {
grid-column: 1 / -1;
margin: 0 0 0.25rem 0;
color: var(--primary-color);
font-size: 0.9rem;
}
.control-group input[type="checkbox"] {
width: 18px;
height: 18px;
margin-right: 0.5rem;
cursor: pointer;
}
.control-group label:has(input[type="checkbox"]) {
display: flex;
align-items: center;
cursor: pointer;
}
/* Chart Legend - hidden as markers are self-explanatory */
.chart-legend {
display: none;
}
.legend-item {
display: flex;
align-items: center;
gap: 0.35rem;
font-size: 0.8rem;
}
.legend-marker {
width: 12px;
height: 12px;
border-radius: 50%;
display: inline-block;
}
.legend-line {
width: 20px;
height: 16px;
display: inline-flex;
align-items: center;
justify-content: center;
}
.legend-line.ground-truth::before {
content: '';
width: 2px;
height: 100%;
background: repeating-linear-gradient(
to bottom,
#10b981 0px,
#10b981 4px,
transparent 4px,
transparent 7px
);
}
.legend-marker.true-positive {
background: #f87171;
border: 2px solid #ef4444;
border-radius: 50%;
width: 10px;
height: 10px;
}
.legend-marker.close-match {
background: #fde047;
border: 2px solid #eab308;
width: 10px;
height: 10px;
transform: rotate(45deg);
}
.legend-marker.false-positive {
background: transparent;
border-radius: 0;
width: 0;
height: 0;
border-style: solid;
border-width: 0 6px 10px 6px;
border-color: transparent transparent #f97316 transparent;
}
/* Moving Average Controls Section */
.ma-controls {
border-left: 3px solid #8b5cf6;
}
.ma-controls .section-title,
.ma-controls .panel-title {
grid-column: 1 / -1;
margin: 0 0 0.25rem 0;
color: #8b5cf6;
font-size: 0.9rem;
}
/* Boundary Controls Section */
.boundary-controls {
border-left: 3px solid #06b6d4;
}
.boundary-controls .section-title,
.boundary-controls .panel-title {
grid-column: 1 / -1;
margin: 0 0 0.25rem 0;
color: #06b6d4;
font-size: 0.9rem;
}
/* Threshold Alert Controls Section */
.threshold-controls {
border-left: 3px solid #ec4899;
}
.threshold-controls .section-title,
.threshold-controls .panel-title {
grid-column: 1 / -1;
margin: 0 0 0.25rem 0;
color: #ec4899;
font-size: 0.9rem;
}
/* Sliding Window Controls Section */
.sliding-window-controls {
border-left: 3px solid #14b8a6;
}
.sliding-window-controls .section-title,
.sliding-window-controls .panel-title {
grid-column: 1 / -1;
margin: 0 0 0.25rem 0;
color: #14b8a6;
font-size: 0.9rem;
}
/* Std Dev Controls Section */
.stddev-controls {
border-left: 3px solid #a855f7;
}
.stddev-controls .section-title,
.stddev-controls .panel-title {
grid-column: 1 / -1;
margin: 0 0 0.25rem 0;
color: #a855f7;
font-size: 0.9rem;
}
/* Accuracy Metrics */
.accuracy-metrics {
background: var(--surface);
border-radius: 6px;
padding: 0.4rem 0.6rem;
margin-bottom: 0.5rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.metrics-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.3rem;
}
.metrics-header h3 {
margin: 0;
font-size: 0.85rem;
}
.metrics-help-btn {
width: 18px;
height: 18px;
border-radius: 50%;
border: 1px solid var(--border-color);
background: var(--surface);
color: var(--text-secondary);
font-size: 0.7rem;
font-weight: 700;
cursor: pointer;
transition: all 0.2s;
display: flex;
align-items: center;
justify-content: center;
}
.metrics-help-btn:hover {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
.metrics-help-btn.active {
background: var(--primary-color);
border-color: var(--primary-color);
color: white;
}
/* Metrics Tutorial Panel */
.metrics-tutorial-panel {
margin-bottom: 0.5rem;
padding: 0.75rem;
background: linear-gradient(135deg, #fef3c7, #fde68a);
border-radius: 6px;
border-left: 3px solid #f59e0b;
animation: slideDown 0.2s ease-out;
}
.metrics-tutorial-content {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(200px, 1fr));
gap: 0.75rem;
}
.metrics-tutorial-section {
background: rgba(255, 255, 255, 0.7);
padding: 0.5rem;
border-radius: 4px;
}
.metrics-tutorial-section h4 {
font-size: 0.75rem;
font-weight: 600;
color: #92400e;
margin-bottom: 0.25rem;
}
.metrics-tutorial-section p,
.metrics-tutorial-section li {
font-size: 0.8rem;
color: var(--text-primary);
line-height: 1.4;
margin: 0;
}
.metrics-tutorial-section ul {
margin: 0.25rem 0 0 1rem;
padding: 0;
}
.metrics-tutorial-section li {
margin-bottom: 0.2rem;
}
.metrics-tutorial-section.metrics-formulas,
.metrics-tutorial-section.metrics-matching {
grid-column: 1 / -1;
}
.highlight-green {
color: #10b981;
font-weight: 600;
}
.highlight-blue {
color: #3b82f6;
font-weight: 600;
}
.highlight-red {
color: #ef4444;
font-weight: 600;
}
.metrics-grid {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 0.4rem;
}
.metric-card {
background: var(--background);
border-radius: 6px;
padding: 0.35rem 0.5rem;
text-align: center;
}
.metric-card h4 {
font-size: 0.7rem;
color: var(--text-secondary);
text-transform: uppercase;
letter-spacing: 0.5px;
margin-bottom: 0.2rem;
}
.metric-card span {
font-size: 1.1rem;
font-weight: 700;
display: block;
line-height: 1.2;
}
.metric-card .metric-desc {
font-size: 0.65rem;
color: var(--text-secondary);
margin-top: 0.15rem;
}
.metric-card.precision span { color: #10b981; }
.metric-card.recall span { color: #3b82f6; }
.metric-card.f1 span { color: #8b5cf6; }
.metric-card.counts {
background: linear-gradient(135deg, #f8fafc, #f1f5f9);
}
.count-details {
display: flex;
justify-content: center;
gap: 0.5rem;
font-size: 0.85rem;
}
.count-details span {
font-size: 0.9rem;
font-weight: normal;
}
.count-details strong {
font-weight: 700;
}
/* Accuracy Table */
.accuracy-table {
width: 100%;
border-collapse: collapse;
font-size: 0.85rem;
}
.accuracy-table th,
.accuracy-table td {
padding: 0.4rem 0.6rem;
text-align: center;
border-bottom: 1px solid var(--border);
}
.accuracy-table th {
background: var(--background);
font-weight: 600;
font-size: 0.75rem;
text-transform: uppercase;
letter-spacing: 0.5px;
color: var(--text-secondary);
}
.accuracy-table th:first-child,
.accuracy-table td:first-child {
text-align: left;
}
.accuracy-table tbody tr:hover {
background: var(--background);
}
.accuracy-table td:nth-child(2) { color: #ef4444; } /* TP - red */
.accuracy-table td:nth-child(3) { color: #eab308; } /* CM - yellow */
.accuracy-table td:nth-child(4) { color: #f97316; } /* FP - orange */
.accuracy-table td:nth-child(5) { color: #64748b; } /* FN - gray */
.accuracy-table td:nth-child(6) { color: #10b981; } /* Precision - green */
.accuracy-table td:nth-child(7) { color: #3b82f6; } /* Recall - blue */
.accuracy-table td:nth-child(8) { color: #8b5cf6; } /* F1 - purple */
.accuracy-table .empty-message {
color: var(--text-secondary);
font-style: italic;
text-align: center;
}
/* Comparison Tables */
.comparison-tables {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1.5rem;
}
.table-wrapper {
overflow-x: auto;
}
.table-wrapper h4 {
margin-bottom: 0.75rem;
color: var(--text-primary);
}
.table-wrapper table {
width: 100%;
font-size: 0.9rem;
}
/* Status badges in tables */
.status-matched {
color: #10b981;
font-weight: 600;
}
.status-missed {
color: #ef4444;
font-weight: 600;
}
.status-fp {
color: #f59e0b;
font-weight: 600;
}
.status-tp {
color: #10b981;
font-weight: 600;
}
/* Summary Stats for All Patterns */
.summary-stats {
background: linear-gradient(135deg, #f0f9ff, #e0f2fe);
border-radius: 10px;
padding: 1.5rem;
margin-bottom: 1.5rem;
display: grid;
grid-template-columns: repeat(auto-fit, minmax(120px, 1fr));
gap: 1rem;
text-align: center;
}
.summary-stat {
padding: 0.5rem;
}
.summary-stat h4 {
font-size: 0.75rem;
color: var(--text-secondary);
text-transform: uppercase;
margin-bottom: 0.25rem;
}
.summary-stat span {
font-size: 1.5rem;
font-weight: 700;
color: var(--primary-color);
}
/* Mini chart with accuracy indicator */
.mini-chart .accuracy-indicator {
display: flex;
justify-content: space-between;
font-size: 0.8rem;
margin-top: 0.5rem;
padding-top: 0.5rem;
border-top: 1px solid var(--border-color);
}
.mini-chart .accuracy-indicator span {
font-size: 0.8rem;
}
.accuracy-good { color: #10b981; }
.accuracy-medium { color: #f59e0b; }
.accuracy-poor { color: #ef4444; }
/* Stacked Charts Container */
.stacked-charts-container {
display: flex;
flex-direction: column;
gap: 0.75rem;
margin-bottom: 1rem;
}
.stacked-chart {
background: var(--surface);
border-radius: 10px;
padding: 1rem 1.25rem;
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.1);
}
.stacked-chart-header {
display: flex;
align-items: center;
gap: 0.5rem;
margin-bottom: 0.5rem;
padding-bottom: 0.5rem;
border-bottom: 1px solid var(--border-color);
}
.stacked-chart-header h4 {
margin: 0;
font-size: 0.95rem;
font-weight: 600;
}
.stacked-chart-header .method-indicator {
width: 12px;
height: 12px;
border-radius: 3px;
}
.stacked-chart-header .method-indicator.otava {
background: var(--primary-color);
}
.stacked-chart-header .method-indicator.ma {
background: #8b5cf6;
}
.stacked-chart-header .method-indicator.boundary {
background: #06b6d4;
}
.stacked-chart-header .method-indicator.threshold {
background: #ec4899;
}
.stacked-chart-header .method-indicator.slidingWindow {
background: #14b8a6;
}
.stacked-chart-header .method-indicator.stdDev {
background: #a855f7;
}
.stacked-chart-header .detection-count {
margin-left: auto;
font-size: 0.8rem;
color: var(--text-secondary);
}
.stacked-chart-header .detection-count strong {
color: var(--text-primary);
}
.stacked-chart canvas {
width: 100% !important;
height: 250px !important;
}
/* First chart (Otava) gets more height */
.stacked-chart:first-child canvas {
height: 300px !important;
}
/* Mix Mode Styles */
.section-header {
display: flex;
justify-content: space-between;
align-items: center;
margin-bottom: 0.5rem;
}
.section-header .section-title {
margin: 0;
}
.mode-toggle {
display: flex;
gap: 0.25rem;
}
.mode-btn {
padding: 0.35rem 0.75rem;
border: 1px solid var(--border-color);
border-radius: 4px;
background: var(--surface);
color: var(--text-secondary);
font-size: 0.8rem;
font-weight: 500;
cursor: pointer;
transition: all 0.2s;
}
.mode-btn:hover {
background: var(--background);
border-color: var(--secondary-color);
}
.mode-btn.active {
background: var(--primary-color);
color: white;
border-color: var(--primary-color);
}
/* Mix info panel */
.mix-info {
display: flex;
align-items: center;
gap: 1rem;
padding: 0.5rem 0.75rem;
background: linear-gradient(135deg, #1e3a5f, #1e293b);
border-radius: 6px;
margin-bottom: 0.5rem;
}
.mix-info.hidden {
display: none;
}
.mix-recipe {
color: #94a3b8;
font-size: 0.85rem;
flex: 1;
}
.mix-recipe .component {
color: #60a5fa;
font-weight: 600;
}
.mix-recipe .operation {
color: #f97316;
font-weight: 600;
padding: 0 0.25rem;
}
.clear-mix-btn {
padding: 0.25rem 0.5rem;
font-size: 0.75rem;
background: rgba(239, 68, 68, 0.2);
color: #f87171;
border: 1px solid rgba(239, 68, 68, 0.3);
border-radius: 4px;
cursor: pointer;
transition: all 0.2s;
}
.clear-mix-btn:hover {
background: rgba(239, 68, 68, 0.3);
border-color: rgba(239, 68, 68, 0.5);
}
/* Hidden rows in mix mode */
.generator-grid.mix-mode .row-3-tile,
.generator-grid.mix-mode .row-4-tile {
display: none;
}
/* Count badge on tiles */
.generator-tile {
position: relative;
}
.tile-count-badge {
position: absolute;
top: -6px;
right: -6px;
background: #ef4444;
color: white;
border-radius: 50%;
width: 20px;
height: 20px;
font-size: 0.7rem;
font-weight: 700;
display: flex;
align-items: center;
justify-content: center;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
z-index: 10;
}
/* Operation tile in mix mode */
.operation-tile {
background: #1e293b !important;
border: 2px solid #3b82f6 !important;
cursor: pointer;
min-height: 80px;
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
}
.operation-tile:hover {
background: #1e3a5f !important;
border-color: #60a5fa !important;
}
.operation-tile .op-label {
font-size: 1.1rem;
font-weight: 700;
color: #60a5fa;
text-transform: uppercase;
}
.operation-tile .op-hint {
font-size: 0.65rem;
color: #64748b;
margin-top: 0.25rem;
}
/* Mix mode tile highlight */
.generator-grid.mix-mode .generator-tile:not(.placeholder):not(.operation-tile) {
cursor: pointer;
}
.generator-grid.mix-mode .generator-tile:not(.placeholder):not(.operation-tile):hover {
border-color: #3b82f6;
box-shadow: 0 0 0 2px rgba(59, 130, 246, 0.3);
}
.generator-grid.mix-mode .generator-tile.in-mix {
background: linear-gradient(135deg, #1e3a5f, #1e293b);
border-color: #3b82f6;
}
.generator-grid.mix-mode .generator-tile.in-mix .generator-tile-name {
color: white;
}
/* Responsive */
@media (max-width: 768px) {
header {
padding: 1.5rem;
}
header h1 {
font-size: 1.5rem;
}
main {
padding: 1rem;
}
.controls {
grid-template-columns: 1fr;
}
.control-actions {
flex-direction: column;
}
.btn-primary,
.btn-secondary {
width: 100%;
}
.chart-grid {
grid-template-columns: 1fr;
}
}
/* ============================================================
Dataset mode — load a bundled or pasted series and compare
Otava algorithm variants on the same data.
============================================================ */
.dataset-section {
background: #fafafa;
border: 1px solid #e2e8f0;
border-radius: 8px;
padding: 16px 20px;
margin: 0 0 20px;
}
.dataset-section.hidden {
display: none;
}
/* The mode toggle bar sits above the per-mode content. */
.mode-toggle-section {
margin-bottom: 8px;
}
.dataset-row {
display: flex;
flex-direction: column;
gap: 8px;
margin-bottom: 16px;
}
.dataset-label {
display: flex;
flex-direction: column;
gap: 4px;
font-size: 14px;
font-weight: 600;
max-width: 480px;
}
.dataset-label select {
padding: 6px 8px;
font: inherit;
border: 1px solid #cbd5e1;
border-radius: 4px;
background: #fff;
}
.dataset-description {
font-size: 13px;
color: #64748b;
margin: 0;
min-height: 1.4em;
}
.dataset-custom {
display: flex;
flex-direction: column;
gap: 4px;
font-size: 14px;
font-weight: 600;
}
.dataset-custom.hidden {
display: none;
}
.dataset-custom textarea {
font-family: ui-monospace, "SF Mono", Monaco, monospace;
font-size: 13px;
padding: 8px;
border: 1px solid #cbd5e1;
border-radius: 4px;
resize: vertical;
}
.dataset-hint {
margin: 8px 0 0;
font-size: 13px;
color: #475569;
}
.dataset-status {
margin: 8px 0 0;
padding: 6px 10px;
background: #eef2ff;
border: 1px solid #c7d2fe;
border-radius: 4px;
font-size: 13px;
color: #1e1b4b;
}
.dataset-status--error {
background: #fef2f2;
border-color: #fecaca;
color: #7f1d1d;
}
.otava-algo-row .algo-unavail {
margin-left: 4px;
color: #94a3b8;
font-style: italic;
}
.dataset-results.hidden {
display: none;
}
.dataset-results h3 {
margin: 16px 0 8px;
}
.dataset-results-table {
width: 100%;
border-collapse: collapse;
font-size: 14px;
}
.dataset-results-table th,
.dataset-results-table td {
border: 1px solid #e2e8f0;
padding: 6px 10px;
text-align: left;
vertical-align: top;
}
.dataset-results-table th {
background: #f1f5f9;
}
.dataset-results-table .swatch {
display: inline-block;
width: 12px;
height: 12px;
border-radius: 2px;
margin-right: 8px;
vertical-align: middle;
}
/* In dataset mode, hide synthetic-data and ground-truth UI. */
body[data-mode="dataset"] .hide-in-dataset {
display: none !important;
}
/* Otava algorithm checkbox group (used in the Otava analysis panel). */
.otava-algos {
display: flex;
flex-direction: column;
gap: 4px;
margin: 4px 0 12px;
font-size: 13px;
}
.otava-algo-row {
display: flex;
align-items: center;
gap: 6px;
white-space: nowrap;
line-height: 1.4;
}
.otava-algo-row input[type="checkbox"] {
flex-shrink: 0;
}
.otava-algo-row input[disabled] {
cursor: not-allowed;
}
.algo-hint {
color: #64748b;
font-size: 11px;
}