"""
Test suite for Habits frontend page structure and navigation
Story US-002: Frontend - Compact habit cards (~100px height)
Story US-003: Frontend - Check/uncheck toggle behavior
Story US-005: Frontend - Stats section collapse with chevron
Story US-006: Frontend - Page structure, layout, and navigation link
Story US-007: Frontend - Habit card component
Story US-008: Frontend - Create habit modal with all options
Story US-009: Frontend - Edit habit modal
Story US-010: Frontend - Check-in interaction (click and long-press)
Story US-011: Frontend - Skip, lives display, and delete confirmation
Story US-012: Frontend - Filter and sort controls
Story US-013: Frontend - Stats section and weekly summary
Story US-014: Frontend - Mobile responsive and touch optimization
"""

import sys
import os
import subprocess
from pathlib import Path

# Add parent directory to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))

def test_habits_html_exists():
    """Test 1: habits.html exists in dashboard/"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    assert habits_path.exists(), "habits.html should exist in dashboard/"
    print("✓ Test 1: habits.html exists")

def test_habits_html_structure():
    """Test 2: Page includes common.css, Lucide icons, and swipe-nav.js"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'href="/echo/common.css"' in content, "Should include common.css"
    assert 'lucide@latest/dist/umd/lucide.min.js' in content, "Should include Lucide icons"
    assert 'src="/echo/swipe-nav.js"' in content, "Should include swipe-nav.js"
    print("✓ Test 2: Page includes required CSS and JS")

def test_page_has_header():
    """Test 3: Page has header with 'Habits' title and 'Add Habit' button"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'class="page-title"' in content, "Should have page-title element"
    assert '>Habits</' in content, "Should have 'Habits' title"
    assert 'Add Habit' in content, "Should have 'Add Habit' button"
    assert 'showAddHabitModal()' in content, "Add Habit button should have onclick handler"
    print("✓ Test 3: Page has header with title and Add Habit button")

def test_empty_state():
    """Test 4: Empty state message shown when no habits exist"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'No habits yet' in content, "Should have empty state message"
    assert 'Create your first habit' in content, "Should have call-to-action"
    assert 'empty-state' in content, "Should have empty-state class"
    print("✓ Test 4: Empty state message present")

def test_grid_container():
    """Test 5: Grid container uses CSS grid with responsive breakpoints (1/2/3 columns)"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'habits-grid' in content, "Should have habits-grid class"
    assert 'display: grid' in content, "Should use CSS grid"
    assert 'grid-template-columns' in content, "Should define grid columns"
    
    # Check responsive breakpoints
    assert '@media (max-width: 768px)' in content or '@media (max-width:768px)' in content, \
        "Should have mobile breakpoint"
    assert 'grid-template-columns: 1fr' in content or 'grid-template-columns:1fr' in content, \
        "Should have 1 column on mobile"
    
    # Check for 2 or 3 column layouts
    assert ('grid-template-columns: repeat(2, 1fr)' in content or 
            'grid-template-columns:repeat(2,1fr)' in content or
            'grid-template-columns: repeat(3, 1fr)' in content or
            'grid-template-columns:repeat(3,1fr)' in content), \
        "Should have multi-column layout for larger screens"
    
    print("✓ Test 5: Grid container with responsive breakpoints")

def test_index_navigation_link():
    """Test 6: index.html navigation includes 'Habits' link with dumbbell icon"""
    index_path = Path(__file__).parent.parent / 'index.html'
    content = index_path.read_text()
    
    assert '/echo/habits.html' in content, "Should link to /echo/habits.html"
    assert 'dumbbell' in content, "Should have dumbbell icon"
    assert '>Habits</' in content, "Should have 'Habits' label"
    
    # Check that Habits link is in the nav
    nav_start = content.find('<nav class="nav">')
    nav_end = content.find('</nav>', nav_start)
    nav_section = content[nav_start:nav_end]
    
    assert '/echo/habits.html' in nav_section, "Habits link should be in navigation"
    assert 'dumbbell' in nav_section, "Dumbbell icon should be in navigation"
    
    print("✓ Test 6: index.html includes Habits navigation link")

def test_page_fetches_habits():
    """Test 7: Page fetches GET /echo/api/habits on load"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert "fetch('/echo/api/habits')" in content or 'fetch("/echo/api/habits")' in content, \
        "Should fetch from /echo/api/habits"
    assert 'loadHabits' in content, "Should have loadHabits function"
    
    # Check that loadHabits is called on page load
    # (either in inline script or as last statement)
    assert content.count('loadHabits()') > 0, "loadHabits should be called"
    
    print("✓ Test 7: Page fetches habits on load")

def test_habit_card_rendering():
    """Test 8: Placeholder habit card rendering exists"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'renderHabitCard' in content, "Should have renderHabitCard function"
    assert 'habit-card' in content, "Should have habit-card class"
    assert 'renderHabits' in content, "Should have renderHabits function"
    
    print("✓ Test 8: Habit card rendering functions exist")

def test_no_console_errors_structure():
    """Test 9: No obvious console error sources (basic structure check)"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for basic script structure
    assert '<script>' in content, "Should have script tags"
    assert 'function' in content, "Should have JavaScript functions"
    
    # Check for proper escaping in rendering
    assert 'escapeHtml' in content or 'textContent' in content, \
        "Should have XSS protection (escapeHtml or textContent)"
    
    print("✓ Test 9: No obvious console error sources")

def test_typecheck():
    """Test 10: HTML file is well-formed"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Basic HTML structure checks
    assert '<!DOCTYPE html>' in content, "Should have DOCTYPE"
    assert '<html' in content and '</html>' in content, "Should have html tags"
    assert '<head>' in content and '</head>' in content, "Should have head tags"
    assert '<body>' in content and '</body>' in content, "Should have body tags"
    
    # Check for matching script tags
    script_open = content.count('<script')
    script_close = content.count('</script>')
    assert script_open == script_close, f"Script tags should match (found {script_open} opens, {script_close} closes)"
    
    print("✓ Test 10: HTML structure is well-formed")

def test_card_colored_border():
    """Test 11: Habit card has colored left border matching habit.color"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'border-left-color' in content or 'borderLeftColor' in content, \
        "Card should have colored left border"
    assert 'habit.color' in content, "Card should use habit.color for border"
    print("✓ Test 11: Card has colored left border")

def test_card_header_icons():
    """Test 12: Card header shows icon, name, settings, and delete"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for icon display
    assert 'habit.icon' in content or 'habit-card-icon' in content, \
        "Card should display habit icon"
    
    # Check for name display
    assert 'habit.name' in content or 'habit-card-name' in content, \
        "Card should display habit name"
    
    # Check for settings (gear) icon
    assert 'settings' in content.lower(), "Card should have settings icon"
    
    # Check for delete (trash) icon
    assert 'trash' in content.lower(), "Card should have delete icon"
    
    print("✓ Test 12: Card header has icon, name, settings, and delete")

def test_card_streak_display():
    """Test 13: Streak displays with fire emoji for current and trophy for best"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert '🔥' in content, "Card should have fire emoji for current streak"
    assert '🏆' in content, "Card should have trophy emoji for best streak"
    assert 'habit.streak' in content or 'streak?.current' in content or 'streak.current' in content, \
        "Card should display streak.current"
    assert 'streak?.best' in content or 'streak.best' in content, \
        "Card should display streak.best"
    
    print("✓ Test 13: Streak display with fire and trophy emojis")

def test_card_checkin_button():
    """Test 14: Check-in button is large and centered"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'habit-card-check-btn' in content or 'check-btn' in content or 'checkin' in content.lower(), \
        "Card should have check-in button"
    assert 'Check In' in content or 'Check in' in content, \
        "Button should have 'Check In' text"
    
    # Check for button styling (large/centered)
    assert 'width: 100%' in content or 'width:100%' in content, \
        "Check-in button should be full-width"
    
    print("✓ Test 14: Check-in button is large and centered")

def test_card_checkin_disabled_when_done():
    """Test 15: Check-in button disabled when already checked today"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'disabled' in content, "Button should have disabled state"
    assert 'Done today' in content or 'Done' in content, \
        "Button should show 'Done today' when disabled"
    assert 'isCheckedToday' in content or 'isDoneToday' in content, \
        "Should have function to check if habit is done today"
    
    print("✓ Test 15: Check-in button disabled when done today")

def test_card_lives_display():
    """Test 16: Lives display shows filled and empty hearts (total 3)"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert '❤️' in content or '♥' in content, "Card should have filled heart emoji"
    assert '🖤' in content or '♡' in content, "Card should have empty heart emoji"
    assert 'habit.lives' in content or 'renderLives' in content, \
        "Card should display lives"
    
    # Check for lives rendering function
    assert 'renderLives' in content or 'lives' in content.lower(), \
        "Should have lives rendering logic"
    
    print("✓ Test 16: Lives display with hearts")

def test_card_completion_rate():
    """Test 17: Completion rate percentage is displayed"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'completion_rate' in content or 'completion' in content, \
        "Card should display completion rate"
    assert '(30d)' in content or '30d' in content, \
        "Completion rate should show 30-day period"
    assert '%' in content, "Completion rate should show percentage"
    
    print("✓ Test 17: Completion rate displayed")

def test_card_footer_category_priority():
    """Test 18: Footer shows category badge and priority"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'habit.category' in content or 'habit-card-category' in content, \
        "Card should display category"
    assert 'habit.priority' in content or 'priority' in content.lower(), \
        "Card should display priority"
    assert 'habit-card-footer' in content or 'footer' in content.lower(), \
        "Card should have footer section"
    
    print("✓ Test 18: Footer shows category and priority")

def test_card_lucide_createicons():
    """Test 19: lucide.createIcons() is called after rendering cards"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that createIcons is called after rendering
    render_pos = content.find('renderHabits')
    if render_pos != -1:
        after_render = content[render_pos:]
        assert 'lucide.createIcons()' in after_render, \
            "lucide.createIcons() should be called after rendering"
    
    print("✓ Test 19: lucide.createIcons() called after rendering")

def test_card_common_css_variables():
    """Test 20: Card uses common.css variables for styling"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for common.css variable usage
    assert '--bg-surface' in content or '--text-primary' in content or '--border' in content, \
        "Card should use common.css variables"
    assert 'var(--' in content, "Should use CSS variables"
    
    print("✓ Test 20: Card uses common.css variables")

def test_typecheck_us007():
    """Test 21: Typecheck passes for US-007"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    assert habits_path.exists(), "habits.html should exist"
    
    # Check that all functions are properly defined
    content = habits_path.read_text()
    assert 'function renderHabitCard(' in content, "renderHabitCard function should be defined"
    assert 'function isCheckedToday(' in content, "isCheckedToday function should be defined"
    assert 'function getLastCheckInfo(' in content, "getLastCheckInfo function should be defined"
    assert 'function renderLives(' in content, "renderLives function should be defined"
    assert 'function getPriorityLevel(' in content, "getPriorityLevel function should be defined"
    
    print("✓ Test 21: Typecheck passes (all functions defined)")

def test_modal_opens_on_add_habit_click():
    """Test 22: Modal opens when clicking 'Add Habit' button"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'showAddHabitModal()' in content, "Add Habit button should call showAddHabitModal()"
    assert 'function showAddHabitModal(' in content, "showAddHabitModal function should be defined"
    assert 'modal-overlay' in content or 'habitModal' in content, "Should have modal overlay element"
    print("✓ Test 22: Modal opens on Add Habit button click")

def test_modal_closes_on_x_and_outside_click():
    """Test 23: Modal closes on X button or clicking outside"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'closeHabitModal()' in content, "Should have closeHabitModal function"
    assert 'modal-close' in content or 'onclick="closeHabitModal()"' in content, \
        "X button should call closeHabitModal()"
    
    # Check for click outside handler
    assert 'e.target === modal' in content or 'event.target' in content, \
        "Should handle clicking outside modal"
    print("✓ Test 23: Modal closes on X button and clicking outside")

def test_modal_has_all_form_fields():
    """Test 24: Form has all required fields"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Required fields
    assert 'habitName' in content or 'name' in content.lower(), "Form should have name field"
    assert 'habitCategory' in content or 'category' in content.lower(), "Form should have category field"
    assert 'habitPriority' in content or 'priority' in content.lower(), "Form should have priority field"
    assert 'habitNotes' in content or 'notes' in content.lower(), "Form should have notes field"
    assert 'frequencyType' in content or 'frequency' in content.lower(), "Form should have frequency field"
    assert 'reminderTime' in content or 'reminder' in content.lower(), "Form should have reminder time field"
    
    print("✓ Test 24: Form has all required fields")

def test_color_picker_presets_and_custom():
    """Test 25: Color picker shows preset swatches and custom hex input"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'color-picker' in content or 'colorSwatches' in content or 'color-swatch' in content, \
        "Should have color picker"
    assert 'customColor' in content or 'custom' in content.lower(), \
        "Should have custom color input"
    assert '#RRGGBB' in content or 'pattern=' in content, \
        "Custom color should have hex pattern"
    assert 'presetColors' in content or '#3B82F6' in content or '#EF4444' in content, \
        "Should have preset colors"
    
    print("✓ Test 25: Color picker with presets and custom hex")

