# CH-01 through CH-03: Figma Chart Production Specs

---

## CH-01: OPS MULTI-TERM TREND (Area Chart)

### Chart: `RP/Charts/CH-01-OPS-Trend`

#### ApexCharts Configuration

```javascript
{
    chart: {
        type: 'area',
        height: 260,
        toolbar: { show: false },
        fontFamily: 'Inter, sans-serif',
        background: 'transparent',
        sparkline: { enabled: false }
    },
    colors: ['#1E5FA8', '#94A3B8'],
    series: [
        {
            name: 'Your OPS',
            data: [65, 72, 68, 75, 78, 82]
        },
        {
            name: 'Class Average',
            data: [60, 63, 62, 68, 70, 72]
        }
    ],
    xaxis: {
        categories: ['Term 1', 'Term 2', 'Term 3', 'Term 4', 'Term 5', 'Term 6'],
        labels: {
            style: {
                fontSize: '12px',
                fontFamily: 'Inter',
                colors: '#64748B'  // muted-text
            }
        },
        axisBorder: { show: false },
        axisTicks: { show: false }
    },
    yaxis: {
        min: 0,
        max: 100,
        tickAmount: 5,
        labels: {
            formatter: (val) => val + '%',
            style: {
                fontSize: '12px',
                fontFamily: 'Inter',
                colors: '#64748B'
            }
        }
    },
    stroke: {
        curve: 'smooth',
        width: [3, 2],
        dashArray: [0, 5]  // solid for student, dashed for class avg
    },
    fill: {
        type: 'gradient',
        gradient: {
            shadeIntensity: 1,
            opacityFrom: 0.3,
            opacityTo: 0.05,
            stops: [0, 90, 100]
        }
    },
    grid: {
        borderColor: '#E2E8F0',
        strokeDashArray: 4,
        padding: { left: 8, right: 8 }
    },
    tooltip: {
        shared: true,
        intersect: false,
        theme: 'light',
        y: { formatter: (val) => val + '%' }
    },
    legend: {
        position: 'bottom',
        horizontalAlign: 'center',
        fontSize: '12px',
        fontFamily: 'Inter',
        markers: { width: 12, height: 3, radius: 2 },
        itemMargin: { horizontal: 16 }
    },
    states: {
        hover: { filter: { type: 'none' } }
    }
}
```

#### Visual Layout

```
┌──────────────────────────────────────────────────┐
│  OPS Trend                                       │
│                                                  │
│  100% ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─  │
│                                                  │
│   80% ────────────────●───────────●──────●───    │
│                     ╱     ╲      ╱                │
│   60% ──●─────●──╱─────────╲──╱─────────●───    │
│         ╲   ╱  ╱             ╲╱                  │
│   40% ───●─╱──╱─── ═══════════════════════       │
│                ╲  ╱  (class avg - dashed)         │
│   20% ───────────╱                               │
│                                                  │
│    0% ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─  │
│                                                  │
│    T1    T2    T3    T4    T5    T6              │
│                                                  │
│  ● Your OPS  ━━━ Class Average                   │
└──────────────────────────────────────────────────┘
```

