Claude Code Plugins

Community-maintained marketplace

Feedback

waste-dev-report-visualizer

@tryinhard1080/wastewise-skill-system
0
0

Generate professional interactive dashboards and comprehensive spec sheets for multifamily development waste management plans. Calculates volumes, costs, ROI, payback periods, and equipment requirements. Use when user mentions development projects, trash management plans, waste analysis, compactor analysis, cost optimization, or needs professional reports for developers, contractors, or property managers.

Install Skill

1Download skill
2Enable skills in Claude

Open claude.ai/settings/capabilities and find the "Skills" section

3Upload to Claude

Click "Upload skill" and select the downloaded ZIP file

Note: Please verify skill by going through its instructions before using it.

SKILL.md

name waste-dev-report-visualizer
description Generate professional interactive dashboards and comprehensive spec sheets for multifamily development waste management plans. Calculates volumes, costs, ROI, payback periods, and equipment requirements. Use when user mentions development projects, trash management plans, waste analysis, compactor analysis, cost optimization, or needs professional reports for developers, contractors, or property managers.

Waste Dev Report Visualizer

What This Skill Does

Transforms raw development project data into professional, interactive waste management analysis reports including:

  • Interactive HTML Dashboard with 6+ dynamic charts, building selector, and cost comparisons
  • Comprehensive Spec Sheet with detailed calculations, equipment specs, regulatory compliance, and implementation plans
  • Automated volume calculations using EPA/industry standards (0.16 CY/unit/week waste, 4:1 compaction ratios)
  • Complete financial analysis with payback periods, per-unit costs, and ROI projections
  • Equipment recommendations (compactors, containers, handling equipment)
  • Regulatory compliance verification (AB 341, AB 1826, AB 1383, LA City codes)

Perfect for presenting to executives, property managers, developers, or contractors at Greystar or other multifamily operators.

When to Use

Invoke this skill when the user:

  • Uploads development project data with building information (units, square footage)
  • Mentions "trash management plan", "waste analysis", "compactor study"
  • Asks for "dashboard", "spec sheet", or "professional report" for waste services
  • Needs cost optimization analysis for waste operations
  • Wants to compare loose vs compacted service scenarios
  • Keywords: waste dev, development waste, trash plan, compactor ROI, payback analysis, multifamily waste

How It Works

Step 1: Load and Validate Project Data

import pandas as pd
import json
from datetime import datetime

# Load building data
df = pd.read_csv('project_data.csv')

# Validate required columns
required_cols = ['building_name', 'units', 'commercial_sf', 'building_type']
if not all(col in df.columns for col in required_cols):
    raise ValueError(f"Missing required columns. Need: {required_cols}")

# Load equipment specs
with open('equipment_specs.json', 'r') as f:
    equipment = json.load(f)

print(f"โœ“ Loaded {len(df)} buildings")
print(f"โœ“ Total units: {df['units'].sum()}")

Step 2: Calculate Waste Volumes Using Industry Standards

# EPA/Industry standard generation rates
WASTE_PER_UNIT = 0.16  # CY per unit per week
RECYCLING_PER_UNIT = 0.16  # CY per unit per week
COMPOST_PER_UNIT = 0.012  # CY per unit per week
COMPACTION_RATIO = 4.0  # 4:1 compression

# Commercial waste rates (lbs/SF/week)
RESTAURANT_WASTE = 1.25
RETAIL_WASTE = 0.07
RESTAURANT_RECYCLING = 0.40  # 40% diversion
RESTAURANT_COMPOST = 0.25  # 25% diversion

def calculate_volumes(row):
    """Calculate weekly waste volumes for a building"""
    units = row['units']
    commercial_sf = row.get('commercial_sf', 0)
    
    # Residential volumes
    loose_waste = units * WASTE_PER_UNIT
    compacted_waste = loose_waste / COMPACTION_RATIO
    
    loose_recycling = units * RECYCLING_PER_UNIT
    compacted_recycling = loose_recycling / COMPACTION_RATIO
    
    compost = units * COMPOST_PER_UNIT
    
    # Commercial volumes (if applicable)
    if commercial_sf > 0:
        com_waste_lbs = commercial_sf * RESTAURANT_WASTE
        com_waste_cy = com_waste_lbs / 125  # lbs to CY conversion
        loose_waste += com_waste_cy * (1 - RESTAURANT_RECYCLING - RESTAURANT_COMPOST)
        loose_recycling += com_waste_cy * RESTAURANT_RECYCLING
        compost += com_waste_cy * RESTAURANT_COMPOST
    
    return {
        'loose_waste_cy': loose_waste,
        'compacted_waste_cy': compacted_waste,
        'loose_recycling_cy': loose_recycling,
        'compacted_recycling_cy': compacted_recycling,
        'compost_cy': compost,
        'cardboard_boxes_week': units * 3.5  # Average 3.5 boxes/unit/week
    }

# Apply calculations
df['volumes'] = df.apply(calculate_volumes, axis=1)
volumes_df = pd.json_normalize(df['volumes'])
df = pd.concat([df, volumes_df], axis=1)

Step 3: Calculate Service Costs and Labor

# Athens Services 2023 Rate Schedule
FRONT_LOAD_RATE = 9.64  # $/CY/pickup
DISPOSAL_WASTE = 81.77  # $/ton
DISPOSAL_ORGANICS = 106.19  # $/ton
BIN_SIZE = 3  # CY standard bin
WEEKS_PER_MONTH = 4.33

# Labor rates
LABOR_RATE = 21.00  # $/hour
TIME_TO_MOVE_BINS = 0.5  # hours (one-time per collection day)
TIME_PER_BIN = 0.15  # hours to rake/rotate each bin