def test_icon_picker_grid():
    """Test 26: Icon picker shows grid of common Lucide icons"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'icon-picker' in content or 'iconPicker' in content, \
        "Should have icon picker"
    assert 'icon-option' in content or 'commonIcons' in content, \
        "Should have icon options"
    assert 'selectIcon' in content, "Should have selectIcon function"
    
    # Check for common icons
    icon_count = sum([1 for icon in ['dumbbell', 'moon', 'book', 'brain', 'heart'] 
                      if icon in content])
    assert icon_count >= 3, "Should have at least 3 common icons"
    
    print("✓ Test 26: Icon picker with grid of Lucide icons")

def test_frequency_params_conditional():
    """Test 27: Frequency params display conditionally based on type"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'updateFrequencyParams' in content, "Should have updateFrequencyParams function"
    assert 'frequencyParams' in content, "Should have frequency params container"
    assert 'specific_days' in content, "Should handle specific_days frequency"
    assert 'x_per_week' in content, "Should handle x_per_week frequency"
    assert 'custom' in content.lower(), "Should handle custom frequency"
    
    # Check for conditional rendering (day checkboxes for specific_days)
    assert 'day-checkbox' in content or "['Mon', 'Tue'" in content or 'Mon' in content, \
        "Should have day checkboxes for specific_days"
    
    print("✓ Test 27: Frequency params display conditionally")

def test_client_side_validation():
    """Test 28: Client-side validation prevents submit without name"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'required' in content, "Name field should be required"
    assert 'trim()' in content, "Should trim input values"
    
    # Check for validation in submit function
    submit_func = content[content.find('function submitHabitForm'):]
    assert 'if (!name)' in submit_func or 'name.length' in submit_func, \
        "Should validate name is not empty"
    assert 'showToast' in submit_func and 'error' in submit_func, \
        "Should show error toast for validation failures"
    
    print("✓ Test 28: Client-side validation checks name required")

def test_submit_posts_to_api():
    """Test 29: Submit sends POST /echo/api/habits (or PUT for edit) and refreshes list"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'submitHabitForm' in content, "Should have submitHabitForm function"
    
    submit_func = content[content.find('function submitHabitForm'):]
    # Check for conditional URL and method (since US-009 added edit support)
    assert ('/echo/api/habits' in submit_func), \
        "Should use /echo/api/habits endpoint"
    assert ("'POST'" in submit_func or '"POST"' in submit_func or "'PUT'" in submit_func or '"PUT"' in submit_func), \
        "Should use POST or PUT method"
    assert 'JSON.stringify' in submit_func, "Should send JSON body"
    assert 'loadHabits()' in submit_func, "Should refresh habit list on success"
    
    print("✓ Test 29: Submit POSTs to API and refreshes list")

def test_loading_state_on_submit():
    """Test 30: Loading state shown on submit button during API call"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    submit_func = content[content.find('function submitHabitForm'):]
    assert 'disabled = true' in submit_func or '.disabled' in submit_func, \
        "Submit button should be disabled during API call"
    assert 'Creating' in submit_func or 'loading' in submit_func.lower(), \
        "Should show loading text"
    assert 'disabled = false' in submit_func, \
        "Submit button should be re-enabled after API call"
    
    print("✓ Test 30: Loading state on submit button")

def test_toast_notifications():
    """Test 31: Toast notification shown for success and error"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'showToast' in content, "Should have showToast function"
    assert 'toast' in content, "Should have toast styling"
    
    toast_func = content[content.find('function showToast'):]
    assert 'success' in toast_func and 'error' in toast_func, \
        "Toast should handle both success and error types"
    assert 'check-circle' in toast_func or 'alert-circle' in toast_func, \
        "Toast should show appropriate icons"
    assert 'setTimeout' in toast_func or 'remove()' in toast_func, \
        "Toast should auto-dismiss"
    
    print("✓ Test 31: Toast notifications for success and error")

def test_modal_no_console_errors():
    """Test 32: No obvious console error sources in modal code"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that modal functions exist
    assert 'function showAddHabitModal(' in content, "showAddHabitModal should be defined"
    assert 'function closeHabitModal(' in content, "closeHabitModal should be defined"
    assert 'function submitHabitForm(' in content, "submitHabitForm should be defined"
    assert 'function updateFrequencyParams(' in content, "updateFrequencyParams should be defined"
    
    # Check for proper error handling
    submit_func = content[content.find('function submitHabitForm'):]
    assert 'try' in submit_func and 'catch' in submit_func, \
        "Submit function should have try-catch error handling"
    
    print("✓ Test 32: No obvious console error sources")

def test_typecheck_us008():
    """Test 33: Typecheck passes for US-008 (all modal functions defined)"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check all new functions are defined
    required_functions = [
        'showAddHabitModal',
        'closeHabitModal',
        'initColorPicker',
        'selectColor',
        'initIconPicker',
        'selectIcon',
        'updateFrequencyParams',
        'submitHabitForm',
        'showToast'
    ]
    
    for func in required_functions:
        assert f'function {func}(' in content or f'const {func} =' in content, \
            f"{func} function should be defined"
    
    print("✓ Test 33: Typecheck passes (all modal functions defined)")

def test_edit_modal_opens_on_gear_icon():
    """Test 34: Clicking gear icon on habit card opens edit modal"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that gear icon exists with onclick handler
    assert 'settings' in content, "Should have settings icon (gear)"
    assert "showEditHabitModal" in content, "Should have showEditHabitModal function call"
    
    # Check that showEditHabitModal function is defined and not a placeholder
    assert 'function showEditHabitModal(habitId)' in content, "showEditHabitModal should be defined"
    assert 'editingHabitId = habitId' in content or 'editingHabitId=habitId' in content, \
        "Should set editingHabitId"
    assert 'const habit = habits.find(h => h.id === habitId)' in content or \
           'const habit=habits.find(h=>h.id===habitId)' in content, \
        "Should find habit by ID"
    
    print("✓ Test 34: Edit modal opens on gear icon click")

def test_edit_modal_prepopulated():
    """Test 35: Edit modal is pre-populated with all existing habit data"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that form fields are pre-populated
    assert "getElementById('habitName').value = habit.name" in content or \
           "getElementById('habitName').value=habit.name" in content, \
        "Should pre-populate habit name"
    assert "getElementById('habitCategory').value = habit.category" in content or \
           "getElementById('habitCategory').value=habit.category" in content, \
        "Should pre-populate category"
    assert "getElementById('habitPriority').value = habit.priority" in content or \
           "getElementById('habitPriority').value=habit.priority" in content, \
        "Should pre-populate priority"
    assert "getElementById('habitNotes').value = habit.notes" in content or \
           "getElementById('habitNotes').value=habit.notes" in content, \
        "Should pre-populate notes"
    assert "getElementById('frequencyType').value = habit.frequency" in content or \
           "getElementById('frequencyType').value=habit.frequency" in content, \
        "Should pre-populate frequency type"
    
    # Check color and icon selection
    assert 'selectedColor = habit.color' in content or 'selectedColor=habit.color' in content, \
        "Should set selectedColor from habit"
    assert 'selectedIcon = habit.icon' in content or 'selectedIcon=habit.icon' in content, \
        "Should set selectedIcon from habit"
    
    print("✓ Test 35: Edit modal pre-populated with habit data")

def test_edit_modal_title_and_button():
    """Test 36: Modal title shows 'Edit Habit' and button shows 'Save Changes'"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that modal title is changed to Edit Habit
    assert "modalTitle.textContent = 'Edit Habit'" in content or \
           'modalTitle.textContent="Edit Habit"' in content or \
           "modalTitle.textContent='Edit Habit'" in content, \
        "Should set modal title to 'Edit Habit'"
    
    # Check that submit button text is changed
    assert "submitBtnText.textContent = 'Save Changes'" in content or \
           'submitBtnText.textContent="Save Changes"' in content or \
           "submitBtnText.textContent='Save Changes'" in content, \
        "Should set button text to 'Save Changes'"
    
    print("✓ Test 36: Modal title shows 'Edit Habit' and button shows 'Save Changes'")

def test_edit_modal_frequency_params():
    """Test 37: Frequency params display correctly for habit's current frequency type"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that updateFrequencyParams is called
    assert 'updateFrequencyParams()' in content, "Should call updateFrequencyParams()"
    
    # Check that frequency params are pre-populated for specific types
    assert 'specific_days' in content and 'habit.frequency.days' in content, \
        "Should handle specific_days frequency params"
    assert 'x_per_week' in content and 'habit.frequency.count' in content, \
        "Should handle x_per_week frequency params"
    assert 'custom' in content and 'habit.frequency.interval' in content, \
        "Should handle custom frequency params"
    
    # Check that day checkboxes are pre-populated
    assert 'cb.checked = habit.frequency.days.includes' in content or \
           'cb.checked=habit.frequency.days.includes' in content, \
        "Should pre-select days for specific_days frequency"
    
    print("✓ Test 37: Frequency params display correctly for current frequency")

def test_edit_modal_icon_color_pickers():
    """Test 38: Icon and color pickers show current selections"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that pickers are initialized after setting values
    assert 'initColorPicker()' in content, "Should call initColorPicker()"
    assert 'initIconPicker()' in content, "Should call initIconPicker()"
    
    # Check that selectedColor and selectedIcon are set before initialization
    showEditIndex = content.find('function showEditHabitModal')
    initColorIndex = content.find('initColorPicker()', showEditIndex)
    selectedColorIndex = content.find('selectedColor = habit.color', showEditIndex)
    
    assert selectedColorIndex > 0 and selectedColorIndex < initColorIndex, \
        "Should set selectedColor before calling initColorPicker()"
    
    print("✓ Test 38: Icon and color pickers show current selections")

def test_edit_modal_submit_put():
    """Test 39: Submit sends PUT /echo/api/habits/{id} and refreshes list on success"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that editingHabitId is tracked
    assert 'let editingHabitId' in content or 'editingHabitId' in content, \
        "Should track editingHabitId"
    
    # Check that isEditing is determined
    assert 'const isEditing = editingHabitId !== null' in content or \
           'const isEditing=editingHabitId!==null' in content or \
           'isEditing = editingHabitId !== null' in content, \
        "Should determine if editing"
    
    # Check that URL and method are conditional
    assert "const url = isEditing ? `/echo/api/habits/${editingHabitId}` : '/echo/api/habits'" in content or \
           'const url=isEditing?`/echo/api/habits/${editingHabitId}`' in content or \
           "url = isEditing ? `/echo/api/habits/${editingHabitId}` : '/echo/api/habits'" in content, \
        "URL should be conditional based on isEditing"
    
    assert "const method = isEditing ? 'PUT' : 'POST'" in content or \
           "const method=isEditing?'PUT':'POST'" in content or \
           "method = isEditing ? 'PUT' : 'POST'" in content, \
        "Method should be conditional (PUT for edit, POST for create)"
    
    # Check that loadHabits is called after success
    assert 'await loadHabits()' in content, "Should refresh habit list after success"
    
    print("✓ Test 39: Submit sends PUT and refreshes list")

def test_edit_modal_toast_messages():
    """Test 40: Toast shown for success and error"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for conditional success message
    assert "isEditing ? 'Habit updated!' : 'Habit created successfully!'" in content or \
           "isEditing?'Habit updated!':'Habit created successfully!'" in content, \
        "Should show different toast message for edit vs create"
    
    # Check that error toast handles both edit and create
    assert 'Failed to ${isEditing' in content or 'Failed to ' + '${isEditing' in content, \
        "Error toast should be conditional"
    
    print("✓ Test 40: Toast messages for success and error")

def test_edit_modal_add_resets_state():
    """Test 41: showAddHabitModal resets editingHabitId and modal UI"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Find showAddHabitModal function
    add_modal_start = content.find('function showAddHabitModal()')
    add_modal_end = content.find('function ', add_modal_start + 1)
    add_modal_func = content[add_modal_start:add_modal_end]
    
    # Check that editingHabitId is reset
    assert 'editingHabitId = null' in add_modal_func or 'editingHabitId=null' in add_modal_func, \
        "showAddHabitModal should reset editingHabitId to null"
    
    # Check that modal title is reset to 'Add Habit'
    assert "modalTitle.textContent = 'Add Habit'" in add_modal_func or \
           'modalTitle.textContent="Add Habit"' in add_modal_func, \
        "Should reset modal title to 'Add Habit'"
    
    # Check that button text is reset to 'Create Habit'
    assert "submitBtnText.textContent = 'Create Habit'" in add_modal_func or \
           'submitBtnText.textContent="Create Habit"' in add_modal_func, \
        "Should reset button text to 'Create Habit'"
    
    print("✓ Test 41: showAddHabitModal resets editing state")

def test_edit_modal_close_resets_state():
    """Test 42: closeHabitModal resets editingHabitId"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Find closeHabitModal function
    close_modal_start = content.find('function closeHabitModal()')
    close_modal_end = content.find('function ', close_modal_start + 1)
    close_modal_func = content[close_modal_start:close_modal_end]
    
    # Check that editingHabitId is reset when closing
    assert 'editingHabitId = null' in close_modal_func or 'editingHabitId=null' in close_modal_func, \
        "closeHabitModal should reset editingHabitId to null"
    
    print("✓ Test 42: closeHabitModal resets editing state")

def test_edit_modal_no_console_errors():
    """Test 43: No obvious console error sources in edit modal code"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for common error patterns
    assert content.count('getElementById(') > 0, "Should use getElementById"
    
    # Check that habit is validated before use
    showEditIndex = content.find('function showEditHabitModal')
    showEditEnd = content.find('\n        }', showEditIndex + 500)  # Find end of function
    showEditFunc = content[showEditIndex:showEditEnd]
    
    assert 'if (!habit)' in showEditFunc or 'if(!habit)' in showEditFunc, \
        "Should check if habit exists before using it"
    assert 'showToast' in showEditFunc and 'error' in showEditFunc, \
        "Should show error toast if habit not found"
    
    print("✓ Test 43: No obvious console error sources")

