---
phase: 04-polish-audio
plan: 02
type: execute
wave: 1
depends_on: []
files_modified:
  - src/styles/main.css
  - src/main.ts
autonomous: true
requirements: [PLSH-01, PLSH-02, PLSH-03, PLSH-04, PLSH-05]

must_haves:
  truths:
    - "Fallende Buchstaben schweben seitlich wie Blaetter (sinusfoermiger Sway)"
    - "Sternenstaub-Particles erscheinen bei richtigem Tastendruck (CSS pseudo-elements)"
    - "Companion-Avatar schwebt sanft auf und ab"
    - "Bei 700px Breite: Tasten kleiner, Fonts skaliert, Grid angepasst"
    - "Unbehandelte Exceptions zeigen kindgerechtes Overlay mit Reload-Button"
    - "Alle Animationen respektieren prefers-reduced-motion"
  artifacts:
    - path: "src/styles/main.css"
      provides: "Leaf-fall animation, stardust particles, companion float, responsive, error overlay"
      contains: "@keyframes leaf-fall"
    - path: "src/main.ts"
      provides: "Global error handler"
      contains: "addEventListener.*error"
  key_links:
    - from: "src/styles/main.css"
      to: "index.html"
      via: "Error overlay element"
      pattern: "error-overlay"
---

<objective>
Visuelles Polish: Verbesserte Animationen (Blaetter-Fall, Sternenstaub, Avatar-Schweben), Responsive bis 700px, globaler Error-Handler.

Purpose: Sanfte, kindgerechte Animationen und robuste Fehlerbehandlung per D-06 bis D-11 aus CONTEXT.md.
Output: Erweiterte main.css mit neuen Animationen + Responsive, Error-Handler in main.ts + Overlay in index.html.
</objective>

<execution_context>
@$HOME/.claude/get-shit-done/workflows/execute-plan.md
@$HOME/.claude/get-shit-done/templates/summary.md
</execution_context>

<context>
@.planning/PROJECT.md
@.planning/ROADMAP.md
@.planning/phases/04-polish-audio/04-CONTEXT.md

@src/styles/main.css
@src/main.ts
@index.html
</context>

<tasks>

<task type="auto">
  <name>Task 1: Enhanced CSS animations + responsive layout</name>
  <files>src/styles/main.css</files>
  <read_first>src/styles/main.css, .planning/phases/04-polish-audio/04-CONTEXT.md</read_first>
  <action>
1. Replace `@keyframes letter-float` with `@keyframes leaf-fall` (per D-06):
   ```css
   @keyframes leaf-fall {
     0% { transform: translateY(-20px) translateX(0) rotate(0deg); opacity: 0; }
     10% { opacity: 1; }
     25% { transform: translateY(25%) translateX(15px) rotate(5deg); }
     50% { transform: translateY(50%) translateX(-10px) rotate(-3deg); }
     75% { transform: translateY(75%) translateX(12px) rotate(4deg); }
     100% { transform: translateY(100%) translateX(-5px) rotate(-2deg); opacity: 0.8; }
   }
   ```
   Update `.falling-letter` to use `animation: leaf-fall 2.5s ease-in-out infinite` instead of `letter-float`.

2. Enhance `.falling-letter--dissolve` with stardust particles (per D-07):
   Add CSS `::before` and `::after` pseudo-elements:
   ```css
   .falling-letter--dissolve::before,
   .falling-letter--dissolve::after {
     content: '';
     position: absolute;
     width: 6px;
     height: 6px;
     border-radius: 50%;
     background: var(--accent-gold);
     animation: stardust 0.6s ease-out forwards;
   }
   .falling-letter--dissolve::before {
     top: 30%;
     left: 20%;
     animation-delay: 0s;
   }
   .falling-letter--dissolve::after {
     top: 40%;
     right: 20%;
     background: var(--accent-pink);
     animation-delay: 0.1s;
   }
   ```
   Add `@keyframes stardust`:
   ```css
   @keyframes stardust {
     0% { transform: scale(1) translate(0, 0); opacity: 1; }
     100% { transform: scale(0) translate(var(--dx, 20px), var(--dy, -30px)); opacity: 0; }
   }
   ```
   Add 4 more particles via box-shadow on the pseudo-elements for more sparkle effect.

3. Add/enhance companion float animation (per D-08):
   ```css
   .companion-area__avatar {
     animation: companion-float 3s ease-in-out infinite;
   }
   @keyframes companion-float {
     0%, 100% { transform: translateY(0); }
     50% { transform: translateY(-8px); }
   }
   ```

4. Add `prefers-reduced-motion` (per D-09):
   ```css
   @media (prefers-reduced-motion: reduce) {
     .falling-letter,
     .companion-area__avatar,
     .forest__element-img {
       animation: none !important;
     }
     .falling-letter--dissolve::before,
     .falling-letter--dissolve::after {
       animation: none !important;
     }
   }
   ```