def calculate_costs(row):
    """Calculate monthly service and labor costs"""
    
    # Scenario 1: Loose service
    loose_waste_bins = row['loose_waste_cy'] / BIN_SIZE
    loose_recycle_bins = row['loose_recycling_cy'] / BIN_SIZE
    compost_toters = row['compost_cy'] / 0.5  # 96-gal toters
    
    loose_pickups_week = loose_waste_bins + loose_recycle_bins + compost_toters
    loose_pickups_month = loose_pickups_week * WEEKS_PER_MONTH
    
    loose_waste_cost = (loose_waste_bins * WEEKS_PER_MONTH * 
                        FRONT_LOAD_RATE * BIN_SIZE)
    loose_recycle_cost = (loose_recycle_bins * WEEKS_PER_MONTH * 
                          FRONT_LOAD_RATE * BIN_SIZE * 0.65)  # 35% discount
    compost_cost = compost_toters * WEEKS_PER_MONTH * 97.00  # Fixed toter rate
    
    loose_total = loose_waste_cost + loose_recycle_cost + compost_cost
    
    # Scenario 2: Compacted waste only
    comp_waste_bins = row['compacted_waste_cy'] / BIN_SIZE
    comp_pickups_week = comp_waste_bins + loose_recycle_bins + compost_toters
    
    comp_waste_cost = comp_waste_bins * WEEKS_PER_MONTH * FRONT_LOAD_RATE * BIN_SIZE
    comp_total = comp_waste_cost + loose_recycle_cost + compost_cost
    
    # Scenario 3: Both compacted
    comp_recycle_bins = row['compacted_recycling_cy'] / BIN_SIZE
    both_pickups_week = comp_waste_bins + comp_recycle_bins + compost_toters
    
    comp_recycle_cost = comp_recycle_bins * WEEKS_PER_MONTH * FRONT_LOAD_RATE * BIN_SIZE * 0.65
    both_total = comp_waste_cost + comp_recycle_cost + compost_cost
    
    # Labor costs
    loose_labor = ((TIME_TO_MOVE_BINS * 1) + (TIME_PER_BIN * loose_pickups_week)) * WEEKS_PER_MONTH * LABOR_RATE
    comp_labor = ((TIME_TO_MOVE_BINS * 1) + (TIME_PER_BIN * comp_pickups_week)) * WEEKS_PER_MONTH * LABOR_RATE
    both_labor = ((TIME_TO_MOVE_BINS * 1) + (TIME_PER_BIN * both_pickups_week)) * WEEKS_PER_MONTH * LABOR_RATE
    
    return {
        'loose_service': loose_total,
        'loose_labor': loose_labor,
        'loose_total': loose_total + loose_labor,
        'comp_service': comp_total,
        'comp_labor': comp_labor,
        'comp_total': comp_total + comp_labor,
        'both_service': both_total,
        'both_labor': both_labor,
        'both_total': both_total + both_labor,
        'loose_containers': loose_pickups_week,
        'comp_containers': comp_pickups_week,
        'both_containers': both_pickups_week
    }

df['costs'] = df.apply(calculate_costs, axis=1)
costs_df = pd.json_normalize(df['costs'])
df = pd.concat([df, costs_df], axis=1)

Step 4: Calculate ROI and Payback Periods

# Equipment costs
COMPACTOR_COST = 43796.90  # Per unit
WASTE_CADDY = 10093.00
PALLET_JACK = 7907.00

def calculate_payback(row):
    """Calculate payback periods for equipment investment"""
    units = row['units']
    
    # Savings calculations
    comp_waste_savings = row['loose_total'] - row['comp_total']
    both_savings = row['loose_total'] - row['both_total']
    
    # Equipment costs
    single_compactor_cost = COMPACTOR_COST
    dual_compactor_cost = COMPACTOR_COST * 2
    
    # Payback in months
    comp_payback = (single_compactor_cost / comp_waste_savings) if comp_waste_savings > 0 else 999
    both_payback = (dual_compactor_cost / both_savings) if both_savings > 0 else 999
    
    # Per unit costs
    loose_per_unit = row['loose_total'] / units
    comp_per_unit = row['comp_total'] / units
    both_per_unit = row['both_total'] / units
    
    return {
        'comp_monthly_savings': comp_waste_savings,
        'both_monthly_savings': both_savings,
        'comp_annual_savings': comp_waste_savings * 12,
        'both_annual_savings': both_savings * 12,
        'comp_payback_months': comp_payback,
        'both_payback_months': both_payback,
        'comp_equipment_cost': single_compactor_cost,
        'both_equipment_cost': dual_compactor_cost,
        'loose_cost_per_unit': loose_per_unit,
        'comp_cost_per_unit': comp_per_unit,
        'both_cost_per_unit': both_per_unit,
        'container_reduction_pct': ((row['loose_containers'] - row['both_containers']) / 
                                     row['loose_containers'] * 100)
    }

df['payback'] = df.apply(calculate_payback, axis=1)
payback_df = pd.json_normalize(df['payback'])
df = pd.concat([df, payback_df], axis=1)

# Summary metrics
print(f"\n๐Ÿ“Š PORTFOLIO SUMMARY")
print(f"Total Monthly Savings (Both Compacted): ${df['both_monthly_savings'].sum():,.0f}")
print(f"Total Annual Savings: ${df['both_annual_savings'].sum():,.0f}")
print(f"Average Payback Period: {df['both_payback_months'].mean():.0f} months")
print(f"Total Equipment Investment: ${df['both_equipment_cost'].sum():,.0f}")

Step 5: Calculate Yards Per Door Benchmarks

# Industry benchmarks for yards per door per month
BENCHMARKS = {
    'garden-style': {'min': 2.0, 'max': 2.25, 'optimal': 2.1},
    'mid-rise': {'min': 1.3, 'max': 1.7, 'optimal': 1.5},
    'high-rise': {'min': 1.0, 'max': 1.5, 'optimal': 1.2}
}

def calculate_yards_per_door(row):
    """
    Calculate yards of service per door per month for benchmarking
    
    For dumpster service:
    Yards/Door = (Container_Size ร— Containers ร— Pickups/Week ร— 4.33) / Units
    
    For compactor service:
    Yards/Door = ((Tons ร— 2000) / 138) / Units
    Where 138 lbs/ydยณ is EPA standard density for loose MSW
    """
    units = row['units']
    building_type = row.get('building_type', 'mid-rise').lower()
    
    # Get appropriate benchmark
    if 'garden' in building_type:
        benchmark = BENCHMARKS['garden-style']
    elif 'high' in building_type or 'tower' in building_type:
        benchmark = BENCHMARKS['high-rise']
    else:
        benchmark = BENCHMARKS['mid-rise']
    
    # Calculate yards/door for loose service (dumpster formula)
    loose_waste_containers = row['loose_waste_cy'] / BIN_SIZE
    loose_pickups_week = loose_waste_containers + (row['loose_recycling_cy'] / BIN_SIZE)
    loose_yards_per_door = (BIN_SIZE * loose_pickups_week * WEEKS_PER_MONTH) / units
    
    # Calculate yards/door for compacted service
    # Estimate tonnage: (CY ร— 138 lbs/ydยณ) / 2000 lbs/ton
    comp_waste_tons_month = (row['compacted_waste_cy'] * WEEKS_PER_MONTH * 138) / 2000
    comp_yards_per_door = ((comp_waste_tons_month * 2000) / 138) / units
    
    # Calculate yards/door for both compacted
    both_waste_tons_month = (row['compacted_waste_cy'] * WEEKS_PER_MONTH * 138) / 2000
    both_recycle_tons_month = (row['compacted_recycling_cy'] * WEEKS_PER_MONTH * 138) / 2000
    total_tons = both_waste_tons_month + both_recycle_tons_month
    both_yards_per_door = ((total_tons * 2000) / 138) / units
    
    # Compare to benchmarks
    loose_vs_benchmark = ((loose_yards_per_door - benchmark['optimal']) / 
                          benchmark['optimal'] * 100)
    both_vs_benchmark = ((both_yards_per_door - benchmark['optimal']) / 
                         benchmark['optimal'] * 100)
    
    return {
        'loose_yards_per_door': loose_yards_per_door,
        'comp_yards_per_door': comp_yards_per_door,
        'both_yards_per_door': both_yards_per_door,
        'benchmark_min': benchmark['min'],
        'benchmark_max': benchmark['max'],
        'benchmark_optimal': benchmark['optimal'],
        'loose_vs_benchmark_pct': loose_vs_benchmark,
        'both_vs_benchmark_pct': both_vs_benchmark,
        'within_benchmark': (both_yards_per_door >= benchmark['min'] and 
                            both_yards_per_door <= benchmark['max'])
    }