def test_typecheck_us009():
    """Test 44: Typecheck passes - all edit modal functions and variables defined"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that editingHabitId is declared
    assert 'let editingHabitId' in content, "editingHabitId should be declared"
    
    # Check that showEditHabitModal is fully implemented (not placeholder)
    assert 'function showEditHabitModal(habitId)' in content, "showEditHabitModal should be defined"
    assert 'alert' not in content[content.find('function showEditHabitModal'):content.find('function showEditHabitModal')+1000], \
        "showEditHabitModal should not be a placeholder with alert()"
    
    # Check that submitHabitForm handles both create and edit
    assert 'const isEditing' in content or 'isEditing' in content, \
        "submitHabitForm should determine if editing"
    
    print("✓ Test 44: Typecheck passes (edit modal fully implemented)")

def test_checkin_simple_click():
    """Test 45: Simple click on check-in button sends POST request"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that checkInHabit function exists and does POST
    assert 'function checkInHabit' in content or 'async function checkInHabit' in content, \
        "checkInHabit function should be defined"
    
    checkin_start = content.find('function checkInHabit')
    checkin_end = content.find('\n        }', checkin_start + 500)
    checkin_func = content[checkin_start:checkin_end]
    
    assert "fetch(`/echo/api/habits/${habitId}/check`" in checkin_func or \
           'fetch(`/echo/api/habits/${habitId}/check`' in checkin_func, \
        "Should POST to /echo/api/habits/{id}/check"
    assert "method: 'POST'" in checkin_func, "Should use POST method"
    
    print("✓ Test 45: Simple click sends POST to check-in endpoint")

def test_checkin_detail_modal_structure():
    """Test 46: Check-in detail modal exists with note, rating, and mood fields"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check modal exists
    assert 'id="checkinModal"' in content, "Should have check-in detail modal"
    assert 'Check-In Details' in content or 'Check-in Details' in content, \
        "Modal should have title 'Check-In Details'"
    
    # Check for note textarea
    assert 'id="checkinNote"' in content, "Should have note textarea"
    assert '<textarea' in content, "Should have textarea element"
    
    # Check for rating stars
    assert 'rating-star' in content, "Should have rating star elements"
    assert 'selectRating' in content, "Should have selectRating function"
    
    # Check for mood buttons
    assert 'mood-btn' in content, "Should have mood button elements"
    assert 'selectMood' in content, "Should have selectMood function"
    assert '😊' in content and '😐' in content and '😞' in content, \
        "Should have happy, neutral, and sad emojis"
    
    print("✓ Test 46: Check-in detail modal has note, rating, and mood fields")

def test_checkin_long_press_handler():
    """Test 47: Long-press (mobile) and right-click (desktop) handlers exist"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for long-press handling functions
    assert 'handleCheckInButtonPress' in content, \
        "Should have handleCheckInButtonPress function"
    assert 'handleCheckInButtonRelease' in content, \
        "Should have handleCheckInButtonRelease function"
    
    # Check for contextmenu event (right-click)
    assert "contextmenu" in content, "Should handle contextmenu event for right-click"
    
    # Check for touch/mouse events
    assert "mousedown" in content, "Should handle mousedown event"
    assert "mouseup" in content, "Should handle mouseup event"
    assert "touchstart" in content or "touch" in content, \
        "Should handle touch events for mobile"
    
    # Check for long-press timer
    assert 'longPressTimer' in content, "Should track long-press timer"
    assert '500' in content, "Should use 500ms delay for long-press"
    
    print("✓ Test 47: Long-press and right-click handlers exist")

def test_checkin_detail_modal_functions():
    """Test 48: Modal functions (show, close, selectRating, selectMood) are defined"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check modal control functions
    assert 'function showCheckInDetailModal' in content, \
        "Should have showCheckInDetailModal function"
    assert 'function closeCheckinModal' in content, \
        "Should have closeCheckinModal function"
    
    # Check selection functions
    assert 'function selectRating' in content, "Should have selectRating function"
    assert 'function selectMood' in content, "Should have selectMood function"
    
    # Check submit function
    assert 'function submitCheckInDetail' in content or 'async function submitCheckInDetail' in content, \
        "Should have submitCheckInDetail function"
    
    print("✓ Test 48: Check-in modal functions are defined")

def test_checkin_detail_submit():
    """Test 49: Detail modal submit sends note, rating, and mood"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Find submitCheckInDetail function
    submit_start = content.find('function submitCheckInDetail')
    submit_end = content.find('\n        }', submit_start + 1000)
    submit_func = content[submit_start:submit_end]
    
    # Check it builds body with optional fields
    assert 'body.note' in submit_func or 'if (note)' in submit_func, \
        "Should add note to body if provided"
    assert 'body.rating' in submit_func or 'checkInRating' in submit_func, \
        "Should add rating to body if provided"
    assert 'body.mood' in submit_func or 'checkInMood' in submit_func, \
        "Should add mood to body if provided"
    
    # Check it POSTs to API
    assert "fetch(`/echo/api/habits/" in submit_func, "Should POST to API"
    assert "/check`" in submit_func, "Should POST to check endpoint"
    
    print("✓ Test 49: Detail modal submit includes optional fields")

def test_checkin_toast_with_streak():
    """Test 50: Toast notification shows 'Habit checked! 🔥 Streak: X'"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for toast with streak message
    assert 'Habit checked!' in content, "Should show 'Habit checked!' message"
    assert '🔥' in content, "Should include fire emoji in streak message"
    assert 'Streak:' in content, "Should show streak count"
    
    # Check that streak value comes from API response
    checkin_start = content.find('function checkInHabit')
    checkin_area = content[checkin_start:checkin_start+5000]  # Increased for toggle implementation
    
    assert 'updatedHabit' in checkin_area or 'await response.json()' in checkin_area, \
        "Should get updated habit from response"
    assert 'streak' in checkin_area, "Should access streak from response"
    
    print("✓ Test 50: Toast shows 'Habit checked! 🔥 Streak: X'")

def test_checkin_button_disabled_after():
    """Test 51: Check-in button shows checked state after check-in (toggle design)"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that renderHabitCard uses isCheckedToday to determine state
    assert 'isCheckedToday(habit)' in content, \
        "Should check if habit is checked today"
    
    # Check button uses 'checked' class instead of disabled (US-003 toggle behavior)
    assert 'isDoneToday ? \'checked\' : \'\'' in content or \
           '${isDoneToday ? \'checked\' : \'\'}' in content, \
        "Button should use 'checked' class (not disabled)"
    
    # Check button displays checkmark when done (compact design)
    assert 'isDoneToday ? \'✓\' : \'○\'' in content or \
           '${isDoneToday ? \'✓\' : \'○\'}' in content, \
        "Button should show ✓ when checked, ○ when unchecked (compact)"
    
    print("✓ Test 51: Button shows checked state after check-in (toggle design)")

def test_checkin_pulse_animation():
    """Test 52: Pulse animation plays on card after successful check-in"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for pulse animation CSS
    assert '@keyframes pulse' in content, "Should define pulse animation"
    assert 'transform: scale' in content, "Pulse should use scale transform"
    assert '.pulse' in content, "Should have pulse CSS class"
    
    # Check that checkInHabit adds pulse class
    checkin_start = content.find('function checkInHabit')
    checkin_area = content[checkin_start:checkin_start+5000]  # Increased for toggle implementation
    
    assert 'pulse' in checkin_area or 'classList.add' in checkin_area, \
        "Should add pulse class to card after check-in"
    
    print("✓ Test 52: Pulse animation defined and applied")

def test_checkin_prevent_context_menu():
    """Test 53: Right-click prevents default context menu"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for preventDefault on contextmenu
    press_handler_start = content.find('function handleCheckInButtonPress')
    press_handler_end = content.find('\n        }', press_handler_start + 1000)
    press_handler = content[press_handler_start:press_handler_end]
    
    assert 'contextmenu' in press_handler, "Should check for contextmenu event"
    assert 'preventDefault()' in press_handler, "Should call preventDefault on right-click"
    
    print("✓ Test 53: Right-click prevents default context menu")

def test_checkin_event_listeners_attached():
    """Test 54: Event listeners are attached to check-in buttons in renderHabits"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Find renderHabits function
    render_start = content.find('function renderHabits()')
    render_end = content.find('\n        }', render_start + 2000)
    render_func = content[render_start:render_end]
    
    # Check that event listeners are attached
    assert 'addEventListener' in render_func, \
        "Should attach event listeners after rendering"
    assert 'contextmenu' in render_func or 'contextmenu' in content[render_end:render_end+1000], \
        "Should attach contextmenu listener"
    assert 'mousedown' in render_func or 'mousedown' in content[render_end:render_end+1000], \
        "Should attach mousedown listener"
    
    # Check that we iterate through habits to attach listeners
    assert 'habits.forEach' in render_func or 'for' in render_func, \
        "Should iterate through habits to attach listeners"
    
    print("✓ Test 54: Event listeners attached in renderHabits")

def test_typecheck_us010():
    """Test 55: Typecheck passes - all check-in functions defined"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check all required functions are defined
    required_functions = [
        'checkInHabit',
        'showCheckInDetailModal',
        'closeCheckinModal',
        'selectRating',
        'selectMood',
        'submitCheckInDetail',
        'handleCheckInButtonPress',
        'handleCheckInButtonRelease',
        'handleCheckInButtonCancel'
    ]
    
    for func in required_functions:
        assert f'function {func}' in content or f'async function {func}' in content, \
            f"{func} should be defined"
    
    # Check state variables
    assert 'let checkInHabitId' in content, "checkInHabitId should be declared"
    assert 'let checkInRating' in content, "checkInRating should be declared"
    assert 'let checkInMood' in content, "checkInMood should be declared"
    assert 'let longPressTimer' in content, "longPressTimer should be declared"
    
    print("✓ Test 55: Typecheck passes (all check-in functions and variables defined)")

# ========== US-011 Tests: Skip, lives display, and delete confirmation ==========

def test_skip_button_visible():
    """Test 56: Skip functionality exists (hidden in compact card view)"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Skip button is hidden in compact view, but skipHabitDay function still exists
    assert 'async function skipHabitDay' in content or 'function skipHabitDay' in content, \
        "skipHabitDay function should exist for skip functionality"
    
    # In compact design, skip button and lives are NOT visible on card
    # This is correct behavior for US-002 compact cards
    
    print("✓ Test 56: Skip functionality exists (hidden in compact card view)")

def test_skip_confirmation_dialog():
    """Test 57: Clicking skip shows confirmation dialog"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check skipHabitDay function exists
    assert 'async function skipHabitDay' in content, "skipHabitDay function should exist"
    
    # Check confirmation dialog
    assert 'Use 1 life to skip today?' in content, "Skip confirmation dialog should ask 'Use 1 life to skip today?'"
    assert 'confirm(' in content, "Should use confirm dialog"
    
    print("✓ Test 57: Clicking skip shows confirmation dialog")

def test_skip_sends_post_and_refreshes():
    """Test 58: Confirming skip sends POST /echo/api/habits/{id}/skip and refreshes card"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check API endpoint
    assert "/echo/api/habits/${habitId}/skip" in content, "Should POST to /echo/api/habits/{id}/skip"
    assert "method: 'POST'" in content, "Should use POST method"
    
    # Check refresh
    assert 'await loadHabits()' in content, "Should refresh habits list after skip"
    
    print("✓ Test 58: Confirming skip sends POST /echo/api/habits/{id}/skip and refreshes card")

def test_skip_button_disabled_when_no_lives():
    """Test 59: Skip logic handles lives correctly (compact view hides UI)"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Skip functionality exists even though UI is hidden in compact view
    # The logic for handling lives still needs to exist
    assert 'skipHabitDay' in content, "Skip function should exist"
    
    # In compact design, skip button is hidden so this test just verifies function exists
    
    print("✓ Test 59: Skip logic exists (UI hidden in compact view)")

def test_skip_toast_message():
    """Test 60: Toast shows 'Day skipped. X lives remaining.' after skip"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check toast message format
    assert 'Day skipped' in content, "Toast should include 'Day skipped'"
    assert 'remaining' in content, "Toast should show remaining lives"
    
    # Check life/lives plural handling
    assert "remainingLives === 1 ? 'life' : 'lives'" in content, "Should handle singular/plural for lives"
    
    print("✓ Test 60: Toast shows 'Day skipped. X lives remaining.' after skip")

def test_delete_confirmation_with_habit_name():
    """Test 61: Clicking trash icon shows delete confirmation dialog with habit name"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check delete function exists
    assert 'async function deleteHabit' in content, "deleteHabit function should exist"
    
    # Check confirmation uses habit name
    assert 'Delete ${habitName}?' in content or 'Delete ' in content, "Delete confirmation should include habit name"
    assert 'This cannot be undone' in content, "Delete confirmation should warn 'This cannot be undone'"
    
    print("✓ Test 61: Clicking trash icon shows delete confirmation dialog with habit name")

