App._effPeriod = '7d';
App.renderEfficiency = function() {
      var self = this;
      var period = this._effPeriod || '7d';
      var effTab = this._effTab || 'performance';
      var tabBar = '<div class="tabs" style="margin-bottom:1rem">'
        + '<button data-eff-tab="performance"' + (effTab === 'performance' ? ' class="active"' : '') + '>Performance</button>'
        + '<button data-eff-tab="recommendations"' + (effTab === 'recommendations' ? ' class="active"' : '') + '>Recommendations</button>'
        + '</div>';
      if (effTab === 'recommendations') {
        var quickTips = self._quickTipsHtml || '';
        return this.renderRecommendations().then(function(recommendationsHtml) {
          return tabBar + quickTips + '<div style="margin-top:1.5rem"></div>' + recommendationsHtml;
        });
      }
      return Promise.all([
        api('/api/stats/efficiency?period=' + encodeURIComponent(period)),
        api('/api/models/selections?limit=80').catch(function() { return { events: [] }; }),
        api('/api/models/routing-diagnostics').catch(function() { return { config: {} }; }),
        api('/api/config').catch(function() { return {}; })
      ]).then(function(arr) {
        var report = arr[0] || {};
        var modelSelections = (arr[1] && arr[1].events) ? arr[1].events : [];
        var configData = arr[3] || {};
        var persistedRoutingConfig = (configData && configData.models && configData.models.routing) ? configData.models.routing : {};
        var routingConfig = Object.assign({}, (arr[2] && arr[2].config) ? arr[2].config : {}, persistedRoutingConfig);
        var routingProfile = deriveRoutingProfile(routingConfig);
        App._routingProfileDefaults = normalizeRoutingProfile(routingProfile);
        if (!App._routingProfileDraft) App._routingProfileDraft = normalizeRoutingProfile({ correctness: routingProfile.correctness, cost: routingProfile.cost, speed: routingProfile.speed });
        App._routingProfileDraft = normalizeRoutingProfile(App._routingProfileDraft);

        var models = report.models || {};
        var ts = report.time_series || [];
        var totals = report.totals || {};
        var modelNames = Object.keys(models).sort(function(a, b) {
          return (models[b].cost.total || 0) - (models[a].cost.total || 0);
        });

        var spider = renderRoutingSpiderSvg(App._routingProfileDraft || routingProfile);
        var persistedLabel = '';
        if (App._routingProfilePersistedAt) {
          var savedAt = new Date(App._routingProfilePersistedAt);
          var savedText = Number.isNaN(savedAt.getTime()) ? App._routingProfilePersistedAt : savedAt.toLocaleString();
          persistedLabel = '<div style="margin-top:0.45rem;font-size:0.6875rem;color:var(--muted)">'
            + (App._routingProfilePersisted ? 'Saved to config: ' : 'Applied: ')
            + esc(savedText)
            + '</div>';
        }
        var profileCard = '<div class="card" style="margin-bottom:1rem;padding-bottom:0.75rem"><div class="card-title">Routing Weights (Correctness / Cost / Speed)</div>'
          + '<div style="font-size:0.75rem;color:var(--muted);margin-bottom:0.65rem">Operator profile mapped onto routing controls. Adjust and apply to persist to runtime config.</div>'
          + '<div class="routing-profile-grid">'
          + '<div id="routing-profile-spider-host">' + spider + '</div>'
          + '<div>'
          + '<div class="routing-slider-row"><label for="routing-slider-correctness"><span>Correctness</span><span id="routing-slider-correctness-val">' + round2((App._routingProfileDraft || routingProfile).correctness).toFixed(2) + '</span></label><input id="routing-slider-correctness" data-routing-slider="correctness" type="range" min="0" max="1" step="0.01" value="' + round2((App._routingProfileDraft || routingProfile).correctness).toFixed(2) + '"></div>'
          + '<div class="routing-slider-row"><label for="routing-slider-cost"><span>Cost</span><span id="routing-slider-cost-val">' + round2((App._routingProfileDraft || routingProfile).cost).toFixed(2) + '</span></label><input id="routing-slider-cost" data-routing-slider="cost" type="range" min="0" max="1" step="0.01" value="' + round2((App._routingProfileDraft || routingProfile).cost).toFixed(2) + '"></div>'
          + '<div class="routing-slider-row"><label for="routing-slider-speed"><span>Speed</span><span id="routing-slider-speed-val">' + round2((App._routingProfileDraft || routingProfile).speed).toFixed(2) + '</span></label><input id="routing-slider-speed" data-routing-slider="speed" type="range" min="0" max="1" step="0.01" value="' + round2((App._routingProfileDraft || routingProfile).speed).toFixed(2) + '"></div>'
          + '<div style="font-size:0.72rem;color:var(--muted);margin-top:0.35rem">Total: <span id="routing-slider-total">' + routingProfileTotal((App._routingProfileDraft || routingProfile)).toFixed(2) + '</span> / 1.00</div>'
          + '<div class="routing-profile-actions"><button class="btn" id="routing-profile-apply" style="font-size:0.6875rem;padding:0.3rem 0.7rem">Apply profile</button><button class="btn secondary" id="routing-profile-reset" style="font-size:0.6875rem;padding:0.3rem 0.7rem">Reset</button></div>'
          + persistedLabel
          + '</div></div></div>';

        // Context budget card
        App._contextBudgetDefaults = normalizeContextBudget((configData && configData.context_budget) || {});
        if (!App._contextBudgetDraft) App._contextBudgetDraft = normalizeContextBudget(App._contextBudgetDefaults);
        App._contextBudgetDraft = normalizeContextBudget(App._contextBudgetDraft);
        var budgetCfg = App._contextBudgetDraft;
        var bL0 = budgetCfg.l0, bL1 = budgetCfg.l1, bL2 = budgetCfg.l2, bL3 = budgetCfg.l3;
        var chMin = budgetCfg.channel_minimum;
        var budgetPersistedLabel = '';
        if (App._contextBudgetPersistedAt) {
          var budgetSavedAt = new Date(App._contextBudgetPersistedAt);
          var budgetSavedText = Number.isNaN(budgetSavedAt.getTime()) ? App._contextBudgetPersistedAt : budgetSavedAt.toLocaleString();
          budgetPersistedLabel = '<div style="margin-top:0.45rem;font-size:0.6875rem;color:var(--muted)">'
            + (App._contextBudgetPersisted ? 'Saved to config: ' : 'Applied: ')
            + esc(budgetSavedText)
            + '</div>';
        }
        var budgetCard = '<div class="card" style="margin-bottom:1rem;padding-bottom:0.75rem"><div class="card-title">Context Budget (Tokens per Complexity Level)</div>'
          + '<div style="font-size:0.75rem;color:var(--muted);margin-bottom:0.65rem">Controls how many tokens the agent assembles per turn at each complexity level.</div>'
          + '<div class="routing-slider-row"><label for="budget-l0"><span>L0 (Trivial)</span><span id="budget-l0-val">' + bL0 + '</span></label><input id="budget-l0" data-budget-slider="l0" type="range" min="1000" max="16000" step="500" value="' + bL0 + '"></div>'
          + '<div class="routing-slider-row"><label for="budget-l1"><span>L1 (Low)</span><span id="budget-l1-val">' + bL1 + '</span></label><input id="budget-l1" data-budget-slider="l1" type="range" min="2000" max="32000" step="500" value="' + bL1 + '"></div>'
          + '<div class="routing-slider-row"><label for="budget-l2"><span>L2 (Moderate)</span><span id="budget-l2-val">' + bL2 + '</span></label><input id="budget-l2" data-budget-slider="l2" type="range" min="4000" max="64000" step="1000" value="' + bL2 + '"></div>'
          + '<div class="routing-slider-row"><label for="budget-l3"><span>L3 (High)</span><span id="budget-l3-val">' + bL3 + '</span></label><input id="budget-l3" data-budget-slider="l3" type="range" min="8000" max="128000" step="1000" value="' + bL3 + '"></div>'
          + '<div class="settings-row" style="margin-top:0.5rem"><div class="settings-label" style="font-size:0.72rem">Channel Minimum</div><select id="budget-channel-min" style="font-size:0.72rem;padding:0.25rem 0.5rem;border:1px solid var(--border);border-radius:4px;background:var(--surface);color:var(--text)"><option value="L0"' + (chMin === 'L0' ? ' selected' : '') + '>L0</option><option value="L1"' + (chMin === 'L1' ? ' selected' : '') + '>L1</option><option value="L2"' + (chMin === 'L2' ? ' selected' : '') + '>L2</option><option value="L3"' + (chMin === 'L3' ? ' selected' : '') + '>L3</option></select></div>'
          + '<div class="routing-profile-actions"><button class="btn" id="budget-apply" style="font-size:0.6875rem;padding:0.3rem 0.7rem">Apply budget</button><button class="btn secondary" id="budget-reset" style="font-size:0.6875rem;padding:0.3rem 0.7rem">Reset</button></div>'
          + budgetPersistedLabel
          + '</div>';

        var decisionGraph = renderModelDecisionGraph(modelSelections, App._modelGraphFocusTurn, App._modelGraphFocusModel, App._modelGraphFocusEdge);

        // Period selector
        var periods = ['1h', '24h', '7d', '30d', 'all'];
        var periodBar = '<div style="display:flex;gap:0.5rem;margin-bottom:1.25rem;flex-wrap:wrap">';
        periods.forEach(function(p) {
          var cls = p === period ? 'background:var(--accent);color:var(--bg)' : 'background:var(--surface);color:var(--muted);border:1px solid var(--border)';
          periodBar += '<button data-eff-period="' + p + '" style="padding:0.375rem 0.875rem;border-radius:4px;font-family:var(--font);font-size:0.8125rem;cursor:pointer;border:none;' + cls + '">' + p.toUpperCase() + '</button>';
        });
        periodBar += '</div>';

        // Cost overview banner
        var banner = '<div class="card" style="margin-bottom:1rem;background:linear-gradient(135deg,var(--surface) 0%,rgba(193,128,255,0.08) 100%)">'
          + '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:1rem">'
          + '<div><div style="font-size:0.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:0.25rem">Total Cost</div><div style="font-size:1.5rem;font-weight:700;color:var(--accent)">$' + (totals.total_cost || 0).toFixed(4) + '</div></div>'
          + '<div><div style="font-size:0.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:0.25rem">Cache Savings</div><div style="font-size:1.5rem;font-weight:700;color:var(--success)">$' + (totals.total_cache_savings || 0).toFixed(4) + '</div></div>'
          + '<div><div style="font-size:0.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:0.25rem">Total Turns</div><div style="font-size:1.5rem;font-weight:700">' + (totals.total_turns || 0).toLocaleString() + '</div></div>'
          + '<div><div style="font-size:0.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:0.25rem">Models Active</div><div style="font-size:1.5rem;font-weight:700">' + modelNames.length + '</div></div>'
          + '</div></div>';

        // Model comparison cards
        var trendArrow = function(t) {
          if (t === 'increasing') return '<span style="color:var(--error)">&#9650;</span>';
          if (t === 'decreasing') return '<span style="color:var(--success)">&#9660;</span>';
          return '<span style="color:var(--muted)">&#9644;</span>';
        };
        var trendArrowGood = function(t) {
          if (t === 'increasing') return '<span style="color:var(--success)">&#9650;</span>';
          if (t === 'decreasing') return '<span style="color:var(--error)">&#9660;</span>';
          return '<span style="color:var(--muted)">&#9644;</span>';
        };

        var metricHelp = {
          'output_density': 'Output tokens per input token. Higher = more content per context. Range: 0.3-0.8.',
          'cache_hit_rate': 'Percentage served from cache. Target: > 30%.',
          'cost_per_turn': 'Average cost per conversation turn.',
          'budget_utilization': 'How much of allocated context budget is used.'
        };

        var modelColors = ['#c180ff', '#22c55e', '#f59e0b', '#ef4444', '#8b5cf6', '#06b6d4', '#ec4899', '#14b8a6'];
        var cards = '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(300px,1fr));gap:1rem;margin-bottom:1.25rem">';
        modelNames.forEach(function(name, idx) {
          var m = models[name];
          var c = m.cost || {};
          var t = m.trend || {};
          var color = modelColors[idx % modelColors.length];
          var isMostExpensive = totals.most_expensive_model === name;
          var isMostEfficient = totals.most_efficient_model === name;
          var badges = '';
          if (isMostExpensive) badges += '<span style="background:rgba(239,68,68,0.15);color:var(--error);padding:0.125rem 0.5rem;border-radius:3px;font-size:0.6875rem;margin-right:0.25rem">HIGHEST COST</span>';
          if (isMostEfficient) badges += '<span style="background:rgba(34,197,94,0.15);color:var(--success);padding:0.125rem 0.5rem;border-radius:3px;font-size:0.6875rem">MOST EFFICIENT</span>';

          var lastInvoke = m.last_invoked_at || null;
          var isRecent = lastInvoke && (Date.now() - new Date(lastInvoke).getTime()) < 24 * 60 * 60 * 1000;
          var hasErrors = (m.error_count || 0) > (m.success_count || 0) * 0.1;
          var healthBadge = '';
          if (!lastInvoke) {
            healthBadge = '<span class="badge muted">Not tested</span>';
          } else if (hasErrors) {
            healthBadge = '<span class="badge error">Degraded</span>';
          } else if (isRecent) {
            healthBadge = '<span class="badge success">Healthy</span>';
          } else {
            healthBadge = '<span class="badge muted">Idle</span>';
          }

          cards += '<div class="card" style="border-left:3px solid ' + color + '">'
            + '<div style="display:flex;justify-content:space-between;align-items:center;margin-bottom:0.75rem"><div style="font-weight:600;font-size:0.9375rem">' + esc(name) + '</div><div>' + healthBadge + ' ' + badges + '</div></div>'
            + '<div style="display:grid;grid-template-columns:1fr 1fr;gap:0.5rem;font-size:0.8125rem">'
            + '<div><span style="color:var(--muted)">Turns</span><div style="font-weight:600">' + m.total_turns.toLocaleString() + '</div></div>'
            + '<div><span style="color:var(--muted)">Total Cost</span><div style="font-weight:600;color:' + color + '">$' + c.total.toFixed(4) + '</div></div>'
            + '<div><span style="color:var(--muted)" title="' + metricHelp['output_density'] + '">Output Density</span><div style="font-weight:600">' + m.avg_output_density.toFixed(3) + ' ' + trendArrowGood(t.output_density) + '</div></div>'
            + '<div><span style="color:var(--muted)" title="' + metricHelp['cost_per_turn'] + '">Cost/Turn</span><div style="font-weight:600">$' + c.effective_per_turn.toFixed(4) + ' ' + trendArrow(t.cost_per_turn) + '</div></div>'
            + '<div><span style="color:var(--muted)" title="' + metricHelp['cache_hit_rate'] + '">Cache Hit Rate</span><div style="font-weight:600">' + (m.cache_hit_rate * 100).toFixed(1) + '% ' + trendArrowGood(t.cache_hit_rate) + '</div></div>'
            + '<div><span style="color:var(--muted)">Cache Savings</span><div style="font-weight:600;color:var(--success)">$' + c.cache_savings.toFixed(4) + '</div></div>'
            + '<div><span style="color:var(--muted)">$/Output Token</span><div style="font-weight:600">' + (c.per_output_token * 1000).toFixed(4) + '/1k</div></div>'
            + '<div><span style="color:var(--muted)">Cost Trend</span><div style="font-weight:600">' + trendArrow(c.cumulative_trend) + ' ' + esc(c.cumulative_trend) + '</div></div>'
            + '</div>';

          // Cost attribution bar
          var attr = c.attribution || {};
          var attrBar = '<div style="margin-top:0.75rem"><div style="font-size:0.6875rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:0.375rem">Input Cost Attribution</div>';
          var sys = attr.system_prompt || {};
          var mem = attr.memories || {};
          var hist = attr.history || {};
          if (sys.pct > 0 || mem.pct > 0 || hist.pct > 0) {
            attrBar += '<div style="display:flex;height:8px;border-radius:4px;overflow:hidden;margin-bottom:0.375rem">';
            if (sys.pct > 0) attrBar += '<div style="width:' + sys.pct + '%;background:#c180ff" title="System prompt: ' + sys.pct.toFixed(1) + '%"></div>';
            if (mem.pct > 0) attrBar += '<div style="width:' + mem.pct + '%;background:#22c55e" title="Memories: ' + mem.pct.toFixed(1) + '%"></div>';
            if (hist.pct > 0) attrBar += '<div style="width:' + hist.pct + '%;background:#f59e0b" title="History: ' + hist.pct.toFixed(1) + '%"></div>';
            attrBar += '</div>';
            attrBar += '<div style="display:flex;gap:0.75rem;font-size:0.6875rem;color:var(--muted)">';
            if (sys.pct > 0) attrBar += '<span style="color:#c180ff">\u25cf System ' + sys.pct.toFixed(0) + '%</span>';
            if (mem.pct > 0) attrBar += '<span style="color:#22c55e">\u25cf Memory ' + mem.pct.toFixed(0) + '%</span>';
            if (hist.pct > 0) attrBar += '<span style="color:#f59e0b">\u25cf History ' + hist.pct.toFixed(0) + '%</span>';
            attrBar += '</div>';
          } else {
            attrBar += '<div style="font-size:0.75rem;color:var(--muted);font-style:italic">No context snapshot data available</div>';
          }
          attrBar += '</div>';
          cards += attrBar + '</div>';
        });
        cards += '</div>';

        if (modelNames.length === 0) {
          cards = '<div class="card" style="text-align:center;padding:2rem;color:var(--muted)"><div style="font-size:1.5rem;margin-bottom:0.5rem">No inference data</div><div style="font-size:0.875rem">Run some inference requests to see efficiency metrics here.</div></div>';
        }

        // Time series chart (CSS bar chart)
        var tsChart = '';
        if (ts.length > 0) {
          var maxCost = Math.max.apply(null, ts.map(function(p) { return p.cost; }));
          if (maxCost === 0) maxCost = 1;
          tsChart = '<div class="card" style="margin-bottom:1.25rem"><div style="font-weight:600;margin-bottom:0.75rem">Cost Over Time</div>';
          tsChart += '<div style="display:flex;align-items:flex-end;gap:2px;height:120px;padding-bottom:1.5rem;position:relative">';
          var buckets = [];
          ts.forEach(function(p) { if (buckets.indexOf(p.bucket) === -1) buckets.push(p.bucket); });
          var bucketTotals = {};
          ts.forEach(function(p) { bucketTotals[p.bucket] = (bucketTotals[p.bucket] || 0) + p.cost; });

          var maxBucketCost = Math.max.apply(null, Object.keys(bucketTotals).map(function(k) { return bucketTotals[k]; }));
          if (maxBucketCost === 0) maxBucketCost = 1;

          buckets.forEach(function(b, i) {
            var pct = (bucketTotals[b] / maxBucketCost) * 100;
            var shortDate = b.slice(5);
            var colorIdx = i % modelColors.length;
            tsChart += '<div style="flex:1;display:flex;flex-direction:column;align-items:center;min-width:0">'
              + '<div style="width:100%;background:' + modelColors[colorIdx] + ';border-radius:2px 2px 0 0;height:' + Math.max(pct, 2) + '%;opacity:0.85;transition:height 0.3s" title="' + b + ': $' + bucketTotals[b].toFixed(4) + '"></div>'
              + '<div style="font-size:0.5625rem;color:var(--muted);margin-top:0.25rem;transform:rotate(-45deg);white-space:nowrap">' + shortDate + '</div>'
              + '</div>';
          });
          tsChart += '</div></div>';
        }

        // Model comparison table (sortable)
        var table = '';
        if (modelNames.length > 0) {
          table = '<div class="card" style="margin-bottom:1.25rem"><div style="font-weight:600;margin-bottom:0.75rem">Model Comparison</div>'
            + '<div class="table-wrap"><table><thead><tr>'
            + '<th>Model</th><th>Turns</th><th>Output Density</th><th>Cache Hit %</th>'
            + '<th>Cost/Turn</th><th>Total Cost</th><th>Cache Savings</th><th>Cost Trend</th>'
            + '</tr></thead><tbody>';
          modelNames.forEach(function(name) {
            var m = models[name];
            var c = m.cost || {};
            var t = m.trend || {};
            table += '<tr>'
              + '<td class="card-mono">' + esc(name) + '</td>'
              + '<td>' + m.total_turns.toLocaleString() + '</td>'
              + '<td>' + m.avg_output_density.toFixed(3) + '</td>'
              + '<td>' + (m.cache_hit_rate * 100).toFixed(1) + '%</td>'
              + '<td>$' + c.effective_per_turn.toFixed(4) + '</td>'
              + '<td>$' + c.total.toFixed(4) + '</td>'
              + '<td style="color:var(--success)">$' + c.cache_savings.toFixed(4) + '</td>'
              + '<td>' + trendArrow(c.cumulative_trend) + ' ' + esc(c.cumulative_trend) + '</td>'
              + '</tr>';
          });
          table += '</tbody></table></div></div>';
        }

        var assignment = report.subagent_assignment || {};
        var assignmentSection = '';
        if (assignment.overall && assignment.by_subagent) {
          var overall = assignment.overall || {};
          var bySubagent = assignment.by_subagent || {};
          var assignments = assignment.assignments || {};
          var names = Object.keys(bySubagent).sort(function(a, b) {
            return (bySubagent[b].total || 0) - (bySubagent[a].total || 0);
          });
          assignmentSection = '<div class="card" style="margin-bottom:1.25rem"><div style="font-weight:600;margin-bottom:0.75rem">Subagent Assignment Efficacy</div>';
          assignmentSection += '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:0.75rem;margin-bottom:0.75rem;font-size:0.8125rem">';
          assignmentSection += '<div><span style="color:var(--muted)">Delegations</span><div style="font-weight:600">' + (overall.total || 0) + '</div></div>';
          assignmentSection += '<div><span style="color:var(--muted)">Success Rate</span><div style="font-weight:600">' + (((overall.success_rate || 0) * 100).toFixed(1)) + '%</div></div>';
          assignmentSection += '<div><span style="color:var(--muted)">Timeout-like</span><div style="font-weight:600;color:var(--warning)">' + (overall.timeout_like || 0) + '</div></div>';
          assignmentSection += '<div><span style="color:var(--muted)">P95 Duration</span><div style="font-weight:600">' + (overall.p95_duration_ms || 0).toFixed(0) + ' ms</div></div>';
          assignmentSection += '</div>';
          assignmentSection += '<div class="table-wrap"><table><thead><tr><th>Subagent</th><th>Assigned Model</th><th>Fallbacks</th><th>Success %</th><th>Timeouts</th><th>Avg ms</th><th>P95 ms</th></tr></thead><tbody>';
          names.forEach(function(name) {
            var stat = bySubagent[name] || {};
            var cfg = assignments[name] || {};
            var fallbackList = cfg.fallback_models || [];
            assignmentSection += '<tr>'
              + '<td>' + esc(name) + '</td>'
              + '<td class="card-mono">' + esc(cfg.configured_model || '—') + '</td>'
              + '<td>' + esc((fallbackList && fallbackList.length) ? fallbackList.join(', ') : '—') + '</td>'
              + '<td>' + (((stat.success_rate || 0) * 100).toFixed(1)) + '%</td>'
              + '<td>' + (stat.timeout_like || 0) + '</td>'
              + '<td>' + (stat.avg_duration_ms || 0).toFixed(0) + '</td>'
              + '<td>' + (stat.p95_duration_ms || 0).toFixed(0) + '</td>'
              + '</tr>';
          });
          assignmentSection += '</tbody></table></div></div>';
        }

        // Inline optimization tips with actionable buttons
        var tips = '<div class="card"><div style="font-weight:600;margin-bottom:0.75rem">\u26a1 Quick Optimizations</div><div style="font-size:0.8125rem;color:var(--muted)">';
        var tipList = [];
        modelNames.forEach(function(name) {
          var m = models[name];
          if (m.cache_hit_rate < 0.3 && m.total_turns > 5) {
            tipList.push(
              '<div style="padding:0.375rem 0;border-bottom:1px solid var(--border);display:flex;justify-content:space-between;gap:0.75rem;align-items:center;flex-wrap:wrap">'
              + '<div><span style="color:var(--warning)">\u25cf</span> <strong>' + esc(name) + '</strong> has a low cache hit rate (' + (m.cache_hit_rate * 100).toFixed(0) + '%). Consider enabling semantic caching.</div>'
              + '<button class="btn secondary" data-action="enable-semantic-cache" data-model="' + esc(name) + '" style="font-size:0.6875rem;padding:0.25rem 0.625rem;white-space:nowrap">Enable Caching</button>'
              + '</div>'
            );
          }
          if (m.cost && m.cost.effective_per_turn > 0.05) {
            tipList.push('<div style="padding:0.375rem 0;border-bottom:1px solid var(--border)"><span style="color:var(--error)">\u25cf</span> <strong>' + esc(name) + '</strong> costs $' + m.cost.effective_per_turn.toFixed(4) + '/turn. Consider a lighter model for simple tasks.</div>');
          }
          if (m.avg_output_density < 0.1 && m.total_turns > 5) {
            tipList.push('<div style="padding:0.375rem 0;border-bottom:1px solid var(--border)"><span style="color:var(--warning)">\u25cf</span> <strong>' + esc(name) + '</strong> has low output density (' + m.avg_output_density.toFixed(3) + '). Large inputs produce little output.</div>');
          }
        });
        if (tipList.length === 0) {
          tipList.push('<div style="padding:0.375rem 0;color:var(--success)">\u2714 All models operating efficiently. No optimizations needed.</div>');
        }
        tips += tipList.join('') + '</div></div>';

        // Store tips for use in Recommendations tab
        self._quickTipsHtml = tips;
        return tabBar + profileCard + budgetCard + decisionGraph + periodBar + banner + cards + tsChart + table + assignmentSection;
      });
};

