from __future__ import annotations
import os, datetime
from jinja2 import Template

_TEMPLATE = """
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>FlakeRadar Report - {{ project }}</title>
<script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
<link href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css" rel="stylesheet">
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@300;400;500;600;700;800;900&family=JetBrains+Mono:wght@400;500;600;700&display=swap" rel="stylesheet">
<style>
/* CSS Variables for Theme */
:root {
  --primary-color: #6366f1;
  --primary-light: #818cf8;
  --primary-dark: #4f46e5;
  --secondary-color: #06b6d4;
  --success-color: #059669;
  --success-light: #10b981;
  --warning-color: #d97706;
  --warning-light: #f59e0b;
  --danger-color: #dc2626;
  --danger-light: #ef4444;
  --purple-color: #7c3aed;
  --pink-color: #ec4899;
  
  --gray-50: #f8fafc;
  --gray-100: #f1f5f9;
  --gray-200: #e2e8f0;
  --gray-300: #cbd5e1;
  --gray-400: #94a3b8;
  --gray-500: #64748b;
  --gray-600: #475569;
  --gray-700: #334155;
  --gray-800: #1e293b;
  --gray-900: #0f172a;
  
  --border-radius: 16px;
  --border-radius-sm: 8px;
  --border-radius-lg: 24px;
  
  --shadow-sm: 0 1px 2px 0 rgb(0 0 0 / 0.05);
  --shadow-md: 0 4px 6px -1px rgb(0 0 0 / 0.1), 0 2px 4px -2px rgb(0 0 0 / 0.1);
  --shadow-lg: 0 10px 15px -3px rgb(0 0 0 / 0.1), 0 4px 6px -4px rgb(0 0 0 / 0.1);
  --shadow-xl: 0 20px 25px -5px rgb(0 0 0 / 0.1), 0 10px 10px -5px rgb(0 0 0 / 0.04);
  --shadow-glow: 0 0 20px rgb(99 102 241 / 0.15);
  
  --gradient-primary: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
  --gradient-secondary: linear-gradient(135deg, #f093fb 0%, #f5576c 100%);
  --gradient-success: linear-gradient(135deg, #4facfe 0%, #00f2fe 100%);
  --gradient-warning: linear-gradient(135deg, #fa709a 0%, #fee140 100%);
  --gradient-glass: rgba(255, 255, 255, 0.1);
}

/* Reset and Base Styles */
* { 
  margin: 0; 
  padding: 0; 
  box-sizing: border-box; 
}

::selection {
  background: var(--primary-color);
  color: white;
}

body { 
  font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, 'Helvetica Neue', sans-serif;
  line-height: 1.6;
  color: var(--gray-800);
  background: var(--gradient-primary);
  min-height: 100vh;
  overflow-x: hidden;
}

/* Glass morphism backdrop */
body::before {
  content: '';
  position: fixed;
  top: 0;
  left: 0;
  width: 100%;
  height: 100%;
  background: url('data:image/svg+xml,<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 1000 1000"><defs><radialGradient id="a" cx="50%" cy="50%"><stop offset="0%" stop-color="%23ffffff" stop-opacity="0.1"/><stop offset="100%" stop-color="%23ffffff" stop-opacity="0"/></radialGradient></defs><circle cx="200" cy="200" r="150" fill="url(%23a)"/><circle cx="800" cy="300" r="200" fill="url(%23a)"/><circle cx="400" cy="700" r="180" fill="url(%23a)"/><circle cx="900" cy="800" r="120" fill="url(%23a)"/></svg>');
  pointer-events: none;
  z-index: -1;
}

/* Header */
.header {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-bottom: 1px solid rgba(255, 255, 255, 0.2);
  box-shadow: var(--shadow-lg);
  position: sticky;
  top: 0;
  z-index: 100;
  padding: 1.5rem 0;
  transition: all 0.3s ease;
}

.header::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: linear-gradient(90deg, 
    var(--primary-color) 0%, 
    var(--secondary-color) 50%, 
    var(--purple-color) 100%);
  opacity: 0.03;
  z-index: -1;
}

.header-content {
  max-width: 1400px;
  margin: 0 auto;
  padding: 0 2rem;
  display: flex;
  justify-content: space-between;
  align-items: center;
}

.logo {
  display: flex;
  align-items: center;
  gap: 1rem;
  font-size: 1.75rem;
  font-weight: 800;
  background: linear-gradient(135deg, var(--primary-color), var(--purple-color));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  position: relative;
}

.logo i {
  font-size: 2.5rem;
  background: linear-gradient(135deg, var(--primary-color), var(--purple-color));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
  filter: drop-shadow(0 4px 8px rgba(99, 102, 241, 0.3));
  animation: pulse 3s ease-in-out infinite;
}

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

.project-info {
  text-align: right;
  display: flex;
  flex-direction: column;
  gap: 0.5rem;
}

.project-name {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--gray-800);
  background: linear-gradient(135deg, var(--gray-800), var(--gray-600));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.generated-time {
  font-size: 0.875rem;
  color: var(--gray-600);
  display: flex;
  align-items: center;
  gap: 0.5rem;
  justify-content: flex-end;
  background: var(--gray-100);
  padding: 0.5rem 1rem;
  border-radius: var(--border-radius-sm);
  border: 1px solid var(--gray-200);
}

/* Main Container */
.container {
  max-width: 1400px;
  margin: 0 auto;
  padding: 3rem 2rem;
}

/* Stats Cards */
.stats-grid {
  display: grid;
  grid-template-columns: repeat(auto-fit, minmax(280px, 1fr));
  gap: 2rem;
  margin-bottom: 3rem;
}

.stat-card {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  padding: 2rem;
  border-radius: var(--border-radius);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: var(--shadow-xl);
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
}

.stat-card::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg, var(--primary-color), var(--secondary-color));
  border-radius: var(--border-radius) var(--border-radius) 0 0;
}

.stat-card:hover {
  transform: translateY(-8px) scale(1.02);
  box-shadow: var(--shadow-xl), var(--shadow-glow);
  border-color: rgba(99, 102, 241, 0.3);
}

.stat-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 1.5rem;
}

.stat-title {
  font-size: 0.875rem;
  color: var(--gray-600);
  font-weight: 600;
  text-transform: uppercase;
  letter-spacing: 0.1em;
}

.stat-icon {
  width: 3.5rem;
  height: 3.5rem;
  display: flex;
  align-items: center;
  justify-content: center;
  font-size: 1.5rem;
  border-radius: 50%;
  position: relative;
  overflow: hidden;
}

.stat-icon::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  bottom: 0;
  background: inherit;
  opacity: 0.1;
  border-radius: 50%;
}

.stat-value {
  font-size: 3rem;
  font-weight: 800;
  line-height: 1;
  margin-bottom: 0.5rem;
  background: linear-gradient(135deg, var(--gray-800), var(--gray-600));
  -webkit-background-clip: text;
  -webkit-text-fill-color: transparent;
  background-clip: text;
}

.stat-change {
  font-size: 0.875rem;
  margin-top: 1rem;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.5rem 1rem;
  background: var(--gray-50);
  border-radius: var(--border-radius-sm);
  border: 1px solid var(--gray-200);
  color: var(--gray-700);
  font-weight: 500;
}

.icon-flaky { 
  background: linear-gradient(135deg, var(--warning-light), var(--warning-color));
  color: white;
  box-shadow: 0 8px 16px rgba(245, 158, 11, 0.3);
}

.icon-stable { 
  background: linear-gradient(135deg, var(--success-light), var(--success-color));
  color: white;
  box-shadow: 0 8px 16px rgba(16, 185, 129, 0.3);
}

.icon-total { 
  background: linear-gradient(135deg, var(--primary-light), var(--primary-color));
  color: white;
  box-shadow: 0 8px 16px rgba(99, 102, 241, 0.3);
}

.icon-critical { 
  background: linear-gradient(135deg, var(--danger-light), var(--danger-color));
  color: white;
  box-shadow: 0 8px 16px rgba(239, 68, 68, 0.3);
}

/* Filters */
.filters {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  padding: 2rem;
  border-radius: var(--border-radius);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: var(--shadow-lg);
  margin-bottom: 3rem;
  position: relative;
}

.filters::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg, var(--secondary-color), var(--primary-color));
  border-radius: var(--border-radius) var(--border-radius) 0 0;
}

.filter-row {
  display: flex;
  gap: 2rem;
  align-items: end;
  flex-wrap: wrap;
}

.filter-group {
  display: flex;
  flex-direction: column;
  gap: 0.75rem;
  min-width: 200px;
}

.filter-label {
  font-size: 0.875rem;
  font-weight: 600;
  color: var(--gray-700);
  display: flex;
  align-items: center;
  gap: 0.5rem;
}

.filter-input {
  padding: 0.75rem 1.25rem;
  border: 2px solid var(--gray-200);
  border-radius: var(--border-radius-sm);
  font-size: 0.875rem;
  font-weight: 500;
  transition: all 0.3s ease;
  background: white;
  box-shadow: var(--shadow-sm);
}

.filter-input:focus {
  outline: none;
  border-color: var(--primary-color);
  box-shadow: 0 0 0 4px rgba(99, 102, 241, 0.1), var(--shadow-md);
  transform: translateY(-2px);
}

.filter-input:hover {
  border-color: var(--gray-300);
  transform: translateY(-1px);
}

.filter-buttons {
  display: flex;
  gap: 0.75rem;
  margin-left: auto;
  flex-wrap: wrap;
}

.filter-btn {
  padding: 0.75rem 1.5rem;
  border: 2px solid transparent;
  border-radius: var(--border-radius-sm);
  font-size: 0.875rem;
  font-weight: 600;
  cursor: pointer;
  transition: all 0.3s ease;
  position: relative;
  overflow: hidden;
  text-transform: uppercase;
  letter-spacing: 0.05em;
  min-width: 100px;
}

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

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

.filter-btn.active {
  background: linear-gradient(135deg, var(--primary-color), var(--primary-dark));
  color: white;
  box-shadow: 0 8px 16px rgba(99, 102, 241, 0.3);
  transform: translateY(-2px);
}

.filter-btn:not(.active) {
  background: white;
  color: var(--gray-700);
  border-color: var(--gray-200);
  box-shadow: var(--shadow-sm);
}

.filter-btn:not(.active):hover {
  background: var(--gray-50);
  border-color: var(--gray-300);
  transform: translateY(-2px);
  box-shadow: var(--shadow-md);
}

/* Chart Container */
.chart-container {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  padding: 2.5rem;
  border-radius: var(--border-radius);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: var(--shadow-xl);
  margin-bottom: 3rem;
  position: relative;
}

.chart-container::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg, var(--purple-color), var(--pink-color));
  border-radius: var(--border-radius) var(--border-radius) 0 0;
}

.chart-header {
  display: flex;
  justify-content: space-between;
  align-items: center;
  margin-bottom: 2rem;
  padding-bottom: 1rem;
  border-bottom: 2px solid var(--gray-100);
}

.chart-title {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--gray-800);
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.chart-title::before {
  content: '📈';
  font-size: 1.25rem;
}

.chart-controls {
  display: flex;
  align-items: center;
  gap: 1rem;
  padding: 0.75rem 1.25rem;
  background: var(--gray-50);
  border-radius: var(--border-radius-sm);
  border: 1px solid var(--gray-200);
}

.chart-canvas {
  max-height: 450px;
  filter: drop-shadow(0 4px 8px rgba(0, 0, 0, 0.1));
}

/* Table */
.table-container {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border-radius: var(--border-radius);
  border: 1px solid rgba(255, 255, 255, 0.3);
  box-shadow: var(--shadow-xl);
  overflow: hidden;
  margin-bottom: 3rem;
  position: relative;
}

.table-container::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg, var(--success-color), var(--secondary-color));
  border-radius: var(--border-radius) var(--border-radius) 0 0;
}

.table-header {
  padding: 2rem;
  border-bottom: 2px solid var(--gray-100);
  background: linear-gradient(135deg, var(--gray-50), white);
}

.table-title {
  font-size: 1.5rem;
  font-weight: 700;
  color: var(--gray-800);
  margin-bottom: 0.75rem;
  display: flex;
  align-items: center;
  gap: 0.75rem;
}

.table-description {
  color: var(--gray-600);
  font-size: 0.95rem;
  line-height: 1.6;
  font-weight: 500;
}

.table-wrapper {
  overflow-x: auto;
  max-height: 600px;
  overflow-y: auto;
}

.table-wrapper::-webkit-scrollbar {
  width: 8px;
  height: 8px;
}

.table-wrapper::-webkit-scrollbar-track {
  background: var(--gray-100);
}

.table-wrapper::-webkit-scrollbar-thumb {
  background: var(--gray-300);
  border-radius: 4px;
}

.table-wrapper::-webkit-scrollbar-thumb:hover {
  background: var(--gray-400);
}

table {
  width: 100%;
  border-collapse: collapse;
}

th, td {
  padding: 1.25rem 1rem;
  text-align: left;
  border-bottom: 1px solid var(--gray-100);
  vertical-align: middle;
}

th {
  background: linear-gradient(135deg, var(--gray-50), var(--gray-100));
  font-weight: 700;
  color: var(--gray-800);
  font-size: 0.875rem;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  position: sticky;
  top: 0;
  z-index: 10;
  border-bottom: 2px solid var(--gray-200);
  cursor: pointer;
  transition: all 0.2s ease;
}

th:hover {
  background: linear-gradient(135deg, var(--gray-100), var(--gray-200));
  color: var(--primary-color);
}

tr {
  transition: all 0.2s ease;
}

tr:hover {
  background: linear-gradient(135deg, var(--gray-50), rgba(99, 102, 241, 0.02));
  transform: scale(1.005);
  box-shadow: 0 4px 8px rgba(0, 0, 0, 0.08);
}

.test-name {
  font-weight: 600;
  color: var(--gray-800);
  font-family: 'JetBrains Mono', 'Fira Code', 'Monaco', 'Menlo', monospace;
  font-size: 0.875rem;
  background: var(--gray-50);
  padding: 0.5rem 0.75rem;
  border-radius: var(--border-radius-sm);
  border: 1px solid var(--gray-200);
  display: inline-block;
  max-width: 300px;
  overflow: hidden;
  text-overflow: ellipsis;
  white-space: nowrap;
}

.status-badge {
  padding: 0.5rem 1rem;
  border-radius: 9999px;
  font-size: 0.75rem;
  font-weight: 700;
  text-transform: uppercase;
  letter-spacing: 0.1em;
  display: inline-flex;
  align-items: center;
  gap: 0.5rem;
  border: 2px solid transparent;
  transition: all 0.2s ease;
  position: relative;
  overflow: hidden;
}

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

.status-badge:hover::before {
  left: 100%;
}

.status-flaky {
  background: linear-gradient(135deg, var(--warning-light), var(--warning-color));
  color: white;
  box-shadow: 0 4px 8px rgba(245, 158, 11, 0.3);
}

.status-flaky::after {
  content: '⚠️';
  font-size: 0.75rem;
}

.status-stable {
  background: linear-gradient(135deg, var(--success-light), var(--success-color));
  color: white;
  box-shadow: 0 4px 8px rgba(16, 185, 129, 0.3);
}

.status-stable::after {
  content: '✅';
  font-size: 0.75rem;
}

.status-failing {
  background: linear-gradient(135deg, var(--danger-light), var(--danger-color));
  color: white;
  box-shadow: 0 4px 8px rgba(239, 68, 68, 0.3);
}

.status-failing::after {
  content: '❌';
  font-size: 0.75rem;
}

.flake-rate {
  font-weight: 700;
  font-size: 0.95rem;
  padding: 0.25rem 0.75rem;
  border-radius: var(--border-radius-sm);
  display: inline-block;
  min-width: 60px;
  text-align: center;
}

.flake-rate.high { 
  color: white;
  background: linear-gradient(135deg, var(--danger-color), var(--danger-light));
  box-shadow: 0 4px 8px rgba(220, 38, 38, 0.3);
}

.flake-rate.medium { 
  color: white;
  background: linear-gradient(135deg, var(--warning-color), var(--warning-light));
  box-shadow: 0 4px 8px rgba(217, 119, 6, 0.3);
}

.flake-rate.low { 
  color: white;
  background: linear-gradient(135deg, var(--success-color), var(--success-light));
  box-shadow: 0 4px 8px rgba(5, 150, 105, 0.3);
}

.confidence-score {
  font-weight: 700;
  font-size: 0.95rem;
  padding: 0.25rem 0.75rem;
  border-radius: var(--border-radius-sm);
  display: inline-block;
  min-width: 60px;
  text-align: center;
}

.confidence-score.high { 
  color: white;
  background: linear-gradient(135deg, var(--success-color), var(--success-light));
  box-shadow: 0 4px 8px rgba(5, 150, 105, 0.3);
}

.confidence-score.medium { 
  color: white;
  background: linear-gradient(135deg, var(--warning-color), var(--warning-light));
  box-shadow: 0 4px 8px rgba(217, 119, 6, 0.3);
}

.confidence-score.low { 
  color: white;
  background: linear-gradient(135deg, var(--danger-color), var(--danger-light));
  box-shadow: 0 4px 8px rgba(220, 38, 38, 0.3);
}

.ai-insight {
  font-style: italic;
  color: var(--gray-700);
  font-size: 0.875rem;
  line-height: 1.6;
  max-width: 350px;
  background: var(--gray-50);
  padding: 0.75rem;
  border-radius: var(--border-radius-sm);
  border-left: 4px solid var(--primary-color);
  position: relative;
}

.ai-insight::before {
  content: '🤖';
  position: absolute;
  top: 0.5rem;
  right: 0.5rem;
  font-size: 1rem;
  opacity: 0.5;
}

.ai-insight strong {
  color: var(--primary-color);
  font-weight: 700;
  display: block;
  margin-bottom: 0.25rem;
}

/* Priority Indicators */
.priority-indicator {
  display: flex;
  align-items: center;
  justify-content: center;
  width: 2.5rem;
  height: 2.5rem;
  border-radius: 50%;
  position: relative;
  transition: all 0.3s ease;
}

.priority-indicator:hover {
  transform: scale(1.1);
}

.priority-icon {
  font-size: 1.25rem;
  position: relative;
  z-index: 1;
}

.priority-high { 
  background: linear-gradient(135deg, var(--danger-color), var(--danger-light));
  color: white;
  box-shadow: 0 6px 12px rgba(220, 38, 38, 0.4);
  animation: pulse-danger 2s infinite;
}

.priority-medium { 
  background: linear-gradient(135deg, var(--warning-color), var(--warning-light));
  color: white;
  box-shadow: 0 6px 12px rgba(217, 119, 6, 0.4);
}

.priority-low { 
  background: linear-gradient(135deg, var(--success-color), var(--success-light));
  color: white;
  box-shadow: 0 6px 12px rgba(5, 150, 105, 0.4);
}

@keyframes pulse-danger {
  0%, 100% { box-shadow: 0 6px 12px rgba(220, 38, 38, 0.4); }
  50% { box-shadow: 0 6px 20px rgba(220, 38, 38, 0.7); }
}

/* Footer */
.footer {
  background: rgba(255, 255, 255, 0.95);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  padding: 3rem 2rem;
  text-align: center;
  color: var(--gray-600);
  font-size: 0.875rem;
  border-top: 1px solid rgba(255, 255, 255, 0.2);
  margin-top: 4rem;
  position: relative;
}

.footer::before {
  content: '';
  position: absolute;
  top: 0;
  left: 0;
  right: 0;
  height: 4px;
  background: linear-gradient(90deg, 
    var(--primary-color) 0%, 
    var(--secondary-color) 25%, 
    var(--purple-color) 50%, 
    var(--pink-color) 75%, 
    var(--success-color) 100%);
}

.footer-links {
  display: flex;
  justify-content: center;
  gap: 3rem;
  margin-bottom: 2rem;
  flex-wrap: wrap;
}

.footer-link {
  color: var(--gray-700);
  text-decoration: none;
  font-weight: 600;
  transition: all 0.3s ease;
  display: flex;
  align-items: center;
  gap: 0.5rem;
  padding: 0.75rem 1.5rem;
  border-radius: var(--border-radius-sm);
  border: 2px solid var(--gray-200);
  background: white;
  box-shadow: var(--shadow-sm);
}

.footer-link:hover {
  color: var(--primary-color);
  border-color: var(--primary-color);
  transform: translateY(-3px);
  box-shadow: var(--shadow-lg);
  background: linear-gradient(135deg, white, var(--gray-50));
}

.footer p {
  font-weight: 500;
  color: var(--gray-600);
  margin-top: 1rem;
  font-size: 1rem;
}

/* Responsive Design */
@media (max-width: 768px) {
  .container { 
    padding: 1.5rem 1rem; 
  }
  
  .header-content { 
    flex-direction: column; 
    gap: 1.5rem; 
    text-align: center; 
    padding: 0 1rem;
  }
  
  .logo {
    font-size: 1.5rem;
  }
  
  .logo i {
    font-size: 2rem;
  }
  
  .project-name {
    font-size: 1.25rem;
  }
  
  .stats-grid { 
    grid-template-columns: 1fr; 
    gap: 1.5rem;
  }
  
  .stat-card {
    padding: 1.5rem;
  }
  
  .stat-value {
    font-size: 2.5rem;
  }
  
  .filter-row { 
    flex-direction: column; 
    align-items: stretch; 
    gap: 1.5rem;
  }
  
  .filter-group {
    min-width: auto;
  }
  
  .filter-buttons { 
    margin-left: 0; 
    justify-content: center;
  }
  
  .chart-header { 
    flex-direction: column; 
    align-items: stretch; 
    gap: 1rem; 
  }
  
  .chart-title {
    font-size: 1.25rem;
    text-align: center;
  }
  
  .table-header {
    padding: 1.5rem;
  }
  
  .table-title {
    font-size: 1.25rem;
  }
  
  .footer-links {
    flex-direction: column;
    gap: 1rem;
    align-items: center;
  }
  
  .footer-link {
    width: 200px;
    justify-content: center;
  }
  
  th, td {
    padding: 0.75rem 0.5rem;
    font-size: 0.8rem;
  }
  
  .test-name {
    max-width: 200px;
    font-size: 0.75rem;
  }
  
  .ai-insight {
    max-width: 250px;
    font-size: 0.8rem;
  }
}

@media (max-width: 480px) {
  .container {
    padding: 1rem 0.5rem;
  }
  
  .header {
    padding: 1rem 0;
  }
  
  .header-content {
    padding: 0 0.5rem;
  }
  
  .stat-card {
    padding: 1rem;
  }
  
  .stat-value {
    font-size: 2rem;
  }
  
  .filter-input {
    padding: 0.5rem 0.75rem;
  }
  
  .filter-btn {
    padding: 0.5rem 1rem;
    font-size: 0.8rem;
    min-width: 80px;
  }
  
  .chart-container, .table-container, .filters {
    padding: 1.5rem;
  }
  
  .table-wrapper {
    font-size: 0.75rem;
  }
  
  .priority-indicator {
    width: 2rem;
    height: 2rem;
  }
  
  .priority-icon {
    font-size: 1rem;
  }
}

/* Animation */
@keyframes fadeIn {
  from { 
    opacity: 0; 
    transform: translateY(30px); 
  }
  to { 
    opacity: 1; 
    transform: translateY(0); 
  }
}

@keyframes slideInLeft {
  from {
    opacity: 0;
    transform: translateX(-50px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes slideInRight {
  from {
    opacity: 0;
    transform: translateX(50px);
  }
  to {
    opacity: 1;
    transform: translateX(0);
  }
}

@keyframes scaleIn {
  from {
    opacity: 0;
    transform: scale(0.9);
  }
  to {
    opacity: 1;
    transform: scale(1);
  }
}

.fade-in {
  animation: fadeIn 0.8s ease-out;
}

.slide-in-left {
  animation: slideInLeft 0.6s ease-out;
}

.slide-in-right {
  animation: slideInRight 0.6s ease-out;
}

.scale-in {
  animation: scaleIn 0.5s ease-out;
}

/* Staggered animation delays */
.stats-grid .stat-card:nth-child(1) { animation-delay: 0.1s; }
.stats-grid .stat-card:nth-child(2) { animation-delay: 0.2s; }
.stats-grid .stat-card:nth-child(3) { animation-delay: 0.3s; }
.stats-grid .stat-card:nth-child(4) { animation-delay: 0.4s; }

/* Loading States */
.loading {
  display: flex;
  justify-content: center;
  align-items: center;
  min-height: 300px;
  flex-direction: column;
  gap: 1rem;
}

.spinner {
  width: 50px;
  height: 50px;
  border: 4px solid var(--gray-200);
  border-top: 4px solid var(--primary-color);
  border-radius: 50%;
  animation: spin 1s linear infinite;
  box-shadow: var(--shadow-md);
}

.loading-text {
  color: var(--gray-600);
  font-weight: 500;
  text-align: center;
  font-size: 1rem;
}

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

/* Hover Effects */
.interactive-hover {
  transition: all 0.3s ease;
}

.interactive-hover:hover {
  transform: translateY(-2px);
  box-shadow: var(--shadow-lg);
}

/* Glass Effect Utilities */
.glass {
  background: rgba(255, 255, 255, 0.1);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.2);
}

.glass-dark {
  background: rgba(0, 0, 0, 0.1);
  backdrop-filter: blur(20px);
  -webkit-backdrop-filter: blur(20px);
  border: 1px solid rgba(255, 255, 255, 0.1);
}

/* Focus States */
*:focus {
  outline: 2px solid var(--primary-color);
  outline-offset: 2px;
}

button:focus,
.filter-btn:focus {
  outline: 3px solid rgba(99, 102, 241, 0.5);
  outline-offset: 2px;
}

/* Print Styles */
@media print {
  body {
    background: white !important;
  }
  
  .header, .footer {
    background: white !important;
    box-shadow: none !important;
  }
  
  .stat-card, .table-container, .chart-container, .filters {
    background: white !important;
    box-shadow: none !important;
    border: 1px solid var(--gray-300) !important;
  }
  
  .filter-row {
    display: none !important;
  }
}
</style>
</head>
<body>
  <header class="header">
    <div class="header-content">
      <div class="logo">
        <i class="fas fa-radar"></i>
        <span>FlakeRadar</span>
      </div>
      <div class="project-info">
        <div class="project-name">{{ project }}</div>
        <div class="generated-time">
          <i class="fas fa-clock"></i>
          Generated: {{ generated_formatted }}
        </div>
      </div>
    </div>
  </header>

  <div class="container">
    <!-- Stats Overview -->
    <div class="stats-grid fade-in">
      <div class="stat-card">
        <div class="stat-header">
          <div class="stat-title">Total Tests</div>
          <div class="stat-icon icon-total">
            <i class="fas fa-vials"></i>
          </div>
        </div>
        <div class="stat-value">{{ total_tests }}</div>
        <div class="stat-change">
          <i class="fas fa-chart-line"></i>
          Across all test runs
        </div>
      </div>

      <div class="stat-card">
        <div class="stat-header">
          <div class="stat-title">Flaky Tests</div>
          <div class="stat-icon icon-flaky">
            <i class="fas fa-exclamation-triangle"></i>
          </div>
        </div>
        <div class="stat-value">{{ flaky_count }}</div>
        <div class="stat-change">
          <i class="fas fa-percentage"></i>
          {{ flaky_percentage }}% of total
        </div>
      </div>

      <div class="stat-card">
        <div class="stat-header">
          <div class="stat-title">Confidence Score</div>
          <div class="stat-icon icon-total">
            <i class="fas fa-chart-pie"></i>
          </div>
        </div>
        <div class="stat-value">{{ avg_confidence }}%</div>
        <div class="stat-change">
          <i class="fas fa-brain"></i>
          Statistical reliability
        </div>
      </div>

      <div class="stat-card">
        <div class="stat-header">
          <div class="stat-title">Critical Issues</div>
          <div class="stat-icon icon-critical">
            <i class="fas fa-fire"></i>
          </div>
        </div>
        <div class="stat-value">{{ critical_count }}</div>
        <div class="stat-change">
          <i class="fas fa-arrow-up"></i>
          High flake rate (>50%)
        </div>
      </div>
    </div>

    <!-- Time-to-Fix Analysis -->
    {% if worst_offenders %}
    <div class="table-container fade-in">
      <div class="table-header">
        <h2 class="table-title">⏱️ Worst Flaky Test Offenders (Time-to-Fix)</h2>
        <p class="table-description">
          Tests that have been flaky the longest - prioritize these for fixes
        </p>
      </div>
      <div class="table-wrapper">
        <table>
          <thead>
            <tr>
              <th>Test Name</th>
              <th>Days Flaky</th>
              <th>Total Failures</th>
              <th>Status</th>
              <th>Priority</th>
            </tr>
          </thead>
          <tbody>
            {% for offender in worst_offenders[:5] %}
            <tr>
              <td class="test-name">{{ offender[0] }}</td>
              <td>{{ offender[7] }} days</td>
              <td>{{ offender[5] }}</td>
              <td>
                <span class="status-badge {{ 'status-failing' if offender[6] == 'Still Flaky' else 'status-stable' }}">
                  {{ offender[6] }}
                </span>
              </td>
              <td>
                {% if offender[7] > 7 %}
                  <span class="priority-high"><i class="fas fa-exclamation-circle"></i> High</span>
                {% elif offender[7] > 3 %}
                  <span class="priority-medium"><i class="fas fa-exclamation-triangle"></i> Medium</span>
                {% else %}
                  <span class="priority-low"><i class="fas fa-check-circle"></i> Low</span>
                {% endif %}
              </td>
            </tr>
            {% endfor %}
          </tbody>
        </table>
      </div>
    </div>
    {% endif %}

    <!-- Root Cause Clustering -->
    {% if cluster_analysis %}
    <div class="table-container fade-in">
      <div class="table-header">
        <h2 class="table-title">🔍 Root Cause Analysis</h2>
        <p class="table-description">
          Failures clustered by common patterns - fix the root cause to resolve multiple test failures
        </p>
      </div>
      <div class="table-wrapper">
        <table>
          <thead>
            <tr>
              <th>Root Cause Category</th>
              <th>Failure Count</th>
              <th>Affected Tests</th>
              <th>Severity</th>
              <th>Common Keywords</th>
            </tr>
          </thead>
          <tbody>
            {% for cluster_key, cluster_info in cluster_analysis.items() %}
            <tr>
              <td style="font-weight: 600;">{{ cluster_info.signature.replace('_', ' ').title() }}</td>
              <td>{{ cluster_info.count }}</td>
              <td>{{ cluster_info.affected_tests|length }}</td>
              <td>
                {% if cluster_info.severity == 'critical' %}
                  <span class="status-badge status-failing">Critical</span>
                {% elif cluster_info.severity == 'high' %}
                  <span class="status-badge status-flaky">High</span>
                {% else %}
                  <span class="status-badge status-stable">{{ cluster_info.severity.title() }}</span>
                {% endif %}
              </td>
              <td style="font-size: 0.8rem;">{{ cluster_info.common_keywords|join(', ') }}</td>
            </tr>
            {% endfor %}
          </tbody>
        </table>
      </div>
    </div>
    {% endif %}

    <!-- Filters -->
    <div class="filters fade-in">
      <div class="filter-row">
        <div class="filter-group">
          <label class="filter-label">Search Tests</label>
          <input type="text" class="filter-input" id="searchInput" placeholder="Search by test name...">
        </div>
        <div class="filter-group">
          <label class="filter-label">Minimum Flake Rate</label>
          <input type="range" class="filter-input" id="flakeRateSlider" min="0" max="100" value="0">
          <span id="flakeRateValue">0%</span>
        </div>
        <div class="filter-buttons">
          <button class="filter-btn active" data-filter="all">All</button>
          <button class="filter-btn" data-filter="flaky">Flaky Only</button>
          <button class="filter-btn" data-filter="stable">Stable Only</button>
          <button class="filter-btn" data-filter="critical">Critical</button>
        </div>
      </div>
    </div>

    <!-- Chart -->
    <div class="chart-container fade-in">
      <div class="chart-header">
        <h2 class="chart-title">Test Flakiness Trend</h2>
        <div class="chart-controls">
          <span style="font-size: 0.875rem; color: var(--gray-600);">
            <i class="fas fa-info-circle"></i> Tests sorted by flake rate (highest to lowest)
          </span>
        </div>
      </div>
      <canvas id="flakeChart" class="chart-canvas"></canvas>
    </div>

    <!-- Test Results Table -->
    <div class="table-container fade-in">
      <div class="table-header">
        <h2 class="table-title">Test Results Analysis</h2>
        <p class="table-description">
          Detailed breakdown of test performance with AI-powered insights and recommendations
        </p>
      </div>
      <div class="table-wrapper">
        <table id="testTable">
          <thead>
            <tr>
              <th>Priority</th>
              <th>Test Name</th>
              <th>Status</th>
              <th>Pass</th>
              <th>Fail</th>
              <th>Total</th>
              <th>Transitions</th>
              <th>Flake Rate</th>
              <th>Confidence</th>
              <th>AI Insights</th>
            </tr>
          </thead>
          <tbody>
            {% for t in tests %}
            <tr class="test-row" data-flaky="{{ t.suspect_flaky|lower }}" data-rate="{{ t.flake_rate }}">
              <td>
                <div class="priority-indicator">
                  {% if t.flake_rate > 0.5 %}
                    <i class="fas fa-exclamation-circle priority-icon priority-high"></i>
                  {% elif t.flake_rate > 0.2 %}
                    <i class="fas fa-exclamation-triangle priority-icon priority-medium"></i>
                  {% else %}
                    <i class="fas fa-check-circle priority-icon priority-low"></i>
                  {% endif %}
                </div>
              </td>
              <td class="test-name">{{ t.full_name }}</td>
              <td>
                {% if t.always_failing %}
                  <span class="status-badge status-failing">
                    Always Fails
                  </span>
                {% elif t.truly_flaky %}
                  <span class="status-badge status-flaky">
                    Flaky
                  </span>
                {% else %}
                  <span class="status-badge status-stable">
                    Stable
                  </span>
                {% endif %}
              </td>
              <td>{{ t.pass_count }}</td>
              <td>{{ t.fail_count }}</td>
              <td>{{ t.total_runs }}</td>
              <td>{{ t.transitions }}</td>
              <td>
                <span class="flake-rate {{ 'high' if t.flake_rate > 0.5 else 'medium' if t.flake_rate > 0.2 else 'low' }}">
                  {{ '%.1f'|format(t.flake_rate*100) }}%
                </span>
              </td>
              <td>
                <span class="confidence-score {{ 'high' if t.confidence_score > 0.8 else 'medium' if t.confidence_score > 0.6 else 'low' }}">
                  {{ '%.0f'|format(t.confidence_score*100) }}%
                </span>
              </td>
              <td class="ai-insight">
                {% if t.ai %}
                  <strong>{{ t.ai.split(':')[0] if ':' in t.ai else 'Analysis' }}:</strong>
                  {{ t.ai.split(':', 1)[1] if ':' in t.ai else t.ai }}
                {% else %}
                  <span style="color: var(--gray-400);">No insights available</span>
                {% endif %}
              </td>
            </tr>
            {% endfor %}
          </tbody>
        </table>
      </div>
    </div>
  </div>

  <footer class="footer">
    <div class="footer-links">
      <a href="#" class="footer-link">
        <i class="fas fa-download"></i> Export Data
      </a>
      <a href="#" class="footer-link">
        <i class="fas fa-share"></i> Share Report
      </a>
      <a href="#" class="footer-link">
        <i class="fas fa-cog"></i> Configure
      </a>
      <a href="#" class="footer-link">
        <i class="fas fa-question-circle"></i> Help
      </a>
    </div>
    <p>{{ footer_text }}</p>
  </footer>

  <script>
    // Initialize dashboard
    document.addEventListener('DOMContentLoaded', function() {
      initializeChart();
      initializeFilters();
      initializeTable();
    });

    // Chart initialization
    function initializeChart() {
      const ctx = document.getElementById('flakeChart').getContext('2d');
      const testData = [
        {% for t in tests %}
        {
          name: '{{ t.full_name }}',
          flakeRate: {{ t.flake_rate * 100 }},
          totalRuns: {{ t.total_runs }},
          transitions: {{ t.transitions }},
          isFlaky: {{ 'true' if t.suspect_flaky else 'false' }}
        }{% if not loop.last %},{% endif %}
        {% endfor %}
      ];

      // Sort by flake rate for better trend visualization
      testData.sort((a, b) => b.flakeRate - a.flakeRate);

      const chart = new Chart(ctx, {
        type: 'line',
        data: {
          labels: testData.map((t, index) => `Test ${index + 1}`),
          datasets: [{
            label: 'Flake Rate Trend',
            data: testData.map(t => t.flakeRate),
            backgroundColor: (context) => {
              const chart = context.chart;
              const {ctx, chartArea} = chart;
              if (!chartArea) return null;
              
              const gradient = ctx.createLinearGradient(0, chartArea.bottom, 0, chartArea.top);
              gradient.addColorStop(0, 'rgba(99, 102, 241, 0.1)');
              gradient.addColorStop(0.5, 'rgba(99, 102, 241, 0.3)');
              gradient.addColorStop(1, 'rgba(99, 102, 241, 0.6)');
              return gradient;
            },
            borderColor: (context) => {
              const index = context.dataIndex;
              const value = testData[index]?.flakeRate || 0;
              if (value > 50) return '#dc2626';
              if (value > 20) return '#d97706';
              return '#059669';
            },
            borderWidth: 3,
            fill: true,
            tension: 0.4,
            pointRadius: 8,
            pointHoverRadius: 12,
            pointBackgroundColor: (context) => {
              const index = context.dataIndex;
              const value = testData[index]?.flakeRate || 0;
              if (value > 50) return '#dc2626';
              if (value > 20) return '#d97706';
              return '#059669';
            },
            pointBorderColor: '#ffffff',
            pointBorderWidth: 3,
            pointHoverBorderWidth: 4,
            pointShadowColor: 'rgba(0, 0, 0, 0.3)',
            pointShadowBlur: 10
          }]
        },
        options: {
          responsive: true,
          maintainAspectRatio: false,
          interaction: {
            intersect: false,
            mode: 'index'
          },
          plugins: {
            legend: {
              display: true,
              position: 'top',
              align: 'center',
              labels: {
                usePointStyle: true,
                padding: 25,
                font: {
                  size: 14,
                  weight: '600',
                  family: 'Inter'
                },
                color: '#374151'
              }
            },
            tooltip: {
              backgroundColor: 'rgba(0, 0, 0, 0.9)',
              titleColor: 'white',
              bodyColor: 'white',
              titleFont: {
                size: 16,
                weight: '600',
                family: 'Inter'
              },
              bodyFont: {
                size: 14,
                family: 'Inter'
              },
              borderColor: 'rgba(99, 102, 241, 0.5)',
              borderWidth: 2,
              cornerRadius: 12,
              displayColors: false,
              callbacks: {
                title: function(context) {
                  const dataIndex = context[0].dataIndex;
                  return testData[dataIndex].name.split('#')[1] || testData[dataIndex].name;
                },
                label: function(context) {
                  const dataIndex = context.dataIndex;
                  const test = testData[dataIndex];
                  return [
                    `Flake Rate: ${test.flakeRate.toFixed(1)}%`,
                    `Total Runs: ${test.totalRuns}`,
                    `Transitions: ${test.transitions}`,
                    `Status: ${test.isFlaky ? 'Flaky' : 'Stable'}`
                  ];
                }
              }
            }
          },
          scales: {
            x: {
              display: true,
              title: {
                display: true,
                text: 'Tests (sorted by flake rate)',
                font: {
                  size: 16,
                  weight: '600',
                  family: 'Inter'
                },
                color: '#374151'
              },
              grid: {
                display: false
              },
              ticks: {
                font: {
                  size: 12,
                  family: 'Inter'
                },
                color: '#6b7280'
              }
            },
            y: {
              display: true,
              title: {
                display: true,
                text: 'Flake Rate (%)',
                font: {
                  size: 16,
                  weight: '600',
                  family: 'Inter'
                },
                color: '#374151'
              },
              min: 0,
              max: 100,
              grid: {
                color: 'rgba(0, 0, 0, 0.05)',
                lineWidth: 1
              },
              ticks: {
                font: {
                  size: 12,
                  family: 'Inter'
                },
                color: '#6b7280',
                callback: function(value) {
                  return value + '%';
                }
              }
            }
          },
          elements: {
            line: {
              borderCapStyle: 'round',
              borderJoinStyle: 'round'
            },
            point: {
              hoverBackgroundColor: 'white',
              hoverBorderWidth: 4
            }
          }
        }
      });
    }

    // Filter functionality
    function initializeFilters() {
      const searchInput = document.getElementById('searchInput');
      const flakeRateSlider = document.getElementById('flakeRateSlider');
      const flakeRateValue = document.getElementById('flakeRateValue');
      const filterButtons = document.querySelectorAll('.filter-btn[data-filter]');

      let currentFilter = 'all';

      // Search functionality
      searchInput.addEventListener('input', function() {
        filterTable();
      });

      // Flake rate slider
      flakeRateSlider.addEventListener('input', function() {
        flakeRateValue.textContent = this.value + '%';
        filterTable();
      });

      // Filter buttons
      filterButtons.forEach(button => {
        button.addEventListener('click', function() {
          filterButtons.forEach(btn => btn.classList.remove('active'));
          this.classList.add('active');
          currentFilter = this.dataset.filter;
          filterTable();
        });
      });

      function filterTable() {
        const searchTerm = searchInput.value.toLowerCase();
        const minFlakeRate = parseInt(flakeRateSlider.value);
        const rows = document.querySelectorAll('#testTable tbody tr');

        rows.forEach(row => {
          const testName = row.querySelector('.test-name').textContent.toLowerCase();
          const flakeRate = parseFloat(row.dataset.rate) * 100;
          const isFlaky = row.dataset.flaky === 'true';
          
          let show = true;

          // Search filter
          if (searchTerm && !testName.includes(searchTerm)) {
            show = false;
          }

          // Flake rate filter
          if (flakeRate < minFlakeRate) {
            show = false;
          }

          // Category filter
          if (currentFilter === 'flaky' && !isFlaky) {
            show = false;
          } else if (currentFilter === 'stable' && isFlaky) {
            show = false;
          } else if (currentFilter === 'critical' && flakeRate <= 50) {
            show = false;
          }

          row.style.display = show ? '' : 'none';
        });
      }
    }

    // Table functionality
    function initializeTable() {
      const table = document.getElementById('testTable');
      const headers = table.querySelectorAll('th');
      
      headers.forEach((header, index) => {
        header.style.cursor = 'pointer';
        header.addEventListener('click', () => sortTable(index));
      });
    }

    function sortTable(column) {
      const table = document.getElementById('testTable');
      const tbody = table.querySelector('tbody');
      const rows = Array.from(tbody.querySelectorAll('tr'));
      
      const sortedRows = rows.sort((a, b) => {
        const aVal = a.cells[column].textContent.trim();
        const bVal = b.cells[column].textContent.trim();
        
        if (!isNaN(aVal) && !isNaN(bVal)) {
          return parseFloat(bVal) - parseFloat(aVal);
        }
        return aVal.localeCompare(bVal);
      });
      
      tbody.innerHTML = '';
      sortedRows.forEach(row => tbody.appendChild(row));
    }

    // Chart type toggle - removed as we now use line chart only
  </script>
</body>
</html>
"""