def test_delete_sends_delete_request():
    """Test 62: Confirming delete sends DELETE /echo/api/habits/{id} and removes card"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check DELETE request
    assert "method: 'DELETE'" in content, "Should use DELETE method"
    assert "/echo/api/habits/${habitId}" in content or "/echo/api/habits/" in content, "Should DELETE to /echo/api/habits/{id}"
    
    # Check refresh (removes card from DOM via re-render)
    assert 'await loadHabits()' in content, "Should refresh habits list after delete"
    
    print("✓ Test 62: Confirming delete sends DELETE /echo/api/habits/{id} and removes card")

def test_delete_toast_message():
    """Test 63: Toast shows 'Habit deleted' after deletion"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check success toast
    assert 'Habit deleted' in content, "Toast should say 'Habit deleted'"
    
    print("✓ Test 63: Toast shows 'Habit deleted' after deletion")

def test_skip_delete_no_console_errors():
    """Test 64: No obvious console error sources in skip and delete code"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check error handling in skipHabitDay
    skip_func = content[content.find('async function skipHabitDay'):content.find('async function skipHabitDay') + 1500]
    assert 'try' in skip_func and 'catch' in skip_func, "skipHabitDay should have try/catch"
    assert 'console.error' in skip_func, "skipHabitDay should log errors"
    
    # Check error handling in deleteHabit
    delete_func = content[content.find('async function deleteHabit'):content.find('async function deleteHabit') + 1500]
    assert 'try' in delete_func and 'catch' in delete_func, "deleteHabit should have try/catch"
    assert 'console.error' in delete_func, "deleteHabit should log errors"
    
    print("✓ Test 64: No obvious console error sources in skip and delete code")

def test_typecheck_us011():
    """Test 65: Typecheck passes (all skip and delete functions defined)"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check function definitions
    functions = [
        'skipHabitDay',
        'deleteHabit',
    ]
    
    for func in functions:
        assert f"function {func}" in content, \
            f"{func} should be defined"
    
    # Check that habits are cached for delete
    assert 'localStorage.setItem' in content, "Should cache habits in localStorage"
    assert 'habitsCache' in content, "Should use 'habitsCache' key"
    
    print("✓ Test 65: Typecheck passes (all skip and delete functions defined)")

### US-012: Filter and sort controls ###

def test_filter_bar_exists():
    """Test 66: Filter bar with category, status, and sort dropdowns appears above habit grid"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'class="filter-bar"' in content, "Should have filter-bar element"
    assert 'id="categoryFilter"' in content, "Should have category filter dropdown"
    assert 'id="statusFilter"' in content, "Should have status filter dropdown"
    assert 'id="sortSelect"' in content, "Should have sort dropdown"
    print("✓ Test 66: Filter bar with dropdowns exists")

def test_category_filter_options():
    """Test 67: Category filter has All, Work, Health, Growth, Personal options"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for category options
    assert 'value="all">All</option>' in content, "Should have 'All' option"
    assert 'value="work">Work</option>' in content, "Should have 'Work' option"
    assert 'value="health">Health</option>' in content, "Should have 'Health' option"
    assert 'value="growth">Growth</option>' in content, "Should have 'Growth' option"
    assert 'value="personal">Personal</option>' in content, "Should have 'Personal' option"
    print("✓ Test 67: Category filter has correct options")

def test_status_filter_options():
    """Test 68: Status filter has All, Active Today, Done Today, Overdue options"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'value="all">All</option>' in content, "Should have 'All' option"
    assert 'value="active_today">Active Today</option>' in content, "Should have 'Active Today' option"
    assert 'value="done_today">Done Today</option>' in content, "Should have 'Done Today' option"
    assert 'value="overdue">Overdue</option>' in content, "Should have 'Overdue' option"
    print("✓ Test 68: Status filter has correct options")

def test_sort_dropdown_options():
    """Test 69: Sort dropdown has Priority, Name, and Streak options (asc/desc)"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'value="priority_asc"' in content, "Should have 'Priority (Low to High)' option"
    assert 'value="priority_desc"' in content, "Should have 'Priority (High to Low)' option"
    assert 'value="name_asc"' in content, "Should have 'Name A-Z' option"
    assert 'value="name_desc"' in content, "Should have 'Name Z-A' option"
    assert 'value="streak_desc"' in content, "Should have 'Streak (Highest)' option"
    assert 'value="streak_asc"' in content, "Should have 'Streak (Lowest)' option"
    print("✓ Test 69: Sort dropdown has correct options")

def test_filter_functions_exist():
    """Test 70: applyFiltersAndSort, filterHabits, and sortHabits functions are defined"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'function applyFiltersAndSort()' in content, "Should have applyFiltersAndSort function"
    assert 'function filterHabits(' in content, "Should have filterHabits function"
    assert 'function sortHabits(' in content, "Should have sortHabits function"
    assert 'function restoreFilters()' in content, "Should have restoreFilters function"
    print("✓ Test 70: Filter and sort functions are defined")

def test_filter_calls_on_change():
    """Test 71: Filter dropdowns call applyFiltersAndSort on change"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'onchange="applyFiltersAndSort()"' in content, "Filters should call applyFiltersAndSort on change"
    
    # Count how many times onchange appears (should be 3: category, status, sort)
    count = content.count('onchange="applyFiltersAndSort()"')
    assert count >= 3, f"Should have at least 3 onchange handlers, found {count}"
    print("✓ Test 71: Filter dropdowns call applyFiltersAndSort on change")

def test_localstorage_persistence():
    """Test 72: Filter selections are saved to localStorage"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert "localStorage.setItem('habitCategoryFilter'" in content, "Should save category filter to localStorage"
    assert "localStorage.setItem('habitStatusFilter'" in content, "Should save status filter to localStorage"
    assert "localStorage.setItem('habitSort'" in content, "Should save sort to localStorage"
    print("✓ Test 72: Filter selections saved to localStorage")

def test_localstorage_restore():
    """Test 73: Filter selections are restored from localStorage on page load"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert "localStorage.getItem('habitCategoryFilter')" in content, "Should restore category filter from localStorage"
    assert "localStorage.getItem('habitStatusFilter')" in content, "Should restore status filter from localStorage"
    assert "localStorage.getItem('habitSort')" in content, "Should restore sort from localStorage"
    assert 'restoreFilters()' in content, "Should call restoreFilters on page load"
    print("✓ Test 73: Filter selections restored from localStorage")

def test_filter_logic_implementation():
    """Test 74: filterHabits function checks category and status correctly"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check category filter logic
    assert "categoryFilter !== 'all'" in content, "Should check if category filter is not 'all'"
    assert "habit.category" in content, "Should compare habit.category"
    
    # Check status filter logic
    assert "statusFilter !== 'all'" in content, "Should check if status filter is not 'all'"
    assert "should_check_today" in content or "shouldCheckToday" in content, "Should use should_check_today for status filtering"
    print("✓ Test 74: Filter logic checks category and status")

def test_sort_logic_implementation():
    """Test 75: sortHabits function handles all sort options"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that sort function handles all options
    assert "'priority_asc'" in content, "Should handle priority_asc"
    assert "'priority_desc'" in content, "Should handle priority_desc"
    assert "'name_asc'" in content, "Should handle name_asc"
    assert "'name_desc'" in content, "Should handle name_desc"
    assert "'streak_desc'" in content, "Should handle streak_desc"
    assert "'streak_asc'" in content, "Should handle streak_asc"
    assert 'localeCompare' in content, "Should use localeCompare for name sorting"
    print("✓ Test 75: Sort logic handles all options")

def test_backend_provides_should_check_today():
    """Test 76: Backend API enriches habits with should_check_today field"""
    api_path = Path(__file__).parent.parent / 'api.py'
    content = api_path.read_text()
    
    # Check that should_check_today is added in handle_habits_get
    assert "should_check_today" in content, "Backend should add should_check_today field"
    assert "habits_helpers.should_check_today" in content, "Should use should_check_today helper"
    print("✓ Test 76: Backend provides should_check_today field")

def test_typecheck_us012():
    """Test 77: Typecheck passes for api.py"""
    api_path = Path(__file__).parent.parent / 'api.py'
    result = os.system(f'python3 -m py_compile {api_path} 2>/dev/null')
    assert result == 0, "api.py should pass typecheck (syntax check)"
    print("✓ Test 77: Typecheck passes")

# ============================================================================
# US-013: Frontend - Stats section and weekly summary
# ============================================================================

def test_stats_section_exists():
    """Test 78: Stats section exists with 4 metric cards"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'id="statsSection"' in content, "Should have statsSection element"
    assert 'class="stats-row"' in content, "Should have stats-row container"
    assert 'class="stat-card"' in content, "Should have stat-card elements"
    
    # Check for the 4 metrics
    assert 'id="statTotalHabits"' in content, "Should have Total Habits metric"
    assert 'id="statAvgCompletion"' in content, "Should have Avg Completion metric"
    assert 'id="statBestStreak"' in content, "Should have Best Streak metric"
    assert 'id="statTotalLives"' in content, "Should have Total Lives metric"
    
    print("✓ Test 78: Stats section with 4 metric cards exists")

def test_stats_labels_correct():
    """Test 79: Stat cards have correct labels"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'Total Habits' in content, "Should have 'Total Habits' label"
    assert 'Avg Completion (30d)' in content or 'Avg Completion' in content, \
        "Should have 'Avg Completion' label"
    assert 'Best Streak' in content, "Should have 'Best Streak' label"
    assert 'Total Lives' in content, "Should have 'Total Lives' label"
    
    print("✓ Test 79: Stat cards have correct labels")

def test_weekly_summary_exists():
    """Test 80: Weekly summary section exists and is collapsible"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'class="weekly-summary"' in content, "Should have weekly-summary section"
    assert 'class="weekly-summary-header"' in content, "Should have clickable header"
    assert 'Weekly Summary' in content, "Should have 'Weekly Summary' title"
    assert 'toggleWeeklySummary()' in content, "Should have toggle function"
    assert 'id="weeklySummaryContent"' in content, "Should have collapsible content container"
    assert 'id="weeklySummaryChevron"' in content, "Should have chevron icon"
    
    print("✓ Test 80: Weekly summary section exists and is collapsible")

def test_weekly_chart_structure():
    """Test 81: Weekly chart displays bars for Mon-Sun"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'id="weeklyChart"' in content, "Should have weeklyChart container"
    assert 'class="weekly-chart"' in content, "Should have weekly-chart class"
    
    # Check for bar rendering in JS
    assert 'weekly-bar' in content, "Should render weekly bars in CSS/JS"
    assert 'weekly-day-label' in content, "Should have day labels"
    
    print("✓ Test 81: Weekly chart structure exists")

def test_weekly_stats_text():
    """Test 82: Weekly stats show completed and skipped counts"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'id="weeklyCompletedText"' in content, "Should have completed count element"
    assert 'id="weeklySkippedText"' in content, "Should have skipped count element"
    assert 'completed this week' in content, "Should have 'completed this week' text"
    assert 'skipped this week' in content, "Should have 'skipped this week' text"
    
    print("✓ Test 82: Weekly stats text elements exist")

def test_stats_functions_exist():
    """Test 83: renderStats and renderWeeklySummary functions exist"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert 'function renderStats()' in content, "Should have renderStats function"
    assert 'function renderWeeklySummary()' in content, "Should have renderWeeklySummary function"
    assert 'function toggleWeeklySummary()' in content, "Should have toggleWeeklySummary function"
    
    print("✓ Test 83: Stats rendering functions exist")

def test_stats_calculations():
    """Test 84: Stats calculations use client-side logic"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for total habits calculation
    assert 'totalHabits' in content, "Should calculate total habits"
    
    # Check for avg completion calculation
    assert 'avgCompletion' in content or 'completion_rate_30d' in content, \
        "Should calculate average completion rate"
    
    # Check for best streak calculation
    assert 'bestStreak' in content or 'Math.max' in content, \
        "Should calculate best streak across all habits"
    
    # Check for total lives calculation
    assert 'totalLives' in content or '.lives' in content, \
        "Should calculate total lives"
    
    print("✓ Test 84: Stats calculations implemented")

def test_weekly_chart_bars_proportional():
    """Test 85: Weekly chart bars are proportional to completion count"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that bars use height proportional to count
    assert 'height' in content and ('style' in content or 'height:' in content), \
        "Should set bar height dynamically"
    assert 'maxCompletions' in content or 'Math.max' in content, \
        "Should calculate max for scaling"
    
    print("✓ Test 85: Weekly chart bars are proportional")

def test_stats_called_from_render():
    """Test 86: renderStats is called when renderHabits is called"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Find renderHabits function
    render_habits_start = content.find('function renderHabits()')
    assert render_habits_start > 0, "renderHabits function should exist"
    
    # Check that renderStats is called within renderHabits
    render_habits_section = content[render_habits_start:render_habits_start + 2000]
    assert 'renderStats()' in render_habits_section, \
        "renderStats() should be called from renderHabits()"
    
    print("✓ Test 86: renderStats called from renderHabits")

def test_stats_css_styling():
    """Test 87: Stats section has proper CSS styling"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    assert '.stats-section' in content, "Should have stats-section CSS"
    assert '.stats-row' in content, "Should have stats-row CSS"
    assert '.stat-card' in content, "Should have stat-card CSS"
    assert '.weekly-summary' in content, "Should have weekly-summary CSS"
    assert '.weekly-chart' in content, "Should have weekly-chart CSS"
    assert '.weekly-bar' in content, "Should have weekly-bar CSS"
    
    print("✓ Test 87: Stats CSS styling exists")