App._recPeriod = '30d';
App.renderRecommendations = function() {
      var self = this;
      var period = this._recPeriod || '30d';
      return api('/api/recommendations?period=' + encodeURIComponent(period)).then(function(data) {
        var recs = data.recommendations || [];
        var profile = data.profile || {};
        var count = data.count || 0;

        var periods = ['7d', '30d', 'all'];
        var periodBar = '<div style="display:flex;gap:0.5rem;margin-bottom:1.25rem;flex-wrap:wrap;align-items:center">';
        periodBar += '<span style="font-size:0.75rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-right:0.5rem">Period</span>';
        periods.forEach(function(p) {
          var cls = p === period ? 'background:var(--accent);color:var(--bg)' : 'background:var(--surface);color:var(--muted);border:1px solid var(--border)';
          periodBar += '<button data-rec-period="' + p + '" style="padding:0.375rem 0.875rem;border-radius:4px;font-family:var(--font);font-size:0.8125rem;cursor:pointer;border:none;' + cls + '">' + p.toUpperCase() + '</button>';
        });
        periodBar += '<button id="btn-deep-analysis" style="margin-left:auto;padding:0.375rem 1rem;border-radius:4px;font-family:var(--font);font-size:0.8125rem;cursor:pointer;border:1px solid var(--accent);background:var(--accent-dim);color:var(--accent)">Generate Deep Analysis</button>';
        periodBar += '</div>';

        var banner = '<div class="card" style="margin-bottom:1rem;background:linear-gradient(135deg,var(--surface) 0%,rgba(193,128,255,0.08) 100%)">'
          + '<div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(140px,1fr));gap:1rem">'
          + '<div><div style="font-size:0.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:0.25rem">Recommendations</div><div style="font-size:1.5rem;font-weight:700;color:var(--accent)">' + count + '</div></div>'
          + '<div><div style="font-size:0.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:0.25rem">Total Turns</div><div style="font-size:1.5rem;font-weight:700">' + (profile.total_turns || 0).toLocaleString() + '</div></div>'
          + '<div><div style="font-size:0.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:0.25rem">Total Cost</div><div style="font-size:1.5rem;font-weight:700;color:var(--accent)">$' + (profile.total_cost || 0).toFixed(4) + '</div></div>'
          + '<div><div style="font-size:0.7rem;color:var(--muted);text-transform:uppercase;letter-spacing:0.06em;margin-bottom:0.25rem">Cache Hit Rate</div><div style="font-size:1.5rem;font-weight:700">' + ((profile.cache_hit_rate || 0) * 100).toFixed(1) + '%</div></div>'
          + '</div></div>';

        var priorityColor = function(p) {
          if (p === 'High') return 'var(--error)';
          if (p === 'Medium') return 'var(--warning)';
          return '#c180ff';
        };
        var priorityBg = function(p) {
          if (p === 'High') return 'rgba(239,68,68,0.1)';
          if (p === 'Medium') return 'rgba(234,179,8,0.1)';
          return 'rgba(193,128,255,0.1)';
        };
        var categoryIcon = function(cat) {
          var icons = {
            QueryCrafting: '\u270e',
            ModelSelection: '\u2699',
            SessionManagement: '\u{1f4ac}',
            MemoryLeverage: '\u{1f9e0}',
            CostOptimization: '\u{1f4b0}',
            ToolUsage: '\u{1f527}',
            Configuration: '\u2699'
          };
          return icons[cat] || '\u2139';
        };

        var cards = '';
        if (recs.length === 0) {
          cards = '<div class="card" style="text-align:center;padding:2rem;color:var(--muted)">'
            + '<div style="font-size:1.5rem;margin-bottom:0.5rem">No recommendations</div>'
            + '<div style="font-size:0.875rem">Not enough data to generate recommendations yet. Run more inference requests.</div></div>';
        } else {
          recs.forEach(function(rec, idx) {
            var color = priorityColor(rec.priority);
            var bg = priorityBg(rec.priority);
            var icon = categoryIcon(rec.category);
            var evidenceId = 'rec-evidence-' + idx;

            cards += '<div class="card" style="border-left:3px solid ' + color + ';margin-bottom:0.75rem">'
              + '<div style="display:flex;justify-content:space-between;align-items:flex-start;margin-bottom:0.5rem">'
              + '<div style="display:flex;align-items:center;gap:0.5rem">'
              + '<span style="font-size:1.125rem">' + icon + '</span>'
              + '<div style="font-weight:600;font-size:0.9375rem">' + esc(rec.title) + '</div>'
              + '</div>'
              + '<span style="background:' + bg + ';color:' + color + ';padding:0.125rem 0.625rem;border-radius:3px;font-size:0.6875rem;font-weight:600;text-transform:uppercase;flex-shrink:0">' + esc(rec.priority) + '</span>'
              + '</div>';

            cards += '<div style="font-size:0.8125rem;color:var(--muted);margin-bottom:0.5rem">' + esc(rec.explanation) + '</div>';
            cards += '<div style="font-size:0.8125rem;padding:0.5rem 0.75rem;background:rgba(193,128,255,0.06);border-radius:4px;margin-bottom:0.5rem"><strong style="color:var(--accent)">Action:</strong> ' + esc(rec.action) + '</div>';

            if (rec.estimated_impact) {
              var imp = rec.estimated_impact;
              var impactParts = [];
              if (imp.monthly_savings) impactParts.push('<span style="color:var(--success)">Est. savings: $' + imp.monthly_savings.toFixed(4) + '</span>');
              if (imp.quality_change) impactParts.push('<span style="color:var(--accent)">' + esc(imp.quality_change) + '</span>');
              if (impactParts.length > 0) {
                cards += '<div style="font-size:0.75rem;display:flex;gap:1rem;margin-bottom:0.5rem">' + impactParts.join('') + '</div>';
              }
            }

            if (rec.evidence && rec.evidence.length > 0) {
              cards += '<div style="margin-top:0.25rem">'
                + '<button data-rec-evidence-toggle="' + evidenceId + '" aria-expanded="false" style="background:none;border:none;color:var(--muted);font-family:var(--font);font-size:0.75rem;cursor:pointer;padding:0">\u25b6 Evidence (' + rec.evidence.length + ')</button>'
                + '<div id="' + evidenceId + '" style="display:none;margin-top:0.375rem">';
              rec.evidence.forEach(function(ev) {
                cards += '<div style="font-size:0.75rem;padding:0.25rem 0;border-bottom:1px solid var(--border)">'
                  + '<span style="color:var(--accent)">' + esc(ev.metric) + '</span>: '
                  + '<span style="font-weight:600">' + esc(ev.value) + '</span>'
                  + ' <span style="color:var(--muted)">(' + esc(ev.context) + ')</span></div>';
              });
              cards += '</div></div>';
            }

            cards += '</div>';
          });
        }

        var deepAnalysisContainer = '<div id="deep-analysis-result" style="display:none;margin-top:1rem"></div>';

        setTimeout(function() {
          document.querySelectorAll('[data-rec-period]').forEach(function(btn) {
            btn.addEventListener('click', function() {
              self._recPeriod = btn.getAttribute('data-rec-period');
              self._effTab = 'recommendations';
              self.navigate('efficiency');
            });
          });
          var deepBtn = document.getElementById('btn-deep-analysis');
          if (deepBtn) {
            deepBtn.addEventListener('click', function() {
              deepBtn.disabled = true;
              deepBtn.textContent = 'Generating...';
              api('/api/recommendations/generate?period=' + encodeURIComponent(self._recPeriod || '30d'), { method: 'POST' }).then(function(res) {
                var container = document.getElementById('deep-analysis-result');
                if (container) {
                  container.style.display = 'block';
                  var actions = (res.actions || []).map(function(a) { return '<li style="margin:0.25rem 0">' + esc(a) + '</li>'; }).join('');
                  var savings = (res.summary && res.summary.estimated_monthly_savings != null) ? '$' + Number(res.summary.estimated_monthly_savings).toFixed(4) : '—';
                  var html = '<div class="card"><div style="font-weight:600;margin-bottom:0.75rem">Deep Analysis</div>'
                    + '<div style="font-size:0.8125rem;color:var(--muted);margin-bottom:0.5rem">' + esc(res.message || 'Analysis complete') + '</div>'
                    + '<div style="font-size:0.75rem;color:var(--text);margin-bottom:0.75rem"><strong>Estimated monthly savings:</strong> ' + esc(savings) + '</div>'
                    + (actions ? '<div style="font-size:0.75rem;margin-bottom:0.375rem;color:var(--muted)">Prioritized actions</div><ol style="margin:0;padding-left:1rem;font-size:0.75rem">' + actions + '</ol>' : '<div style="font-size:0.75rem;color:var(--muted)">No prioritized actions returned.</div>')
                    + '</div>';
                  setHtml(container, html);
                }
                deepBtn.disabled = false;
                deepBtn.textContent = 'Generate Deep Analysis';
              }).catch(function() {
                deepBtn.disabled = false;
                deepBtn.textContent = 'Generate Deep Analysis';
              });
            });
          }
        }, 0);

        return periodBar + banner + cards + deepAnalysisContainer;
      });
};