5. Add responsive styles at bottom (per D-10):
   ```css
   @media (max-width: 700px) {
     .keyboard__key {
       min-width: 32px;
       height: 32px;
       font-size: clamp(10px, 2.5vw, 14px);
     }
     .keyboard__key--space {
       min-width: 120px;
     }
     h1 { font-size: clamp(20px, 5vw, 32px); }
     h2 { font-size: clamp(18px, 4vw, 24px); }
     body { font-size: clamp(14px, 3.5vw, 16px); }
     .welcome__companions {
       grid-template-columns: repeat(2, 1fr);
     }
     .forest__grid {
       grid-template-columns: repeat(3, 1fr);
       grid-template-rows: repeat(4, 1fr);
     }
     .lesson__keyboard {
       transform: scale(0.85);
       transform-origin: top center;
     }
   }
   ```
  </action>
  <verify>
    <automated>cd /home/dev/workspace/zauberwald && grep -c "leaf-fall\|stardust\|companion-float\|prefers-reduced-motion\|max-width.*700" src/styles/main.css</automated>
  </verify>
  <acceptance_criteria>
    - main.css contains @keyframes leaf-fall with translateX sway
    - main.css contains @keyframes stardust on .falling-letter--dissolve pseudo-elements
    - main.css contains @keyframes companion-float on .companion-area__avatar
    - main.css contains @media (prefers-reduced-motion: reduce) disabling animations
    - main.css contains @media (max-width: 700px) with keyboard key size 32px
    - .falling-letter uses leaf-fall animation instead of letter-float
  </acceptance_criteria>
  <done>All animations enhanced with leaf-fall sway, stardust particles, companion float. Responsive down to 700px. prefers-reduced-motion respected.</done>
</task>

<task type="auto">
  <name>Task 2: Global error handler + error overlay</name>
  <files>index.html, src/main.ts, src/styles/main.css</files>
  <read_first>index.html, src/main.ts, src/styles/main.css</read_first>
  <action>
1. In `index.html` (per D-11): Add error overlay element BEFORE the script tag, outside all sections:
   ```html
   <div id="error-overlay" class="error-overlay" style="display:none">
     <div class="error-overlay__content">
       <p class="error-overlay__icon">&#x1F333;</p>
       <p class="error-overlay__message">Oh, der Wald braucht kurz eine Pause...</p>
       <button class="error-overlay__btn" onclick="location.reload()">Nochmal versuchen</button>
     </div>
   </div>
   ```

2. In `src/styles/main.css`: Add error overlay styles:
   ```css
   .error-overlay {
     position: fixed;
     inset: 0;
     background: rgba(255, 248, 240, 0.95);
     z-index: 9999;
     display: flex;
     align-items: center;
     justify-content: center;
   }
   .error-overlay__content {
     text-align: center;
     padding: 2rem;
   }
   .error-overlay__icon {
     font-size: 4rem;
     margin-bottom: 1rem;
   }
   .error-overlay__message {
     font-family: 'Quicksand', sans-serif;
     font-size: 1.25rem;
     color: var(--text-dark);
     margin-bottom: 1.5rem;
   }
   .error-overlay__btn {
     font-family: 'Quicksand', sans-serif;
     font-size: 1rem;
     padding: 0.75rem 2rem;
     background: var(--accent-green);
     color: white;
     border: none;
     border-radius: 12px;
     cursor: pointer;
   }
   ```

3. In `src/main.ts` (per D-11): Add global error handlers BEFORE DOMContentLoaded:
   ```typescript
   window.addEventListener('error', (event) => {
     console.error('Global error:', event.error);
     const overlay = document.getElementById('error-overlay');
     if (overlay) overlay.style.display = 'flex';
   });
   window.addEventListener('unhandledrejection', (event) => {
     console.error('Unhandled rejection:', event.reason);
     const overlay = document.getElementById('error-overlay');
     if (overlay) overlay.style.display = 'flex';
   });
   ```
   Keep the existing `DOMContentLoaded` listener intact.

NOTE: Plan 01 also modifies main.ts (mute button wiring). These changes are independent -- error handlers go at the top of the file, mute button wiring goes inside the DOMContentLoaded callback. If Plan 01 runs first, read the updated file. If this plan runs first, the other will read the updated file.
  </action>
  <verify>
    <automated>cd /home/dev/workspace/zauberwald && grep -c "error-overlay\|addEventListener.*error\|unhandledrejection" index.html src/main.ts src/styles/main.css</automated>
  </verify>
  <acceptance_criteria>
    - index.html contains div#error-overlay with child elements
    - main.ts contains window.addEventListener for both 'error' and 'unhandledrejection'
    - main.css contains .error-overlay styles with position: fixed and z-index: 9999
    - Error overlay shows "Oh, der Wald braucht kurz eine Pause..." message
    - Reload button calls location.reload()
  </acceptance_criteria>
  <done>Unhandled exceptions show kindgerechtes overlay with reload button. Console.error preserved for debugging.</done>
</task>

</tasks>

<verification>
- `npx tsc --noEmit` passes
- `npm run lint` passes
- grep confirms leaf-fall, stardust, companion-float, reduced-motion, 700px responsive in CSS
- grep confirms error handler in main.ts
- grep confirms error-overlay in index.html
</verification>

<success_criteria>
Animations polished (leaf-fall sway, stardust particles, companion float), responsive to 700px, global error handler catching uncaught exceptions with child-friendly overlay.
</success_criteria>

<output>
After completion, create `.planning/phases/04-polish-audio/04-02-SUMMARY.md`
</output>