def test_stats_no_console_errors():
    """Test 88: No obvious console error sources in stats code"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check that functions are properly defined
    assert 'function renderStats()' in content, "renderStats should be defined"
    assert 'function renderWeeklySummary()' in content, "renderWeeklySummary should be defined"
    assert 'function toggleWeeklySummary()' in content, "toggleWeeklySummary should be defined"
    
    # Check DOM element IDs are referenced correctly
    assert "getElementById('statsSection')" in content or \
           'getElementById("statsSection")' in content, \
           "Should reference statsSection element"
    assert "getElementById('statTotalHabits')" in content or \
           'getElementById("statTotalHabits")' in content, \
           "Should reference statTotalHabits element"
    
    print("✓ Test 88: No obvious console error sources")

def test_typecheck_us013():
    """Test 89: Typecheck passes for api.py"""
    api_path = Path(__file__).parent.parent / 'api.py'
    result = os.system(f'python3 -m py_compile {api_path} 2>/dev/null')
    assert result == 0, "api.py should pass typecheck (syntax check)"
    print("✓ Test 89: Typecheck passes")

def test_mobile_grid_responsive():
    """Test 90: Grid shows 1 column on screens below 768px"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for mobile breakpoint
    assert '@media (max-width: 768px)' in content, "Should have mobile breakpoint"
    assert 'grid-template-columns: 1fr' in content, "Should use 1 column on mobile"
    print("✓ Test 90: Grid is responsive for mobile (1 column)")

def test_tablet_grid_responsive():
    """Test 91: Grid shows 2 columns between 768px and 1200px"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for tablet breakpoint
    assert '@media (min-width: 769px) and (max-width: 1200px)' in content, "Should have tablet breakpoint"
    assert 'repeat(2, 1fr)' in content, "Should use 2 columns on tablet"
    print("✓ Test 91: Grid shows 2 columns on tablet screens")

def test_touch_targets_44px():
    """Test 92: All buttons and interactive elements have minimum 44px touch target"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for minimum touch target sizes in mobile styles
    assert 'min-width: 44px' in content, "Should have min-width 44px for touch targets"
    assert 'min-height: 44px' in content, "Should have min-height 44px for touch targets"
    # Compact check button uses 44px on mobile (not 48px)
    assert 'habit-card-check-btn-compact' in content, "Compact check button should exist"
    print("✓ Test 92: Touch targets meet 44px minimum on mobile")

def test_modals_scrollable_mobile():
    """Test 93: Modals are scrollable with max-height 90vh on small screens"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check modal has max-height and overflow
    assert 'max-height: 90vh' in content, "Modal should have max-height 90vh"
    assert 'overflow-y: auto' in content, "Modal should have overflow-y auto for scrolling"
    print("✓ Test 93: Modals are scrollable on small screens")

def test_pickers_wrap_mobile():
    """Test 94: Icon and color pickers wrap properly on mobile"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for mobile grid adjustments in @media query
    mobile_section = content[content.find('@media (max-width: 768px)'):content.find('@media (max-width: 768px)') + 3000]
    
    assert 'grid-template-columns: repeat(4, 1fr)' in mobile_section, "Pickers should use 4 columns on mobile"
    print("✓ Test 94: Icon and color pickers wrap properly on mobile")

def test_filter_bar_stacks_mobile():
    """Test 95: Filter options stack vertically on mobile"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for filter options mobile styles
    mobile_section = content[content.find('@media (max-width: 768px)'):content.find('@media (max-width: 768px)') + 3000]
    
    assert '.filter-options' in mobile_section or '.filter-group' in mobile_section, \
        "Should have filter options mobile styles"
    assert 'flex-direction: column' in mobile_section, "Filter options should stack vertically"
    print("✓ Test 95: Filter options stack vertically on mobile")

def test_stats_2x2_mobile():
    """Test 96: Stats row shows 2x2 grid on mobile"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for stats row mobile layout
    mobile_section = content[content.find('@media (max-width: 768px)'):content.find('@media (max-width: 768px)') + 3000]
    
    assert '.stats-row' in mobile_section, "Should have stats-row mobile styles"
    assert 'grid-template-columns: repeat(2, 1fr)' in mobile_section, "Stats should use 2x2 grid on mobile"
    print("✓ Test 96: Stats row shows 2x2 grid on mobile")

def test_swipe_nav_integration():
    """Test 97: swipe-nav.js is integrated for page navigation"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check swipe-nav.js is included
    assert 'src="/echo/swipe-nav.js"' in content, "Should include swipe-nav.js"
    
    # Check swipe-nav.js has habits.html in pages array
    swipe_nav_path = Path(__file__).parent.parent / 'swipe-nav.js'
    if swipe_nav_path.exists():
        swipe_content = swipe_nav_path.read_text()
        assert 'habits.html' in swipe_content, "swipe-nav.js should include habits.html in pages array"
    
    print("✓ Test 97: swipe-nav.js is integrated")

def test_mobile_form_inputs():
    """Test 98: Form inputs are touch-friendly on mobile"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for form input mobile styles
    mobile_section = content[content.find('@media (max-width: 768px)'):content.find('@media (max-width: 768px)') + 3000]
    
    assert '.form-input' in mobile_section or 'min-height: 44px' in mobile_section, "Form inputs should have mobile styles"
    print("✓ Test 98: Form inputs are touch-friendly on mobile")

def test_mobile_no_console_errors():
    """Test 99: No obvious console error sources in mobile-specific code"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Basic sanity checks
    assert '<style>' in content, "Should have style tags"
    assert '@media' in content, "Should have media queries"
    assert '</style>' in content, "Style tags should be closed"
    print("✓ Test 99: No obvious console error sources")

def test_typecheck_us014():
    """Test 100: Typecheck passes after US-014 changes"""
    api_path = Path(__file__).parent.parent / 'api.py'
    result = os.system(f'python3 -m py_compile {api_path}')
    assert result == 0, "api.py should pass typecheck"
    print("✓ Test 100: Typecheck passes")

def test_mobile_day_checkboxes_wrap():
    """Test 101: Day checkboxes wrap properly on mobile"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for day checkboxes mobile styles
    mobile_section = content[content.find('@media (max-width: 768px)'):content.find('@media (max-width: 768px)') + 3000]
    
    assert '.day-checkboxes' in mobile_section, "Should have day-checkboxes mobile styles"
    print("✓ Test 101: Day checkboxes wrap properly on mobile")

def run_all_tests():
    """Run all tests in sequence"""
    tests = [
        # US-006 tests
        test_habits_html_exists,
        test_habits_html_structure,
        test_page_has_header,
        test_empty_state,
        test_grid_container,
        test_index_navigation_link,
        test_page_fetches_habits,
        test_habit_card_rendering,
        test_no_console_errors_structure,
        test_typecheck,
        # US-007 tests
        test_card_colored_border,
        test_card_header_icons,
        test_card_streak_display,
        test_card_checkin_button,
        test_card_checkin_disabled_when_done,
        test_card_lives_display,
        test_card_completion_rate,
        test_card_footer_category_priority,
        test_card_lucide_createicons,
        test_card_common_css_variables,
        test_typecheck_us007,
        # US-008 tests
        test_modal_opens_on_add_habit_click,
        test_modal_closes_on_x_and_outside_click,
        test_modal_has_all_form_fields,
        test_color_picker_presets_and_custom,
        test_icon_picker_grid,
        test_frequency_params_conditional,
        test_client_side_validation,
        test_submit_posts_to_api,
        test_loading_state_on_submit,
        test_toast_notifications,
        test_modal_no_console_errors,
        test_typecheck_us008,
        # US-009 tests
        test_edit_modal_opens_on_gear_icon,
        test_edit_modal_prepopulated,
        test_edit_modal_title_and_button,
        test_edit_modal_frequency_params,
        test_edit_modal_icon_color_pickers,
        test_edit_modal_submit_put,
        test_edit_modal_toast_messages,
        test_edit_modal_add_resets_state,
        test_edit_modal_close_resets_state,
        test_edit_modal_no_console_errors,
        test_typecheck_us009,
        # US-010 tests
        test_checkin_simple_click,
        test_checkin_detail_modal_structure,
        test_checkin_long_press_handler,
        test_checkin_detail_modal_functions,
        test_checkin_detail_submit,
        test_checkin_toast_with_streak,
        test_checkin_button_disabled_after,
        test_checkin_pulse_animation,
        test_checkin_prevent_context_menu,
        test_checkin_event_listeners_attached,
        test_typecheck_us010,
        # US-011 tests
        test_skip_button_visible,
        test_skip_confirmation_dialog,
        test_skip_sends_post_and_refreshes,
        test_skip_button_disabled_when_no_lives,
        test_skip_toast_message,
        test_delete_confirmation_with_habit_name,
        test_delete_sends_delete_request,
        test_delete_toast_message,
        test_skip_delete_no_console_errors,
        test_typecheck_us011,
        # US-012 tests
        test_filter_bar_exists,
        test_category_filter_options,
        test_status_filter_options,
        test_sort_dropdown_options,
        test_filter_functions_exist,
        test_filter_calls_on_change,
        test_localstorage_persistence,
        test_localstorage_restore,
        test_filter_logic_implementation,
        test_sort_logic_implementation,
        test_backend_provides_should_check_today,
        test_typecheck_us012,
        # US-013 tests
        test_stats_section_exists,
        test_stats_labels_correct,
        test_weekly_summary_exists,
        test_weekly_chart_structure,
        test_weekly_stats_text,
        test_stats_functions_exist,
        test_stats_calculations,
        test_weekly_chart_bars_proportional,
        test_stats_called_from_render,
        test_stats_css_styling,
        test_stats_no_console_errors,
        test_typecheck_us013,
        # US-014 tests
        test_mobile_grid_responsive,
        test_tablet_grid_responsive,
        test_touch_targets_44px,
        test_modals_scrollable_mobile,
        test_pickers_wrap_mobile,
        test_filter_bar_stacks_mobile,
        test_stats_2x2_mobile,
        test_swipe_nav_integration,
        test_mobile_form_inputs,
        test_mobile_no_console_errors,
        test_typecheck_us014,
        test_mobile_day_checkboxes_wrap,
        # US-002 tests (Compact cards)
        test_compact_card_structure,
        test_compact_card_visible_elements,
        test_compact_card_hidden_elements,
        test_progress_percentage_rounded,
        test_compact_card_height_css,
        test_compact_button_circle_style,
        test_next_check_date_function,
        test_compact_card_mobile_friendly,
        test_progress_bar_styling,
        test_compact_card_color_accent,
        test_compact_viewport_320px,
        test_typecheck_us002,
        # US-003 tests (Check/uncheck toggle)
        test_check_button_not_disabled_when_checked,
        test_check_button_clickable_title,
        test_check_button_checked_css,
        test_checkin_habit_toggle_logic,
        test_checkin_optimistic_ui_update,
        test_checkin_error_reversion,
        test_streak_updates_after_toggle,
        test_event_listeners_on_all_buttons,
        test_toast_messages_for_toggle,
        test_delete_request_format,
        test_typecheck_us003,
        # US-004 tests (Search/filter collapse)
        test_filter_toolbar_icons,
        test_search_container_collapsible,
        test_filter_container_collapsible,
        test_toggle_functions_exist,
        test_toggle_logic,
        test_css_animations,
        test_esc_key_listener,
        test_click_outside_listener,
        test_search_function_exists,
        test_search_input_listener,
        test_render_habits_uses_search,
        test_event_listeners_initialized,
        test_typecheck_us004,
        # US-005 tests (Stats section collapse)
        test_stats_section_collapsed_by_default,
        test_stats_header_clickable_with_chevron,
        test_toggle_function_exists,
        test_chevron_rotates_on_expand,
        test_content_displays_when_visible,
        test_localstorage_save_on_toggle,
        test_restore_function_exists,
        test_restore_expands_when_false,
        test_restore_collapses_by_default,
        test_restore_called_on_page_load,
        test_css_transition_300ms,
        test_height_constraint_collapsed,
        test_typecheck_us005,
        # US-006 tests
        test_icon_picker_is_dropdown,
        test_icon_picker_has_search_input,
        test_icon_picker_max_height_300px,
        test_icon_picker_toggle_functions,
        test_icon_picker_visible_class_toggle,
        test_icon_picker_filter_function,
        test_icon_picker_closes_on_selection,
        test_icon_picker_click_outside_closes,
        test_icon_picker_updates_trigger_display,
        test_icon_picker_css_dropdown_styles,
        test_icon_picker_chevron_rotation,
        test_icon_picker_search_autofocus,
        test_typecheck_us006,
        # US-007 tests (Modal backdrop and touch optimization)
        test_modal_backdrop_opacity,
        test_filter_icon_buttons_44px,
        test_compact_check_button_44px,
        test_action_buttons_44px,
        test_modal_close_button_44px,
        test_all_interactive_elements_touch_friendly,
        test_typecheck_us007,
    ]
    
    print(f"\nRunning {len(tests)} frontend tests for US-002, US-003, US-004, US-005, US-006 through US-014...\n")
    
    failed = []
    for test in tests:
        try:
            test()
        except AssertionError as e:
            print(f"✗ {test.__name__}: {e}")
            failed.append((test.__name__, str(e)))
        except Exception as e:
            print(f"✗ {test.__name__}: Unexpected error: {e}")
            failed.append((test.__name__, str(e)))
    
    print(f"\n{'='*60}")
    if failed:
        print(f"FAILED: {len(failed)} test(s) failed:")
        for name, error in failed:
            print(f"  - {name}: {error}")
        sys.exit(1)
    else:
        print(f"SUCCESS: All {len(tests)} tests passed!")
        sys.exit(0)

# ==================== US-002 Tests ====================
# Frontend: Compact habit cards (~100px height)

