{% extends "base.html" %}
{% block title %}Moment-Curvature - ConcreteDesignPy{% endblock %}

{% block head %}
<script src="https://cdn.jsdelivr.net/npm/plotly.js-dist-min/plotly.min.js"></script>
<style>
.mc-layout { display: flex; gap: 2rem; align-items: flex-start; }
.mc-left { flex: 0 0 480px; }
.mc-right { flex: 1; min-width: 0; }
.mc-right .results-panel { position: sticky; top: 1rem; }
.mc-charts { display: grid; grid-template-columns: 1fr 1fr; gap: 1rem; margin-top: 1rem; }
.report-section {
    background: #fff; border: 1px solid var(--gray-200);
    border-radius: var(--radius); padding: 1.25rem; margin-bottom: 1rem;
}
.report-section h4 {
    font-size: .95rem; color: var(--primary-dark); margin: 0 0 .75rem;
    padding-bottom: .35rem; border-bottom: 2px solid var(--primary-light);
}
.report-eq { padding: .6rem 1rem; border-radius: 4px; margin: .5rem 0; font-size: .9rem; }
.report-ref { font-size: .78rem; color: #3b82f6; font-style: italic; margin: 0; }
.report-table {
    width: 100%; border-collapse: collapse; font-size: .8rem; margin: .5rem 0;
}
.report-table th {
    background: var(--primary-dark); color: #fff; padding: .45rem .6rem;
    text-align: center; font-weight: 600; font-size: .78rem;
}
.report-table td {
    padding: .4rem .6rem; text-align: center; border-bottom: 1px solid var(--gray-200);
    font-family: "SF Mono","Fira Code",monospace; font-size: .8rem;
}
.report-table tr:nth-child(even) { background: var(--gray-50); }
.report-result {
    background: #dcfce7; padding: .6rem 1rem; border-radius: 4px; margin: .5rem 0;
    font-size: .95rem; font-weight: 700;
}
</style>
{% endblock %}

{% block content %}
<div class="calc-page">
    <a href="/" class="back-link">&larr; All Calculators</a>
    <h1>Moment-Curvature Analysis</h1>
    <p class="ref">M-&phi; Diagram &mdash; NSCP 2015 / ACI 318-19</p>

    <div class="mc-layout">
        <div class="mc-left">
            <form id="calc-form" class="calc-form">
                <div class="form-section">
                    <h3>Analysis Mode</h3>
                    <div style="display:flex;gap:.5rem;">
                        <button type="button" id="btn-quick" class="btn-primary" style="flex:1;" onclick="setMode('quick')">Quick (6-Point)</button>
                        <button type="button" id="btn-advanced" class="btn-secondary" style="flex:1;" onclick="setMode('advanced')">Advanced (Incremental)</button>
                    </div>
                </div>
                <div class="form-section">
                    <h3>Section</h3>
                    <div class="form-row">
                        <div class="form-group"><label>Width, b (mm)</label><input type="number" name="b" value="450" required></div>
                        <div class="form-group"><label>Height, h (mm)</label><input type="number" name="h" value="600" required></div>
                        <div class="form-group"><label>Eff. depth, d (mm)</label><input type="number" name="d" value="550" required></div>
                    </div>
                </div>
                <div class="form-section">
                    <h3>Material &amp; Steel</h3>
                    <div class="form-row">
                        <div class="form-group"><label>f'c (MPa)</label><input type="number" name="fc" value="30" step="0.1" required></div>
                        <div class="form-group"><label>fy (MPa)</label><input type="number" name="fy" value="415" step="0.1" required></div>
                    </div>
                    <div class="form-row">
                        <div class="form-group"><label>Bar diameter (mm)</label><input type="number" id="db_tension" name="db_tension" value="25" step="1" required oninput="updateAs()"></div>
                        <div class="form-group"><label>No. of bars, n</label><input type="number" id="n_tension" name="n_tension" value="4" min="1" step="1" required oninput="updateAs()"></div>
                    </div>
                    <div class="form-row">
                        <div class="form-group"><label>As tension (mm&sup2;)</label><input type="number" id="as_tension" name="as_tension" value="1963.50" step="0.01" readonly style="background:#f3f4f6;"></div>
                        <div class="form-group"><label>Es (MPa)</label><input type="number" name="es" value="200000"></div>
                    </div>
                </div>
                <div class="form-section" id="axial-section" style="display:none;">
                    <h3>Loading</h3>
                    <div class="form-row">
                        <div class="form-group"><label>Axial Load, P (kN)</label><input type="number" name="axial_load" value="0" step="1"><p style="font-size:.75rem;color:var(--gray-400);margin:.25rem 0 0;">+ compression, - tension</p></div>
                    </div>
                </div>
                <button type="submit" class="btn-primary" style="width:100%;">Analyze</button>
            </form>
        </div>

        <div class="mc-right">
            <div id="results" class="results-panel" style="display:none;">
                <h2>Results</h2>
                <div id="results-summary"></div>
                <div id="chart-mphi" style="width:100%;"></div>
            </div>
        </div>
    </div>

    <div class="mc-charts" style="display:none;" id="charts-row">
        <div id="chart-section" style="width:100%;"></div>
        <div id="chart-strain-stress" style="width:100%;"></div>
    </div>

    <div id="results-report" style="display:none; margin-top:1.5rem;"></div>
</div>

<script>
var currentMode = 'quick';

function updateAs() {
    var db = parseFloat(document.getElementById('db_tension').value) || 0;
    var n = parseInt(document.getElementById('n_tension').value) || 0;
    var as = n * Math.PI * db * db / 4;
    document.getElementById('as_tension').value = as.toFixed(2);
}
updateAs();

function setMode(mode) {
    currentMode = mode;
    document.getElementById('btn-quick').className = mode === 'quick' ? 'btn-primary' : 'btn-secondary';
    document.getElementById('btn-advanced').className = mode === 'advanced' ? 'btn-primary' : 'btn-secondary';
    document.getElementById('axial-section').style.display = mode === 'advanced' ? '' : 'none';
}

document.getElementById('calc-form').addEventListener('submit', function(e) {
    e.preventDefault();
    var form = this;
    var payload = {
        b: parseFloat(form.b.value), h: parseFloat(form.h.value),
        d: parseFloat(form.d.value), fc: parseFloat(form.fc.value),
        fy: parseFloat(form.fy.value), as_tension: parseFloat(form.as_tension.value),
        es: parseFloat(form.es.value),
    };

    if (currentMode === 'advanced') {
        payload.axial_load = parseFloat(form.axial_load.value) || 0;
        // Run both quick and advanced in parallel
        var quickDone = false, advDone = false;
        var quickResult = null, advResult = null;
        function onBothDone() {
            if (!quickDone || !advDone) return;
            var pts = quickResult.points || [];
            var sp = quickResult.section_properties || {};
            var advPts = advResult.points || [];
            var hog = advResult.hognestad_params || {};
            renderResultsBoth(payload, pts, sp, advPts, hog);
        }
        submitCalc('/api/section/moment-curvature', payload, function(r) { quickResult = r; quickDone = true; onBothDone(); });
        submitCalc('/api/section/moment-curvature-advanced', payload, function(r) { advResult = r; advDone = true; onBothDone(); });
        return;
    }

    submitCalc('/api/section/moment-curvature', payload, function(result) {
        var pts = result.points || [];
        var sp = result.section_properties || {};

        // ── Summary Table ──
        var s = '<table class="report-table">';
        s += '<tr><th>Point</th><th>Event</th><th>&phi; (1/mm)</th><th>M (kN-m)</th></tr>';
        for (var i = 0; i < pts.length; i++) {
            var p = pts[i];
            s += '<tr><td>P' + p.point + '</td><td style="text-align:left;">' + p.event + '</td>';
            s += '<td>' + (p.phi ? p.phi.toExponential(4) : '0') + '</td>';
            s += '<td>' + (p.moment_knm || 0).toFixed(2) + '</td></tr>';
        }
        s += '</table>';
        document.getElementById('results-summary').innerHTML = s;

        // ── Chart 1: M-phi Plotly ──
        renderMPhiChart(pts);

        // ── Chart 2: Section Visualization ──
        renderSectionChart(payload, sp);

        // ── Chart 3: Strain-Stress at Ultimate ──
        renderStrainStressChart(payload, sp, pts);

        // Show charts row
        document.getElementById('charts-row').style.display = '';

        // ── Full Report ──
        renderReport(payload, sp, pts);
    });
});

function renderResultsBoth(payload, pts, sp, advPts, hog) {
    // Summary table for 6-point
    var s = '<h3 style="margin:0 0 .5rem;">Quick (6-Point) Results</h3>';
    s += '<table class="report-table">';
    s += '<tr><th>Point</th><th>Event</th><th>&phi; (1/mm)</th><th>M (kN-m)</th></tr>';
    for (var i = 0; i < pts.length; i++) {
        var p = pts[i];
        s += '<tr><td>P' + p.point + '</td><td style="text-align:left;">' + p.event + '</td>';
        s += '<td>' + (p.phi ? p.phi.toExponential(4) : '0') + '</td>';
        s += '<td>' + (p.moment_knm || 0).toFixed(2) + '</td></tr>';
    }
    s += '</table>';
    document.getElementById('results-summary').innerHTML = s;

    // M-phi chart with both curves
    renderMPhiChartBoth(pts, advPts);

    // Section and strain/stress charts
    renderSectionChart(payload, sp);

    // Hognestad stress-strain chart instead of linear strain/stress
    renderHognestadChart(hog);

    document.getElementById('charts-row').style.display = '';

    // Report
    renderAdvancedReport(payload, sp, pts, advPts, hog);
}

function renderMPhiChartBoth(pts, advPts) {
    var traces = [];

    // Advanced smooth curve
    if (advPts.length > 0) {
        var advPhis = [0], advM = [0];
        for (var i = 0; i < advPts.length; i++) {
            advPhis.push(advPts[i].phi || 0);
            advM.push(advPts[i].moment_knm || 0);
        }
        traces.push({
            x: advPhis, y: advM, mode: 'lines',
            name: 'Advanced (Hognestad)',
            line: { color: '#dc2626', width: 2.5 },
        });
    }

    // 6-point curve
    var phis = [0], moments = [0];
    for (var i = 0; i < pts.length; i++) {
        phis.push(pts[i].phi || 0);
        moments.push(pts[i].moment_knm || 0);
    }
    traces.push({
        x: phis, y: moments, mode: 'lines+markers',
        name: 'Quick (6-Point)',
        line: { color: '#2563eb', width: 2, dash: 'dash' },
        marker: { size: 8, color: '#2563eb' },
    });

    // Point labels
    for (var j = 0; j < pts.length; j++) {
        traces.push({
            x: [pts[j].phi], y: [pts[j].moment_knm],
            mode: 'markers+text', showlegend: false,
            marker: { size: 8, color: '#2563eb', symbol: 'circle' },
            text: ['P' + pts[j].point], textposition: 'top right',
            textfont: { size: 9, color: '#2563eb' },
        });
    }

    var layout = {
        title: { text: 'Moment-Curvature Diagram', font: { size: 14 } },
        xaxis: { title: 'Curvature, \u03c6 (1/mm)', rangemode: 'tozero', gridcolor: '#e5e7eb', tickformat: '.2e' },
        yaxis: { title: 'Moment, M (kN-m)', rangemode: 'tozero', gridcolor: '#e5e7eb' },
        height: 450,
        margin: { t: 40, r: 20, b: 60, l: 70 },
        plot_bgcolor: '#fff', paper_bgcolor: '#fff',
        showlegend: true,
        legend: { x: 1, xanchor: 'right', y: 0.05, bgcolor: 'rgba(255,255,255,0.85)', font: { size: 10 } },
        hovermode: 'closest',
    };
    Plotly.newPlot('chart-mphi', traces, layout, { responsive: true, displayModeBar: false });
}

function renderHognestadChart(hog) {
    if (!hog || !hog.strains) return;
    var traces = [{
        x: hog.strains, y: hog.stresses, mode: 'lines',
        name: 'Hognestad Model',
        line: { color: '#dc2626', width: 2.5 },
        fill: 'tozeroy', fillcolor: 'rgba(220,38,38,0.08)',
    }];
    // Mark eco and ecu
    var ecoStress = hog.fc;
    var ecuStress = 0.85 * hog.fc;
    traces.push({
        x: [hog.eco, hog.ecu], y: [ecoStress, ecuStress],
        mode: 'markers+text', showlegend: false,
        marker: { size: 10, color: '#1e40af', symbol: 'diamond' },
        text: ['\u03b5co=' + hog.eco.toFixed(4), '\u03b5cu=' + hog.ecu],
        textposition: ['top center', 'top center'],
        textfont: { size: 9, color: '#1e40af' },
    });

    var layout = {
        title: { text: 'Hognestad Concrete Stress-Strain Model', font: { size: 14 } },
        xaxis: { title: 'Strain, \u03b5c', rangemode: 'tozero', gridcolor: '#e5e7eb' },
        yaxis: { title: 'Stress (MPa)', rangemode: 'tozero', gridcolor: '#e5e7eb' },
        height: 450,
        margin: { t: 40, r: 20, b: 60, l: 60 },
        plot_bgcolor: '#fff', paper_bgcolor: '#fff',
        showlegend: false,
    };
    Plotly.newPlot('chart-strain-stress', traces, layout, { responsive: true, displayModeBar: false });
}

function renderAdvancedReport(payload, sp, pts, advPts, hog) {
    var h = '';

    h += '<div class="report-section">';
    h += '<h4>Advanced Analysis &mdash; Hognestad Concrete Model with Fiber Approach</h4>';
    h += '<p class="report-ref">Hognestad Parabolic Concrete Model</p>';

    h += '<p style="font-size:.85rem;margin-top:.75rem;"><b>Concrete Model (Hognestad):</b></p>';
    h += '<div class="report-eq">\\[ \\varepsilon_{co} = \\frac{2 f\'_c}{E_c} = \\frac{2 \\times ' + payload.fc + '}{' + sp.ec_mod + '} = ' + hog.eco + ' \\]</div>';
    h += '<div class="report-eq">\\[ \\text{Ascending: } f_c = f\'_c \\left( \\frac{2\\varepsilon_c}{\\varepsilon_{co}} - \\left(\\frac{\\varepsilon_c}{\\varepsilon_{co}}\\right)^2 \\right) \\quad \\text{for } \\varepsilon_c \\leq \\varepsilon_{co} \\]</div>';
    h += '<div class="report-eq">\\[ \\text{Descending: } f_c = f\'_c \\left( 1 - 0.15 \\frac{\\varepsilon_c - \\varepsilon_{co}}{\\varepsilon_{cu} - \\varepsilon_{co}} \\right) \\quad \\text{for } \\varepsilon_{co} < \\varepsilon_c \\leq \\varepsilon_{cu} \\]</div>';

    h += '<p style="font-size:.85rem;margin-top:.75rem;"><b>Steel Model:</b> Elastic-perfectly-plastic</p>';
    h += '<div class="report-eq">\\[ f_s = \\min(E_s \\cdot \\varepsilon_s, \\, f_y) \\]</div>';

    if (payload.axial_load && payload.axial_load !== 0) {
        h += '<p style="font-size:.85rem;"><b>Axial Load:</b> P = ' + payload.axial_load + ' kN (' + (payload.axial_load > 0 ? 'compression' : 'tension') + ')</p>';
    }
    h += '</div>';

    // Incremental results table
    h += '<div class="report-section">';
    h += '<h4>Incremental M-&phi; Results (60 steps)</h4>';
    h += '<div style="max-height:400px;overflow-y:auto;border:1px solid var(--gray-200);border-radius:4px;">';
    h += '<table class="report-table">';
    h += '<tr><th>Step</th><th>&epsilon;<sub>c,top</sub></th><th>c (mm)</th><th>&phi; (1/mm)</th><th>M (kN-m)</th></tr>';
    for (var i = 0; i < advPts.length; i++) {
        var ap = advPts[i];
        h += '<tr><td>' + (i+1) + '</td><td>' + ap.ec_top.toFixed(6) + '</td><td>' + ap.c + '</td>';
        h += '<td>' + ap.phi.toExponential(4) + '</td><td>' + ap.moment_knm + '</td></tr>';
    }
    h += '</table></div>';
    h += '</div>';

    // Comparison
    h += '<div class="report-section">';
    h += '<h4>QAQC &mdash; Quick vs Advanced Comparison</h4>';
    h += '<table class="report-table">';
    h += '<tr><th>Parameter</th><th>Quick (6-Point)</th><th>Advanced (Hognestad)</th></tr>';
    var quickUlt = pts.length > 0 ? pts[pts.length - 1] : { moment_knm: 0, phi: 0 };
    var advUlt = advPts.length > 0 ? advPts[advPts.length - 1] : { moment_knm: 0, phi: 0 };
    h += '<tr><td style="text-align:left;">Ultimate Moment (kN-m)</td><td>' + quickUlt.moment_knm + '</td><td>' + advUlt.moment_knm + '</td></tr>';
    h += '<tr><td style="text-align:left;">Ultimate Curvature (1/mm)</td><td>' + (quickUlt.phi ? quickUlt.phi.toExponential(4) : '0') + '</td><td>' + (advUlt.phi ? advUlt.phi.toExponential(4) : '0') + '</td></tr>';
    var mDiff = quickUlt.moment_knm !== 0 ? (((advUlt.moment_knm - quickUlt.moment_knm) / quickUlt.moment_knm) * 100).toFixed(1) : 'N/A';
    h += '<tr><td style="text-align:left;">Moment Difference</td><td colspan="2">' + mDiff + '%</td></tr>';
    h += '<tr><td style="text-align:left;">Concrete Model</td><td>Whitney Block</td><td>Hognestad Parabolic</td></tr>';
    h += '<tr><td style="text-align:left;">Curve Resolution</td><td>6 points</td><td>' + advPts.length + ' points</td></tr>';
    h += '</table>';
    h += '</div>';

    document.getElementById('results-report').style.display = '';
    document.getElementById('results-report').innerHTML = h;
    if (window.MathJax) MathJax.typeset();
}

function renderMPhiChart(pts) {
    var phis = [0], moments = [0];
    for (var i = 0; i < pts.length; i++) {
        phis.push(pts[i].phi || 0);
        moments.push(pts[i].moment_knm || 0);
    }

    var traces = [
        {
            x: phis, y: moments, mode: 'lines+markers',
            name: 'M-\u03c6 Curve',
            line: { color: '#2563eb', width: 2.5 },
            marker: { size: 8, color: '#2563eb' },
        },
    ];

    // Add point labels
    for (var j = 0; j < pts.length; j++) {
        traces.push({
            x: [pts[j].phi], y: [pts[j].moment_knm],
            mode: 'markers+text', showlegend: false,
            marker: { size: 10, color: '#dc2626', symbol: 'circle' },
            text: ['P' + pts[j].point],
            textposition: 'top right',
            textfont: { size: 10, color: '#dc2626', family: 'Arial' },
        });
    }

    var layout = {
        title: { text: 'Moment-Curvature Diagram', font: { size: 14 } },
        xaxis: { title: 'Curvature, \u03c6 (1/mm)', rangemode: 'tozero', gridcolor: '#e5e7eb', tickformat: '.2e' },
        yaxis: { title: 'Moment, M (kN-m)', rangemode: 'tozero', gridcolor: '#e5e7eb' },
        height: 450,
        margin: { t: 40, r: 20, b: 60, l: 70 },
        plot_bgcolor: '#fff', paper_bgcolor: '#fff',
        showlegend: false,
        hovermode: 'closest',
    };
    Plotly.newPlot('chart-mphi', traces, layout, { responsive: true, displayModeBar: false });
}

function renderSectionChart(payload, sp) {
    var b = payload.b, h = payload.h, d = payload.d;
    var kd = sp.kd || 0;
    var cover = h - d;

    // Build section shapes
    var shapes = [
        // Outer section rectangle
        { type: 'rect', x0: 0, y0: 0, x1: b, y1: h, line: { color: '#333', width: 2 }, fillcolor: 'rgba(200,200,200,0.15)' },
        // Neutral axis line
        { type: 'line', x0: -30, y0: h - kd, x1: b + 30, y1: h - kd, line: { color: '#dc2626', width: 2, dash: 'dash' } },
        // Effective depth line
        { type: 'line', x0: -20, y0: h - d, x1: b + 20, y1: h - d, line: { color: '#2563eb', width: 1.5, dash: 'dot' } },
    ];

    // Tension rebar (bottom)
    var nBars = Math.round(payload.as_tension / (Math.PI * 12.5 * 12.5));
    if (nBars < 2) nBars = 2;
    if (nBars > 10) nBars = 10;
    var barR = 12;
    var spacing = (b - 2 * cover) / (nBars - 1);
    var rebarX = [], rebarY = [];
    for (var i = 0; i < nBars; i++) {
        var cx = cover + i * spacing;
        rebarX.push(cx);
        rebarY.push(h - d);
    }

    var traces = [
        // Rebar markers
        {
            x: rebarX, y: rebarY, mode: 'markers', name: 'Tension Steel',
            marker: { size: 14, color: '#1e40af', symbol: 'circle', line: { width: 2, color: '#fff' } },
        },
        // Compression zone fill
        {
            x: [0, b, b, 0, 0], y: [h, h, h - kd, h - kd, h],
            fill: 'toself', fillcolor: 'rgba(239,68,68,0.15)',
            line: { color: 'rgba(239,68,68,0.4)', width: 1 },
            name: 'Compression Zone', mode: 'lines',
        },
    ];

    var annotations = [
        { x: b + 40, y: h - kd, text: 'NA (kd=' + kd.toFixed(1) + ')', showarrow: false, font: { size: 10, color: '#dc2626' } },
        { x: b + 40, y: h - d, text: 'd=' + d + 'mm', showarrow: false, font: { size: 10, color: '#2563eb' } },
        { x: b / 2, y: h + 25, text: 'b=' + b + 'mm', showarrow: false, font: { size: 10, color: '#333' } },
        { x: -45, y: h / 2, text: 'h=' + h + 'mm', showarrow: false, font: { size: 10, color: '#333' }, textangle: -90 },
    ];

    var layout = {
        title: { text: 'Cross-Section', font: { size: 14 } },
        xaxis: { visible: false, range: [-80, b + 100], scaleanchor: 'y' },
        yaxis: { visible: false, range: [-30, h + 50] },
        shapes: shapes,
        annotations: annotations,
        height: 450,
        margin: { t: 40, r: 20, b: 20, l: 20 },
        plot_bgcolor: '#fff', paper_bgcolor: '#fff',
        showlegend: false,
    };
    Plotly.newPlot('chart-section', traces, layout, { responsive: true, displayModeBar: false });
}

function renderStrainStressChart(payload, sp, pts) {
    var H = payload.h, d = payload.d, b = payload.b;
    var kd = sp.kd || 0;
    var fc = payload.fc, fy = payload.fy, es = payload.es;
    var ecu = 0.003;
    var cover = H - d;

    // Strain values
    var strainTop = ecu;
    var strainNA = 0;
    var strainAtD = -ecu * (d - kd) / kd;
    var strainBot = -ecu * (H - kd) / kd;

    // Stress values (Whitney block)
    var beta1 = sp.beta1 || 0.85;
    var a = beta1 * kd;
    var stressBlock = 0.85 * fc;
    var stressSteel = Math.min(Math.abs(strainAtD) * es, fy);

    // Use subplots: [section] [strain] [stress] [forces]
    var traces = [];

    // ── Panel 1: Section outline (x1) ──
    traces.push({
        x: [0, b, b, 0, 0], y: [0, 0, H, H, 0],
        mode: 'lines', line: { color: '#333', width: 2 },
        xaxis: 'x', yaxis: 'y', showlegend: false, hoverinfo: 'skip',
    });
    // Compression zone fill
    traces.push({
        x: [0, b, b, 0, 0], y: [H, H, H - a, H - a, H],
        fill: 'toself', fillcolor: 'rgba(220,38,38,0.12)',
        line: { color: 'rgba(220,38,38,0.4)', width: 1 },
        xaxis: 'x', yaxis: 'y', showlegend: false, hoverinfo: 'skip',
    });
    // Tension rebar
    var nBars = Math.round(payload.as_tension / (Math.PI * 12.5 * 12.5));
    if (nBars < 2) nBars = 2; if (nBars > 8) nBars = 8;
    var barSpacing = (b - 2 * cover) / Math.max(nBars - 1, 1);
    var rebarX = [], rebarY = [];
    for (var i = 0; i < nBars; i++) { rebarX.push(cover + i * barSpacing); rebarY.push(H - d); }
    traces.push({
        x: rebarX, y: rebarY, mode: 'markers',
        marker: { size: 10, color: '#1e40af', symbol: 'circle', line: { width: 1.5, color: '#fff' } },
        xaxis: 'x', yaxis: 'y', showlegend: false, hoverinfo: 'skip',
    });

    // ── Panel 2: Strain diagram (x2) ──
    traces.push({
        x: [strainTop, strainNA, strainBot],
        y: [H, H - kd, 0],
        mode: 'lines', line: { color: '#dc2626', width: 2.5 },
        xaxis: 'x2', yaxis: 'y', name: 'Strain Profile', showlegend: false,
    });
    // Strain fill (compression side)
    traces.push({
        x: [0, strainTop, strainNA, 0], y: [H, H, H - kd, H - kd],
        fill: 'toself', fillcolor: 'rgba(220,38,38,0.08)',
        line: { width: 0 }, xaxis: 'x2', yaxis: 'y', showlegend: false, hoverinfo: 'skip',
    });
    // Strain fill (tension side)
    traces.push({
        x: [0, strainNA, strainBot, 0], y: [H - kd, H - kd, 0, 0],
        fill: 'toself', fillcolor: 'rgba(37,99,235,0.08)',
        line: { width: 0 }, xaxis: 'x2', yaxis: 'y', showlegend: false, hoverinfo: 'skip',
    });

    // ── Panel 3: Stress diagram (x3) ──
    // Whitney rectangular block
    traces.push({
        x: [0, stressBlock, stressBlock, 0],
        y: [H, H, H - a, H - a],
        fill: 'toself', fillcolor: 'rgba(220,38,38,0.2)',
        line: { color: '#dc2626', width: 2 },
        xaxis: 'x3', yaxis: 'y', name: '0.85f\'c Block', showlegend: false,
    });
    // Steel stress as arrow-like marker
    traces.push({
        x: [0, -stressSteel], y: [H - d, H - d],
        mode: 'lines+markers', line: { color: '#1e40af', width: 2.5 },
        marker: { size: [0, 8], symbol: ['circle', 'triangle-left'], color: '#1e40af' },
        xaxis: 'x3', yaxis: 'y', name: 'fs = ' + stressSteel.toFixed(0) + ' MPa', showlegend: false,
    });

    // ── Panel 4: Internal forces (x4) ──
    var Cc = stressBlock * a * b / 1000; // kN
    var Ts = stressSteel * payload.as_tension / 1000; // kN
    // Compression force arrow
    traces.push({
        x: [0, Cc], y: [H - a / 2, H - a / 2],
        mode: 'lines+markers', line: { color: '#dc2626', width: 3 },
        marker: { size: [0, 10], symbol: ['circle', 'triangle-right'], color: '#dc2626' },
        xaxis: 'x4', yaxis: 'y', showlegend: false,
    });
    // Tension force arrow
    traces.push({
        x: [0, -Ts], y: [H - d, H - d],
        mode: 'lines+markers', line: { color: '#1e40af', width: 3 },
        marker: { size: [0, 10], symbol: ['circle', 'triangle-left'], color: '#1e40af' },
        xaxis: 'x4', yaxis: 'y', showlegend: false,
    });

    // NA line across all panels
    var shapes = [];
    ['x', 'x2', 'x3', 'x4'].forEach(function(xa) {
        shapes.push({
            type: 'line', x0: 0, x1: 1, y0: H - kd, y1: H - kd,
            xref: xa + ' domain', line: { color: '#666', width: 1.5, dash: 'dashdot' },
        });
    });

    var annotations = [
        // Panel titles
        { x: 0.06, y: 1.06, xref: 'paper', yref: 'paper', text: '<b>Section</b>', showarrow: false, font: { size: 11, color: '#333' } },
        { x: 0.32, y: 1.06, xref: 'paper', yref: 'paper', text: '<b>Strain</b>', showarrow: false, font: { size: 11, color: '#333' } },
        { x: 0.60, y: 1.06, xref: 'paper', yref: 'paper', text: '<b>Stress (MPa)</b>', showarrow: false, font: { size: 11, color: '#333' } },
        { x: 0.88, y: 1.06, xref: 'paper', yref: 'paper', text: '<b>Forces (kN)</b>', showarrow: false, font: { size: 11, color: '#333' } },
        // Key values
        { x: strainTop, y: H, xref: 'x2', text: '\u03b5cu=' + strainTop.toFixed(4), showarrow: false, font: { size: 9, color: '#dc2626' }, yshift: 8 },
        { x: strainAtD, y: H - d, xref: 'x2', text: '\u03b5s=' + strainAtD.toFixed(4), showarrow: false, font: { size: 9, color: '#1e40af' }, yshift: -12 },
        { x: stressBlock / 2, y: H - a / 2, xref: 'x3', text: (stressBlock).toFixed(1), showarrow: false, font: { size: 9, color: '#fff', family: 'Arial Black' } },
        { x: Cc / 2, y: H - a / 2, xref: 'x4', text: 'Cc=' + Cc.toFixed(0), showarrow: false, font: { size: 9, color: '#dc2626' }, yshift: 12 },
        { x: -Ts / 2, y: H - d, xref: 'x4', text: 'Ts=' + Ts.toFixed(0), showarrow: false, font: { size: 9, color: '#1e40af' }, yshift: -12 },
        // NA label
        { x: 1.02, y: H - kd, xref: 'x4 domain', text: 'N.A.', showarrow: false, font: { size: 9, color: '#666' } },
        // Dimension labels
        { x: -0.02, y: H - a, xref: 'x3 domain', text: 'a=' + a.toFixed(1), showarrow: false, font: { size: 8, color: '#dc2626' }, xanchor: 'right' },
    ];

    var layout = {
        title: { text: 'Section Analysis at Ultimate Limit State', font: { size: 14 }, y: 0.98 },
        yaxis: { title: 'Depth (mm)', range: [-10, H + 30], gridcolor: '#f0f0f0', zeroline: false },
        xaxis:  { domain: [0, 0.15], visible: false, range: [-20, b + 20] },
        xaxis2: { domain: [0.20, 0.42], zeroline: true, zerolinecolor: '#999', zerolinewidth: 1.5, gridcolor: '#f0f0f0', tickformat: '.3f', title: '' },
        xaxis3: { domain: [0.48, 0.72], zeroline: true, zerolinecolor: '#999', zerolinewidth: 1.5, gridcolor: '#f0f0f0', title: '' },
        xaxis4: { domain: [0.78, 1.0], zeroline: true, zerolinecolor: '#999', zerolinewidth: 1.5, gridcolor: '#f0f0f0', title: '' },
        height: 500,
        margin: { t: 50, r: 30, b: 30, l: 60 },
        plot_bgcolor: '#fff', paper_bgcolor: '#fff',
        showlegend: false,
        shapes: shapes,
        annotations: annotations,
    };
    Plotly.newPlot('chart-strain-stress', traces, layout, { responsive: true, displayModeBar: false });
}

function renderReport(payload, sp, pts) {
    var h = '';

    // Section Properties
    h += '<div class="report-section">';
    h += '<h4>1. Section Properties</h4>';
    h += '<p class="report-ref">NSCP 2015 / ACI 318-19</p>';
    h += '<div class="report-eq">\\[ E_c = 4700\\sqrt{f\'_c} = 4700\\sqrt{' + payload.fc + '} = ' + sp.ec + ' \\text{ MPa} \\]</div>';
    h += '<div class="report-eq">\\[ n = \\frac{E_s}{E_c} = \\frac{' + payload.es + '}{' + sp.ec + '} = ' + sp.n + ' \\]</div>';
    h += '<div class="report-eq">\\[ f_r = 0.62\\sqrt{f\'_c} = 0.62\\sqrt{' + payload.fc + '} = ' + sp.fr + ' \\text{ MPa} \\]</div>';
    h += '</div>';

    // Uncracked Section
    h += '<div class="report-section">';
    h += '<h4>2. Uncracked Transformed Section</h4>';
    h += '<div class="report-eq">\\[ I_g = \\frac{bh^3}{12} = \\frac{' + payload.b + ' \\times ' + payload.h + '^3}{12} = ' + sp.ig.toExponential(4) + ' \\text{ mm}^4 \\]</div>';
    h += '<div class="report-eq">\\[ \\bar{y} = ' + sp.y_bar + ' \\text{ mm (from top)} \\]</div>';
    h += '<div class="report-eq">\\[ I_t = ' + sp.it.toExponential(4) + ' \\text{ mm}^4 \\text{ (transformed)} \\]</div>';
    h += '</div>';

    // Cracked Section
    h += '<div class="report-section">';
    h += '<h4>3. Cracked Section Analysis</h4>';
    h += '<div class="report-eq">\\[ \\frac{b}{2} k_d^2 + n A_s k_d - n A_s d = 0 \\]</div>';
    h += '<div class="report-eq">\\[ k_d = ' + sp.kd + ' \\text{ mm (cracked neutral axis depth)} \\]</div>';
    h += '<div class="report-eq">\\[ I_{cr} = \\frac{b \\cdot k_d^3}{3} + n A_s (d - k_d)^2 = ' + sp.icr.toExponential(4) + ' \\text{ mm}^4 \\]</div>';
    h += '</div>';

    // 6-Point M-phi Table
    h += '<div class="report-section">';
    h += '<h4>4. 6-Point Moment-Curvature Results</h4>';
    h += '<table class="report-table">';
    h += '<tr><th>Point</th><th>Event</th><th>&phi; (1/mm)</th><th>&phi; (rad/m)</th><th>M (kN-m)</th></tr>';
    for (var i = 0; i < pts.length; i++) {
        var p = pts[i];
        var phiRadM = ((p.phi || 0) * 1000).toExponential(4);
        h += '<tr><td>P' + p.point + '</td><td style="text-align:left;">' + p.event + '</td>';
        h += '<td>' + (p.phi ? p.phi.toExponential(4) : '0') + '</td>';
        h += '<td>' + phiRadM + '</td>';
        h += '<td>' + (p.moment_knm || 0).toFixed(2) + '</td></tr>';
    }
    h += '</table>';
    h += '</div>';

    // Key Calculations for Each Point
    h += '<div class="report-section">';
    h += '<h4>5. Key Point Derivations</h4>';

    h += '<p style="font-size:.85rem;margin-top:.5rem;"><b>P1 &mdash; Just Before Cracking:</b></p>';
    h += '<div class="report-eq">\\[ M_{cr} = \\frac{f_r \\cdot I_t}{h - \\bar{y}} \\quad ; \\quad \\phi_1 = \\frac{M_{cr}}{E_c \\cdot I_t} \\]</div>';

    h += '<p style="font-size:.85rem;margin-top:.5rem;"><b>P2 &mdash; Just After Cracking:</b></p>';
    h += '<div class="report-eq">\\[ M = M_{cr} \\quad ; \\quad \\phi_2 = \\frac{M_{cr}}{E_c \\cdot I_{cr}} \\]</div>';

    h += '<p style="font-size:.85rem;margin-top:.5rem;"><b>P3 &mdash; Elastic Limit (0.45f\'c):</b></p>';
    h += '<div class="report-eq">\\[ \\varepsilon_c = \\frac{0.45 f\'_c}{E_c} \\quad ; \\quad \\phi_3 = \\frac{\\varepsilon_c}{k_d} \\]</div>';

    h += '<p style="font-size:.85rem;margin-top:.5rem;"><b>P4 &mdash; Steel Yields:</b></p>';
    h += '<div class="report-eq">\\[ \\varepsilon_y = \\frac{f_y}{E_s} \\quad ; \\quad \\phi_4 = \\frac{\\varepsilon_y}{d - k_d} \\]</div>';

    h += '<p style="font-size:.85rem;margin-top:.5rem;"><b>P5 &mdash; Concrete Peak Strain (&epsilon;<sub>co</sub> = 0.002):</b></p>';
    h += '<div class="report-eq">\\[ c = \\frac{A_s f_y}{0.85 f\'_c \\beta_1 b} \\quad ; \\quad \\phi_5 = \\frac{\\varepsilon_{co}}{c} \\]</div>';

    h += '<p style="font-size:.85rem;margin-top:.5rem;"><b>P6 &mdash; Concrete Ultimate (&epsilon;<sub>cu</sub> = 0.003):</b></p>';
    h += '<div class="report-eq">\\[ \\phi_6 = \\frac{\\varepsilon_{cu}}{c} \\quad ; \\quad M_u = A_s f_y \\left(d - \\frac{a}{2}\\right) \\]</div>';
    h += '</div>';

    // QAQC Comparison
    h += '<div class="report-section">';
    h += '<h4>6. QAQC &mdash; Method Comparison</h4>';
    h += '<p class="report-ref">Comparison between simplified 6-point method (this tool) and fiber layer method (Excel reference)</p>';
    h += '<table class="report-table">';
    h += '<tr><th>Aspect</th><th>This Tool (6-Point)</th><th>Excel (Fiber Layer)</th></tr>';
    h += '<tr><td style="text-align:left;">Method</td><td>Closed-form 6 key points</td><td>20-layer fiber discretization</td></tr>';
    h += '<tr><td style="text-align:left;">Curvature range</td><td>0 to &epsilon;<sub>cu</sub>/c</td><td>0 to &epsilon;<sub>y</sub> (incremental)</td></tr>';
    h += '<tr><td style="text-align:left;">Axial load</td><td>Not included (pure flexure)</td><td>Included (P = ' + 194 + ' kips)</td></tr>';
    h += '<tr><td style="text-align:left;">Stress-strain model</td><td>Linear elastic + Whitney block</td><td>Elastic-perfectly-plastic steel, parabolic concrete</td></tr>';
    h += '<tr><td style="text-align:left;">Units</td><td>SI (MPa, mm, kN-m)</td><td>Imperial (ksi, in, in-kips)</td></tr>';
    h += '<tr><td style="text-align:left;">Resolution</td><td>6 discrete points</td><td>20 incremental points</td></tr>';
    h += '<tr><td style="text-align:left;">Best for</td><td>Quick design checks, code compliance</td><td>Detailed nonlinear analysis, P-M interaction</td></tr>';
    h += '</table>';

    h += '<p style="font-size:.85rem;margin-top:.75rem;"><b>Validation Notes:</b></p>';
    h += '<ul style="font-size:.85rem;color:var(--gray-600);margin:.25rem 0 0 1.5rem;">';
    h += '<li>Both methods produce bilinear-like curves with initial stiff (uncracked) and post-cracking regions</li>';
    h += '<li>Cracking moment and yield point should be close between methods for same section properties</li>';
    h += '<li>The fiber method captures nonlinear stress distribution more accurately near ultimate</li>';
    h += '<li>For pure flexure without axial load, the 6-point method provides reliable design values per ACI 318</li>';
    h += '</ul>';
    h += '</div>';

    document.getElementById('results-report').style.display = '';
    document.getElementById('results-report').innerHTML = h;
    if (window.MathJax) MathJax.typeset();
}
</script>
{% endblock %}