df['benchmarks'] = df.apply(calculate_yards_per_door, axis=1)
benchmarks_df = pd.json_normalize(df['benchmarks'])
df = pd.concat([df, benchmarks_df], axis=1)

# Benchmark summary
print(f"\n๐Ÿ“ YARDS PER DOOR BENCHMARKS")
for idx, row in df.iterrows():
    status = "โœ“ Within" if row['within_benchmark'] else "โš  Outside"
    print(f"{row['building_name']}: {row['both_yards_per_door']:.2f} yd/door/mo "
          f"({status} benchmark {row['benchmark_min']:.1f}-{row['benchmark_max']:.1f})")

Step 6: Generate Interactive Dashboard

def generate_dashboard(df, project_name):
    """Create interactive HTML dashboard with Chart.js"""
    
    html = f'''<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{project_name} - Waste Management Dashboard</title>
    <script src="https://cdn.jsdelivr.net/npm/chart.js"></script>
    <style>
        * {{ margin: 0; padding: 0; box-sizing: border-box; }}
        body {{
            font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif;
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            padding: 20px;
            color: #1a202c;
        }}
        .container {{
            max-width: 1400px;
            margin: 0 auto;
        }}
        .header {{
            background: white;
            padding: 30px;
            border-radius: 12px;
            margin-bottom: 30px;
            box-shadow: 0 10px 30px rgba(0,0,0,0.1);
        }}
        .header h1 {{
            font-size: 32px;
            color: #2d3748;
            margin-bottom: 10px;
        }}
        .header p {{
            color: #718096;
            font-size: 16px;
        }}
        .metrics {{
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
            gap: 20px;
            margin-bottom: 30px;
        }}
        .metric-card {{
            background: white;
            padding: 25px;
            border-radius: 12px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.08);
        }}
        .metric-value {{
            font-size: 36px;
            font-weight: bold;
            color: #2d3748;
            margin: 10px 0;
        }}
        .metric-label {{
            color: #718096;
            font-size: 14px;
            text-transform: uppercase;
            letter-spacing: 0.5px;
        }}
        .metric-change {{
            color: #48bb78;
            font-size: 14px;
            font-weight: 600;
        }}
        .charts {{
            display: grid;
            grid-template-columns: repeat(auto-fit, minmax(500px, 1fr));
            gap: 30px;
            margin-bottom: 30px;
        }}
        .chart-card {{
            background: white;
            padding: 25px;
            border-radius: 12px;
            box-shadow: 0 4px 15px rgba(0,0,0,0.08);
        }}
        .chart-title {{
            font-size: 18px;
            font-weight: 600;
            margin-bottom: 20px;
            color: #2d3748;
        }}
        .building-selector {{
            display: flex;
            gap: 10px;
            margin-bottom: 20px;
            flex-wrap: wrap;
        }}
        .building-btn {{
            padding: 10px 20px;
            border: 2px solid #e2e8f0;
            background: white;
            border-radius: 8px;
            cursor: pointer;
            transition: all 0.3s;
            font-weight: 600;
        }}
        .building-btn:hover {{
            border-color: #667eea;
            background: #f7fafc;
        }}
        .building-btn.active {{
            background: #667eea;
            color: white;
            border-color: #667eea;
        }}
        table {{
            width: 100%;
            border-collapse: collapse;
            margin-top: 15px;
        }}
        th, td {{
            padding: 12px;
            text-align: left;
            border-bottom: 1px solid #e2e8f0;
        }}
        th {{
            background: #f7fafc;
            font-weight: 600;
            color: #2d3748;
        }}
        .recommendation {{
            background: linear-gradient(135deg, #48bb78 0%, #38a169 100%);
            color: white;
            padding: 30px;
            border-radius: 12px;
            margin-top: 30px;
        }}
        .recommendation h2 {{
            margin-bottom: 15px;
            font-size: 24px;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>๐Ÿ—๏ธ {project_name}</h1>
            <p>Comprehensive Waste Management Analysis & Optimization Report</p>
            <p style="margin-top: 10px; font-weight: 600;">Generated: {datetime.now().strftime("%B %d, %Y at %I:%M %p")}</p>
        </div>
        
        <div class="metrics">
'''
    
    # Calculate total metrics
    total_units = df['units'].sum()
    total_savings = df['both_monthly_savings'].sum()
    avg_payback = df['both_payback_months'].mean()
    container_reduction = ((df['loose_containers'].sum() - df['both_containers'].sum()) / 
                           df['loose_containers'].sum() * 100)
    
    html += f'''
            <div class="metric-card">
                <div class="metric-label">Total Units</div>
                <div class="metric-value">{total_units:,.0f}</div>
            </div>
            <div class="metric-card">
                <div class="metric-label">Monthly Savings</div>
                <div class="metric-value">${total_savings:,.0f}</div>
                <div class="metric-change">โ†‘ With full compaction</div>
            </div>
            <div class="metric-card">
                <div class="metric-label">Avg Payback Period</div>
                <div class="metric-value">{avg_payback:.0f} mo</div>
            </div>
            <div class="metric-card">
                <div class="metric-label">Container Reduction</div>
                <div class="metric-value">{container_reduction:.0f}%</div>
                <div class="metric-change">โ†“ Fewer pickups needed</div>
            </div>
        </div>
'''
    
    # Add charts section with Chart.js
    html += '''
        <div class="building-selector" id="buildingSelector">
            <button class="building-btn active" onclick="selectBuilding('all')">All Buildings</button>
    '''
    
    for idx, row in df.iterrows():
        html += f'<button class="building-btn" onclick="selectBuilding({idx})">{row["building_name"]}</button>'
    
    html += '''
        </div>
        
        <div class="charts">
            <div class="chart-card">
                <div class="chart-title">๐Ÿ“Š Cost Comparison by Scenario</div>
                <canvas id="costChart"></canvas>
            </div>
            <div class="chart-card">
                <div class="chart-title">๐Ÿ“ฆ Container Requirements</div>
                <canvas id="containerChart"></canvas>
            </div>
            <div class="chart-card">
                <div class="chart-title">๐Ÿ’ฐ Monthly Savings Analysis</div>
                <canvas id="savingsChart"></canvas>
            </div>
            <div class="chart-card">
                <div class="chart-title">โฑ๏ธ Equipment Payback Periods</div>
                <canvas id="paybackChart"></canvas>
            </div>
            <div class="chart-card">
                <div class="chart-title">๐Ÿข Cost Per Unit Comparison</div>
                <canvas id="perUnitChart"></canvas>
            </div>
            <div class="chart-card">
                <div class="chart-title">๐Ÿ“ˆ Annual ROI by Building</div>
                <canvas id="roiChart"></canvas>
            </div>
        </div>
'''
    
    # Add recommendation section
    best_building = df.loc[df['both_payback_months'].idxmin()]
    
    html += f'''
        <div class="recommendation">
            <h2>โœ… Recommendation: Full Compaction System</h2>
            <p style="font-size: 18px; margin-bottom: 20px;">
                Implement compaction for both waste and recycling across all buildings.
            </p>
            <div style="display: grid; grid-template-columns: repeat(auto-fit, minmax(200px, 1fr)); gap: 20px;">
                <div>
                    <strong>Total Monthly Savings:</strong><br>
                    <span style="font-size: 28px;">${total_savings:,.0f}</span>
                </div>
                <div>
                    <strong>Annual Savings:</strong><br>
                    <span style="font-size: 28px;">${total_savings * 12:,.0f}</span>
                </div>
                <div>
                    <strong>Average Payback:</strong><br>
                    <span style="font-size: 28px;">{avg_payback:.0f} months</span>
                </div>
                <div>
                    <strong>Container Reduction:</strong><br>
                    <span style="font-size: 28px;">{container_reduction:.0f}%</span>
                </div>
            </div>
            <p style="margin-top: 20px; font-size: 16px;">
                ๐Ÿ† <strong>Best Performer:</strong> {best_building['building_name']} shows fastest payback 
                at {best_building['both_payback_months']:.0f} months with ${best_building['both_monthly_savings']:,.0f}/month savings.
            </p>
        </div>
    </div>
    
    <script>
        // Data from Python
        const buildingData = {json.dumps(df.to_dict('records'))};
        
        // Chart instances
        let charts = {{}};
        
        function selectBuilding(index) {{
            // Update button states
            document.querySelectorAll('.building-btn').forEach(btn => btn.classList.remove('active'));
            event.target.classList.add('active');
            
            // Update charts
            updateCharts(index);
        }}
        
        function updateCharts(index) {{
            const data = index === 'all' ? buildingData : [buildingData[index]];
            
            // Cost Comparison Chart
            const costLabels = data.map(b => b.building_name);
            const looseData = data.map(b => b.loose_total);
            const compData = data.map(b => b.comp_total);
            const bothData = data.map(b => b.both_total);
            
            if (charts.cost) charts.cost.destroy();
            charts.cost = new Chart(document.getElementById('costChart'), {{
                type: 'bar',
                data: {{
                    labels: costLabels,
                    datasets: [
                        {{ label: 'Loose Service', data: looseData, backgroundColor: '#fc8181' }},
                        {{ label: 'Compacted Waste', data: compData, backgroundColor: '#fbd38d' }},
                        {{ label: 'Both Compacted', data: bothData, backgroundColor: '#68d391' }}
                    ]
                }},
                options: {{
                    responsive: true,
                    plugins: {{ legend: {{ position: 'bottom' }} }},
                    scales: {{ y: {{ beginAtZero: true, title: {{ display: true, text: 'Monthly Cost ($)' }} }} }}
                }}
            }});
            
            // Container Requirements Chart
            const looseContainers = data.map(b => b.loose_containers);
            const compContainers = data.map(b => b.comp_containers);
            const bothContainers = data.map(b => b.both_containers);
            
            if (charts.containers) charts.containers.destroy();
            charts.containers = new Chart(document.getElementById('containerChart'), {{
                type: 'bar',
                data: {{
                    labels: costLabels,
                    datasets: [
                        {{ label: 'Loose', data: looseContainers, backgroundColor: '#fc8181' }},
                        {{ label: 'Comp Waste', data: compContainers, backgroundColor: '#fbd38d' }},
                        {{ label: 'Both Comp', data: bothContainers, backgroundColor: '#68d391' }}
                    ]
                }},
                options: {{
                    responsive: true,
                    plugins: {{ legend: {{ position: 'bottom' }} }},
                    scales: {{ y: {{ beginAtZero: true, title: {{ display: true, text: 'Containers/Week' }} }} }}
                }}
            }});
            
            // Continue with other charts...
            // Savings Chart
            const compSavings = data.map(b => b.comp_monthly_savings);
            const bothSavings = data.map(b => b.both_monthly_savings);
            
            if (charts.savings) charts.savings.destroy();
            charts.savings = new Chart(document.getElementById('savingsChart'), {{
                type: 'bar',
                data: {{
                    labels: costLabels,
                    datasets: [
                        {{ label: 'Comp Waste Only', data: compSavings, backgroundColor: '#fbd38d' }},
                        {{ label: 'Both Compacted', data: bothSavings, backgroundColor: '#68d391' }}
                    ]
                }},
                options: {{
                    responsive: true,
                    plugins: {{ legend: {{ position: 'bottom' }} }},
                    scales: {{ y: {{ beginAtZero: true, title: {{ display: true, text: 'Monthly Savings ($)' }} }} }}
                }}
            }});
            
            // Payback Chart
            const compPayback = data.map(b => b.comp_payback_months);
            const bothPayback = data.map(b => b.both_payback_months);
            
            if (charts.payback) charts.payback.destroy();
            charts.payback = new Chart(document.getElementById('paybackChart'), {{
                type: 'bar',
                data: {{
                    labels: costLabels,
                    datasets: [
                        {{ label: 'Comp Waste Only', data: compPayback, backgroundColor: '#fbd38d' }},
                        {{ label: 'Both Compacted', data: bothPayback, backgroundColor: '#68d391' }}
                    ]
                }},
                options: {{
                    responsive: true,
                    plugins: {{ legend: {{ position: 'bottom' }} }},
                    scales: {{ y: {{ beginAtZero: true, title: {{ display: true, text: 'Months to Payback' }} }} }}
                }}
            }});
            
            // Per Unit Cost Chart
            const looseCPU = data.map(b => b.loose_cost_per_unit);
            const compCPU = data.map(b => b.comp_cost_per_unit);
            const bothCPU = data.map(b => b.both_cost_per_unit);
            
            if (charts.perUnit) charts.perUnit.destroy();
            charts.perUnit = new Chart(document.getElementById('perUnitChart'), {{
                type: 'bar',
                data: {{
                    labels: costLabels,
                    datasets: [
                        {{ label: 'Loose', data: looseCPU, backgroundColor: '#fc8181' }},
                        {{ label: 'Comp Waste', data: compCPU, backgroundColor: '#fbd38d' }},
                        {{ label: 'Both Comp', data: bothCPU, backgroundColor: '#68d391' }}
                    ]
                }},
                options: {{
                    responsive: true,
                    plugins: {{ legend: {{ position: 'bottom' }} }},
                    scales: {{ y: {{ beginAtZero: true, title: {{ display: true, text: 'Cost Per Unit ($/month)' }} }} }}
                }}
            }});
            
            // ROI Chart
            const annualROI = data.map(b => b.both_annual_savings);
            
            if (charts.roi) charts.roi.destroy();
            charts.roi = new Chart(document.getElementById('roiChart'), {{
                type: 'bar',
                data: {{
                    labels: costLabels,
                    datasets: [
                        {{ label: 'Annual Savings', data: annualROI, backgroundColor: '#68d391' }}
                    ]
                }},
                options: {{
                    responsive: true,
                    plugins: {{ legend: {{ display: false }} }},
                    scales: {{ y: {{ beginAtZero: true, title: {{ display: true, text: 'Annual Savings ($)' }} }} }}
                }}
            }});
        }}
        
        // Initialize with all buildings
        updateCharts('all');
    </script>
</body>
</html>'''
    
    return html