def render_report(project: str, test_rows, out_path: str, worst_offenders=None, cluster_analysis=None):
    # Calculate statistics
    total_tests = len(test_rows)
    flaky_tests = [t for t in test_rows if t.get("suspect_flaky", False)]
    flaky_count = len(flaky_tests)
    stable_count = total_tests - flaky_count
    critical_count = len([t for t in test_rows if t.get("flake_rate", 0) > 0.5])
    
    # Calculate average confidence score
    avg_confidence = sum(t.get("confidence_score", 0) for t in test_rows) / total_tests if total_tests > 0 else 0
    
    flaky_percentage = round((flaky_count / total_tests * 100) if total_tests > 0 else 0, 1)
    
    # Format the generated timestamp
    generated_timestamp = datetime.datetime.utcnow()
    generated_formatted = generated_timestamp.strftime("%B %d, %Y at %I:%M %p UTC")
    
    # Footer text
    footer_text = "FlakeRadar - Intelligent Test Flakiness Analysis. Configure push mode to share with your team."
    
    tmpl = Template(_template_minify(_TEMPLATE))
    html = tmpl.render(
        project=project,
        generated=generated_timestamp.isoformat(),
        generated_formatted=generated_formatted,
        tests=test_rows,
        total_tests=total_tests,
        flaky_count=flaky_count,
        stable_count=stable_count,
        critical_count=critical_count,
        flaky_percentage=flaky_percentage,
        avg_confidence=round(avg_confidence * 100, 1),
        worst_offenders=worst_offenders or [],
        cluster_analysis=cluster_analysis or {},
        footer_text=footer_text
    )
    with open(out_path, "w", encoding="utf-8") as f:
        f.write(html)
    return out_path

def _template_minify(s: str) -> str:
    return "\n".join(line.rstrip() for line in s.splitlines())