#### Colors
- Student line: `color/secondary` (#1E5FA8)
- Student fill: gradient from #1E5FA8 at 30% to transparent
- Class average: `color/muted-text` (#94A3B8), dashed
- Grid lines: `color/border` (#E2E8F0), dashed

#### Dark Mode Overrides
- Grid: #334155
- Labels: #94A3B8
- Student fill: gradient from #1E5FA8 at 20% to transparent
- Tooltip BG: #1E293B
- Tooltip text: #E2E8F0

#### Responsive
- Desktop: Full width, 260px height
- Tablet: Full width, 220px height
- Mobile: Full width, 200px height, simplified labels

---

## CH-02: ATTENDANCE HEATMAP (Calendar)

### Chart: `RP/Charts/CH-02-Attendance-Heatmap`

#### Implementation (Custom — not ApexCharts)

This is a custom HTML/CSS grid, not a standard chart library component.

```
Grid Structure:
├── Month Header (40px)
│   ← Previous    June 2026    Next →
│
├── Day Labels Row (32px)
│   Mon  Tue  Wed  Thu  Fri
│
├── Week 1 (48px)
│   [1] [2] [3] [4] [5]
│
├── Week 2 (48px)
│   [8] [9] [10] [11] [12]
│
├── Week 3 (48px)
│   [15] [16] [17] [18] [19]
│
├── Week 4 (48px)
│   [22] [23] [24] [25] [26]
│
├── Week 5 (48px)
│   [29] [30] [—] [—] [—]
│
└── Legend (24px)
    ● Present  ● Late  ● Absent  ● No Class
```

#### Cell Color Assignment

```javascript
function getCellColor(date, attendanceData) {
    const record = attendanceData.find(r => r.date === date);
    if (!record) {
        if (isWeekend(date)) return 'hidden';
        return 'no-class';  // #E2E8F0 (light) / #334155 (dark)
    }
    switch(record.status) {
        case 'present': return 'present';  // #22C55E / #4ADE80
        case 'late': return 'late';        // #F59E0B / #FBBF24
        case 'absent': return 'absent';    // #DC2626 / #F87171
        default: return 'no-class';
    }
}
```

#### Cell States

| State | BG | Text | Border | Special |
|-------|-----|------|--------|---------|
| Present | gamification/heatmap-present | #FFF | none | — |
| Late | gamification/heatmap-late | #FFF | none | — |
| Absent | gamification/heatmap-absent | #FFF | none | — |
| No Class | gamification/heatmap-noclass | gamification/heatmap-noclass-text | none | — |
| Today | — | — | 2px color/secondary | Ring highlight |
| Hover | — | — | 2px color/secondary | Tooltip appears |

#### Tooltip

```html
<div class="heatmap-tooltip" x-show="hovered">
    <div class="date">{formattedDate}</div>
    <div class="status">
        <span class="dot" style="background: {statusColor}"></span>
        {statusText}
    </div>
    <div class="subject">{subjectName}</div>
</div>
```

- Position: Absolute, above cell
- BG: `color/surface-elevated`
- Shadow: `shadow/md`
- Border-radius: 8px
- Padding: 8px 12px
- Transition: opacity 200ms

---

## CH-03: OPS COMPONENT BREAKDOWN (Donut Chart)

### Chart: `RP/Charts/CH-03-OPS-Breakdown`

#### ApexCharts Configuration

```javascript
{
    chart: {
        type: 'donut',
        height: 280,
        fontFamily: 'Inter, sans-serif',
        background: 'transparent'
    },
    colors: ['#1E5FA8', '#22C55E', '#F59E0B', '#8B5CF6', '#EC4899'],
    series: [24.6, 15.0, 23.0, 10.5, 9.0],
    labels: ['Exams', 'Assignments', 'Attendance', 'Participation', 'Behavior'],
    plotOptions: {
        pie: {
            donut: {
                size: '65%',
                labels: {
                    show: true,
                    name: {
                        show: true,
                        fontSize: '14px',
                        fontFamily: 'Inter',
                        fontWeight: 500,
                        color: '#64748B'
                    },
                    value: {
                        show: true,
                        fontSize: '24px',
                        fontFamily: 'Inter',
                        fontWeight: 700,
                        color: '#0F172A',
                        formatter: (val) => Math.round(val) + '%'
                    },
                    total: {
                        show: true,
                        label: 'OPS Score',
                        fontSize: '14px',
                        fontFamily: 'Inter',
                        fontWeight: 500,
                        color: '#64748B',
                        formatter: () => '78%'
                    }
                }
            }
        }
    },
    stroke: {
        width: 2,
        colors: ['#FFFFFF']  // or '#1E293B' in dark mode
    },
    dataLabels: {
        enabled: false
    },
    legend: {
        position: 'right',
        fontSize: '12px',
        fontFamily: 'Inter',
        markers: { width: 10, height: 10, radius: 2 },
        itemMargin: { vertical: 4, horizontal: 0 },
        formatter: (label, opts) => {
            const score = opts.w.config.series[opts.seriesIndex];
            return `${label}: ${score} pts`;
        }
    },
    tooltip: {
        y: {
            formatter: (val) => val + ' pts'
        }
    },
    responsive: [
        {
            breakpoint: 768,
            options: {
                legend: { position: 'bottom' }
            }
        }
    ]
}
```

#### Visual Layout

```
┌──────────────────────────────────────────────────┐
│                                                  │
│          ┌─────────────────┐                     │
│          │     ╭─────╮     │                     │
│          │   ╱  OPS   ╲    │   ● Exams: 24.6 pts│
│          │  │  Score   │   │   ● Assignments: 15 │
│          │  │   78%    │   │   ● Attendance: 23  │
│          │   ╲  82/100 ╱    │   ● Particip.: 10.5│
│          │     ╰─────╯     │   ● Behavior: 9     │
│          └─────────────────┘                     │
│                                                  │
└──────────────────────────────────────────────────┘
```

#### Colors (5 segments)

| Segment | Color | Points |
|---------|-------|--------|
| Exams (30%) | #1E5FA8 (secondary) | 24.6 |
| Assignments (20%) | #22C55E (success) | 15.0 |
| Attendance (25%) | #F59E0B (warning) | 23.0 |
| Participation (15%) | #8B5CF6 (purple) | 10.5 |
| Behavior (10%) | #EC4899 (pink) | 9.0 |

#### Dark Mode Overrides
- Stroke between segments: #1E293B (dark surface)
- Center text: #F8FAFC (header-text)
- Legend text: #E2E8F0 (body-text)

#### Responsive
- Desktop: Donut left (60%), Legend right (40%)
- Tablet: Donut top, Legend bottom
- Mobile: Donut center, Legend below, horizontal scroll

---

## CHART CONTAINER PATTERNS

### All charts must follow this container pattern:

```
RP/Card (shadow/sm, padding/md)
├── Header (Horizontal, justify: space-between)
│   ├── Title (Display/H5, 18px, Medium)
│   └── Controls (tabs, filter, or "View All" button)
│
├── Chart area
│   Width: 100%
│   Height: {chart-specific}
│
└── Footer (optional)
    Summary stats or "Last updated: X" (Body/XS, muted)
```

### Chart Loading State
```
RP/Card
├── Header (real)
├── RP/Skeleton (type: rect, height: 260px)
└── Footer (skeleton lines)
```

### Chart Empty State
```
RP/Card
├── Header (real)
├── RP/EmptyState
│   Icon: bar-chart-2
│   Title: "No data available"
│   Description: "Data will appear here once records are added."
└── Footer (hidden)
```

---

## APEXCHARTS THEME OVERRIDE

### Global ApexCharts theme for RP Learning Portal

```javascript
// Light mode theme
const rpLightTheme = {
    chart: {
        background: 'transparent',
        toolbar: { show: false },
        fontFamily: 'Inter, sans-serif'
    },
    colors: ['#1E5FA8', '#22C55E', '#F59E0B', '#DC2626', '#8B5CF6', '#EC4899'],
    grid: {
        borderColor: '#E2E8F0',
        strokeDashArray: 4
    },
    xaxis: {
        labels: { style: { colors: '#64748B', fontSize: '12px' } },
        axisBorder: { color: '#E2E8F0' },
        axisTicks: { color: '#E2E8F0' }
    },
    yaxis: {
        labels: { style: { colors: '#64748B', fontSize: '12px' } }
    },
    tooltip: {
        theme: 'light',
        style: { fontSize: '12px' }
    },
    legend: {
        labels: { colors: '#1E293B', fontSize: '12px' }
    }
};

// Dark mode theme
const rpDarkTheme = {
    ...rpLightTheme,
    grid: { borderColor: '#334155', strokeDashArray: 4 },
    xaxis: {
        labels: { style: { colors: '#94A3B8', fontSize: '12px' } },
        axisBorder: { color: '#334155' },
        axisTicks: { color: '#334155' }
    },
    yaxis: {
        labels: { style: { colors: '#94A3B8', fontSize: '12px' } }
    },
    tooltip: { theme: 'dark' },
    legend: {
        labels: { colors: '#E2E8F0', fontSize: '12px' }
    }
};
```

### Chart Color Palette

| Position | Color Name | Hex | Use |
|----------|-----------|-----|-----|
| 1 | Royal Blue | #1E5FA8 | Primary data series |
| 2 | Success Green | #22C55E | Positive/attendance |
| 3 | Warning Amber | #F59E0B | Caution/behavior |
| 4 | Danger Red | #DC2626 | Negative/alerts |
| 5 | Purple | #8B5CF6 | Third series |
| 6 | Pink | #EC4899 | Fourth series |

### Chart Accessibility
- All charts must have `aria-label` describing the chart content
- Data tables must be available as alternative (toggle or screen reader)
- Color alone must not convey meaning — use patterns/labels too
- Minimum contrast 3:1 for chart elements against background