# Generate dashboard
dashboard_html = generate_dashboard(df, "Bundy Blocks Development")

# Save to file
with open('/mnt/user-data/outputs/waste_management_dashboard.html', 'w') as f:
    f.write(dashboard_html)

print("โœ“ Dashboard generated: waste_management_dashboard.html")

Step 7: Generate Comprehensive Spec Sheet

def generate_spec_sheet(df, project_name, equipment):
    """Create detailed technical specification document"""
    
    html = f'''<!DOCTYPE html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>{project_name} - Technical Specification</title>
    <style>
        @media print {{
            body {{ margin: 0; }}
            .no-print {{ display: none; }}
            .page-break {{ page-break-after: always; }}
        }}
        * {{ margin: 0; padding: 0; box-sizing: border-box; }}
        body {{
            font-family: 'Helvetica Neue', Arial, sans-serif;
            line-height: 1.6;
            color: #2d3748;
            background: #f7fafc;
            padding: 40px 20px;
        }}
        .container {{
            max-width: 900px;
            margin: 0 auto;
            background: white;
            padding: 60px;
            box-shadow: 0 10px 40px rgba(0,0,0,0.1);
        }}
        .header {{
            border-bottom: 4px solid #667eea;
            padding-bottom: 30px;
            margin-bottom: 40px;
        }}
        .header h1 {{
            font-size: 36px;
            color: #2d3748;
            margin-bottom: 10px;
        }}
        .header .subtitle {{
            font-size: 18px;
            color: #718096;
        }}
        h2 {{
            font-size: 24px;
            color: #2d3748;
            margin-top: 40px;
            margin-bottom: 20px;
            padding-bottom: 10px;
            border-bottom: 2px solid #e2e8f0;
        }}
        h3 {{
            font-size: 18px;
            color: #4a5568;
            margin-top: 25px;
            margin-bottom: 15px;
        }}
        table {{
            width: 100%;
            border-collapse: collapse;
            margin: 20px 0;
            font-size: 14px;
        }}
        th, td {{
            padding: 12px;
            text-align: left;
            border: 1px solid #e2e8f0;
        }}
        th {{
            background: #f7fafc;
            font-weight: 600;
            color: #2d3748;
        }}
        tr:hover {{
            background: #f7fafc;
        }}
        .highlight {{
            background: #c6f6d5;
            font-weight: 600;
        }}
        .warning {{
            background: #fed7d7;
        }}
        .executive-summary {{
            background: linear-gradient(135deg, #667eea 0%, #764ba2 100%);
            color: white;
            padding: 30px;
            border-radius: 8px;
            margin-bottom: 40px;
        }}
        .executive-summary h2 {{
            color: white;
            border: none;
            margin-top: 0;
        }}
        .metric-box {{
            display: inline-block;
            background: rgba(255,255,255,0.2);
            padding: 15px 20px;
            border-radius: 6px;
            margin: 10px 10px 10px 0;
        }}
        .metric-box strong {{
            display: block;
            font-size: 12px;
            text-transform: uppercase;
            letter-spacing: 1px;
            opacity: 0.9;
        }}
        .metric-box span {{
            display: block;
            font-size: 24px;
            font-weight: bold;
            margin-top: 5px;
        }}
        .btn-group {{
            margin: 30px 0;
            display: flex;
            gap: 15px;
        }}
        .btn {{
            padding: 12px 24px;
            background: #667eea;
            color: white;
            text-decoration: none;
            border-radius: 6px;
            font-weight: 600;
            cursor: pointer;
            border: none;
            transition: all 0.3s;
        }}
        .btn:hover {{
            background: #5568d3;
        }}
        .formula {{
            background: #f7fafc;
            padding: 15px;
            border-left: 4px solid #667eea;
            font-family: 'Courier New', monospace;
            margin: 15px 0;
        }}
        .note {{
            background: #fef5e7;
            border-left: 4px solid #f39c12;
            padding: 15px;
            margin: 15px 0;
        }}
        ul {{
            margin: 15px 0 15px 30px;
        }}
        li {{
            margin: 8px 0;
        }}
    </style>
</head>
<body>
    <div class="container">
        <div class="header">
            <h1>๐Ÿ“‹ {project_name}</h1>
            <div class="subtitle">Comprehensive Trash Management Plan & Technical Specifications</div>
            <div class="subtitle" style="margin-top: 10px; font-weight: 600;">
                Prepared by: Advantage Waste, Greystar Real Estate Partners<br>
                Date: {datetime.now().strftime("%B %d, %Y")}
            </div>
        </div>
        
        <div class="btn-group no-print">
            <button class="btn" onclick="window.print()">๐Ÿ–จ๏ธ Print / Save as PDF</button>
            <button class="btn" onclick="downloadHTML()">๐Ÿ’พ Download HTML</button>
        </div>
'''
    
    # Executive Summary
    total_units = df['units'].sum()
    total_savings_monthly = df['both_monthly_savings'].sum()
    total_savings_annual = total_savings_monthly * 12
    avg_payback = df['both_payback_months'].mean()
    total_investment = df['both_equipment_cost'].sum()
    
    html += f'''
        <div class="executive-summary">
            <h2>Executive Summary</h2>
            <p style="font-size: 16px; margin-bottom: 20px;">
                This comprehensive waste management plan analyzes three development scenarios for {total_units:,.0f} 
                total residential units with commercial space. Our analysis recommends implementing full compaction 
                systems (waste + recycling) across all buildings for optimal cost savings and operational efficiency.
            </p>
            <div>
                <div class="metric-box">
                    <strong>Monthly Savings</strong>
                    <span>${total_savings_monthly:,.0f}</span>
                </div>
                <div class="metric-box">
                    <strong>Annual Savings</strong>
                    <span>${total_savings_annual:,.0f}</span>
                </div>
                <div class="metric-box">
                    <strong>Payback Period</strong>
                    <span>{avg_payback:.0f} months</span>
                </div>
                <div class="metric-box">
                    <strong>Total Investment</strong>
                    <span>${total_investment:,.0f}</span>
                </div>
            </div>
        </div>
        
        <h2>1. Building Summary</h2>
        <table>
            <thead>
                <tr>
                    <th>Building</th>
                    <th>Units</th>
                    <th>Commercial SF</th>
                    <th>Current Cost</th>
                    <th>Optimized Cost</th>
                    <th>Monthly Savings</th>
                    <th>Payback</th>
                </tr>
            </thead>
            <tbody>
'''
    
    for idx, row in df.iterrows():
        html += f'''
                <tr>
                    <td><strong>{row['building_name']}</strong></td>
                    <td>{row['units']:,.0f}</td>
                    <td>{row.get('commercial_sf', 0):,.0f}</td>
                    <td>${row['loose_total']:,.0f}</td>
                    <td class="highlight">${row['both_total']:,.0f}</td>
                    <td class="highlight">${row['both_monthly_savings']:,.0f}</td>
                    <td>{row['both_payback_months']:.0f} mo</td>
                </tr>
'''
    
    html += f'''
            </tbody>
            <tfoot>
                <tr style="font-weight: bold; background: #f7fafc;">
                    <td>TOTAL</td>
                    <td>{total_units:,.0f}</td>
                    <td>{df.get('commercial_sf', 0).sum():,.0f}</td>
                    <td>${df['loose_total'].sum():,.0f}</td>
                    <td>${df['both_total'].sum():,.0f}</td>
                    <td>${total_savings_monthly:,.0f}</td>
                    <td>{avg_payback:.0f} mo</td>
                </tr>
            </tfoot>
        </table>
        
        <h2>2. Calculation Methodology</h2>
        
        <h3>2.1 Base Generation Rates (Per Unit/Week)</h3>
        <div class="formula">
Residential:
โ€ข Waste: 0.16 CY (32 gallons) per unit/week
โ€ข Recycling: 0.16 CY (32 gallons) per unit/week  
โ€ข Compost: 0.012 CY (2.4 gallons) per unit/week
โ€ข Cardboard: 3.5 boxes per unit/week

Commercial (Restaurant):
โ€ข Waste: 1.25 lbs/SF/week
โ€ข Recycling: 40% diversion rate
โ€ข Compost: 25% diversion rate
        </div>
        
        <h3>2.2 Compaction Ratios</h3>
        <div class="formula">
Waste Compaction: 4:1 ratio
Recycling Compaction: 4:1 ratio

Example: 31.2 CY loose waste รท 4 = 7.8 CY compacted
        </div>
        
        <h3>2.3 Cost Calculations</h3>
        <div class="formula">
Athens Services 2023 Rate Schedule:
โ€ข Front Load Rate: $9.64 per CY per pickup
โ€ข Disposal Fee (Waste): $81.77 per ton
โ€ข Disposal Fee (Organics): $106.19 per ton
โ€ข Recycling: No disposal fee (35% discount on service)
โ€ข Compost Toter (96-gal): $97.00 per pickup

Monthly Service Cost Formula:
= (Bins ร— Weekly Pickups ร— 4.33 weeks) ร— ($9.64 ร— Bin Size)

Labor Cost Formula:
= [(0.5 hrs base) + (0.15 hrs ร— containers)] ร— 4.33 weeks ร— $21/hr
        </div>
        
        <h3>2.4 Payback Period Calculation</h3>
        <div class="formula">
Payback (months) = Equipment Cost รท Monthly Savings

Monthly Savings = (Loose Total Cost) - (Compacted Total Cost)

Where Total Cost = Service Cost + Labor Cost
        </div>
        
        <div class="page-break"></div>
        
        <h2>3. Equipment Specifications</h2>
        
        <h3>3.1 Container Specifications</h3>
        
        <table>
            <thead>
                <tr>
                    <th>Container Type</th>
                    <th>Capacity</th>
                    <th>Dimensions</th>
                    <th>Dry Weight</th>
                    <th>Max Fill</th>
                </tr>
            </thead>
            <tbody>
                <tr>
                    <td><strong>Front Load Bin</strong></td>
                    <td>{BIN_SIZE} CY</td>
                    <td>6' ร— 4' ร— 4' (L ร— W ร— H)</td>
                    <td>450 lbs</td>
                    <td>1,350 lbs</td>
                </tr>
                <tr>
                    <td><strong>Compacted Bin</strong></td>
                    <td>{BIN_SIZE} CY</td>
                    <td>6' ร— 4' ร— 4' (L ร— W ร— H)</td>
                    <td>675 lbs</td>
                    <td>4,000 lbs</td>
                </tr>
                <tr>
                    <td><strong>Organic Waste Toter</strong></td>
                    <td>96 gal (0.48 CY)</td>
                    <td>46\" ร— 28\" ร— 34\" (H ร— W ร— D)</td>
                    <td>50 lbs</td>
                    <td>325 lbs</td>
                </tr>
            </tbody>
        </table>
        
        <div class="note">
            <strong>๐Ÿ“ฆ Container Notes:</strong>
            <ul style="margin: 10px 0 0 20px;">
                <li><strong>Compacted Bins:</strong> Reinforced steel (10-12 gauge) vs standard (12-14 gauge). 
                150-300 lbs heavier to withstand compaction forces.</li>
                <li><strong>Clearance Required:</strong> Minimum 14' overhead for front-load truck arms.</li>
                <li><strong>Side Clearances:</strong> 3-4 feet on service side, 2 feet on non-service sides.</li>
                <li><strong>Max Fill Weights:</strong> Include container + waste. Exceeding limits may result in overage charges.</li>
            </ul>
        </div>
        
        <h3>3.2 Compactor Systems</h3>
        <table>
            <tr>
                <th>Item</th>
                <th>Specification</th>
                <th>Cost</th>
            </tr>
            <tr>
                <td>Chute-Fed Compactor</td>
                <td>2-3 CY capacity, 4:1 compaction ratio</td>
                <td>${COMPACTOR_COST:,.2f}</td>
            </tr>
            <tr>
                <td>Compactor Quantity</td>
                <td>2 per building (waste + recycling)</td>
                <td>${COMPACTOR_COST * 2:,.2f}</td>
            </tr>
            <tr>
                <td>Waste Caddy</td>
                <td>Internal waste transport system</td>
                <td>${WASTE_CADDY:,.2f}</td>
            </tr>
            <tr>
                <td>Electric Pallet Jack</td>
                <td>Container handling equipment</td>
                <td>${PALLET_JACK:,.2f}</td>
            </tr>
        </table>
        
        <h3>3.3 Container Requirements by Scenario</h3>
'''
    
    for idx, row in df.iterrows():
        html += f'''
        <p><strong>{row['building_name']} ({row['units']} units)</strong></p>
        <table>
            <tr>
                <th>Scenario</th>
                <th>Waste</th>
                <th>Recycling</th>
                <th>Compost</th>
                <th>Total/Week</th>
                <th>Monthly Cost</th>
            </tr>
            <tr>
                <td>Loose Service</td>
                <td>{row['loose_waste_cy'] / BIN_SIZE:.0f} bins</td>
                <td>{row['loose_recycling_cy'] / BIN_SIZE:.0f} bins</td>
                <td>{row['compost_cy'] / 0.5:.0f} toters</td>
                <td>{row['loose_containers']:.0f}</td>
                <td>${row['loose_total']:,.0f}</td>
            </tr>
            <tr>
                <td>Compacted Waste</td>
                <td>{row['compacted_waste_cy'] / BIN_SIZE:.0f} bins</td>
                <td>{row['loose_recycling_cy'] / BIN_SIZE:.0f} bins</td>
                <td>{row['compost_cy'] / 0.5:.0f} toters</td>
                <td>{row['comp_containers']:.0f}</td>
                <td>${row['comp_total']:,.0f}</td>
            </tr>
            <tr class="highlight">
                <td><strong>Both Compacted (Recommended)</strong></td>
                <td><strong>{row['compacted_waste_cy'] / BIN_SIZE:.0f} bins</strong></td>
                <td><strong>{row['compacted_recycling_cy'] / BIN_SIZE:.0f} bins</strong></td>
                <td><strong>{row['compost_cy'] / 0.5:.0f} toters</strong></td>
                <td><strong>{row['both_containers']:.0f}</strong></td>
                <td><strong>${row['both_total']:,.0f}</strong></td>
            </tr>
        </table>
'''
    
    # Add yards per door benchmarks section
    html += '''
        <div class="page-break"></div>
        
        <h2>4. Industry Benchmarks & Performance Metrics</h2>
        
        <h3>4.1 Yards Per Door Analysis</h3>
        <p>Industry standard metric for measuring waste service consumption. Enables apples-to-apples comparison across properties and service types.</p>
        
        <table>
            <thead>
                <tr>
                    <th>Building</th>
                    <th>Type</th>
                    <th>Loose Service</th>
                    <th>Both Compacted</th>
                    <th>Benchmark Range</th>
                    <th>Status</th>
                </tr>
            </thead>
            <tbody>
'''
    
    for idx, row in df.iterrows():
        status_class = "highlight" if row['within_benchmark'] else "warning"
        status_text = "โœ“ Within Range" if row['within_benchmark'] else "โš  Outside Range"
        
        html += f'''
                <tr>
                    <td><strong>{row['building_name']}</strong></td>
                    <td>{row.get('building_type', 'mid-rise').title()}</td>
                    <td>{row['loose_yards_per_door']:.2f} yd/door/mo</td>
                    <td class="{status_class}">{row['both_yards_per_door']:.2f} yd/door/mo</td>
                    <td>{row['benchmark_min']:.1f} - {row['benchmark_max']:.1f}</td>
                    <td>{status_text}</td>
                </tr>
'''
    
    html += '''
            </tbody>
        </table>
        
        <div class="formula">
<strong>Calculation Methods:</strong>

<strong>For Dumpster Service:</strong>
Yards/Door = (Container_Size_CY ร— Number_of_Containers ร— Pickups/Week ร— 4.33) / Units

<strong>For Compactor Service:</strong>
Yards/Door = ((Total_Monthly_Tons ร— 2000) / 138) / Units

Where 138 lbs/ydยณ is EPA/ENERGY STAR standard density for loose MSW
        </div>
        
        <h3>4.2 Cost Per Door Benchmarks</h3>
        <table>
            <thead>
                <tr>
                    <th>Building</th>
                    <th>Loose Service</th>
                    <th>Both Compacted</th>
                    <th>Optimal Range</th>
                    <th>Performance</th>
                </tr>
            </thead>
            <tbody>
'''
    
    # Add cost per door comparison
    for idx, row in df.iterrows():
        building_type = row.get('building_type', 'mid-rise').lower()
        if 'garden' in building_type:
            optimal_range = "$18-22"
        elif 'high' in building_type:
            optimal_range = "$12-18"
        else:
            optimal_range = "$15-20"
        
        performance = "โœ“ Excellent" if row['both_cost_per_unit'] < 22 else "โ—‹ Good" if row['both_cost_per_unit'] < 28 else "โš  High"
        
        html += f'''
                <tr>
                    <td><strong>{row['building_name']}</strong></td>
                    <td>${row['loose_cost_per_unit']:.2f}/door</td>
                    <td class="highlight">${row['both_cost_per_unit']:.2f}/door</td>
                    <td>{optimal_range}/door</td>
                    <td>{performance}</td>
                </tr>
'''
    
    html += '''
            </tbody>
        </table>
        
        <div class="note">
            <strong>๐Ÿ“Š Benchmark Interpretation:</strong>
            <ul>
                <li><strong>Garden-Style:</strong> Target 2.0-2.25 yards/door, $18-22/door with compaction</li>
                <li><strong>Mid-Rise:</strong> Target 1.3-1.7 yards/door, $15-20/door with compaction</li>
                <li><strong>High-Rise:</strong> Target 1.0-1.5 yards/door, $12-18/door with compaction</li>
                <li><strong>Above Benchmark:</strong> May indicate over-servicing, contamination, or illegal dumping</li>
                <li><strong>Below Benchmark:</strong> May indicate insufficient service or high compaction efficiency</li>
            </ul>
        </div>
    '''
    
    html += f'''
        <div class="page-break"></div>
        
        <h2>5. Regulatory Compliance</h2>
        
        <h3>5.1 California State Requirements</h3>
        <ul>
            <li><strong>AB 341 (Recycling):</strong> Mandatory commercial recycling for businesses and multifamily 
            properties with 5+ units</li>
            <li><strong>AB 1826 (Organics):</strong> Mandatory organic waste recycling for commercial/multifamily 
            generators</li>
            <li><strong>AB 1383 (SLCP):</strong> Reduce organic waste disposal 75% by 2025, recover 20% edible food</li>
            <li><strong>SB 1383 Compliance:</strong> Requires monitoring, education, contamination prevention programs</li>
        </ul>
        
        <h3>5.2 LA City Requirements</h3>
        <ul>
            <li><strong>Recycling Room Size:</strong> Minimum 100 SF for buildings with โ‰ฅ51 units (8 ft ceiling height)</li>
            <li><strong>Container Access:</strong> Bins must be accessible within 150 ft of collection point</li>
            <li><strong>Fire Code (NFPA 82):</strong> Compactor rooms require proper ventilation, sprinklers, fire-rated 
            construction</li>
            <li><strong>ADA Compliance:</strong> Accessible routes to recycling areas, appropriate signage</li>
        </ul>
        
        <div class="note">
            <strong>โš ๏ธ Note:</strong> All buildings in this project meet or exceed regulatory requirements for 
            recycling room sizing and equipment accessibility.
        </div>
        
        <h2>6. Recommended Service Schedules</h2>
        
        <table>
            <thead>
                <tr>
                    <th>Building</th>
                    <th>Waste (Compacted)</th>
                    <th>Recycling (Compacted)</th>
                    <th>Compost</th>
                    <th>Cardboard</th>
                </tr>
            </thead>
            <tbody>
'''
    
    for idx, row in df.iterrows():
        waste_pickups = int(row['compacted_waste_cy'] / BIN_SIZE)
        recycle_pickups = int(row['compacted_recycling_cy'] / BIN_SIZE)
        compost_pickups = int(row['compost_cy'] / 0.5)
        cardboard_daily = int(row['cardboard_boxes_week'] / 7)
        
        html += f'''
                <tr>
                    <td><strong>{row['building_name']}</strong></td>
                    <td>{waste_pickups}ร— per week</td>
                    <td>{recycle_pickups}ร— per week</td>
                    <td>{compost_pickups}ร— per week</td>
                    <td>~{cardboard_daily} boxes/day</td>
                </tr>
'''
    
    html += '''
            </tbody>
        </table>
        
        <h2>7. Maintenance Requirements</h2>
        
        <h3>7.1 Daily Maintenance</h3>
        <ul>
            <li>Visual inspection of compactor operation</li>
            <li>Check for jams or unusual noises</li>
            <li>Ensure chutes are clear and clean</li>
            <li>Monitor fill levels on all containers</li>
        </ul>
        
        <h3>7.2 Weekly Maintenance</h3>
        <ul>
            <li>Deep clean compactor chutes and hoppers</li>
            <li>Inspect safety interlocks and door seals</li>
            <li>Check hydraulic fluid levels</li>
            <li>Clean container staging areas</li>
        </ul>
        
        <h3>7.3 Quarterly Maintenance</h3>
        <ul>
            <li>Professional compactor servicing by certified technician</li>
            <li>Hydraulic system inspection</li>
            <li>Electrical system check</li>
            <li>Replace worn parts as needed</li>
        </ul>
        
        <h3>7.4 Annual Maintenance</h3>
        <ul>
            <li>Comprehensive equipment audit</li>
            <li>Safety system recertification</li>
            <li>Pest control inspection and treatment</li>
            <li>Service contract renewal and rate review</li>
        </ul>
        
        <div class="page-break"></div>
        
        <h2>8. Implementation Plan</h2>
        
        <h3>Phase 1: Planning & Design (Weeks 1-2)</h3>
        <ul>
            <li>Finalize compactor room designs with architect</li>
            <li>Submit plans for city permitting</li>
            <li>Order compactor equipment (12-16 week lead time)</li>
            <li>Coordinate with Athens Services for container delivery</li>
        </ul>
        
        <h3>Phase 2: Construction & Installation (Weeks 3-20)</h3>
        <ul>
            <li>Complete compactor room construction</li>
            <li>Install electrical, ventilation, fire suppression systems</li>
            <li>Deliver and install compactor equipment</li>
            <li>Final inspections and permitting sign-offs</li>
        </ul>
        
        <h3>Phase 3: Service Setup (Weeks 21-22)</h3>
        <ul>
            <li>Coordinate service schedules with Athens Services</li>
            <li>Deliver waste, recycling, and compost containers</li>
            <li>Set up billing and service agreements</li>
            <li>Train property management staff on operations</li>
        </ul>
        
        <h3>Phase 4: Resident Education (Weeks 23-24)</h3>
        <ul>
            <li>Create resident education materials (flyers, signage)</li>
            <li>Host waste sorting demonstration events</li>
            <li>Install clear, multilingual signage in common areas</li>
            <li>Set up contamination monitoring program</li>
        </ul>
        
        <h3>Phase 5: Monitoring & Optimization (Ongoing)</h3>
        <ul>
            <li>Track monthly waste volumes and costs</li>
            <li>Monitor contamination rates and adjust education</li>
            <li>Quarterly service reviews with Athens Services</li>
            <li>Annual cost benchmarking and optimization</li>
        </ul>
        
        <h2>9. Key Contacts</h2>
        
        <table>
            <tr>
                <th>Organization</th>
                <th>Contact</th>
                <th>Role</th>
            </tr>
            <tr>
                <td>Advantage Waste</td>
                <td>Richard Bates</td>
                <td>Director, Waste & Diversion Strategies</td>
            </tr>
            <tr>
                <td>Athens Services</td>
                <td>Account Manager</td>
                <td>Waste Hauler & Service Provider</td>
            </tr>
            <tr>
                <td>Equipment Vendor</td>
                <td>TBD</td>
                <td>Compactor Sales & Installation</td>
            </tr>
            <tr>
                <td>Greystar Operations</td>
                <td>Property Manager</td>
                <td>On-site Operations Management</td>
            </tr>
        </table>
        
        <h2>10. Appendices</h2>
        
        <h3>Appendix A: Rate Schedule</h3>
        <p>Complete Athens Services 2023 rate schedule available upon request.</p>
        
        <h3>Appendix B: Equipment Specifications</h3>
        <p>Detailed compactor technical specifications and CAD drawings available upon request.</p>
        
        <h3>Appendix C: Regulatory Documents</h3>
        <p>Full text of AB 341, AB 1826, AB 1383, and LA City ordinances available upon request.</p>
        
        <h3>Appendix D: Resident Education Materials</h3>
        <p>Sample flyers, posters, and signage templates available upon request.</p>
        
        <div style="margin-top: 60px; padding-top: 30px; border-top: 2px solid #e2e8f0; text-align: center; color: #718096;">
            <p><strong>Advantage Waste | Greystar Real Estate Partners</strong></p>
            <p>Simplifying waste management for multifamily communities nationwide</p>
            <p style="margin-top: 10px;">Generated: {datetime.now().strftime("%B %d, %Y at %I:%M %p")}</p>
        </div>
    </div>
    
    <script>
        function downloadHTML() {{
            const html = document.documentElement.outerHTML;
            const blob = new Blob([html], {{ type: 'text/html' }});
            const url = URL.createObjectURL(blob);
            const a = document.createElement('a');
            a.href = url;
            a.download = '{project_name.replace(" ", "_")}_Spec_Sheet.html';
            a.click();
        }}
    </script>
</body>
</html>'''
    
    return html

