feat tuck insight explainers behind info toggle

Replace always-visible explainer paragraphs with a collapsible panel toggled by an ⓘ button in each card header. Uses Bootstrap collapse with aria-expanded/aria-controls for WCAG compliance. The SVG info-circle icon has aria-hidden and the button carries an aria-label for screen readers.

Commit
3b753c2d30fec7b2d3675278326bd47f3ce567a7
Author
GPT-5 medium <codex@openai.com>
Author date
Committer
GPT-5 medium <codex@openai.com>
Committer date
Changed files
roles/dashboard/public/css/app.css
index 544432da..9fc2e7bd 100644..100644
@@ -57,6 +57,19 @@
57 57 margin-bottom: 0.5rem;
58 58 }
59 59
60 Added: /* Info toggle button in insight card headers */
61 Added: .info-toggle {
62 Added: line-height: 1;
63 Added: opacity: 0.5;
64 Added: transition: opacity 0.15s;
65 Added: }
66 Added:
67 Added: .info-toggle:hover,
68 Added: .info-toggle:focus-visible,
69 Added: .info-toggle[aria-expanded="true"] {
70 Added: opacity: 1;
71 Added: }
72 Added:
60 73 #toolbar .toolbar-items {
61 74 min-width: 0;
62 75 }
roles/dashboard/templates/dashboard/insights.html.ep
index ba2ddb7a..bf821c2f 100644..100644
@@ -14,15 +14,31 @@
14 14 <div class="row g-3">
15 15 <div class="col-12" id="stability">
16 16 <div class="card">
17 Removed: <div class="card-header">
17 Added: <div class="card-header d-flex align-items-start justify-content-between">
18 18 <h2 class="h6 mb-0">System Stability</h2>
19 Removed: <p class="text-body-secondary small mb-0 mt-1">
20 Removed: A <strong>lower score means more stable</strong>.
21 Removed: This index is the rolling standard deviation (σ) of all probe values
22 Removed: over a 6-hour window, normalised to each probe's optimal range.
23 Removed: Spikes indicate rapid or large deviations from normal operating conditions.
24 Removed: </p>
19 Added: <button class="btn btn-sm btn-link text-body-secondary p-0 ms-2 info-toggle"
20 Added: type="button"
21 Added: data-bs-toggle="collapse"
22 Added: data-bs-target="#info-stability"
23 Added: aria-expanded="false"
24 Added: aria-controls="info-stability"
25 Added: aria-label="About this chart">
26 Added: <svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
27 Added: <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
28 Added: <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
29 Added: </svg>
30 Added: </button>
25 31 </div>
32 Added: <div class="collapse" id="info-stability">
33 Added: <div class="card-body border-bottom py-2">
34 Added: <p class="text-body-secondary small mb-0">
35 Added: A <strong>lower score means more stable</strong>.
36 Added: This index is the rolling standard deviation (σ) of all probe values
37 Added: over a 6-hour window, normalised to each probe's optimal range.
38 Added: Spikes indicate rapid or large deviations from normal operating conditions.
39 Added: </p>
40 Added: </div>
41 Added: </div>
26 42 <div class="card-body">
27 43 <div class="chart-wrap">
28 44 <canvas id="chart-stability" role="img" aria-label="System stability score — lower is better"></canvas>
@@ -33,13 +49,29 @@
33 49
34 50 <div class="col-12" id="rate-of-change">
35 51 <div class="card">
36 Removed: <div class="card-header">
52 Added: <div class="card-header d-flex align-items-start justify-content-between">
37 53 <h2 class="h6 mb-0">Rate of Change</h2>
38 Removed: <p class="text-body-secondary small mb-0 mt-1">
39 Removed: Normalised rate of change per probe (% of optimal range per hour).
40 Removed: Values near zero mean the parameter is steady.
41 Removed: </p>
54 Added: <button class="btn btn-sm btn-link text-body-secondary p-0 ms-2 info-toggle"
55 Added: type="button"
56 Added: data-bs-toggle="collapse"
57 Added: data-bs-target="#info-derivatives"
58 Added: aria-expanded="false"
59 Added: aria-controls="info-derivatives"
60 Added: aria-label="About this chart">
61 Added: <svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
62 Added: <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
63 Added: <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
64 Added: </svg>
65 Added: </button>
42 66 </div>
67 Added: <div class="collapse" id="info-derivatives">
68 Added: <div class="card-body border-bottom py-2">
69 Added: <p class="text-body-secondary small mb-0">
70 Added: Normalised rate of change per probe (% of optimal range per hour).
71 Added: Values near zero mean the parameter is steady.
72 Added: </p>
73 Added: </div>
74 Added: </div>
43 75 <div class="card-body">
44 76 <div class="chart-wrap">
45 77 <canvas id="chart-derivatives" role="img" aria-label="Normalised rate of change per probe"></canvas>
@@ -50,12 +82,28 @@
50 82
51 83 <div class="col-12" id="diurnal">
52 84 <div class="card">
53 Removed: <div class="card-header">
85 Added: <div class="card-header d-flex align-items-start justify-content-between">
54 86 <h2 class="h6 mb-0">DO Diurnal Pattern</h2>
55 Removed: <p class="text-body-secondary small mb-0 mt-1">
56 Removed: Day/night DO cycle &mdash; each line is one day, bold is the average
57 Removed: </p>
87 Added: <button class="btn btn-sm btn-link text-body-secondary p-0 ms-2 info-toggle"
88 Added: type="button"
89 Added: data-bs-toggle="collapse"
90 Added: data-bs-target="#info-diurnal"
91 Added: aria-expanded="false"
92 Added: aria-controls="info-diurnal"
93 Added: aria-label="About this chart">
94 Added: <svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
95 Added: <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
96 Added: <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
97 Added: </svg>
98 Added: </button>
58 99 </div>
100 Added: <div class="collapse" id="info-diurnal">
101 Added: <div class="card-body border-bottom py-2">
102 Added: <p class="text-body-secondary small mb-0">
103 Added: Day/night DO cycle &mdash; each line is one day, bold is the average.
104 Added: </p>
105 Added: </div>
106 Added: </div>
59 107 <div class="card-body">
60 108 <div class="chart-wrap">
61 109 <canvas id="chart-diurnal" role="img" aria-label="Dissolved oxygen diurnal overlay"></canvas>
@@ -66,12 +114,28 @@
66 114
67 115 <div class="col-12" id="do-orp-overlay">
68 116 <div class="card">
69 Removed: <div class="card-header">
117 Added: <div class="card-header d-flex align-items-start justify-content-between">
70 118 <h2 class="h6 mb-0">DO &amp; ORP Over Time</h2>
71 Removed: <p class="text-body-secondary small mb-0 mt-1">
72 Removed: Dual-axis overlay &mdash; correlated drops indicate oxygen-driven redox shifts
73 Removed: </p>
119 Added: <button class="btn btn-sm btn-link text-body-secondary p-0 ms-2 info-toggle"
120 Added: type="button"
121 Added: data-bs-toggle="collapse"
122 Added: data-bs-target="#info-do-orp"
123 Added: aria-expanded="false"
124 Added: aria-controls="info-do-orp"
125 Added: aria-label="About this chart">
126 Added: <svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
127 Added: <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
128 Added: <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
129 Added: </svg>
130 Added: </button>
74 131 </div>
132 Added: <div class="collapse" id="info-do-orp">
133 Added: <div class="card-body border-bottom py-2">
134 Added: <p class="text-body-secondary small mb-0">
135 Added: Dual-axis overlay &mdash; correlated drops indicate oxygen-driven redox shifts.
136 Added: </p>
137 Added: </div>
138 Added: </div>
75 139 <div class="card-body">
76 140 <div class="chart-wrap">
77 141 <canvas id="chart-overlay-do-orp" role="img" aria-label="DO and ORP overlay chart"></canvas>
@@ -82,11 +146,27 @@
82 146
83 147 <div class="col-12" id="ph-do-lag">
84 148 <div class="card">
85 Removed: <div class="card-header">
149 Added: <div class="card-header d-flex align-items-start justify-content-between">
86 150 <h2 class="h6 mb-0">pH &#8596; DO Relationship</h2>
87 Removed: <p class="text-body-secondary small mb-0 mt-1">
88 Removed: Nitrification link &mdash; DO drops often precede pH drops
89 Removed: </p>
151 Added: <button class="btn btn-sm btn-link text-body-secondary p-0 ms-2 info-toggle"
152 Added: type="button"
153 Added: data-bs-toggle="collapse"
154 Added: data-bs-target="#info-ph-do"
155 Added: aria-expanded="false"
156 Added: aria-controls="info-ph-do"
157 Added: aria-label="About this chart">
158 Added: <svg width="18" height="18" viewBox="0 0 16 16" fill="currentColor" aria-hidden="true">
159 Added: <path d="M8 15A7 7 0 1 1 8 1a7 7 0 0 1 0 14m0 1A8 8 0 1 0 8 0a8 8 0 0 0 0 16"/>
160 Added: <path d="m8.93 6.588-2.29.287-.082.38.45.083c.294.07.352.176.288.469l-.738 3.468c-.194.897.105 1.319.808 1.319.545 0 1.178-.252 1.465-.598l.088-.416c-.2.176-.492.246-.686.246-.275 0-.375-.193-.304-.533zM9 4.5a1 1 0 1 1-2 0 1 1 0 0 1 2 0"/>
161 Added: </svg>
162 Added: </button>
163 Added: </div>
164 Added: <div class="collapse" id="info-ph-do">
165 Added: <div class="card-body border-bottom py-2">
166 Added: <p class="text-body-secondary small mb-0">
167 Added: Nitrification link &mdash; DO drops often precede pH drops.
168 Added: </p>
169 Added: </div>
90 170 </div>
91 171 <div class="card-body">
92 172 <div class="chart-wrap">