Fix easter egg persistence bug where custom bead styles from the 404
page easter eggs (200, 404, 666, etc.) would persist across page reloads
and browser sessions when they should only last for the current session.
Root cause:
- Easter eggs call updateConfig() which saves to localStorage
- AbacusDisplayProvider loads from localStorage on mount
- Easter egg customization persisted indefinitely
Solution:
- Save original abacus config on 404 page mount
- Restore original config on beforeunload event
- Easter eggs persist while navigating site (client-side routing)
- Easter eggs reset on page reload or tab close
Behavior:
✅ Easter egg persists across Next.js navigation (Link, router.push)
✅ Easter egg resets on page reload (F5, Cmd+R)
✅ Easter egg resets on tab/window close
✅ Restores user's original bead style, not just defaults
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Added productionBrowserSourceMaps: true to Next.js config to enable
source maps in production builds. This will make client-side errors
much easier to debug by showing the original TypeScript source files
and line numbers instead of minified JavaScript.
Trade-off: Slightly larger build artifacts, but worth it for the
improved debugging experience. Source maps are downloaded on-demand
only when DevTools are open.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Fixed production runtime error "TypeError: d.value is not a function"
in tutorial component caused by missing context values.
Root cause:
- TutorialContext interface declared activeGroupTargetColumn and
setActiveGroupTargetColumn properties
- State variables were defined with underscore prefixes (_activeGroupTargetColumn)
indicating they were unused
- These values were not included in the context value object
- Components attempting to call setActiveGroupTargetColumn() received
undefined and crashed with "is not a function"
Fix:
- Removed underscore prefixes from state variable declarations
- Added activeGroupTargetColumn and setActiveGroupTargetColumn to
context value object
- Components now receive proper state and setter functions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Recover all changes from stash including:
- Linter/formatter updates across codebase
- Settings permission updates for git checkout
This commit captures the complete state of work that was
stashed during the previous session's git operations.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add missing subtraction-specific scaffold fields to the fallback displayRules
object in validation.ts to ensure all DisplayRules fields have defaults.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Use type casting to safely access borrowNotation and borrowingHints fields
from formState.displayRules, which may not have these fields if coming from
old worksheet configurations.
Provides fallback to profile defaults when fields are missing.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add missing subtraction-specific scaffold fields to DisplayRules and
ResolvedDisplayOptions interfaces, and include them in resolveDisplayForProblem.
This fixes TypeScript errors and ensures these fields are properly resolved
for each problem in smart difficulty mode.
Part of subtraction scaffolding integration that was lost during git stash.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove hardcoded false values for showBorrowNotation and showBorrowingHints
that were preventing these subtraction-specific scaffolds from displaying
in smart difficulty mode.
The displayOptions object already includes these fields from the resolved
display rules, so spreading displayOptions now correctly applies them.
This was work from a previous session that got lost during a git stash/pull.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove the three navigation buttons (Home, Games, Create) since the app
already has a navigation bar. Keep the page clean and focused on the
interactive abacus easter egg experience.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Completely remove the hint text to preserve the mystery and joy of discovery.
Let users find the easter eggs on their own!
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Remove the "Try other HTTP status codes..." hint from the default 404 page.
Now the hint only appears AFTER discovering the first easter egg, preserving
the element of surprise and discovery.
Let users stumble upon the easter eggs organically!
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When the user changes the abacus value to trigger different easter eggs,
the message text now fades in smoothly with a subtle upward motion.
- Add fadeKey state that increments on text changes
- Use key prop on h1 to force re-mount and trigger animation
- Custom fadeInText keyframe: opacity 0→1 with translateY(-10px→0)
- 0.5s ease-out animation timing
- Prevents jarring text swaps, creates polished UX
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Transform 404 page into a vibrant, playful experience with:
Themed Backgrounds:
- Each HTTP status code has custom gradient background
- Animated radial glow effects that pulse with theme colors
- Smooth transitions between themes (0.6s ease-in-out)
- 14 unique color schemes matching easter egg personality
Enhanced Typography:
- Responsive font sizes (1.75rem mobile → 4rem desktop)
- Black font weight for maximum impact
- Dynamic text colors matching each theme
- Glowing text shadows for easter egg modes
- Tight letter spacing (-0.02em) for modern look
Navigation Buttons:
- Added emoji icons (🏠🎮✨)
- Lift-and-scale hover animation
- Colored shadows matching button colors
- Responsive sizing for mobile
- Smooth cubic-bezier transitions
Responsive Layout:
- Increased spacing between abacus and text (2-4rem)
- Mobile-optimized gaps and padding
- Text pushed down to prevent overlap with large abacus
- Smaller screens get appropriate scaling
Dynamic Hints:
- Changes based on active easter egg
- "Try other codes..." vs "Click beads to discover more..."
- Themed text color and opacity
- Italic, medium weight for subtle emphasis
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Scale the interactive 404 abacus to match the hero section sizing with
responsive breakpoints:
- Mobile (base): 1.5x scale
- Small (sm): 2x scale
- Medium (md): 2.5x scale
- Large (lg): 3x scale
Prevent layout dominance on small screens with maxWidth constraints
and centered positioning.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add dynamic custom bead rendering system that allows beads to change appearance
based on their context (active state, position, place value, type, etc.).
Custom Bead Features:
- Add emoji-function, image-function, and svg-function types
- Functions receive CustomBeadContext with bead state and style info
- Support for dynamic rendering based on: active state, position, place value,
bead type (heaven/earth), color, and size
- Enables creative visualizations like traffic lights, themed symbols, etc.
404 Page Easter Eggs:
- Create interactive 404 page with manipulable abacus
- Add 14 HTTP status code easter eggs (200, 201, 301, 400, 401, 403, 418,
420, 451, 500, 503, 666, 777, 911)
- Each code triggers site-wide custom bead transformation
- Use function-based rendering for variety (different emojis per bead
position/state)
- Easter eggs persist until page reload via global AbacusDisplayContext
Storybook Documentation:
- Add comprehensive custom bead stories showing static and function-based usage
- Include examples: active/inactive states, heaven/earth types, place value
colors, traffic lights, color theming
- Document CustomBeadContext API and usage patterns
Technical Implementation:
- Extend CustomBeadContent union type in AbacusContext
- Update AbacusStaticBead and AbacusAnimatedBead to handle function types
- Pass bead context (type, value, active, position, placeValue, color, size)
to custom render functions
- Maintain consistency across static (SSR) and animated (client) rendering
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When displaying difficulty preset descriptions in dropdown, filter out
scaffolds that don't apply to the current operator:
- Addition-only: hide borrowNotation, borrowingHints from summaries
- Subtraction-only: hide carryBoxes, tenFrames from summaries
- Mixed: show all scaffolds
Updated function:
- getScaffoldingSummary(): added operator parameter with conditional
scaffold checking based on operator type
Fixes issue where preset dropdown showed subtraction-specific scaffolds
(borrow notation, borrowing hints) even for addition-only worksheets.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
When adjusting difficulty via Make Harder/Easier buttons, filter out
scaffolds that don't apply to the current operator:
- Addition-only: hide borrowNotation, borrowingHints from descriptions
- Subtraction-only: hide carryBoxes, tenFrames from descriptions
- Mixed: show all scaffolds
Updated functions:
- describeScaffoldingChange(): added operator parameter with filtering logic
- makeHarder(): passes operator to describeScaffoldingChange
- makeEasier(): passes operator to describeScaffoldingChange
- SmartModeControls: passes formState.operator to both functions
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
CRITICAL PEDAGOGICAL FIX: The difficulty progression was removing scaffolding
at the same time regrouping was being introduced, which is backwards!
The Problem:
- Beginner: 0% regrouping, 100% scaffolding ✓
- Early Learner: 25% regrouping, 100% scaffolding ✓
- Intermediate: 75% regrouping, 50% scaffolding ✗ WRONG!
- Advanced/Expert: 90% regrouping, 0% scaffolding ✗ WRONG!
Students were losing scaffolds (answer boxes, place value colors, ten-frames)
exactly when they needed them most - during intensive regrouping practice.
The Fix:
Added new "Practice" difficulty profile between Early Learner and Intermediate:
- Beginner: 0% regrouping, 100% scaffolding (learn structure)
- Early Learner: 25% regrouping, 100% scaffolding (introduce regrouping)
- **Practice: 75% regrouping, 100% scaffolding** ← NEW! (master WITH support)
- Intermediate: 75% regrouping, 50% scaffolding (begin removing support)
- Advanced/Expert: 90% regrouping, 0% scaffolding (full mastery)
Practice Profile Details:
- regrouping: { pAllStart: 0.25, pAnyStart: 0.75 } (same as Intermediate)
- carryBoxes: 'whenRegrouping' (show borrow/carry boxes when needed)
- answerBoxes: 'always' (keep guiding placement during intensive practice)
- placeValueColors: 'always' (keep visual support)
- tenFrames: 'whenRegrouping' (visual aid for regrouping)
Pedagogical Rationale:
Students need a "plateau phase" where they practice regrouping frequently
WITH full scaffolding support before we start removing training wheels.
This is especially critical for subtraction borrowing:
- First encounter borrowing with low frequency (Early Learner)
- Then practice borrowing intensively WITH scaffolds (Practice)
- Then gradually remove scaffolds as mastery develops (Intermediate → Expert)
Impact:
- Teachers selecting "Practice" mode get frequent regrouping with full support
- Smart difficulty progression no longer removes scaffolds prematurely
- Addresses user feedback: "we start turning off scaffolding for subtraction
as soon as we introduce regrouping, which defeats the whole point"
Updated DIFFICULTY_PROGRESSION:
['beginner', 'earlyLearner', 'practice', 'intermediate', 'advanced', 'expert']
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add light/dark mode support to WorksheetPreview component:
- Preview title and subtitle text adapt to theme
- SVG preview container uses themed background
- Pagination text adjusts for readability
- Info box uses blue theme variants (light or dark)
- Maintains brand button colors across themes
- Pass isDark through Suspense boundary
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add light/dark mode support to OrientationPanel and GenerateButton:
- OrientationPanel: themed backgrounds for all sections
- Orientation buttons adapt to theme (selected/unselected states)
- Page number buttons use themed backgrounds
- Problems per page dropdown has themed content
- Dropdown items and labels adjust for readability
- Total badge remains consistent (brand colors)
- GenerateButton panel uses themed background
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add light/dark mode support to all config panel components:
- StudentNameInput: themed input backgrounds and borders
- DigitRangeSection: themed section backgrounds and text
- OperatorSection: themed button states
- ModeSelector: themed mode selection cards
- ProgressiveDifficultyToggle: themed switch and backgrounds
- ToggleOption: themed toggle containers and text
- SmartModeControls & ManualModeControls: pass isDark prop through
All components now respond to light/dark theme with appropriate
backgrounds, borders, and text colors for optimal readability.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add light/dark mode support to AdditionWorksheetClient:
- Page background adapts to theme
- Header text colors adjust for readability
- Card panels use theme-appropriate backgrounds
- Settings status messages use themed colors
- Pass isDark prop to all child components
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
CRITICAL BUG FIX: Subtraction problems weren't generating with expected
borrowing frequency when pAllStart/pAnyStart were set to 100%.
Root Cause:
The old `generateBothBorrow()` used naive digit comparison (digitM < digitS)
to count borrows, which:
1. Doesn't account for cascading borrows across zeros (e.g., 100 - 1)
2. Returns ZERO problems for 2-digit numbers (mathematically impossible
to have both digits show digitM < digitS without negative result)
When user set regrouping to 100%, generator tried to create "both" problems
but failed every time, falling back to random problems or duplicates.
Fixes:
1. Added `countBorrows()` function that simulates actual subtraction algorithm
- Tracks borrow operations through place values
- Counts cascading borrows across zeros correctly
- Example: 100 - 1 = 2 borrows (hundreds → tens → ones)
2. Updated `generateBothBorrow()` to:
- Fall back to ones-only borrowing for 1-2 digit ranges (impossible to get 2+ borrows)
- Favor higher digit counts (3+) when possible
- Use correct borrow counting via `countBorrows()`
3. Changed fallback from [93, 57] (1 borrow) to [100, 1] or [534, 178] (2+ borrows)
Impact:
- 2-digit subtraction with pAll=100% now generates maximum difficulty (ones-only borrowing)
- 3+ digit subtraction with pAll=100% now correctly generates 2+ borrow problems
- User will see appropriate borrowing frequency at all difficulty settings
Test Examples:
- 52 - 17: 1 borrow ✓
- 100 - 1: 2 borrows ✓
- 534 - 178: 2 borrows ✓
- 1000 - 1: 3 borrows ✓
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Add light/dark mode responsiveness to the floating MyAbacus button:
- Light mode: white background with golden accent border
- Dark mode: dark background with golden accent border
- Theme-aware box shadows for better visibility in each mode
- Maintains golden glow effect across both themes
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace native <select> element with Radix UI DropdownMenu and add
full light/dark theme support.
Changes:
- Replace native select with Radix UI DropdownMenu
- Add useTheme hook to detect current theme (light/dark)
- Theme-aware button styling:
- Dark mode: gray.800 background with gray.700 border
- Light mode: white background with gray.300 border
- Fullscreen: black transparent with purple border
- Theme-aware dropdown content:
- Dark mode: gray.900 background
- Light mode: white background
- Proper contrast for all text and hover states
- Add dropdown chevron icon that rotates when open
- Add checkmark (✓) for currently selected language
- Both variants (dropdown-item and inline) now use Radix UI
- Highlight selected language with background color
- Smooth transitions and proper hover states for both themes
Improves accessibility and consistency with other dropdowns.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Make AbacusDisplayDropdown respond to light/dark mode.
Changes:
- Integrate useTheme hook to detect current theme
- Update button styling:
- Dark mode: gray.800 background with gray.700 border
- Light mode: white background with gray.200 border
- Update dropdown content styling:
- Dark mode: gray.900 background with gray.800 border
- Light mode: white background with gray.200 border
- Update all text colors for theme contrast:
- Headers, labels, descriptions adapt to theme
- Update form controls for theme:
- Switch backgrounds (gray.700 dark, gray.300 light)
- Radio button borders and backgrounds
- Volume slider track (gray.700 dark, gray.200 light)
All components now properly support light/dark themes while
maintaining existing fullscreen mode styling.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
- Add two-column CSS Grid layout for landscape orientation (≥480px)
- Implement proper flexbox sizing chain to prevent scrolling:
- Use minHeight: 0 and flex: 1 1 auto throughout container hierarchy
- Only allow overflow on grid container when content truly exceeds viewport
- Compact spacing for better viewport fit:
- Reduced padding: 8px 12px (from 16px 20px)
- Reduced font size: 14px (from 18px)
- Reduced icon size: 18px (from 24px)
- Reduced gaps: 16px base, 20px landscape, 8px on short screens
- Responsive gap sizing based on viewport height
- Column 1: Navigation + Controls
- Column 2: Abacus Style + Language + Theme
The menu now uses proper CSS layout techniques to fit within viewport
bounds, only scrolling when content genuinely exceeds available space.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Improve mobile full-screen menu to better utilize screen space with
larger, more touch-friendly UI elements.
Changes:
- Increase font sizes on mobile (18px links, 24px icons vs 14px/16px)
- Larger padding and gaps (16px-20px vs 10px-14px on desktop)
- Bigger border radius on mobile (12px vs 8px) for modern feel
- Increase section header spacing and size
- Add centered max-width container (600px) with top padding for close button
- Extract controlButtonStyle helper to avoid duplication
- Update all hover states to be theme-aware (light/dark)
Layout improvements:
- Content centered with max-width constraint
- Top padding (60px) to avoid close button overlap
- Consistent spacing between sections (20px margins)
- Icons scale appropriately (24px on mobile vs 16px desktop)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Improve mobile full-screen menu UX with explicit close button and
light/dark theme responsiveness.
Changes:
- Add fixed close button (X) in top-right corner of mobile menu
- Integrate useTheme hook to detect current theme (light/dark)
- Theme-aware styling for menu background, text, and hover states
- Dark mode: Dark gray gradients, light text
- Light mode: Light gray gradients, dark text
- Pass resolvedTheme to MenuContent for consistent theming
- Update hover colors to match theme (purple variants)
UX improvements:
- Close button provides clear affordance for dismissing menu
- Clicking backdrop still closes menu as before
- Menu visually adapts to system/user theme preference
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Refactor hamburger menu to use custom full-screen overlay on mobile
instead of Radix UI dropdown, fixing z-index stacking context issues.
Key changes:
- Extract MenuContent component for shared rendering logic between
mobile and desktop versions
- Implement custom full-screen mobile menu with viewport detection
- Use React Portal to render mobile menu outside header's stacking
context, ensuring it layers above hero abacus (z-index 9999 > 10)
- Desktop continues using Radix UI dropdown menu as before
- Mobile menu closes on navigation and backdrop click
Technical details:
- Header's opacity: 0.95 creates stacking context, constraining child
z-indexes. Portal breaks out to document.body for global z-index.
- Conditional rendering based on viewport width (640px breakpoint)
- Shared MenuContent adapts rendering (plain divs vs Radix components)
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extract Manual Mode section from ConfigPanel into dedicated component:
- Created ManualModeControls.tsx (339 lines)
- Display options toggles with Check All/Uncheck All buttons
- Live preview panel (DisplayOptionsPreview)
- Regrouping frequency double-thumb slider
- ConfigPanel reduced to 207 lines (91.9% reduction from original 2550)
Removed from ConfigPanel:
- SubOption, ToggleOption, DisplayOptionsPreview imports
- defaultAdditionConfig import
- useTranslations hook and 't' variable
- Entire Manual Mode section (lines 210-531)
Fixed parsing error in ManualModeControls:
- Removed extra closing paren from fragment structure
- Formatted with biome
All display options now properly organized:
- Answer boxes, carry/borrow boxes, place value colors
- Ten-frames with sub-option for all problems
- Borrowing notation and hints (conditional on operator)
- Problem numbers, cell borders
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extracted all shared UI sections that appear in both smart and manual modes
to separate components for improved modularity and reusability.
Extracted components:
- DigitRangeSection.tsx: Digit range slider with tick marks (~170 lines)
- OperatorSection.tsx: Operator selection buttons (~120 lines)
- ProgressiveDifficultyToggle.tsx: Progressive difficulty toggle (~90 lines)
Changes:
- Removed unused imports (Slider, Switch - now in extracted components)
- Updated ConfigPanel.tsx to use new components
- File size reduced: 2286 → 1942 lines (-344 lines)
Total progress so far: 2550 → 1942 lines (-608 lines, 23.8% reduction)
Zero functionality change - all components work identically.
Phase 2 of 5 complete.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Extracted Student Name input field to separate component as part of Phase 2.
Changes:
- Created StudentNameInput.tsx component (32 lines)
- Updated ConfigPanel.tsx to use new component
- File size reduced: 2306 → 2286 lines (-20 lines)
Remaining Phase 2 work: Extract DigitRangeSection, OperatorSection, and ProgressiveDifficultyToggle components.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Created config-panel/ subdirectory and extracted reusable UI components
from the monolithic 2550-line ConfigPanel.tsx file.
Extracted components:
- utils.tsx: getScaffoldingSummary() function
- SubOption.tsx: Nested toggle UI component
- ToggleOption.tsx: Main toggle option with description
Changes:
- Created src/app/create/worksheets/addition/components/config-panel/ directory
- Moved 3 helper functions/components to separate files (~240 lines)
- Updated ConfigPanel.tsx to import from new locations
- Removed unused imports (Checkbox, findNearestPreset)
- File size reduced: 2550 → 2306 lines (-244 lines)
Zero functionality change - all components work identically.
Part 1 of 5-phase refactoring plan.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Previously, smart mode hardcoded showBorrowNotation and showBorrowingHints
to false. Now these fields are properly integrated into the display rules
system and scaffolding progression.
Changes:
- Extended DisplayRules interface with borrowNotation and borrowingHints fields
- Added fields to all 13 scaffolding levels and 5 difficulty profiles
- Updated config schemas (V2, V3, V4) with backward-compatible migrations
- Removed hardcoded false values in typstGenerator.ts
- Updated getScaffoldingSummary() to show new scaffolding aids
- Fixed typstGenerator subtraction parameter ordering (showCarryBoxes → showBorrowNotation)
- Fixed borrow hint text rendering (removed extra box wrapper)
Subtraction worksheets now receive the same conditional scaffolding
treatment as addition, with hints appearing at appropriate difficulty
levels and fading as students progress.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Replace hardcoded white colors in transparent nav mode with semantic tokens
that adapt to light/dark themes:
Transparent mode (hero overlay):
- Text: white → text.primary / text.secondary
- Background: rgba(255,255,255,0.08) → bg.subtle / bg.muted
- Borders: rgba(255,255,255,0.15) → border.subtle / border.default
- Hover: rgba(255,255,255,0.25) → interactive.hover
This fixes invisible white text on light backgrounds when viewing the
homepage hero in light mode.
Non-transparent mode (regular nav) remains unchanged with existing colors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Use CSS light-dark() function to support both color schemes:
Decomposition reasoning tooltips:
- Background: white → dark in dark mode
- Borders: light gray → darker in dark mode
- Text: dark → light in dark mode
- Code blocks and steps: proper contrast in both modes
Tutorial player tooltips:
- Blue background adapts to theme
- Text remains white for good contrast
Fixes unreadable light text on light backgrounds in light mode.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Convert blog section from hardcoded rgba colors (dark mode only) to semantic
theme tokens that adapt to light/dark mode:
- text.primary, text.secondary, text.muted for content
- accent.subtle, accent.muted, accent.default for backgrounds/borders
- accent.emphasis for interactive text
This fixes unreadable white text on light backgrounds in light mode.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
Two critical issues fixed:
1. **Duplicate numerals**: Both AbacusSVGRenderer and AbacusReact were rendering
numerals when showNumbers={true}, causing two overlapping number displays.
- Disabled SVG text numerals in AbacusSVGRenderer (line 436: added `false &&`)
- NumberFlow provides better animated numerals, keep only those
2. **White numerals in dark mode**: NumberFlow components were inheriting CSS
color from parent, turning white in dark mode (unreadable on light frames).
- Added explicit color style to NumberFlow: uses themeAwareCustomStyles
- Now consistently dark (rgba(0,0,0,0.8)) regardless of page theme
This was the root cause of the "white numerals everywhere" issue - the
NumberFlow components were inheriting dark mode CSS colors.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The example route was also missing generatePlaceValueColors() calls,
causing "unknown variable: color-ones" errors when rendering subtraction
examples. Added color definitions to both addition and subtraction templates.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The PDF generation route was ignoring the operator and digitRange settings,
always generating 2-digit addition problems regardless of configuration.
The preview worked correctly but PDF generation was broken.
Changes:
- Add conditional logic to call appropriate problem generator based on operator
- Pass digitRange parameter to all problem generators
- Add generatePlaceValueColors() to Typst template for color definitions
- Import DisplayOptions type for internal use in typstHelpers
Fixes worksheet PDF generation for subtraction, mixed, and multi-digit problems.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>
The arrows in borrowing hints were being covered by the diagonal-split-box
colored backgrounds in adjacent cells. This occurred because Typst renders
elements in document order, and arrows placed inside colored boxes appear
below backgrounds from cells rendered later.
Solution: Disable place value colors in borrow boxes entirely. Borrow boxes
now always use stroke-only rendering (no colored backgrounds), which ensures
arrows are never covered. Place value colors still work everywhere else
(minuend, subtrahend, and answer rows).
This is simpler and more maintainable than complex double-render or
compositing approaches, and avoids the fundamental layering limitation.
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-Authored-By: Claude <noreply@anthropic.com>