New Commit: Ship accessibility and offline learning upgrades Adds a reusable sticky reading bar across reader chapters and lessons with live progress, time-left estimates, zen mode toggle, and one-click offline saving. Introduces offline.php download management (view, open, remove, clear), plus cache-backed material save helpers. Expands accessibility and assessment support with reading ruler controls/sync in global a11y settings, improved TTS behavior for quizzes and adaptive diagnostics (toggle speak/stop, sequential option narration, visual highlighting, keyboard shortcuts), and new diagnostic/parent styling. Also upgrades level module mastery cards with live SVG radial rings and adds a full IEP/504 brief generator modal with printable output on the parents page, alongside implementation plan and walkthrough docs.
Repository: Hestenb62/_legacy_backup
Author: Hesten Berger
Commit Message: Ship accessibility and offline learning upgrades Adds a reusable sticky reading bar across reader chapters and lessons with live progress, time-left estimates, zen mode toggle, and one-click offline saving. Introduces offline.php download management (view, open, remove, clear), plus cache-backed material save helpers. Expands accessibility and assessment support with reading ruler controls/sync in global a11y settings, improved TTS behavior for quizzes and adaptive diagnostics (toggle speak/stop, sequential option narration, visual highlighting, keyboard shortcuts), and new diagnostic/parent styling. Also upgrades level module mastery cards with live SVG radial rings and adds a full IEP/504 brief generator modal with printable output on the parents page, alongside implementation plan and walkthrough docs.
URL: https://github.com/Hestenb62/_legacy_backup/commit/ac8855106bb88d63b30bed092af09b2a439fb2dd
Code Changes:
diff --git a/assets/css/components/sticky-reading-bar.css b/assets/css/components/sticky-reading-bar.css
new file mode 100644
index 0000000..29cfa7c
--- /dev/null
+++ b/assets/css/components/sticky-reading-bar.css
@@ -0,0 +1,204 @@
+/* ==========================================================================
+ Sticky Compact Reading Bar
+ High-performance, accessible, glassmorphic reading & lesson progress bar
+ ========================================================================== */
+
+.sticky-reading-bar {
+ position: fixed;
+ top: 0;
+ left: 0;
+ right: 0;
+ z-index: 990;
+ background: color-mix(in srgb, var(--color-bg-surface, #ffffff) 88%, transparent);
+ backdrop-filter: blur(16px);
+ -webkit-backdrop-filter: blur(16px);
+ border-bottom: 1px solid var(--color-border, rgba(0, 0, 0, 0.1));
+ box-shadow: 0 4px 20px -4px rgba(0, 0, 0, 0.12);
+ transform: translateY(-100%);
+ transition: transform 0.25s cubic-bezier(0.16, 1, 0.3, 1), opacity 0.25s ease;
+ opacity: 0;
+ pointer-events: none;
+}
+
+.sticky-reading-bar.is-active {
+ transform: translateY(0);
+ opacity: 1;
+ pointer-events: auto;
+}
+
+body.zen-mode .sticky-reading-bar {
+ top: 0 !important;
+}
+
+.sticky-bar-inner {
+ max-width: 72rem;
+ margin: 0 auto;
+ padding: 0.5rem 1rem;
+ display: flex;
+ align-items: center;
+ justify-content: space-between;
+ gap: 1rem;
+}
+
+/* Left Group */
+.sticky-bar-left {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ min-width: 0;
+ flex: 1 1 auto;
+}
+
+.sticky-bar-back-btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 2rem;
+ height: 2rem;
+ border-radius: var(--radius-full, 9999px);
+ background: var(--color-bg-base, rgba(0, 0, 0, 0.05));
+ border: 1px solid var(--color-border, transparent);
+ color: var(--color-text-main, inherit);
+ text-decoration: none;
+ font-size: 0.8rem;
+ flex-shrink: 0;
+ transition: all 0.15s ease;
+}
+
+.sticky-bar-back-btn:hover {
+ background: var(--color-primary, #3b82f6);
+ color: #ffffff;
+}
+
+.sticky-bar-info {
+ min-width: 0;
+ display: flex;
+ flex-direction: column;
+}
+
+.sticky-bar-title {
+ font-size: 0.85rem;
+ font-weight: 700;
+ color: var(--color-text-main, #0f172a);
+ white-space: nowrap;
+ overflow: hidden;
+ text-overflow: ellipsis;
+ margin: 0;
+ line-height: 1.2;
+}
+
+.sticky-bar-subtitle {
+ font-size: 0.72rem;
+ font-weight: 500;
+ color: var(--color-text-muted, #64748b);
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ margin: 0;
+}
+
+.sticky-badge-pill {
+ display: inline-flex;
+ align-items: center;
+ padding: 0.1rem 0.45rem;
+ border-radius: var(--radius-full, 9999px);
+ font-size: 0.68rem;
+ font-weight: 800;
+ background: color-mix(in srgb, var(--color-primary, #3b82f6) 15%, transparent);
+ color: var(--color-primary, #3b82f6);
+}
+
+/* Center / Meta Metrics */
+.sticky-bar-meta {
+ display: flex;
+ align-items: center;
+ gap: 0.75rem;
+ font-size: 0.78rem;
+ font-weight: 600;
+ color: var(--color-text-muted, #64748b);
+ white-space: nowrap;
+ flex-shrink: 0;
+}
+
+.sticky-time-left {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.35rem;
+}
+
+.sticky-pct-badge {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ min-width: 2.5rem;
+ padding: 0.2rem 0.5rem;
+ border-radius: var(--radius-full, 9999px);
+ background: var(--color-bg-elevated, rgba(0, 0, 0, 0.06));
+ border: 1px solid var(--color-border, transparent);
+ font-family: var(--font-mono, monospace);
+ font-weight: 800;
+ font-size: 0.75rem;
+ color: var(--color-primary, #3b82f6);
+}
+
+/* Right Quick Actions */
+.sticky-bar-actions {
+ display: flex;
+ align-items: center;
+ gap: 0.4rem;
+ flex-shrink: 0;
+}
+
+.sticky-action-btn {
+ display: inline-flex;
+ align-items: center;
+ justify-content: center;
+ width: 2rem;
+ height: 2rem;
+ border-radius: var(--radius-full, 9999px);
+ background: var(--color-bg-base, rgba(0, 0, 0, 0.05));
+ border: 1px solid var(--color-border, transparent);
+ color: var(--color-text-main, inherit);
+ cursor: pointer;
+ font-size: 0.8rem;
+ transition: all 0.15s ease;
+}
+
+.sticky-action-btn:hover {
+ background: var(--color-primary, #3b82f6);
+ color: #ffffff;
+ border-color: var(--color-primary, #3b82f6);
+}
+
+.sticky-action-btn.active {
+ background: var(--color-primary, #3b82f6);
+ color: #ffffff;
+}
+
+/* Bottom Progress Track */
+.sticky-progress-line {
+ position: absolute;
+ bottom: 0;
+ left: 0;
+ right: 0;
+ height: 3px;
+ background: color-mix(in srgb, var(--color-border, #cbd5e1) 50%, transparent);
+ overflow: hidden;
+}
+
+.sticky-progress-fill {
+ height: 100%;
+ width: 0%;
+ background: linear-gradient(90deg, var(--color-primary, #3b82f6), var(--color-accent, #06b6d4));
+ transition: width 0.1s linear;
+}
+
+/* Responsive collapse on mobile */
+@media (max-width: 640px) {
+ .sticky-bar-subtitle {
+ display: none;
+ }
+ .sticky-time-left span {
+ display: none;
+ }
+}
diff --git a/assets/css/pages/diagnostic.css b/assets/css/pages/diagnostic.css
index 44d4ea4..c118667 100644
--- a/assets/css/pages/diagnostic.css
+++ b/assets/css/pages/diagnostic.css
@@ -89,6 +89,52 @@
margin-bottom: 1.25rem;
}
+.diag-speak-btn {
+ display: inline-flex;
+ align-items: center;
+ gap: 0.4rem;
+ margin-left: auto;
+ padding: 0.35rem 0.85rem;
+ font-size: 0.82rem;
+ font-weight: 700;
+ color: var(--color-primary);
+ background: var(--color-primary-light, rgba(225, 29, 72, 0.08));
+ border: 1px solid var(--color-primary);
+ border-radius: var(--radius-full, 9999px);
+ cursor: pointer;
+ transition: all 0.2s ease;
+}
+
+.diag-speak-btn:hover {
+ background: var(--color-primary);
+ color: #ffffff;
+ transform: translateY(-1px);
+}
+
+.diag-speak-btn:focus-visible {
+ outline: 3px solid var(--color-primary);
+ outline-offset: 2px;
+}
+
+.diag-speak-btn.speaking {
+ background: #10b981;
+ color: #ffffff;
+ border-color: #10b981;
+ animation: pulse-diag-speak 1.2s infinite alternate;
+}
+
+@keyframes pulse-diag-speak {
+ 0% { transform: scale(1); box-shadow: 0 0 0 rgba(16, 185, 129, 0.4); }
+ 100% { transform: scale(1.04); box-shadow: 0 0 10px rgba(16, 185, 129, 0.4); }
+}
+
+.diag-option-btn.tts-speaking-option {
+ border-color: var(--color-primary) !important;
+ background-color: var(--color-primary-light, rgba(225, 29, 72, 0.08)) !important;
+ transform: translateX(4px);
+ box-shadow: 0 0 12px rgba(225, 29, 72, 0.25) !important;
+}
+
.diag-subject-badge {
font-size: 0.75rem;
font-weight: 800;
diff --git a/assets/css/pages/parents.css b/assets/css/pages/parents.css
index aaf1606..c0ec52f 100644
--- a/assets/css/pages/parents.css
+++ b/assets/css/pages/parents.css
@@ -1840,3 +1840,349 @@ html {
}
}
+/* ==========================================================================
+ IEP / 504 Meeting Brief Modal & Print Layout
+ ========================================================================== */
+.iep-modal-overlay {
+ position: fixed;
+ inset: 0;
+ background: rgba(15, 23, 42, 0.75);
+ backdrop-filter: blur(8px);
+ -webkit-backdrop-filter: blur(8px);
+ z-index: 10000;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ padding: 1.5rem;
+ animation: iepFadeIn 0.2s ease-out;
+}
+
+@keyframes iepFadeIn {
+ from { opacity: 0; }
+ to { opacity: 1; }
+}
+
+.iep-modal-card {
+ background: var(--color-surface, #ffffff);
+ color: var(--color-text-main, #0f172a);