# Generate spec sheet
spec_html = generate_spec_sheet(df, "Bundy Blocks Development", equipment)

# Save to file
with open('/mnt/user-data/outputs/waste_management_spec_sheet.html', 'w') as f:
    f.write(spec_html)

print("โœ“ Spec sheet generated: waste_management_spec_sheet.html")

Required Libraries

  • pandas - Data manipulation and analysis
  • json - Equipment specs and configuration management
  • datetime - Timestamp generation for reports

Example Usage

User prompt: "I have data for a 3-building development project with 620 total units. Can you create a waste management dashboard and spec sheet?"

Claude will:

  1. Load your CSV with building data (units, commercial SF, building names)
  2. Calculate all waste volumes using EPA standards (0.16 CY/unit/week)
  3. Compare three scenarios: loose, compacted waste only, both compacted
  4. Calculate monthly costs including service + labor
  5. Determine payback periods for equipment investment
  6. Generate interactive HTML dashboard with 6 charts
  7. Create comprehensive spec sheet with all calculations, equipment specs, regulatory compliance
  8. Provide both files ready for download/sharing

Output files:

  • waste_management_dashboard.html - Interactive dashboard with Chart.js visualizations
  • waste_management_spec_sheet.html - 20+ page technical document ready to print/PDF

Tips for Best Results

  • Building data CSV should include: building_name, units, commercial_sf (optional), building_type
  • For commercial spaces, specify square footage and type (restaurant vs retail) for accurate calculations
  • Use realistic unit counts (50-500 units per building typical for multifamily)
  • Specify equipment costs in JSON if different from defaults ($43,796.90 per compactor)
  • Include hauler rate schedules if different from Athens Services 2023 rates
  • Dashboard is fully interactive - click building buttons to filter charts
  • Spec sheet can be printed to PDF directly from browser for professional distribution
  • Both files use Advantage Waste/Greystar branding with purple gradient headers