def test_compact_card_structure():
    """Test 102: Compact card has correct HTML structure"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    # Check for compact card structure with single row
    assert 'class="habit-card-row"' in html, "Card should have habit-card-row for compact layout"
    assert 'class="habit-card-progress-row"' in html, "Card should have progress-row"
    assert 'class="habit-card-next-date"' in html, "Card should have next-date row"
    print("✓ Test 102: Compact card structure exists")

def test_compact_card_visible_elements():
    """Test 103: Card displays only essential visible elements"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    # Visible elements
    assert 'habit-card-icon' in html, "Icon should be visible"
    assert 'habit-card-name' in html, "Name should be visible"
    assert 'habit-card-streak' in html, "Streak should be visible"
    assert 'habit-card-check-btn-compact' in html, "Check button should be visible"
    assert 'habit-card-progress' in html, "Progress bar should be visible"
    assert 'habit-card-next-date' in html, "Next date should be visible"
    print("✓ Test 103: Card displays essential visible elements")

def test_compact_card_hidden_elements():
    """Test 104: Card hides non-essential elements"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    # These should NOT be present in compact design
    assert 'habit-card-lives' not in html, "Lives should be hidden in compact view"
    assert 'habit-card-skip-btn' not in html, "Skip button should be hidden in compact view"
    assert 'habit-card-footer' not in html, "Footer should be hidden in compact view"
    assert 'habit-card-category' not in html, "Category should be hidden in compact view"
    assert 'habit-card-priority' not in html, "Priority should be hidden in compact view"
    assert 'habit-card-last-check' not in html, "Last check info should be hidden in compact view"
    print("✓ Test 104: Card hides non-essential elements")

def test_progress_percentage_rounded():
    """Test 105: Progress percentage is rounded to integer"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    # Check for Math.round in renderHabitCard
    assert 'Math.round(habit.completion_rate_30d' in html, "Progress should use Math.round()"
    # Check there's no decimal formatting like .toFixed()
    assert 'completion_rate_30d || 0).toFixed' not in html, "Should not use toFixed for progress"
    print("✓ Test 105: Progress percentage uses Math.round()")

def test_compact_card_height_css():
    """Test 106: Card has compact height constraints in CSS"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    # Check for height constraints
    assert 'min-height: 90px' in html or 'min-height:90px' in html, "Card should have min-height ~90-100px"
    assert 'max-height: 110px' in html or 'max-height: 120px' in html, "Card should have max-height constraint"
    print("✓ Test 106: Card has compact height CSS constraints")

def test_compact_button_circle_style():
    """Test 107: Check button is compact circular style"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    assert 'habit-card-check-btn-compact' in html, "Should have compact check button class"
    # Check for circular styling
    assert 'border-radius: 50%' in html or 'border-radius:50%' in html, "Compact button should be circular"
    # Check for compact dimensions
    assert any('32px' in html for _ in range(2)), "Compact button should be ~32px"
    print("✓ Test 107: Check button is compact circular style")

def test_next_check_date_function():
    """Test 108: getNextCheckDate function exists and is used"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    assert 'function getNextCheckDate' in html, "getNextCheckDate function should exist"
    assert 'getNextCheckDate(habit)' in html, "getNextCheckDate should be called in renderHabitCard"
    # Check for expected output strings
    assert "'Next: Tomorrow'" in html or '"Next: Tomorrow"' in html, "Should show 'Next: Tomorrow'"
    assert "'Due: Today'" in html or '"Due: Today"' in html, "Should show 'Due: Today'"
    assert "'Next: Upcoming'" in html or '"Next: Upcoming"' in html, "Should show 'Next: Upcoming'"
    print("✓ Test 108: getNextCheckDate function exists and is used")

def test_compact_card_mobile_friendly():
    """Test 109: Compact cards remain compact on mobile"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    # Check mobile media query maintains compact size
    mobile_section = html[html.find('@media (max-width: 768px)'):html.find('@media (max-width: 768px)') + 2000] if '@media (max-width: 768px)' in html else ''
    assert 'habit-card-check-btn-compact' in mobile_section, "Mobile styles should include compact button"
    assert 'min-height: 44px' in mobile_section, "Mobile touch targets should be 44px"
    print("✓ Test 109: Compact cards are mobile-friendly")

def test_progress_bar_styling():
    """Test 110: Progress bar has proper styling"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    assert 'habit-card-progress-bar' in html, "Progress bar container should exist"
    assert 'habit-card-progress-fill' in html, "Progress fill element should exist"
    assert 'habit-card-progress-text' in html, "Progress text should exist"
    # Check for dynamic width styling
    assert 'width: ${completionRate}%' in html, "Progress fill should have dynamic width"
    print("✓ Test 110: Progress bar styling exists")

def test_compact_card_color_accent():
    """Test 111: Card uses habit color for border and progress"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    # Check border-left-color uses habit.color
    assert 'border-left-color: ${habit.color}' in html, "Card should use habit color for left border"
    # Check progress bar uses habit.color
    assert 'background-color: ${habit.color}' in html, "Progress bar should use habit color"
    print("✓ Test 111: Card uses habit color for accents")

def test_compact_viewport_320px():
    """Test 112: Cards render correctly at 320px viewport"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    # Check for text-overflow ellipsis for long names
    assert 'text-overflow: ellipsis' in html, "Long names should use ellipsis"
    assert 'white-space: nowrap' in html, "Card name should not wrap"
    # Check for flex-shrink on action elements
    assert 'flex-shrink: 0' in html, "Action buttons should not shrink"
    print("✓ Test 112: Cards handle 320px viewport width")

def test_typecheck_us002():
    """Test 113: Typecheck passes for US-002 changes"""
    repo_root = Path(__file__).parent.parent.parent
    result = subprocess.run(
        ['python3', '-m', 'py_compile', 'dashboard/api.py'],
        cwd=repo_root,
        capture_output=True,
        text=True
    )
    assert result.returncode == 0, f"Typecheck failed: {result.stderr}"
    print("✓ Test 113: Typecheck passes")

# ===== US-003: Frontend check/uncheck toggle behavior =====

def test_check_button_not_disabled_when_checked():
    """Test 114: Check button is not disabled when habit is checked today"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    # Check that button does not use disabled attribute anymore
    assert 'isDoneToday ? \'disabled\' : \'\'' not in html, "Button should not use disabled attribute"
    # Check that button uses 'checked' class instead
    assert 'isDoneToday ? \'checked\' : \'\'' in html, "Button should use 'checked' class"
    print("✓ Test 114: Check button is not disabled when checked")

def test_check_button_clickable_title():
    """Test 115: Check button has clickable title for both states"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    # Check titles indicate toggle behavior
    assert 'Click to uncheck' in html, "Checked button should say 'Click to uncheck'"
    assert 'Check in' in html, "Unchecked button should say 'Check in'"
    print("✓ Test 115: Button titles indicate toggle behavior")

def test_check_button_checked_css():
    """Test 116: Check button has CSS for checked state (not disabled)"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    # Check for .checked class styling (not :disabled)
    assert '.habit-card-check-btn-compact.checked' in html, "Should have .checked class styling"
    assert 'checked:hover' in html.lower(), "Checked button should have hover state"
    # Check that old :disabled styling is replaced
    disabled_count = html.count('.habit-card-check-btn-compact:disabled')
    assert disabled_count == 0, "Should not have :disabled styling for check button"
    print("✓ Test 116: Check button uses .checked class, not :disabled")

def test_checkin_habit_toggle_logic():
    """Test 117: checkInHabit function implements toggle logic"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    # Check that function finds habit and checks current state
    assert 'const isChecked = isCheckedToday(habit)' in js, "Should check if habit is already checked"
    # Check that it sends DELETE for unchecking
    assert "method: 'DELETE'" in js, "Should send DELETE request for uncheck"
    # Check conditional URL for DELETE
    assert '/check?date=' in js, "DELETE should include date parameter"
    print("✓ Test 117: checkInHabit implements toggle logic")

def test_checkin_optimistic_ui_update():
    """Test 118: Toggle updates UI optimistically before API call"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    # Check for optimistic UI update
    assert 'btn.innerHTML = \'○\'' in js, "Should update button to unchecked optimistically"
    assert 'btn.innerHTML = \'✓\'' in js, "Should update button to checked optimistically"
    # Check for state storage for rollback
    assert 'originalButtonText' in js, "Should store original button text"
    assert 'originalButtonDisabled' in js, "Should store original button state"
    print("✓ Test 118: Toggle uses optimistic UI updates")

def test_checkin_error_reversion():
    """Test 119: Toggle reverts UI on error"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    # Check for error handling and reversion
    assert 'btn.innerHTML = originalButtonText' in js, "Should revert button text on error"
    assert 'btn.disabled = originalButtonDisabled' in js, "Should revert button state on error"
    assert 'originalStreakText' in js, "Should store original streak for reversion"
    print("✓ Test 119: Toggle reverts UI on error")

def test_streak_updates_after_toggle():
    """Test 120: Streak display updates after check/uncheck"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    # Check for streak update
    assert 'streakElement.textContent' in js, "Should update streak element"
    assert 'updatedHabit.streak?.current' in js, "Should use updated streak from response"
    print("✓ Test 120: Streak updates after toggle")

def test_event_listeners_on_all_buttons():
    """Test 121: Event listeners attached to all check buttons (checked and unchecked)"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    # Check that forEach no longer filters by isCheckedToday
    assert 'habits.forEach(habit =>' in js, "Should iterate all habits"
    # Check that checked buttons get simple click listener
    assert "btn.addEventListener('click'," in js, "Checked buttons should have click listener"
    print("✓ Test 121: Event listeners on all check buttons")

def test_toast_messages_for_toggle():
    """Test 122: Different toast messages for check vs uncheck"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    # Check for conditional toast messages
    assert 'Check-in removed' in js or 'removed' in js.lower(), "Should have uncheck message"
    assert 'Habit checked!' in js, "Should have check message"
    print("✓ Test 122: Toast messages distinguish check from uncheck")

def test_delete_request_format():
    """Test 123: DELETE request includes date parameter in query string"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    # Check that DELETE URL includes date query param
    assert '/check?date=${today}' in js, "DELETE should include ?date=YYYY-MM-DD parameter"
    # Check today is formatted as ISO date
    assert "toISOString().split('T')[0]" in js, "Should format today as YYYY-MM-DD"
    print("✓ Test 123: DELETE request has proper date parameter")

def test_typecheck_us003():
    """Test 124: Typecheck passes for US-003 changes"""
    repo_root = Path(__file__).parent.parent.parent
    result = subprocess.run(
        ['python3', '-m', 'py_compile', 'dashboard/api.py'],
        cwd=repo_root,
        capture_output=True,
        text=True
    )
    assert result.returncode == 0, f"Typecheck failed: {result.stderr}"
    print("✓ Test 124: Typecheck passes")

# ========================================
# US-004: Frontend - Search and filter collapse to icons
# ========================================

def test_filter_toolbar_icons():
    """Test 125: Filter bar shows icon toolbar on page load (~40px height)"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for toolbar structure
    assert 'filter-toolbar' in content, "Should have filter-toolbar element"
    assert 'id="searchToggle"' in content, "Should have search toggle button"
    assert 'id="filterToggle"' in content, "Should have filter toggle button"
    assert 'data-lucide="search"' in content, "Should have search icon"
    assert 'data-lucide="sliders"' in content or 'data-lucide="filter"' in content, \
        "Should have filter/sliders icon"
    
    # Check toolbar height
    assert 'min-height: 40px' in content or 'min-height:40px' in content, \
        "Toolbar should be ~40px height"
    
    print("✓ Test 125: Filter toolbar with icons exists")

def test_search_container_collapsible():
    """Test 126: Search container is collapsible with expanded class"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for search container structure
    assert 'search-container' in content, "Should have search-container element"
    assert 'id="searchContainer"' in content, "Search container should have id"
    assert 'id="searchInput"' in content, "Should have search input"
    
    # Check CSS for collapse/expand states
    assert 'max-height: 0' in content, "Collapsed state should have max-height: 0"
    assert '.search-container.expanded' in content or '.expanded' in content, \
        "Should have expanded state CSS"
    
    print("✓ Test 126: Search container is collapsible")

def test_filter_container_collapsible():
    """Test 127: Filter container is collapsible with expanded class"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    content = habits_path.read_text()
    
    # Check for filter container structure
    assert 'filter-container' in content, "Should have filter-container element"
    assert 'id="filterContainer"' in content, "Filter container should have id"
    assert 'filter-options' in content, "Should have filter-options wrapper"
    
    # Check that filter options are inside container
    filter_start = content.find('id="filterContainer"')
    category_pos = content.find('id="categoryFilter"')
    status_pos = content.find('id="statusFilter"')
    sort_pos = content.find('id="sortSelect"')
    
    assert filter_start < category_pos, "Category filter should be inside filter container"
    assert filter_start < status_pos, "Status filter should be inside filter container"
    assert filter_start < sort_pos, "Sort select should be inside filter container"
    
    print("✓ Test 127: Filter container is collapsible")

def test_toggle_functions_exist():
    """Test 128: toggleSearch, toggleFilters, and collapseAll functions defined"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    
    assert 'function toggleSearch()' in js, "Should have toggleSearch function"
    assert 'function toggleFilters()' in js, "Should have toggleFilters function"
    assert 'function collapseAll()' in js, "Should have collapseAll function"
    
    print("✓ Test 128: Toggle functions are defined")

def test_toggle_logic():
    """Test 129: Toggle functions add/remove 'expanded' class"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    
    # Extract toggleSearch function
    toggle_start = js.find('function toggleSearch()')
    toggle_end = js.find('function toggleFilters()', toggle_start)
    toggle_search_code = js[toggle_start:toggle_end]
    
    assert "classList.contains('expanded')" in toggle_search_code, \
        "Should check for expanded state"
    assert "classList.add('expanded')" in toggle_search_code, \
        "Should add expanded class"
    assert "classList.remove('expanded')" in toggle_search_code, \
        "Should remove expanded class"
    assert "classList.add('active')" in toggle_search_code, \
        "Should add active class to button"
    
    print("✓ Test 129: Toggle functions implement expand/collapse logic")