App._TOKEN_ICONS = { ETH: '\u039e', MATIC: '\u25c6', USDC: '\u0024', USDT: '\u0024', DAI: '\u25c7', WETH: '\u039e', WBTC: '\u20bf', cbBTC: '\u20bf' };
App._renderRevenueSwapSummaryCard = function(revenueSwap) {
      var cfg = revenueSwap || {};
      var enabled = cfg.enabled !== false;
      var target = cfg.target_symbol || 'PUSD';
      var chain = cfg.default_chain || 'ETH';
      var chains = Array.isArray(cfg.chains) ? cfg.chains : [];
      var chainRows = chains.map(function(entry) {
        var swapContract = entry.swap_contract_address
          ? '<div style="font-size:0.625rem;color:var(--muted);margin-top:0.2rem">Swap contract: <span class="card-mono">' + esc(entry.swap_contract_address) + '</span></div>'
          : '<div style="font-size:0.625rem;color:var(--muted);margin-top:0.2rem">Swap contract: <span class="card-mono">custom/no override</span></div>';
        return '<div class="settings-nested" style="margin-top:0.6rem">'
          + '<div class="settings-row"><div class="settings-label">' + esc(entry.chain || 'UNSPECIFIED') + '</div><div class="card-mono" style="font-size:0.7rem;word-break:break-all">' + esc(entry.target_contract_address || '\u2014') + '</div></div>'
          + swapContract
          + '</div>';
      }).join('');
      if (!chainRows) chainRows = '<div style="font-size:0.75rem;color:var(--muted);padding-top:0.35rem">No chain targets configured.</div>';
      return '<div class="card" style="margin-bottom:1rem"><div class="card-title">Revenue Swap Policy</div>'
        + '<div class="settings-row"><div class="settings-label">Auto-swap</div><div style="font-family:var(--font-mono)">' + (enabled ? 'enabled' : 'disabled') + '</div></div>'
        + '<div class="settings-row"><div class="settings-label">Default target</div><div style="font-family:var(--font-mono)">' + esc(target) + '</div></div>'
        + '<div class="settings-row"><div class="settings-label">Default chain</div><div style="font-family:var(--font-mono)">' + esc(chain) + '</div></div>'
        + chainRows
        + '</div>';
};
App._renderRevenueStrategySummaryCard = function(rows) {
      var items = Array.isArray(rows) ? rows : [];
      var body = items.length
        ? items.map(function(row) {
            return '<div class="settings-row">'
              + '<div><div style="font-weight:600;font-size:0.8125rem">' + esc(row.strategy || 'unknown') + '</div><div style="font-size:0.625rem;color:var(--muted)">' + esc(String(row.settled_jobs || 0)) + ' settled / ' + esc(String(row.total_jobs || 0)) + ' total</div></div>'
              + '<div style="text-align:right;font-family:var(--font-mono)"><div>$' + Number(row.net_profit_usdc || 0).toFixed(2) + '</div><div style="font-size:0.625rem;color:var(--muted)">priority ' + Number(row.avg_priority_score || 0).toFixed(1) + '</div></div>'
              + '</div>';
          }).join('')
        : '<div style="font-size:0.75rem;color:var(--muted)">No settled strategy data yet.</div>';
      return '<div class="card" style="margin-bottom:1rem"><div class="card-title">Revenue Strategy Summary</div>' + body + '</div>';
};
App._renderRevenueFeedbackSummaryCard = function(rows) {
      var items = Array.isArray(rows) ? rows : [];
      var body = items.length
        ? items.map(function(row) {
            return '<div class="settings-row">'
              + '<div><div style="font-weight:600;font-size:0.8125rem">' + esc(row.strategy || 'unknown') + '</div><div style="font-size:0.625rem;color:var(--muted)">' + esc(String(row.feedback_count || 0)) + ' feedback signals</div></div>'
              + '<div style="text-align:right;font-family:var(--font-mono)"><div>' + Number(row.avg_grade || 0).toFixed(2) + ' / 5.00</div><div style="font-size:0.625rem;color:var(--muted)">' + esc((row.latest_feedback_at || '').replace('T', ' ').slice(0, 19) || '\u2014') + '</div></div>'
              + '</div>';
          }).join('')
        : '<div style="font-size:0.75rem;color:var(--muted)">No feedback recorded yet.</div>';
      return '<div class="card" style="margin-bottom:1rem"><div class="card-title">Revenue Feedback Summary</div>' + body + '</div>';
};
App._renderSeedExerciseReadinessCard = function(readiness) {
      var r = readiness || {};
      var ready = !!r.meets_seed_target;
      var reserve = !!r.minimum_reserve_configured;
      var swapEnabled = !!r.swap_enabled;
      var targetOk = !!r.default_chain_has_target_contract;
      var swapOk = !!r.default_chain_has_swap_contract;
      var target = Number(r.seed_target_usdc || 50);
      var stable = Number(r.stable_balance_usdc || 0);
      var defaultChain = r.default_chain || 'ETH';
      var checks = [
        ['Stable balance', stable.toFixed(2) + ' / ' + target.toFixed(2) + ' USDC', ready],
        ['Minimum reserve', reserve ? 'configured' : 'missing', reserve],
        ['Auto-swap', swapEnabled ? 'enabled' : 'disabled', swapEnabled],
        ['Target contract', targetOk ? 'configured' : 'missing', targetOk],
        ['Swap contract', swapOk ? 'configured' : 'missing', swapOk]
      ];
      var rows = checks.map(function(check) {
        return '<div class="settings-row">'
          + '<div class="settings-label">' + esc(check[0]) + '</div>'
          + '<div style="display:flex;align-items:center;gap:0.5rem"><span class="badge ' + (check[2] ? 'success' : 'warn') + '">' + esc(check[1]) + '</span></div>'
          + '</div>';
      }).join('');
      return '<div class="card" style="margin-bottom:1rem"><div class="card-title">$50 Seed Readiness</div>'
        + '<div style="font-size:0.75rem;color:var(--muted);margin-bottom:0.75rem">Default chain: <span class="card-mono">' + esc(defaultChain) + '</span></div>'
        + rows
        + '</div>';
};
App._renderSeedExerciseProgressCard = function(progress) {
      var p = progress || {};
      var phases = [
        ['Phase 1: seeded + visible', !!p.phase_1_seeded_and_visible],
        ['Phase 1: target met', !!p.phase_1_meets_target],
        ['Phase 2: revenue cycle complete', !!p.phase_2_revenue_cycle_complete],
        ['Phase 3: swap submitted', !!p.phase_3_swap_submitted],
        ['Phase 3: swap reconciled', !!p.phase_3_swap_reconciled],
        ['Phase 3: tax submitted', !!p.phase_3_tax_submitted],
        ['Phase 3: tax reconciled', !!p.phase_3_tax_reconciled],
        ['Phase 4: mechanic clear', !!p.phase_4_mechanic_clear]
      ];
      var rows = phases.map(function(phase) {
        return '<div class="settings-row">'
          + '<div class="settings-label">' + esc(phase[0]) + '</div>'
          + '<div><span class="badge ' + (phase[1] ? 'success' : 'warn') + '">' + (phase[1] ? 'done' : 'pending') + '</span></div>'
          + '</div>';
      }).join('');
      return '<div class="card" style="margin-bottom:1rem"><div class="card-title">Seed Exercise Progress</div>'
        + '<div style="font-size:0.75rem;color:var(--muted);margin-bottom:0.75rem">Next action: ' + esc(p.next_action || 'no action available') + '</div>'
        + rows
        + '</div>';
};
App._renderSeedExercisePlanCard = function(plan) {
      var p = plan || {};
      var phases = Array.isArray(p.phases) ? p.phases : [];
      var phaseRows = phases.length
        ? phases.map(function(phase) {
            return '<div class="settings-nested" style="margin-top:0.6rem">'
              + '<div class="settings-row"><div class="settings-label">' + esc(phase.label || phase.id || 'phase') + '</div><div><span class="badge">' + esc(String(Number(phase.max_spend_usdc || 0).toFixed(2))) + ' USDC cap</span></div></div>'
              + '<div style="font-size:0.75rem;color:var(--muted);margin-top:0.35rem">' + esc(phase.goal || '') + '</div>'
              + '<div style="font-size:0.6875rem;color:var(--muted);margin-top:0.35rem">Success signal: ' + esc(phase.success_signal || '') + '</div>'
              + '</div>';
          }).join('')
        : '<div style="font-size:0.75rem;color:var(--muted)">No seed exercise plan is available.</div>';
      var aborts = Array.isArray(p.abort_conditions) ? p.abort_conditions : [];
      var guidance = Array.isArray(p.operator_guidance) ? p.operator_guidance : [];
      return '<div class="card" style="margin-bottom:1rem"><div class="card-title">$50 Seed Exercise Plan</div>'
        + '<div style="font-size:0.75rem;color:var(--muted);margin-bottom:0.75rem">Constrained live-funds validation plan for treasury, settlement, routing, and repair.</div>'
        + phaseRows
        + '<div style="margin-top:0.9rem;font-size:0.75rem;color:var(--muted)">Abort conditions</div>'
        + (aborts.length ? '<ul style="margin:0.35rem 0 0 1rem;padding:0;color:var(--text)">' + aborts.map(function(item) { return '<li style="margin:0.3rem 0">' + esc(item) + '</li>'; }).join('') + '</ul>' : '<div style="font-size:0.75rem;color:var(--muted)">No abort conditions defined.</div>')
        + '<div style="margin-top:0.9rem;font-size:0.75rem;color:var(--muted)">Operator guidance</div>'
        + (guidance.length ? '<ul style="margin:0.35rem 0 0 1rem;padding:0;color:var(--text)">' + guidance.map(function(item) { return '<li style="margin:0.3rem 0">' + esc(item) + '</li>'; }).join('') + '</ul>' : '<div style="font-size:0.75rem;color:var(--muted)">No operator guidance defined.</div>')
        + '</div>';
};
App._renderRevenueSwapTasksCard = function(rows) {
      var items = Array.isArray(rows) ? rows : [];
      var body = items.length
        ? '<div class="table-wrap"><table><thead><tr><th>Opportunity</th><th>Status</th><th>Target</th><th>Tx</th><th>Updated</th><th>Actions</th></tr></thead><tbody>'
          + items.map(function(row) {
              var source = row.source || {};
              var target = (source.target_asset || 'unknown') + ' on ' + (source.target_chain || 'unknown');
              var txHash = source.swap_tx_hash
                ? '<span class="card-mono" style="font-size:0.625rem">' + esc(String(source.swap_tx_hash).slice(0, 18)) + '\u2026</span>'
                : '<span style="color:var(--muted)">\u2014</span>';
              var updated = row.updated_at ? String(row.updated_at).replace('T', ' ').slice(0, 19) : '\u2014';
              var actions = [];
              if (row.status === 'pending') {
                actions.push('<button class="btn secondary" style="font-size:0.625rem;padding:0.18rem 0.45rem" data-revenue-task-kind="swap" data-revenue-task-action="start" data-opportunity-id="' + esc(row.opportunity_id || '') + '">Start</button>');
                actions.push('<button class="btn secondary" style="font-size:0.625rem;padding:0.18rem 0.45rem" data-revenue-task-kind="swap" data-revenue-task-action="submit" data-opportunity-id="' + esc(row.opportunity_id || '') + '">Submit</button>');
              } else if (row.status === 'in_progress') {
                actions.push('<button class="btn secondary" style="font-size:0.625rem;padding:0.18rem 0.45rem" data-revenue-task-kind="swap" data-revenue-task-action="reconcile" data-opportunity-id="' + esc(row.opportunity_id || '') + '">Reconcile</button>');
                actions.push('<button class="btn secondary" style="font-size:0.625rem;padding:0.18rem 0.45rem" data-revenue-task-kind="swap" data-revenue-task-action="confirm" data-opportunity-id="' + esc(row.opportunity_id || '') + '">Confirm</button>');
                actions.push('<button class="btn secondary" style="font-size:0.625rem;padding:0.18rem 0.45rem" data-revenue-task-kind="swap" data-revenue-task-action="fail" data-opportunity-id="' + esc(row.opportunity_id || '') + '">Fail</button>');
              }
              return '<tr>'
                + '<td><div style="font-weight:600">' + esc(row.opportunity_id || row.id || 'unknown') + '</div><div style="font-size:0.625rem;color:var(--muted)">' + esc(row.title || '') + '</div></td>'
                + '<td>' + esc(row.status || 'unknown') + '</td>'
                + '<td>' + esc(target) + '</td>'
                + '<td>' + txHash + '</td>'
                + '<td style="color:var(--muted)">' + esc(updated) + '</td>'
                + '<td><div style="display:flex;flex-wrap:wrap;gap:0.25rem">' + (actions.join('') || '<span style="color:var(--muted)">—</span>') + '</div></td>'
                + '</tr>';
            }).join('')
          + '</tbody></table></div>'
        : '<div style="font-size:0.75rem;color:var(--muted)">No revenue swap tasks yet.</div>';
      return '<div class="card" style="margin-bottom:1rem"><div class="card-title">Revenue Swap Tasks</div>' + body + '</div>';
};
App._renderRevenueTaxTasksCard = function(rows) {
      var items = Array.isArray(rows) ? rows : [];
      var body = items.length
        ? '<div class="table-wrap"><table><thead><tr><th>Opportunity</th><th>Status</th><th>Destination</th><th>Tx</th><th>Updated</th><th>Actions</th></tr></thead><tbody>'
          + items.map(function(row) {
              var source = row.source || {};
              var dest = (source.destination_wallet || 'unknown') + ' on ' + (source.target_chain || 'unknown');
              var txHash = source.tax_tx_hash
                ? '<span class="card-mono" style="font-size:0.625rem">' + esc(String(source.tax_tx_hash).slice(0, 18)) + '…</span>'
                : '<span style="color:var(--muted)">—</span>';
              var updated = row.updated_at ? String(row.updated_at).replace('T', ' ').slice(0, 19) : '—';
              var actions = [];
              if (row.status === 'pending') {
                actions.push('<button class="btn secondary" style="font-size:0.625rem;padding:0.18rem 0.45rem" data-revenue-task-kind="tax" data-revenue-task-action="start" data-opportunity-id="' + esc(row.opportunity_id || '') + '">Start</button>');
                actions.push('<button class="btn secondary" style="font-size:0.625rem;padding:0.18rem 0.45rem" data-revenue-task-kind="tax" data-revenue-task-action="submit" data-opportunity-id="' + esc(row.opportunity_id || '') + '">Submit</button>');
              } else if (row.status === 'in_progress') {
                actions.push('<button class="btn secondary" style="font-size:0.625rem;padding:0.18rem 0.45rem" data-revenue-task-kind="tax" data-revenue-task-action="reconcile" data-opportunity-id="' + esc(row.opportunity_id || '') + '">Reconcile</button>');
                actions.push('<button class="btn secondary" style="font-size:0.625rem;padding:0.18rem 0.45rem" data-revenue-task-kind="tax" data-revenue-task-action="confirm" data-opportunity-id="' + esc(row.opportunity_id || '') + '">Confirm</button>');
                actions.push('<button class="btn secondary" style="font-size:0.625rem;padding:0.18rem 0.45rem" data-revenue-task-kind="tax" data-revenue-task-action="fail" data-opportunity-id="' + esc(row.opportunity_id || '') + '">Fail</button>');
              }
              return '<tr>'
                + '<td><div style="font-weight:600">' + esc(row.opportunity_id || row.id || 'unknown') + '</div><div style="font-size:0.625rem;color:var(--muted)">' + esc(row.title || '') + '</div></td>'
                + '<td>' + esc(row.status || 'unknown') + '</td>'
                + '<td>' + esc(dest) + '</td>'
                + '<td>' + txHash + '</td>'
                + '<td style="color:var(--muted)">' + esc(updated) + '</td>'
                + '<td><div style="display:flex;flex-wrap:wrap;gap:0.25rem">' + (actions.join('') || '<span style="color:var(--muted)">—</span>') + '</div></td>'
                + '</tr>';
            }).join('')
          + '</tbody></table></div>'
        : '<div style="font-size:0.75rem;color:var(--muted)">No revenue tax tasks yet.</div>';
      return '<div class="card" style="margin-bottom:1rem"><div class="card-title">Revenue Tax Tasks</div>' + body + '</div>';
};
App._renderRevenueSwapSettings = function(revenueSwap) {
      var cfg = revenueSwap || {};
      var chains = Array.isArray(cfg.chains) ? cfg.chains : [];
      var rows = chains.map(function(entry, idx) {
        return '<div class="settings-nested" style="margin-top:0.6rem">'
          + '<div class="settings-row"><div class="settings-label">Chain</div><input class="settings-input" type="text" data-revenue-swap-chain-field="chain" data-revenue-swap-chain-index="' + idx + '" value="' + esc(entry.chain || '') + '" placeholder="ETH"></div>'
          + '<div class="settings-row"><div class="settings-label">Target contract</div><input class="settings-input" type="text" data-revenue-swap-chain-field="target_contract_address" data-revenue-swap-chain-index="' + idx + '" value="' + esc(entry.target_contract_address || '') + '" placeholder="0x... or program id"></div>'
          + '<div class="settings-row"><div class="settings-label">Swap contract</div><input class="settings-input" type="text" data-revenue-swap-chain-field="swap_contract_address" data-revenue-swap-chain-index="' + idx + '" value="' + esc(entry.swap_contract_address || '') + '" placeholder="optional"></div>'
          + '<div style="display:flex;justify-content:flex-end"><button class="btn secondary" data-revenue-swap-remove-chain="' + idx + '">Remove chain</button></div>'
          + '</div>';
      }).join('');
      if (!rows) rows = '<div style="font-size:0.75rem;color:var(--muted)">No chain targets configured yet. Add one below.</div>';
      return '<div class="settings-section"><div class="settings-section-title">Revenue Swap</div>'
        + '<div style="font-size:0.75rem;color:var(--muted);margin-bottom:0.75rem">Default post-settlement conversion policy. Users can disable auto-swap, change the target asset, or configure any chain so long as the contract addresses are supplied.</div>'
        + '<div class="settings-row"><div class="settings-label">Auto-swap by default</div><div class="settings-toggle-wrap"><label class="toggle"><input type="checkbox" data-settings-path="treasury.revenue_swap.enabled"' + (cfg.enabled !== false ? ' checked' : '') + '><span class="toggle-track"></span></label><span class="settings-toggle-label">' + (cfg.enabled !== false ? 'On' : 'Off') + '</span></div></div>'
        + '<div class="settings-row"><div class="settings-label">Target symbol</div><input class="settings-input" type="text" data-settings-path="treasury.revenue_swap.target_symbol" value="' + esc(cfg.target_symbol || 'PUSD') + '" placeholder="PUSD"></div>'
        + '<div class="settings-row"><div class="settings-label">Default chain</div><input class="settings-input" type="text" data-settings-path="treasury.revenue_swap.default_chain" value="' + esc(cfg.default_chain || 'ETH') + '" placeholder="ETH"></div>'
        + '<div class="settings-row"><div class="settings-label">Configured chains</div><div style="width:100%">' + rows + '</div></div>'
        + '<div class="model-order-add" style="margin-top:0.5rem"><input id="revenue-swap-chain-add" class="settings-input" type="text" placeholder="Add chain (e.g. ETH, SOLANA, BSC, ARBITRUM)"><button class="btn secondary" id="revenue-swap-chain-add-btn">Add chain</button></div>'
        + '</div>';
};
