fix(StartPracticeModal): responsive improvements + integrated tutorial CTA

- Full-screen mode at ≤700px height for iPhone SE support
- Two-column grid layout for settings in landscape mode
- Integrated tutorial CTA: combines unlock banner + start button
- Fixed collapsed mode clipping of target skills section
- Made "focusing on weak skills" visible on all screen sizes
- Fixed duplicate CSS media query breakpoints
- BKT: changed computeBktFromHistory to accept Partial<BktComputeExtendedOptions>

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Thomas Hallock 2025-12-18 10:49:49 -06:00
parent 5735ff0810
commit 56742c511d
2 changed files with 577 additions and 349 deletions

File diff suppressed because it is too large Load Diff

View File

@ -75,8 +75,10 @@ function applyTimeDecay(
*/
export function computeBktFromHistory(
results: ProblemResultWithContext[],
options: BktComputeExtendedOptions = DEFAULT_BKT_OPTIONS
options: Partial<BktComputeExtendedOptions> = {}
): BktComputeResult {
// Merge with defaults so callers can override just what they need
const opts: BktComputeExtendedOptions = { ...DEFAULT_BKT_OPTIONS, ...options }
// Sort by timestamp to replay in chronological order
// Note: timestamp may be a Date or a string (from JSON serialization)
const sorted = [...results].sort((a, b) => {
@ -126,7 +128,7 @@ export function computeBktFromHistory(
const evidenceWeight = helpWeight * rtWeight
// Compute BKT updates (conjunctive model)
const blameMethod = options.blameMethod ?? 'heuristic'
const blameMethod = opts.blameMethod ?? 'heuristic'
const updates = result.isCorrect
? updateOnCorrect(skillRecords)
: updateOnIncorrectWithMethod(skillRecords, blameMethod)
@ -158,13 +160,13 @@ export function computeBktFromHistory(
// Apply decay if enabled
let finalPKnown = state.pKnown
if (options.applyDecay && state.lastPracticedAt) {
if (opts.applyDecay && state.lastPracticedAt) {
const daysSinceLastPractice =
(now.getTime() - state.lastPracticedAt.getTime()) / (1000 * 60 * 60 * 24)
finalPKnown = applyTimeDecay(
state.pKnown,
daysSinceLastPractice,
options.decayHalfLifeDays,
opts.decayHalfLifeDays,
state.params.pInit
)
}
@ -175,7 +177,7 @@ export function computeBktFromHistory(
const masteryClassification = classifyMastery(
finalPKnown,
confidence,
options.confidenceThreshold
opts.confidenceThreshold
)
skills.push({