def test_css_animations():
    """Test 130: CSS includes transition animations (300ms ease)"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    css = habits_path.read_text()
    
    # Check for transition properties
    assert 'transition:' in css or 'transition :' in css, "Should have CSS transitions"
    assert '300ms' in css, "Should have 300ms transition duration"
    assert 'ease' in css, "Should use ease timing function"
    
    # Check for max-height transition specifically
    assert 'max-height' in css, "Should animate max-height"
    
    print("✓ Test 130: CSS animations defined (300ms ease)")

def test_esc_key_listener():
    """Test 131: ESC key collapses expanded search/filter"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    
    assert "addEventListener('keydown'" in js, "Should have keydown event listener"
    assert "e.key === 'Escape'" in js or 'e.key === "Escape"' in js, \
        "Should check for Escape key"
    assert 'collapseAll()' in js, "Should call collapseAll on ESC"
    
    print("✓ Test 131: ESC key listener implemented")

def test_click_outside_listener():
    """Test 132: Clicking outside collapses expanded search/filter"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    
    # Find click outside logic
    assert "addEventListener('click'" in js, "Should have click event listener"
    assert '.filter-bar' in js, "Should reference filter-bar element"
    assert 'contains(e.target)' in js, "Should check if click is outside"
    
    # Check that it calls collapseAll when clicked outside
    # Look for the pattern in the entire file since it might be structured across lines
    click_listeners = []
    pos = 0
    while True:
        pos = js.find("addEventListener('click'", pos)
        if pos == -1:
            break
        click_listeners.append(js[pos:pos + 800])
        pos += 1
    
    # Check if any click listener has the collapse logic
    has_collapse = any('collapseAll' in listener for listener in click_listeners)
    assert has_collapse, "Should call collapseAll when clicking outside"
    
    print("✓ Test 132: Click outside listener implemented")

def test_search_function_exists():
    """Test 133: searchHabits function filters by name"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    
    assert 'function searchHabits(' in js, "Should have searchHabits function"
    
    # Check search logic
    search_start = js.find('function searchHabits(')
    search_end = js.find('function ', search_start + 20)
    search_code = js[search_start:search_end]
    
    assert 'toLowerCase()' in search_code, "Should use case-insensitive search"
    assert 'includes(' in search_code, "Should use includes for matching"
    assert 'habit.name' in search_code, "Should search by habit name"
    
    print("✓ Test 133: searchHabits function filters by name")

def test_search_input_listener():
    """Test 134: Search input triggers renderHabits on input event"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    
    # Check for search input event listener
    assert "getElementById('searchInput')" in js or 'getElementById("searchInput")' in js, \
        "Should get searchInput element"
    assert "addEventListener('input'" in js, "Should listen to input events"
    assert 'renderHabits()' in js, "Should call renderHabits when searching"
    
    print("✓ Test 134: Search input listener triggers renderHabits")

def test_render_habits_uses_search():
    """Test 135: renderHabits applies searchHabits before filters"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    
    # Find renderHabits function
    render_start = js.find('function renderHabits()')
    render_section = js[render_start:render_start + 2000]
    
    assert 'searchHabits(' in render_section, "Should call searchHabits"
    assert 'filterHabits(' in render_section, "Should call filterHabits"
    
    # Check that search happens before filter
    search_pos = render_section.find('searchHabits(')
    filter_pos = render_section.find('filterHabits(')
    assert search_pos < filter_pos, "Search should happen before filtering"
    
    print("✓ Test 135: renderHabits applies search before filters")

def test_event_listeners_initialized():
    """Test 136: Toggle button event listeners attached on page load"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    js = habits_path.read_text()
    
    # Find initialization section (near end of script)
    init_section = js[-2000:]  # Last 2000 chars
    
    assert "getElementById('searchToggle')" in init_section or \
           'getElementById("searchToggle")' in init_section, \
           "Should attach listener to searchToggle"
    assert "getElementById('filterToggle')" in init_section or \
           'getElementById("filterToggle")' in init_section, \
           "Should attach listener to filterToggle"
    assert 'toggleSearch' in init_section, "Should attach toggleSearch handler"
    assert 'toggleFilters' in init_section, "Should attach toggleFilters handler"
    
    print("✓ Test 136: Event listeners initialized on page load")

def test_typecheck_us004():
    """Test 137: Typecheck passes for US-004 changes"""
    repo_root = Path(__file__).parent.parent.parent
    result = subprocess.run(
        ['python3', '-m', 'py_compile', 'dashboard/api.py', 'dashboard/habits_helpers.py'],
        cwd=repo_root,
        capture_output=True,
        text=True
    )
    assert result.returncode == 0, f"Typecheck failed: {result.stderr}"
    print("✓ Test 137: Typecheck passes")

# ========== US-005 Tests: Stats section collapse with chevron ==========

def test_stats_section_collapsed_by_default():
    """Test 138: Stats section (weekly summary) starts collapsed by default"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check that weekly-summary-content does NOT have 'visible' class by default in HTML
    assert '<div class="weekly-summary-content" id="weeklySummaryContent">' in content or \
           '<div class="weekly-summary-content"' in content, \
        "weekly-summary-content should not have 'visible' class in HTML"
    
    # Check CSS: content should be display:none when not visible
    assert '.weekly-summary-content {' in content, "Should have weekly-summary-content CSS"
    assert 'display: none' in content, "Content should be display:none by default"
    
    print("✓ Test 138: Stats section starts collapsed (display:none)")

def test_stats_header_clickable_with_chevron():
    """Test 139: Stats header is clickable and has chevron icon"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check header has onclick handler
    assert 'onclick="toggleWeeklySummary()"' in content, \
        "Header should have onclick='toggleWeeklySummary()'"
    
    # Check for chevron icon
    assert 'weekly-summary-chevron' in content, "Should have chevron element"
    assert 'data-lucide="chevron-down"' in content, "Should use Lucide chevron-down icon"
    
    # Check header is styled as clickable
    assert 'cursor: pointer' in content, "Header should have cursor:pointer"
    
    print("✓ Test 139: Stats header is clickable with chevron icon")

def test_toggle_function_exists():
    """Test 140: toggleWeeklySummary function exists and toggles visibility"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check function exists
    assert 'function toggleWeeklySummary()' in content, \
        "toggleWeeklySummary function should be defined"
    
    # Find function body
    func_start = content.find('function toggleWeeklySummary()')
    func_end = content.find('\n        }', func_start + 1000)
    func_body = content[func_start:func_end]
    
    # Check it toggles visibility class
    assert 'classList.contains(\'visible\')' in func_body, \
        "Should check if content has 'visible' class"
    assert 'classList.remove(\'visible\')' in func_body, \
        "Should remove 'visible' class when collapsing"
    assert 'classList.add(\'visible\')' in func_body, \
        "Should add 'visible' class when expanding"
    
    # Check it toggles chevron class
    assert 'classList.remove(\'expanded\')' in func_body, \
        "Should remove 'expanded' class from chevron when collapsing"
    assert 'classList.add(\'expanded\')' in func_body, \
        "Should add 'expanded' class to chevron when expanding"
    
    print("✓ Test 140: toggleWeeklySummary toggles visible and expanded classes")

def test_chevron_rotates_on_expand():
    """Test 141: Chevron rotates 180deg when expanded"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check for chevron rotation CSS
    assert '.weekly-summary-chevron.expanded' in content, \
        "Should have .expanded class styles for chevron"
    assert 'transform: rotate(180deg)' in content, \
        "Chevron should rotate 180deg when expanded"
    
    # Check for transition
    assert 'transition:' in content.lower(), "Chevron should have transition"
    
    print("✓ Test 141: Chevron rotates 180deg when expanded")

def test_content_displays_when_visible():
    """Test 142: Content displays (display:block) when visible class is added"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check for .visible class CSS
    assert '.weekly-summary-content.visible' in content, \
        "Should have CSS for .visible class"
    assert 'display: block' in content, \
        "Content should be display:block when visible"
    
    print("✓ Test 142: Content displays when visible class is added")

def test_localstorage_save_on_toggle():
    """Test 143: toggleWeeklySummary saves state to localStorage"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Find toggleWeeklySummary function
    func_start = content.find('function toggleWeeklySummary()')
    func_end = content.find('\n        }', func_start + 1500)
    func_body = content[func_start:func_end]
    
    # Check it saves to localStorage
    assert 'localStorage.setItem' in func_body, \
        "Should save state to localStorage"
    assert "'habits-stats-collapsed'" in func_body or '"habits-stats-collapsed"' in func_body, \
        "Should use 'habits-stats-collapsed' key"
    assert "'true'" in func_body or '"true"' in func_body, \
        "Should save 'true' for collapsed state"
    assert "'false'" in func_body or '"false"' in func_body, \
        "Should save 'false' for expanded state"
    
    print("✓ Test 143: toggleWeeklySummary saves state to localStorage")

def test_restore_function_exists():
    """Test 144: restoreWeeklySummaryState function exists and loads from localStorage"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check function exists
    assert 'function restoreWeeklySummaryState()' in content, \
        "restoreWeeklySummaryState function should be defined"
    
    # Find function body
    func_start = content.find('function restoreWeeklySummaryState()')
    func_end = content.find('\n        }', func_start + 1000)
    func_body = content[func_start:func_end]
    
    # Check it loads from localStorage
    assert 'localStorage.getItem' in func_body, \
        "Should load state from localStorage"
    assert "'habits-stats-collapsed'" in func_body or '"habits-stats-collapsed"' in func_body, \
        "Should use 'habits-stats-collapsed' key"
    
    print("✓ Test 144: restoreWeeklySummaryState loads from localStorage")

def test_restore_expands_when_false():
    """Test 145: restoreWeeklySummaryState expands when localStorage is 'false'"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Find restore function
    func_start = content.find('function restoreWeeklySummaryState()')
    func_end = content.find('\n        }', func_start + 1000)
    func_body = content[func_start:func_end]
    
    # Check it expands when isCollapsed === 'false'
    assert "isCollapsed === 'false'" in func_body or 'isCollapsed==="false"' in func_body or \
           "isCollapsed === \"false\"" in func_body, \
        "Should check if isCollapsed is 'false'"
    assert 'classList.add(\'visible\')' in func_body, \
        "Should add 'visible' class when expanding"
    assert 'classList.add(\'expanded\')' in func_body, \
        "Should add 'expanded' class to chevron when expanding"
    
    print("✓ Test 145: restoreWeeklySummaryState expands when localStorage is 'false'")

def test_restore_collapses_by_default():
    """Test 146: restoreWeeklySummaryState keeps collapsed when localStorage is null or 'true'"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Find restore function
    func_start = content.find('function restoreWeeklySummaryState()')
    func_end = content.find('\n        }', func_start + 1000)
    func_body = content[func_start:func_end]
    
    # Check it handles null/true cases (else branch or explicit check)
    assert 'else' in func_body, "Should have else branch for collapsed state"
    assert 'classList.remove(\'visible\')' in func_body, \
        "Should remove 'visible' class for collapsed state"
    assert 'classList.remove(\'expanded\')' in func_body, \
        "Should remove 'expanded' class from chevron for collapsed state"
    
    print("✓ Test 146: restoreWeeklySummaryState keeps collapsed by default")

def test_restore_called_on_page_load():
    """Test 147: restoreWeeklySummaryState is called on page load"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check that restore function is called in initialization section
    # It should be called before or near loadHabits()
    init_section = content[-3000:]  # Last 3000 chars
    
    assert 'restoreWeeklySummaryState()' in init_section, \
        "Should call restoreWeeklySummaryState() on page load"
    
    # Check it's called before loadHabits (or at least in the init section)
    restore_pos = init_section.find('restoreWeeklySummaryState()')
    load_pos = init_section.find('loadHabits()')
    assert restore_pos < load_pos, \
        "restoreWeeklySummaryState should be called before loadHabits"
    
    print("✓ Test 147: restoreWeeklySummaryState called on page load")

def test_css_transition_300ms():
    """Test 148: CSS uses 300ms ease transition for animations"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Find weekly-summary CSS sections
    chevron_css_start = content.find('.weekly-summary-chevron')
    chevron_css_end = content.find('}', chevron_css_start)
    chevron_css = content[chevron_css_start:chevron_css_end]
    
    # Check for transition
    assert 'transition:' in chevron_css.lower(), \
        "Chevron should have transition"
    
    # The transition should be in the base CSS (using var(--transition-base) or explicit)
    # var(--transition-base) is typically 300ms ease from common.css
    assert 'var(--transition-base)' in chevron_css or '0.3s' in chevron_css or '300ms' in chevron_css, \
        "Should use 300ms transition (or --transition-base variable)"
    
    print("✓ Test 148: CSS uses transition for smooth animation")

def test_height_constraint_collapsed():
    """Test 149: Collapsed state shows minimal height (~30px header only)"""
    html_path = Path(__file__).parent.parent / 'habits.html'
    content = html_path.read_text()
    
    # Check header padding/height
    header_css_start = content.find('.weekly-summary-header {')
    header_css_end = content.find('}', header_css_start)
    header_css = content[header_css_start:header_css_end]
    
    # Header should have padding to create ~30px height
    assert 'padding:' in header_css.lower(), "Header should have padding"
    
    # Content should be hidden (display:none) when not visible
    content_css_start = content.find('.weekly-summary-content {')
    content_css_end = content.find('}', content_css_start)
    content_css = content[content_css_start:content_css_end]
    
    assert 'display: none' in content_css or 'display:none' in content_css, \
        "Content should be display:none when collapsed"
    
    print("✓ Test 149: Collapsed state shows minimal height (header only)")

def test_typecheck_us005():
    """Test 150: Typecheck passes for US-005 changes"""
    repo_root = Path(__file__).parent.parent.parent
    result = subprocess.run(
        ['python3', '-m', 'py_compile', 'dashboard/api.py', 'dashboard/habits_helpers.py'],
        cwd=repo_root,
        capture_output=True,
        text=True
    )
    assert result.returncode == 0, f"Typecheck failed: {result.stderr}"
    print("✓ Test 150: Typecheck passes")

if __name__ == '__main__':
    run_all_tests()

# US-006: Frontend: Icon picker as compact dropdown
def test_icon_picker_is_dropdown():
    """Test 151: Icon picker renders as dropdown with trigger button"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check for dropdown structure
    assert 'icon-picker-dropdown' in html, "Icon picker should be a dropdown"
    assert 'icon-picker-trigger' in html, "Dropdown should have trigger button"
    assert 'icon-picker-content' in html, "Dropdown should have content container"
    
    # Check trigger button has icon display and chevron
    assert 'selectedIconDisplay' in html, "Trigger should display selected icon"
    assert 'iconPickerChevron' in html, "Trigger should have chevron icon"
    assert 'chevron-down' in html, "Chevron should be down arrow"
    
    print("✓ Test 151 passed: Icon picker is dropdown structure")

def test_icon_picker_has_search_input():
    """Test 152: Dropdown has search input for filtering icons"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check for search input
    assert 'icon-search-input' in html, "Dropdown should have search input"
    assert 'id="iconSearch"' in html, "Search input should have iconSearch id"
    assert 'placeholder="Search icons..."' in html, "Search input should have placeholder"
    assert 'oninput="filterIcons()"' in html, "Search input should trigger filterIcons()"
    
    print("✓ Test 152 passed: Dropdown has search input")

def test_icon_picker_max_height_300px():
    """Test 153: Dropdown content has max-height 300px with scroll"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check for max-height in CSS
    assert 'max-height: 300px' in html, "Icon picker content should have max-height 300px"
    assert 'overflow-y: auto' in html or 'overflow: hidden' in html, "Should have overflow handling"
    
    print("✓ Test 153 passed: Max-height 300px with scroll")

def test_icon_picker_toggle_functions():
    """Test 154: Toggle functions exist for opening/closing dropdown"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check for toggle functions
    assert 'function toggleIconPicker()' in html, "toggleIconPicker function should exist"
    assert 'function openIconPicker()' in html, "openIconPicker function should exist"
    assert 'function closeIconPicker()' in html, "closeIconPicker function should exist"
    assert 'onclick="toggleIconPicker()"' in html, "Trigger should call toggleIconPicker"
    
    print("✓ Test 154 passed: Toggle functions exist")

def test_icon_picker_visible_class_toggle():
    """Test 155: Dropdown uses visible class to show/hide content"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check for visible class handling in CSS
    assert '.icon-picker-content.visible' in html, "CSS should have visible class rule"
    assert 'display: block' in html, "Visible class should display content"
    assert 'display: none' in html, "Hidden state should have display none"
    
    # Check for visible class toggling in JS
    assert "classList.add('visible')" in html, "Should add visible class to open"
    assert "classList.remove('visible')" in html, "Should remove visible class to close"
    
    print("✓ Test 155 passed: Visible class toggle logic")

def test_icon_picker_filter_function():
    """Test 156: filterIcons function filters icons based on search"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check for filterIcons function
    assert 'function filterIcons()' in html, "filterIcons function should exist"
    
    # Check filter logic
    search_section = html[html.find('function filterIcons()'):html.find('function filterIcons()') + 1000]
    assert 'toLowerCase()' in search_section, "Should use case-insensitive search"
    assert 'filter' in search_section, "Should use filter method"
    assert 'includes' in search_section, "Should check if icon name includes query"
    
    print("✓ Test 156 passed: filterIcons function implementation")

def test_icon_picker_closes_on_selection():
    """Test 157: Selecting an icon closes the dropdown"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check that selectIcon calls closeIconPicker
    select_icon_section = html[html.find('function selectIcon('):html.find('function selectIcon(') + 1500]
    assert 'closeIconPicker()' in select_icon_section, "selectIcon should call closeIconPicker"
    
    print("✓ Test 157 passed: Selection closes dropdown")

def test_icon_picker_click_outside_closes():
    """Test 158: Clicking outside dropdown closes it"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check for click outside listener comment and handler
    assert "Click outside icon picker to close" in html, "Should have icon picker click-outside comment"
    
    # Find the icon picker click handler (after the comment)
    click_handler_start = html.find("Click outside icon picker to close")
    if click_handler_start > 0:
        click_handler = html[click_handler_start:click_handler_start + 500]
        assert 'icon-picker-dropdown' in click_handler, "Should reference icon-picker-dropdown"
        assert 'contains' in click_handler, "Should check if click is inside dropdown"
        assert 'closeIconPicker()' in click_handler, "Should close if clicked outside"
    
    print("✓ Test 158 passed: Click outside closes dropdown")

def test_icon_picker_updates_trigger_display():
    """Test 159: Selected icon updates trigger button display"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check that selectIcon updates the trigger display
    select_icon_section = html[html.find('function selectIcon('):html.find('function selectIcon(') + 1500]
    assert 'selectedIconDisplay' in select_icon_section, "Should update selectedIconDisplay element"
    assert 'setAttribute' in select_icon_section, "Should set icon attribute"
    assert 'data-lucide' in select_icon_section, "Should update data-lucide attribute"
    assert 'lucide.createIcons()' in select_icon_section, "Should refresh Lucide icons"
    
    print("✓ Test 159 passed: Trigger display updates on selection")

def test_icon_picker_css_dropdown_styles():
    """Test 160: CSS includes dropdown-specific styles"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check for dropdown-specific CSS
    assert '.icon-picker-dropdown' in html, "Should have dropdown container styles"
    assert '.icon-picker-trigger' in html, "Should have trigger button styles"
    assert '.icon-picker-content' in html, "Should have content container styles"
    assert 'position: absolute' in html, "Content should be absolutely positioned"
    assert 'z-index: 100' in html, "Content should have high z-index"
    
    # Check for hover states
    assert '.icon-picker-trigger:hover' in html, "Should have trigger hover state"
    
    print("✓ Test 160 passed: Dropdown CSS styles present")

def test_icon_picker_chevron_rotation():
    """Test 161: Chevron rotates when dropdown opens"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check for chevron rotation in CSS
    assert 'trigger-chevron' in html, "Chevron should have trigger-chevron class"
    assert 'transform: rotate(180deg)' in html, "Chevron should rotate 180deg when open"
    assert '.open .trigger-chevron' in html or '.icon-picker-trigger.open .trigger-chevron' in html, "Should rotate when trigger has open class"
    
    # Check that open class is toggled
    assert "classList.add('open')" in html, "Should add open class"
    assert "classList.remove('open')" in html, "Should remove open class"
    
    print("✓ Test 161 passed: Chevron rotation logic")

def test_icon_picker_search_autofocus():
    """Test 162: Search input gets focus when dropdown opens"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Check that openIconPicker focuses the search input
    open_icon_picker = html[html.find('function openIconPicker()'):html.find('function openIconPicker()') + 800]
    assert 'focus()' in open_icon_picker, "Should focus search input when opening"
    assert 'setTimeout' in open_icon_picker, "Should use setTimeout for focus after animation"
    
    print("✓ Test 162 passed: Search input autofocus")

def test_typecheck_us006():
    """Test 163: Typecheck passes"""
    result = subprocess.run(
        ['python3', '-m', 'py_compile', 'dashboard/api.py', 'dashboard/habits_helpers.py'],
        cwd='/home/moltbot/clawd',
        capture_output=True,
        text=True
    )
    assert result.returncode == 0, f"Typecheck failed: {result.stderr}"
    print("✓ Test 163 passed: Typecheck successful")


# ========================================
# US-007: Modal backdrop opacity and touch optimization
# ========================================

def test_modal_backdrop_opacity():
    """Test 164: Modal backdrop uses rgba(0, 0, 0, 0.6)"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Find modal-overlay CSS
    modal_overlay = html[html.find('.modal-overlay {'):html.find('.modal-overlay {') + 300]
    assert 'background: rgba(0, 0, 0, 0.6)' in modal_overlay, "Modal backdrop should be rgba(0, 0, 0, 0.6)"
    assert 'rgba(0, 0, 0, 0.7)' not in modal_overlay, "Should not use old opacity value 0.7"
    
    print("✓ Test 164 passed: Modal backdrop opacity is 0.6")

def test_filter_icon_buttons_44px():
    """Test 165: Filter icon buttons have min-height 44px"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Find filter-icon-btn CSS
    filter_btn = html[html.find('.filter-icon-btn {'):html.find('.filter-icon-btn {') + 400]
    assert 'min-width: 44px' in filter_btn, "Filter icon buttons should have min-width 44px"
    assert 'min-height: 44px' in filter_btn, "Filter icon buttons should have min-height 44px"
    assert 'min-height: 36px' not in filter_btn, "Should not use old min-height value 36px"
    
    print("✓ Test 165 passed: Filter icon buttons are 44x44px minimum")

def test_compact_check_button_44px():
    """Test 166: Compact check button is 44x44px"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Find habit-card-check-btn-compact CSS (base style, not mobile override)
    check_btn_start = html.find('.habit-card-check-btn-compact {')
    check_btn = html[check_btn_start:check_btn_start + 500]
    assert 'width: 44px' in check_btn, "Compact check button should have width: 44px"
    assert 'height: 44px' in check_btn, "Compact check button should have height: 44px"
    assert 'width: 32px' not in check_btn, "Should not use old width value 32px"
    assert 'height: 32px' not in check_btn, "Should not use old height value 32px"
    
    print("✓ Test 166 passed: Compact check button is 44x44px")

def test_action_buttons_44px():
    """Test 167: Action buttons (edit/delete) have min 44x44px"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Find habit-card-action-btn CSS (base style, not in media query)
    # Search for all occurrences
    action_btn_matches = []
    start = 0
    while True:
        idx = html.find('.habit-card-action-btn {', start)
        if idx == -1:
            break
        action_btn_matches.append(idx)
        start = idx + 1
    
    # Get the base style (should be the second one, after mobile styles)
    assert len(action_btn_matches) >= 2, "Should have at least 2 .habit-card-action-btn definitions"
    base_style_idx = action_btn_matches[1]  # Second occurrence is the base style
    action_btn = html[base_style_idx:base_style_idx + 500]
    
    assert 'min-width: 44px' in action_btn, "Action buttons should have min-width 44px in base style"
    assert 'min-height: 44px' in action_btn, "Action buttons should have min-height 44px in base style"
    
    print("✓ Test 167 passed: Action buttons have min 44x44px touch targets")

def test_modal_close_button_44px():
    """Test 168: Modal close button has min 44x44px"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # Find modal-close CSS (base style, not in media query)
    # Search for all occurrences
    modal_close_matches = []
    start = 0
    while True:
        idx = html.find('.modal-close {', start)
        if idx == -1:
            break
        modal_close_matches.append(idx)
        start = idx + 1
    
    # Get the base style (second occurrence)
    assert len(modal_close_matches) >= 2, "Should have at least 2 .modal-close definitions"
    base_style_idx = modal_close_matches[1]
    modal_close = html[base_style_idx:base_style_idx + 500]
    
    assert 'min-width: 44px' in modal_close, "Modal close button should have min-width 44px in base style"
    assert 'min-height: 44px' in modal_close, "Modal close button should have min-height 44px in base style"
    
    print("✓ Test 168 passed: Modal close button has min 44x44px touch target")

def test_all_interactive_elements_touch_friendly():
    """Test 169: Verify all key interactive elements meet 44px minimum"""
    habits_path = Path(__file__).parent.parent / 'habits.html'
    html = habits_path.read_text()
    
    # List of interactive elements that should have proper touch targets
    elements = [
        ('.habit-card-check-btn-compact', 'Check button'),
        ('.habit-card-action-btn', 'Action buttons'),
        ('.filter-icon-btn', 'Filter icon buttons'),
        ('.modal-close', 'Modal close button'),
    ]
    
    for selector, name in elements:
        # Find in base styles (not just mobile)
        assert f'{selector}' in html, f"{name} should exist"
        # We've already tested these individually, this is a summary check
    
    print("✓ Test 169 passed: All interactive elements have touch-friendly sizes")

def test_typecheck_us007():
    """Test 170: Typecheck passes after US-007 changes"""
    result = subprocess.run(
        ['python3', '-m', 'py_compile', 'dashboard/api.py', 'dashboard/habits_helpers.py'],
        cwd='/home/moltbot/clawd',
        capture_output=True,
        text=True
    )
    assert result.returncode == 0, f"Typecheck failed: {result.stderr}"
    print("✓ Test 170 passed: Typecheck successful")
