<div class="home-scroll" x-show="activeView === 'home'" x-cloak>
  <div
    class="home-page"
    x-data="{
    concernKeys: ['context', 'constraints', 'verification', 'recovery', 'feedback_loop'],
    concernLabels: {
      context: 'Context',
      constraints: 'Constraints',
      verification: 'Verification',
      recovery: 'Recovery',
      feedback_loop: 'Feedback'
    },
    setupScope() { return report?.scopes?.setup || { status: 'fail', checks: [] }; },
    setupChecks() { return this.setupScope().checks || []; },
    setupTotal() { return this.setupChecks().length; },
    setupPassed() { return this.setupChecks().filter((check) => check.status === 'pass').length; },
    setupComplete() { return this.setupTotal() > 0 && this.setupPassed() === this.setupTotal(); },
    setupBlocked() { return !this.setupComplete(); },
    setupPartial() { return this.setupPassed() > 0 && !this.setupComplete(); },
    setupMissing() { return this.setupPassed() === 0; },
    showPreviewAgents() { return this.agentScores().length === 0; },
    activeSessions() { return currentProjectSessions.filter((session) => session.status === 'active'); },
    primarySession() { return this.activeSessions()[0] || null; },
    sessionLabel(session) {
      if (!session) return 'session';
      return sessionTitleFor(session);
    },
    sessionAge(session) {
      if (!session) return '0m';
      const seconds = typeof session.age === 'number'
        ? session.age
        : Math.max(0, Math.floor((Date.now() - new Date(session.createdAt).getTime()) / 1000));
      const minutes = Math.max(0, Math.floor(seconds / 60));
      const hours = Math.floor(minutes / 60);
      if (hours > 0) return hours + 'h ' + (minutes % 60) + 'm';
      return minutes + 'm';
    },
    openSession(session) {
      if (!session) return;
      if (isSessionBoundLocally(session.id)) {
        activeSessionId = session.id;
        activeView = 'workspace';
        workspacePanel = 'terminal';
        return;
      }
      openServerSession(session);
    },
    endPrimarySession() {
      const session = this.primarySession();
      if (session) endServerSession(session.id);
    },
    auditAgeHours() {
      if (!lastAuditTime) return 0;
      return Math.max(0, Math.floor((Date.now() - new Date(lastAuditTime).getTime()) / 3600000));
    },
    auditAgeText() {
      const prefix = auditCached ? 'cached - ' : 'audited ';
      return prefix + formatAuditAge(lastAuditTime);
    },
    auditStale() { return Boolean(auditCached && this.auditAgeHours() > 24); },
    agentScores() { return report?.agentScores || []; },
    agentColumnCount() { return Math.min(Math.max(this.homeAgents().length, 1), 4); },
    homeAgents() {
      if (!this.showPreviewAgents()) return this.agentScores();
      return supportedAgents.map((agent) => ({ preview: true, id: agent.id, name: agent.name }));
    },
    agentDisplayName(agent) { return agent?.name || agent?.id || 'Agent'; },
    agentScore(agent) {
      if (agent?.preview) return null;
      const harnessChecks = agent?.harness?.checks || [];
      if (harnessChecks.length > 0) {
        const scored = harnessChecks.filter((check) => check.status !== 'skipped');
        if (scored.length === 0) return 100;
        const passed = scored.filter((check) => check.status === 'pass').length;
        return Math.round((passed / scored.length) * 100);
      }
      const agentChecks = agent?.agent?.checks || [];
      if (agentChecks.length > 0) {
        const scored = agentChecks.filter((check) => check.status !== 'skipped');
        if (scored.length === 0) return 100;
        const passed = scored.filter((check) => check.status === 'pass').length;
        return Math.round((passed / scored.length) * 100);
      }
      return null;
    },
    gradeFor(score) {
      if (score === null || Number.isNaN(score)) return '-';
      if (score >= 90) return 'A';
      if (score >= 80) return 'B';
      if (score >= 70) return 'C';
      if (score >= 60) return 'D';
      return 'F';
    },
    toneForScore(score) {
      if (score === null || Number.isNaN(score)) return 'na';
      if (score >= 80) return 'ok';
      if (score >= 70) return 'warn';
      return 'bad';
    },
    agentCardClass(agent) {
      if (agent?.preview) return 'disabled';
      const tone = this.toneForScore(this.agentScore(agent));
      return tone === 'ok' ? '' : tone;
    },
    concern(agent, key) { return agent?.concerns?.[key] || { status: 'fail', score: 0, findings: [], recommendations: [], howToFix: [] }; },
    concernScore(agent, key) {
      if (agent?.preview) return null;
      const item = this.concern(agent, key);
      if (typeof item.score === 'number') return Math.round(item.score);
      return item.status === 'pass' ? 100 : 0;
    },
    concernWidth(agent, key) {
      const score = this.concernScore(agent, key);
      return score === null ? '0%' : Math.max(6, score) + '%';
    },
    concernPctText(agent, key) {
      const score = this.concernScore(agent, key);
      return score === null ? '-' : String(score);
    },
    concernToneClass(agent, key) { return this.toneForScore(this.concernScore(agent, key)); },
    expandedAgentBreakdowns: {},
    agentAllConcernsPassing(agent) {
      if (agent?.preview || !agent?.concerns) return false;
      return this.concernKeys.every((key) => {
        const item = this.concern(agent, key);
        return item.status === 'pass' && this.concernScore(agent, key) >= 100;
      });
    },
    agentBreakdownOpen(agent) {
      return !this.agentAllConcernsPassing(agent) || this.expandedAgentBreakdowns[agent.id] === true;
    },
    toggleAgentBreakdown(agent) {
      if (!agent?.id) return;
      this.expandedAgentBreakdowns[agent.id] = !this.expandedAgentBreakdowns[agent.id];
    },
    recommendationSummary(agent) {
      if (agent?.preview) return 'Skills, hooks, instruction file';
      const recs = Object.values(agent?.concerns || {}).reduce((total, concern) => total + (concern.recommendations || []).length, 0);
      const integrity = this.integrityFailCount(agent);
      const warnings = this.scoreOnlyWarningCount(agent);
      if (recs === 0 && integrity === 0 && warnings === 0) return 'All checks passing';
      if (integrity > 0) return integrity + ' integrity issue' + (integrity === 1 ? '' : 's');
      if (warnings > 0) return warnings + ' score warning' + (warnings === 1 ? '' : 's');
      return recs + ' recommendation' + (recs === 1 ? '' : 's');
    },
    scoreOnlyWarningCount(agent) {
      return (agent?.harness?.checks || []).filter((check) => check.status === 'fail' && check.impact === 'score-only').length;
    },
    integrityFailCount(agent) {
      return Object.values(agent?.concerns || {}).reduce((total, concern) => total + (concern.integrityFail || 0), 0);
    },
    setupCheckPass(id) { return this.setupChecks().some((check) => check.id === id && check.status === 'pass'); },
    allAgentsPassCheck(id) {
      const agents = this.agentScores();
      return agents.length > 0 && agents.every((agent) =>
        (agent.agent?.checks || []).some((check) => check.id === id && check.status === 'pass')
      );
    },
    failureText(check) {
      return check?.failure?.message || check?.failure?.howToFix || '';
    },
    setupCheckDetail(id) {
      const check = this.setupChecks().find((item) => item.id === id && item.status === 'fail');
      return this.failureText(check);
    },
    agentCheckDetail(id) {
      const agents = this.agentScores();
      const active = agents.find((agent) => agent.id === activeRunner);
      const ordered = active ? [active, ...agents.filter((agent) => agent.id !== activeRunner)] : agents;
      const check = ordered
        .flatMap((agent) => agent.agent?.checks || [])
        .find((item) => item.id === id && item.status === 'fail');
      return this.failureText(check);
    },
    verificationGateDetail() {
      return [
        this.setupCheckDetail('config-version'),
        this.setupCheckDetail('config-parses'),
        this.agentCheckDetail('agent-settings')
      ].find((detail) => detail) || '';
    },
    installChecks() {
      return [
        { label: 'Agent instruction files present', ok: this.allAgentsPassCheck('agent-instruction'), detail: this.agentCheckDetail('agent-instruction') },
        { label: 'Agent skills installed and current', ok: this.allAgentsPassCheck('agent-skills'), detail: this.agentCheckDetail('agent-skills') },
        { label: 'Agent guardrails hooks enabled', ok: this.allAgentsPassCheck('agent-guardrails'), detail: this.agentCheckDetail('agent-guardrails') },
        { label: 'Footguns and lessons tracked', ok: this.setupCheckPass('footguns') && this.setupCheckPass('lessons'), detail: this.setupCheckDetail('footguns') || this.setupCheckDetail('lessons') },
        { label: 'Verification gates configured', ok: this.setupCheckPass('config-parses') && this.setupCheckPass('config-version') && this.allAgentsPassCheck('agent-settings'), detail: this.verificationGateDetail() }
      ];
    },
    installChecklistScore() {
      const checks = this.installChecks();
      if (checks.length === 0) return null;
      const passed = checks.filter((check) => check.ok).length;
      return Math.round((passed / checks.length) * 100);
    },
    installCheckIcon(check) { return check.ok ? '&#10003;' : '&#10005;'; },
    installPillTone() {
      if (this.setupComplete()) return 'ok';
      return this.setupPartial() ? 'warn' : 'bad';
    },
    installPillValue() {
      if (this.setupComplete()) return 'Passing';
      return this.setupPartial() ? 'Partial' : 'Not installed';
    },
    installPillDetail() {
      if (this.setupTotal() === 0) return 'audit components';
      return this.setupPassed() + ' of ' + this.setupTotal() + ' components';
    },
    harnessAverage() {
      const scores = this.agentScores().map((agent) => this.agentScore(agent)).filter((score) => score !== null && !Number.isNaN(score));
      if (scores.length === 0) return null;
      return Math.round(scores.reduce((total, score) => total + score, 0) / scores.length);
    },
    readinessScore() {
      const scores = [];
      const installScore = this.installChecklistScore();
      if (installScore !== null && !Number.isNaN(installScore)) scores.push(installScore);
      const harnessScore = this.harnessAverage();
      if (this.setupComplete() && harnessScore !== null && !Number.isNaN(harnessScore)) scores.push(harnessScore);
      if (scores.length === 0) return null;
      return Math.round(scores.reduce((total, score) => total + score, 0) / scores.length);
    },
    ringTone() { return this.toneForScore(this.readinessScore()); },
    ringColor() {
      const tone = this.ringTone();
      if (tone === 'ok') return 'var(--status-pass)';
      if (tone === 'warn') return 'var(--status-waiting)';
      if (tone === 'bad') return 'var(--status-danger)';
      return 'rgba(148, 163, 184, 0.25)';
    },
    ringStyle() {
      const value = this.readinessScore();
      return { '--ring-color': this.ringColor(), '--ring-value': value === null ? '0%' : value + '%' };
    },
    ringLabel() {
      return 'READINESS';
    },
    ringNumber() {
      const value = this.readinessScore();
      return value === null ? '--' : String(value);
    },
    ringShowPct() {
      return this.readinessScore() !== null;
    },
    ringBreakdown() {
      const installScore = this.installChecklistScore();
      const harnessScore = this.setupComplete() ? this.harnessAverage() : null;
      const fmt = (value) => value === null || Number.isNaN(value) ? '--' : value + '%';
      return 'Install ' + fmt(installScore) + ' / Harness ' + fmt(harnessScore);
    },
    atAGrade() { return this.agentScores().filter((agent) => this.agentScore(agent) >= 90 && !this.harnessAgentFailed(agent)).length; },
    harnessBlockingFailures() {
      return this.agentScores().filter((agent) => this.harnessAgentFailed(agent));
    },
    widestGap() {
      const agents = this.agentScores();
      if (agents.length === 0) return 'pending';
      const gaps = this.concernKeys.map((key) => {
        const values = agents.map((agent) => this.concernScore(agent, key)).filter((score) => score !== null);
        const avg = values.length === 0 ? 0 : values.reduce((total, score) => total + score, 0) / values.length;
        return { key, avg };
      }).sort((a, b) => a.avg - b.avg);
      const gap = gaps[0];
      return gap && gap.avg < 90 ? this.concernLabel(gap.key) : 'none';
    },
    concernLabel(key) {
      if (key === 'verification' && this.setupBlocked()) return 'Verification support';
      return this.concernLabels[key] || key;
    },
    sectionMeta() {
      if (this.showPreviewAgents()) return 'preview - audit will populate after install';
      if (this.setupBlocked()) return 'setup incomplete - raw details only';
      const total = this.agentScores().length;
      const failing = this.harnessBlockingFailures().length;
      const gap = this.widestGap();
      const gapText = gap !== 'none' && gap !== 'pending' ? ' - widest gap is ' + gap : '';
      if (failing > 0) return failing + ' of ' + total + ' agents need fixes' + gapText + ' - click for details';
      return this.atAGrade() + ' of ' + total + ' at A' + gapText + ' - click for details';
    },
    harnessPillTone() {
      if (this.setupBlocked() || this.agentScores().length === 0) return 'na';
      if (this.harnessBlockingFailures().length > 0) return 'bad';
      return this.toneForScore(this.harnessAverage());
    },
    harnessPillValue() {
      if (this.setupBlocked()) return 'Setup first';
      if (this.harnessBlockingFailures().length > 0) return 'Needs work';
      const avg = this.harnessAverage();
      if (avg === null) return 'N/A';
      return avg >= 90 ? 'Passing' : 'Needs work';
    },
    harnessPillDetail() {
      if (this.setupBlocked()) return 'finish setup before trusting harness';
      const total = this.agentScores().length;
      if (total === 0) return 'run audit after setup';
      const failing = this.harnessBlockingFailures().length;
      const gap = this.widestGap();
      const gapText = gap !== 'none' && gap !== 'pending' ? ' - ' + gap + ' low' : '';
      if (failing > 0) return failing + ' of ' + total + ' agents have failing checks' + gapText;
      return this.atAGrade() + ' of ' + total + ' agents at A' + gapText;
    },
    learningSummary() { return report?.learningLoop || null; },
    learningIndexEntries() {
      const entries = this.learningSummary()?.indexes;
      return Array.isArray(entries) ? entries : [];
    },
    learningIndexRows() {
      return this.learningIndexEntries().filter((entry) => entry.state !== 'no-bucket');
    },
    learningIndexCount(state) {
      return this.learningIndexEntries().filter((entry) => entry.state === state).length;
    },
    learningIndexAvailable() {
      return this.learningIndexRows().length > 0;
    },
    learningIndexButtonDisabled() {
      return this.setupBlocked() || this.indexRegenerating || !this.learningIndexAvailable();
    },
    learningIndexButtonLabel() {
      if (this.indexRegenerating) return 'Regenerating...';
      if (this.setupBlocked()) return 'Setup first';
      if (!this.learningIndexAvailable()) return 'No indexes';
      return 'Regenerate index';
    },
    learningIndexStateLabel(state) {
      if (state === 'fresh') return 'fresh';
      if (state === 'stale') return 'stale';
      if (state === 'missing') return 'missing';
      return 'not installed';
    },
    learningLoopReady() {
      if (this.setupBlocked()) return false;
      const summary = this.learningSummary();
      return Boolean(summary && summary.status !== 'unavailable');
    },
    learningLoopNaText() {
      if (this.setupMissing()) return 'No learning-loop records yet.';
      if (this.setupBlocked()) return 'Finish setup to unlock learning-loop health.';
      return 'No learning-loop files found for this project.';
    },
    learningBucketMax() {
      const counts = this.learningIndexRows().map((entry) => entry.entryCount || 0);
      return Math.max(1, ...counts);
    },
    learningBarWidth(entry) {
      const count = entry.entryCount || 0;
      if (count <= 0) return '0%';
      return Math.max(5, Math.round((count / this.learningBucketMax()) * 100)) + '%';
    },
    learningBarTone(entry) {
      if (entry.state === 'fresh') return 'ok';
      if (entry.state === 'stale') return 'warn';
      return 'na';
    },
    learningLoopStatusDetail() {
      const summary = this.learningSummary();
      if (!summary) return '';
      const total = this.learningIndexRows().reduce((acc, entry) => acc + (entry.entryCount || 0), 0);
      const parts = [total + ' active entries'];
      if (summary.staleCount > 0) parts.push(summary.staleCount + ' stale');
      if (summary.oversizedCount > 0) parts.push(summary.oversizedCount + ' oversized');
      if (summary.invalidLineRefCount > 0) parts.push(summary.invalidLineRefCount + ' bad refs');
      const indexStale = this.learningIndexCount('stale');
      const indexMissing = this.learningIndexCount('missing');
      if (indexStale > 0) parts.push(indexStale + ' stale index' + (indexStale === 1 ? '' : 'es'));
      if (indexMissing > 0) parts.push(indexMissing + ' missing index' + (indexMissing === 1 ? '' : 'es'));
      return parts.join(', ');
    },
    learningPillTone() {
      if (this.setupBlocked()) return 'na';
      const summary = this.learningSummary();
      if (!summary || summary.status === 'unavailable') return 'na';
      if (this.learningIndexCount('stale') > 0 || this.learningIndexCount('missing') > 0) return 'warn';
      return summary.status === 'fresh' ? 'ok' : 'warn';
    },
    learningPillValue() {
      if (this.setupBlocked()) return 'Setup first';
      const summary = this.learningSummary();
      if (!summary || summary.status === 'unavailable') return 'N/A';
      if (this.learningIndexCount('stale') > 0) return 'Index stale';
      if (this.learningIndexCount('missing') > 0) return 'Index missing';
      return summary.status === 'fresh' ? 'Fresh' : 'Needs review';
    },
    learningPillDetail() {
      if (this.setupBlocked()) return 'created by setup';
      const summary = this.learningSummary();
      if (!summary || summary.status === 'unavailable') return 'no learning-loop files';
      const stale = summary.staleCount || 0;
      const oversized = summary.oversizedCount || 0;
      const fg = typeof summary.footgunCount === 'number' ? summary.footgunCount : null;
      const ls = typeof summary.lessonCount === 'number' ? summary.lessonCount : null;
      const parts = fg !== null && ls !== null
        ? [fg + ' footguns', ls + ' lessons']
        : [summary.recordCount + ' records'];
      if (stale > 0) parts.push(stale + ' stale');
      if (oversized > 0) parts.push(oversized + ' oversized');
      if (summary.invalidLineRefCount > 0) parts.push(summary.invalidLineRefCount + ' bad refs');
      const indexStale = this.learningIndexCount('stale');
      const indexMissing = this.learningIndexCount('missing');
      if (indexStale > 0) parts.push(indexStale + ' stale index' + (indexStale === 1 ? '' : 'es'));
      if (indexMissing > 0) parts.push(indexMissing + ' missing index' + (indexMissing === 1 ? '' : 'es'));
      return parts.join(', ');
    },
    learningOldest() {
      const summary = this.learningSummary();
      return summary?.oldestLastReviewed || null;
    },
    learningTopBuckets() {
      const summary = this.learningSummary();
      return summary?.topBucketsNeedingAction || [];
    },
    qualityLatestDate() {
      if (!homeQualityLatest?.date) return null;
      const time = homeQualityLatest.time || '0000';
      const hour = time.slice(0, 2) || '00';
      const minute = time.slice(2, 4) || '00';
      return new Date(homeQualityLatest.date + 'T' + hour + ':' + minute + ':00');
    },
    qualityPillTone() {
      if (this.setupBlocked()) return 'na';
      if (homeQualityLoading) return 'na';
      if (!homeQualityLatest) return 'warn';
      if (homeQualityLatest.blockerCount > 0) return 'bad';
      if (homeQualityLatest.majorCount > 0) return 'warn';
      return 'ok';
    },
    qualityPillValue() {
      if (this.setupBlocked()) return 'Setup first';
      if (homeQualityLoading) return 'Loading';
      if (!homeQualityLatest) return 'N/A';
      if (homeQualityLatest.blockerCount > 0) return 'Blockers';
      if (homeQualityLatest.majorCount > 0) return 'Attention';
      return 'Recent';
    },
    qualityPillDetail() {
      if (this.setupBlocked()) return 'finish setup before quality';
      if (homeQualityLoading) return '--';
      if (!homeQualityLatest) return 'no saved assessment';
      const date = this.qualityLatestDate();
      const age = date ? formatAuditAge(date) : 'recently';
      if (homeQualityLatest.blockerCount > 0) return age + ', ' + homeQualityLatest.blockerCount + ' blocker' + (homeQualityLatest.blockerCount === 1 ? '' : 's');
      if (homeQualityLatest.majorCount > 0) return age + ', ' + homeQualityLatest.majorCount + ' major';
      return age + ', 0 blockers';
    },
    nextPriority() {
      if (!this.setupComplete()) return 'setup';
      const harnessFail = this.agentScores().some((agent) => this.harnessAgentFailed(agent));
      if (harnessFail) return 'harness';
      const concernFail = this.agentScores().some((agent) =>
        Object.values(agent.concerns || {}).some((item) => item?.status === 'fail')
      );
      const qualityFail = Boolean((homeQualityLatest?.blockerCount || 0) > 0 || (homeQualityLatest?.majorCount || 0) > 0);
      if (concernFail || qualityFail || !homeQualityLatest) return 'completeness';
      return 'healthy';
    },
    failingAgent() {
      const scores = this.agentScores();
      const failing = scores.find((agent) =>
        agent.agent?.status === 'fail' || agent.harness?.status === 'fail' || this.integrityFailCount(agent) > 0 ||
        Object.values(agent.concerns || {}).some((item) => item?.status === 'fail')
      );
      return failing?.id || activeRunner;
    },
    harnessAgentFailed(agent) {
      return agent.agent?.status === 'fail' || agent.harness?.status === 'fail' || this.integrityFailCount(agent) > 0;
    },
    failingHarnessAgent() {
      const failing = this.agentScores().find((agent) => this.harnessAgentFailed(agent));
      return failing?.id || activeRunner;
    },
    nextEyebrow() {
      const priority = this.nextPriority();
      if (priority === 'setup') return this.setupPartial() ? 'FIX FIRST' : 'GET STARTED';
      if (priority === 'harness') return 'FIX FIRST';
      if (priority === 'completeness') return 'RECOMMENDED';
      return 'NEXT ACTION';
    },
    nextTitle() {
      const priority = this.nextPriority();
      if (priority === 'setup') return this.setupPartial() ? 'Finish goat-flow setup' : 'Install goat-flow for ' + agentName(activeRunner);
      if (priority === 'harness') return 'Fix the failing harness checks';
      if (priority === 'completeness') return 'Run a fresh quality assessment';
      return 'Run a skill or pick up active session';
    },
    nextDetail() {
      const priority = this.nextPriority();
      if (priority === 'setup') {
        if (this.setupPartial()) return 'This project has ' + this.setupPassed() + ' of ' + this.setupTotal() + ' setup components. Finish setup before trusting harness and quality signals.';
        return 'Creates config, skills, hooks, lessons, and instruction files for this project.';
      }
      if (priority === 'harness') return 'Use the current audit findings to repair instruction, skill, and integrity gaps.';
      if (priority === 'completeness') return 'Refresh quality history and turn the largest stale findings into concrete next work.';
      return 'The Home checks are healthy. Use the review preset to inspect the next implementation change.';
    },
    nextActionCommand() {
      const priority = this.nextPriority();
      if (priority === 'setup') return 'Generated setup prompt for ' + agentName(activeRunner);
      if (priority === 'harness') return '$ npx goat-flow audit . --harness --agent ' + this.failingHarnessAgent();
      if (priority === 'completeness') return '$ npx goat-flow quality . --agent ' + activeRunner;
      return null;
    },
    nextPrimaryLabel() {
      const priority = this.nextPriority();
      if (priority === 'setup') return this.setupPartial() ? 'Fix with ' + agentName(activeRunner) : (terminalAvailable ? 'Run with ' + agentName(activeRunner) : 'Open Setup');
      if (priority === 'harness') return 'Fix with ' + agentName(activeRunner);
      if (priority === 'completeness') return 'Run assessment';
      return 'Explore codebase';
    },
    nextSecondaryLabel() {
      const priority = this.nextPriority();
      if (priority === 'setup') return 'Setup wizard';
      if (priority === 'harness') return 'Open Setup';
      if (priority === 'completeness') return 'View prompts';
      return 'View prompts';
    },
    async runPrimaryAction() {
      const priority = this.nextPriority();
      if (priority === 'setup') {
        if (terminalAvailable) {
          const setupTarget = activeRunner;
          const setupPrompt = await generateSetupPromptForAgent(setupTarget);
          if (!setupPrompt) return;
          await launchPreset(setupPrompt, activeRunner, 'Setup ' + agentName(setupTarget) + ' via ' + agentName(activeRunner), { cwdPath: projectPath, targetPath: projectPath });
          activeView = 'workspace';
          workspacePanel = 'terminal';
          return;
        }
        activeView = 'setup';
        detectStack();
        return;
      }
      if (priority === 'harness') {
        launchPreset(this.harnessFixPrompt(), activeRunner, 'Harness fix ' + agentName(this.failingHarnessAgent()));
        activeView = 'workspace';
        workspacePanel = 'terminal';
        return;
      }
      if (priority === 'completeness') {
        qualityAgent = activeRunner;
        activeView = 'quality';
        generateQuality({ fast: true });
        generateQualityHistory();
        return;
      }
      const preset = presets.find((item) => item.id === 'explore');
      if (preset) launchPreset(preset.prompt, activeRunner, preset.label, { presetId: preset.id });
      else launchInTerminal('/goat', activeRunner, { promptLabel: 'Explore codebase', cwdPath: projectPath, targetPath: projectPath });
      activeView = 'workspace';
      workspacePanel = 'terminal';
    },
    runSecondaryAction() {
      const priority = this.nextPriority();
      if (priority === 'setup' || priority === 'harness') {
        activeView = 'setup';
        detectStack();
        return;
      }
      activeView = 'prompts';
    },
    formatConcernSummary(agent, key) {
      const item = this.concern(agent, key);
      const findings = item.findings || [];
      if (key === 'verification' && this.setupBlocked()) return 'Setup incomplete; verification evidence is support-only until setup finishes.';
      if (item.status === 'pass' && this.concernScore(agent, key) < 100 && findings.length > 0) return findings[0];
      if (item.status === 'pass') return 'No active findings';
      if (findings.length > 0) return findings[0];
      return 'Concern needs attention';
    },
    formatConcernFix(agent, key) {
      const item = this.concern(agent, key);
      const rec = (item.recommendations || [])[0];
      const fix = (item.howToFix || [])[0];
      if (rec && fix) return rec + ' Fix: ' + fix;
      return rec || fix || 'No fix detail supplied';
    },
    checkBadge(check) {
      const status = check.displayStatus || check.status;
      if (status === 'pass') return 'OK';
      if (status === 'warn') return 'Warn';
      if (status === 'info') return 'Info';
      if (status === 'skipped') return 'Skip';
      return 'Fix';
    },
    checkBadgeClass(check) {
      return check.displayStatus || check.status;
    },
    checkImpactDetail(check) {
      const parts = [];
      if (check.impact === 'scope-fail') parts.push('fails audit status');
      else if (check.impact === 'score-only') parts.push('score-only signal');
      else parts.push('no failing impact');
      if (check.type === 'metric') parts.push('metric evidence');
      if (check.acknowledged) parts.push('acknowledged advisory');
      if (check.evidenceKind === 'structural') parts.push('structural smoke');
      if (check.assurance === 'limited') parts.push('limited assurance');
      return parts.join(' · ');
    },
    detailList(agent, scope) {
      return (agent?.[scope]?.checks || []).map((check) => ({
        id: check.id,
        name: check.name,
        status: check.status,
        displayStatus: check.displayStatus,
        impact: check.impact,
        type: check.type,
        acknowledged: check.acknowledged,
        evidenceKind: check.evidenceKind,
        assurance: check.assurance,
        detail: (check.failure?.message || check.failure?.howToFix || '') ? (check.failure?.message || check.failure?.howToFix) + ' - ' + this.checkImpactDetail(check) : this.checkImpactDetail(check)
      }));
    },
    enforcementRows(agent) {
      return agent?.enforcement?.capabilities || [];
    },
    enforcementBadge(row) {
      if (row.status === 'hard') return 'Hard';
      if (row.status === 'limited') return 'Lim';
      if (row.status === 'soft') return 'Soft';
      if (row.status === 'missing') return 'Miss';
      return 'Unk';
    },
    enforcementBadgeClass(row) {
      if (row.status === 'hard') return 'pass';
      if (row.status === 'missing') return 'fail';
      if (row.status === 'unknown') return 'skipped';
      return 'warn';
    },
    harnessFixPrompt() {
      const scores = this.agentScores();
      if (scores.length === 0) {
        return [
          '/goat-plan re-run goat-flow audit for ' + activeRunner,
          '',
          'Context:',
          '- Project: ' + projectPath,
          '- Target agent: ' + activeRunner,
          '- No agent audit scores are available in the dashboard report.',
          '',
          'Goal:',
          'Run a fresh goat-flow audit and inspect the failing harness checks before editing.',
          '',
          'Constraints:',
          '- Do not guess which agent or scope is failing.',
          '- Re-run `goat-flow audit . --harness --agent ' + activeRunner + '` and report exact output before proposing fixes.'
        ].join('\n');
      }
      const target = this.failingHarnessAgent();
      const agent = scores.find((item) => item.id === target) || scores[0];
      const findings = [];
      if (agent) {
        for (const check of (agent.agent?.checks || [])) {
          if (check.status === 'fail') findings.push('agent/' + check.id + ': ' + (check.failure?.message || check.failure?.howToFix || 'check failed'));
        }
        for (const check of (agent.harness?.checks || [])) {
          if (check.status === 'fail' && check.type !== 'metric' && !check.acknowledged) findings.push('harness/' + check.id + ': ' + (check.failure?.message || check.failure?.howToFix || 'check failed'));
        }
        for (const [key, concern] of Object.entries(agent.concerns || {})) {
          if (concern.status === 'fail') findings.push(key + ': ' + ((concern.findings || []).slice(0, 2).join('; ') || 'check failed'));
        }
      }
      return [
        '/goat-plan fix goat-flow harness findings for ' + target,
        '',
        'Context:',
        '- Project: ' + projectPath,
        '- Target agent: ' + target,
        '- Latest audit age: ' + this.auditAgeText(),
        '- Findings:',
        findings.length ? findings.map((item) => '  - ' + item).join('\n') : '  - Re-run audit and inspect failing harness checks.',
        '',
        'Goal:',
        'Repair the failing goat-flow harness checks while preserving existing project behaviour.',
        '',
        'Constraints:',
        '- Read relevant instruction, skill, lesson, footgun, and pattern files before edits.',
        '- Keep changes minimal and evidence-backed.',
        '- Do not invent incidents, lessons, or footgun evidence.',
        '- Update the milestone/checklist only for tasks actually completed.',
        '- Verify with the dashboard audit/typecheck commands and paste exact pass/fail output.'
      ].join('\n');
    }
  }"
  >
    <div class="home-empty" x-show="!report">
      <div class="home-empty-mark">GF</div>
      <h2>No audit results yet</h2>
      <p>
        Run an audit to populate setup status, agent health, learning-loop
        freshness, and the next action for this project.
      </p>
      <button
        class="gf-btn gf-btn-primary gf-btn-md home-primary"
        @click="runAudit()"
        :disabled="auditing"
      >
        <span x-text="auditing ? 'Running...' : 'Run Audit'"></span>
      </button>
    </div>

    <div x-show="report">
      <div class="sessions-strip" x-show="activeSessions().length > 0">
        <div class="sessions-strip-main">
          <span
            class="gf-status-dot gf-status-running"
            aria-label="Running session"
            >●</span
          >
          <span
            class="session-count"
            x-text="activeSessions().length + ' active session' + (activeSessions().length === 1 ? '' : 's')"
          ></span>
          <span
            class="session-meta"
            x-show="primarySession()"
            x-text="agentName(primarySession()?.runner || activeRunner) + ' - ' + sessionLabel(primarySession()) + ' - ' + sessionAge(primarySession())"
          ></span>
        </div>
        <span class="spacer"></span>
        <button
          class="gf-btn gf-btn-secondary gf-btn-sm"
          @click="openSession(primarySession())"
        >
          Resume
        </button>
        <button
          class="gf-btn gf-btn-danger gf-btn-sm"
          @click="endPrimarySession()"
          x-show="primarySession()"
        >
          End
        </button>
      </div>

      <section class="rollup" :class="{ stale: auditStale() }">
        <div class="rollup-top">
          <div>
            <div class="rollup-kicker" x-show="setupMissing()">
              Home readiness
            </div>
            <div class="rollup-heading">
              <h1
                class="rollup-name"
                x-text="setupMissing() ? 'Install goat-flow for this project' : projectName"
              ></h1>
              <span
                class="rollup-meta"
                x-show="!setupMissing()"
                :class="{ warn: auditStale() }"
                x-text="auditAgeText()"
              ></span>
            </div>
            <p
              class="rollup-subtitle"
              x-show="setupMissing()"
              x-text="'One guided setup unlocks agent health, lessons, and quality tracking.'"
            ></p>
          </div>
          <div class="rollup-actions">
            <span
              class="rollup-meta"
              x-show="setupMissing()"
              :class="{ warn: auditStale() }"
              x-text="auditAgeText()"
            ></span>
            <button
              class="gf-btn gf-btn-secondary gf-btn-sm"
              :class="{ 'btn-warn': auditStale() }"
              @click="runAudit(true)"
              :disabled="auditing"
            >
              <span
                x-text="auditing ? 'Auditing...' : (auditStale() ? 'Re-audit now' : 'Re-audit')"
              ></span>
            </button>
          </div>
        </div>

        <div class="pills">
          <div class="pill" :class="installPillTone()">
            <div class="pill-head">
              <span class="pill-dot" :class="installPillTone()"></span>
              <span class="pill-label">INSTALL</span>
            </div>
            <div
              class="pill-value"
              :class="installPillTone()"
              x-text="installPillValue()"
            ></div>
            <div class="pill-detail" x-text="installPillDetail()"></div>
          </div>

          <div class="pill" :class="harnessPillTone()">
            <div class="pill-head">
              <span class="pill-dot" :class="harnessPillTone()"></span>
              <span class="pill-label">HARNESS</span>
            </div>
            <div
              class="pill-value"
              :class="harnessPillTone()"
              x-text="harnessPillValue()"
            ></div>
            <div class="pill-detail" x-text="harnessPillDetail()"></div>
          </div>

          <div class="pill" :class="learningPillTone()">
            <div class="pill-head">
              <span class="pill-dot" :class="learningPillTone()"></span>
              <span class="pill-label">LEARNING LOOP</span>
            </div>
            <div
              class="pill-value"
              :class="learningPillTone()"
              x-text="learningPillValue()"
            ></div>
            <div class="pill-detail" x-text="learningPillDetail()"></div>
          </div>

          <div class="pill" :class="qualityPillTone()">
            <div class="pill-head">
              <span class="pill-dot" :class="qualityPillTone()"></span>
              <span
                class="pill-label"
                x-text="'QUALITY - ' + agentName(activeRunner)"
              ></span>
            </div>
            <div
              class="pill-value"
              :class="qualityPillTone()"
              x-text="qualityPillValue()"
            ></div>
            <div class="pill-detail" x-text="qualityPillDetail()"></div>
          </div>
        </div>
      </section>

      <section
        class="next-action"
        :class="nextPriority() === 'healthy' ? 'priority-ok' : (nextPriority() === 'completeness' ? 'priority-warn' : 'priority-bad')"
      >
        <div class="next-action-body">
          <div class="next-action-eyebrow" x-text="nextEyebrow()"></div>
          <h2 class="next-action-title" x-text="nextTitle()"></h2>
          <p class="next-action-detail" x-text="nextDetail()"></p>
          <div
            class="next-action-cmd"
            x-show="nextActionCommand()"
            x-text="nextActionCommand()"
          ></div>
        </div>
        <div class="next-action-cta">
          <button
            class="gf-btn gf-btn-secondary gf-btn-md"
            @click="runSecondaryAction()"
          >
            <span x-text="nextSecondaryLabel()"></span>
          </button>
          <button
            class="gf-btn gf-btn-primary gf-btn-md home-primary"
            @click="runPrimaryAction()"
          >
            <span x-text="nextPrimaryLabel()"></span>
          </button>
        </div>
      </section>

      <div class="section-head">
        <span
          class="section-title"
          x-text="showPreviewAgents() ? 'What you get after setup' : (setupBlocked() ? 'AI harness detail' : 'AI harness health')"
        ></span>
        <span class="section-meta" x-text="sectionMeta()"></span>
      </div>

      <section
        class="agent-grid"
        :style="{ '--agent-columns': String(agentColumnCount()) }"
      >
        <template x-for="agent in homeAgents()" :key="agent.id">
          <article
            class="agent-card"
            :class="[agentCardClass(agent), { 'agent-card-selected': !agent.preview && auditDetailAgent === agent.id }]"
          >
            <div
              class="agent-card-button"
              role="button"
              tabindex="0"
              :aria-expanded="String(!agent.preview && auditDetailAgent === agent.id)"
              :aria-controls="'detail-' + agent.id"
              @click="if (!agent.preview) auditDetailAgent = auditDetailAgent === agent.id ? null : agent.id"
              @keydown.enter="if (!agent.preview) auditDetailAgent = auditDetailAgent === agent.id ? null : agent.id"
              @keydown.space.prevent="if (!agent.preview) auditDetailAgent = auditDetailAgent === agent.id ? null : agent.id"
            >
              <div class="agent-card-head">
                <span
                  class="agent-name"
                  x-text="agentDisplayName(agent)"
                ></span>
                <span
                  class="agent-grade"
                  :class="toneForScore(agentScore(agent))"
                >
                  <span
                    class="grade-letter"
                    x-text="gradeFor(agentScore(agent))"
                  ></span>
                  <span
                    class="grade-pct"
                    :class="toneForScore(agentScore(agent))"
                    x-text="agentScore(agent) === null ? 'preview' : agentScore(agent) + '%'"
                  ></span>
                </span>
              </div>
              <div
                class="agent-summary"
                x-text="recommendationSummary(agent)"
              ></div>

              <button
                x-show="agentAllConcernsPassing(agent) && !agentBreakdownOpen(agent)"
                class="agent-all-pass"
                type="button"
                @click.stop="toggleAgentBreakdown(agent)"
                @keydown.enter.stop="toggleAgentBreakdown(agent)"
                @keydown.space.prevent.stop="toggleAgentBreakdown(agent)"
              >
                ✓ All checks passing
              </button>

              <div class="concern-list" x-show="agentBreakdownOpen(agent)">
                <template x-for="key in concernKeys" :key="key">
                  <div
                    class="concern-row"
                    :aria-label="concernLabel(key) + ' ' + concernPctText(agent, key) + '%'"
                  >
                    <span
                      class="concern-label"
                      x-text="concernLabel(key)"
                    ></span>
                    <div class="concern-bar">
                      <div
                        class="concern-fill"
                        :class="concernToneClass(agent, key)"
                        :style="{ width: concernWidth(agent, key) }"
                      ></div>
                    </div>
                    <span
                      class="concern-pct"
                      :class="concernToneClass(agent, key)"
                      x-text="concernPctText(agent, key)"
                    ></span>
                  </div>
                </template>
                <button
                  x-show="agentAllConcernsPassing(agent)"
                  class="gf-btn gf-btn-sm gf-btn-text"
                  type="button"
                  style="margin-top: 4px"
                  @click.stop="toggleAgentBreakdown(agent)"
                >
                  Collapse
                </button>
              </div>
            </div>
          </article>
        </template>
      </section>

      <div
        class="home-detail"
        x-show="auditDetailAgent && agentScores().length > 0"
        x-transition:enter="transition ease-out duration-200"
        x-transition:enter-start="opacity-0 -translate-y-2"
        x-transition:enter-end="opacity-100 translate-y-0"
        x-transition:leave="transition ease-in duration-150"
        x-transition:leave-start="opacity-100 translate-y-0"
        x-transition:leave-end="opacity-0 -translate-y-2"
        @keydown.escape.window="auditDetailAgent = null"
        :id="'detail-' + auditDetailAgent"
      >
        <template x-if="auditDetailAgent">
          <template
            x-for="agent in agentScores().filter(a => a.id === auditDetailAgent)"
            :key="agent.id"
          >
            <div>
              <div class="detail-header">
                <div class="detail-header-left">
                  <span
                    class="agent-name"
                    x-text="agentDisplayName(agent)"
                  ></span>
                  <span
                    class="agent-grade"
                    :class="toneForScore(agentScore(agent))"
                  >
                    <span
                      class="grade-letter"
                      x-text="gradeFor(agentScore(agent))"
                    ></span>
                    <span
                      class="grade-pct"
                      :class="toneForScore(agentScore(agent))"
                      x-text="agentScore(agent) + '%'"
                    ></span>
                  </span>
                </div>
                <button
                  class="detail-close"
                  @click="auditDetailAgent = null"
                  aria-label="Close detail panel"
                >
                  &times;
                </button>
              </div>
              <div class="detail-grid">
                <div class="detail-card">
                  <h4>Agent Setup</h4>
                  <template
                    x-for="check in detailList(agent, 'agent')"
                    :key="check.id"
                  >
                    <div class="detail-row">
                      <span
                        class="detail-status"
                        :class="checkBadgeClass(check)"
                        x-text="checkBadge(check)"
                      ></span>
                      <div>
                        <strong x-text="check.name"></strong>
                        <p x-text="check.detail || 'No detail supplied'"></p>
                      </div>
                    </div>
                  </template>
                </div>

                <div class="detail-card">
                  <h4>Harness Checks</h4>
                  <template
                    x-for="check in detailList(agent, 'harness')"
                    :key="check.id"
                  >
                    <div class="detail-row">
                      <span
                        class="detail-status"
                        :class="checkBadgeClass(check)"
                        x-text="checkBadge(check)"
                      ></span>
                      <div>
                        <strong x-text="check.name"></strong>
                        <p x-text="check.detail"></p>
                      </div>
                    </div>
                  </template>
                </div>

                <div class="detail-card">
                  <h4>Enforcement Matrix</h4>
                  <template x-for="row in enforcementRows(agent)" :key="row.id">
                    <div class="detail-row">
                      <span
                        class="detail-status"
                        :class="enforcementBadgeClass(row)"
                        x-text="enforcementBadge(row)"
                      ></span>
                      <div>
                        <strong x-text="row.label"></strong>
                        <p x-text="row.summary"></p>
                      </div>
                    </div>
                  </template>
                </div>

                <div class="detail-card">
                  <h4>Concern Detail</h4>
                  <template x-for="key in concernKeys" :key="key">
                    <div class="detail-row">
                      <span
                        class="detail-status"
                        :class="concern(agent, key).status"
                        x-text="concern(agent, key).status === 'pass' ? 'OK' : 'Fix'"
                      ></span>
                      <div>
                        <strong x-text="concernLabel(key)"></strong>
                        <p x-text="formatConcernSummary(agent, key)"></p>
                        <p
                          class="detail-fix"
                          x-text="formatConcernFix(agent, key)"
                        ></p>
                      </div>
                    </div>
                  </template>
                </div>
              </div>
            </div>
          </template>
        </template>
      </div>

      <section class="lower-row">
        <article class="panel install-panel">
          <div class="panel-head">
            <span class="panel-title">Install state</span>
            <button
              class="panel-cta"
              x-show="!setupMissing()"
              @click="activeView = 'setup'; detectStack()"
            >
              Setup
            </button>
          </div>

          <div class="install-body">
            <div class="install-checks">
              <template x-for="check in installChecks()" :key="check.label">
                <div class="install-check" :class="{ dim: !check.ok }">
                  <span
                    class="install-check-icon"
                    :class="{ ok: check.ok, bad: !check.ok }"
                    x-html="installCheckIcon(check)"
                  ></span>
                  <span class="install-check-copy">
                    <span x-text="check.label"></span>
                    <span
                      class="install-check-detail"
                      x-show="!check.ok && check.detail"
                      x-text="check.detail"
                    ></span>
                  </span>
                </div>
              </template>
            </div>

            <div class="ring-wrap">
              <div class="ring-chart" :style="ringStyle()">
                <span class="ring-value" :style="{ color: ringColor() }">
                  <span x-text="ringNumber()"></span
                  ><span class="ring-pct" x-show="ringShowPct()">%</span>
                </span>
              </div>
              <span class="ring-label" x-text="ringLabel()"></span>
              <span class="ring-breakdown" x-text="ringBreakdown()"></span>
            </div>
          </div>
        </article>

        <article class="panel loop-panel">
          <div class="panel-head">
            <span class="panel-title">Learning loop</span>
            <button
              type="button"
              class="gf-btn gf-btn-sm gf-btn-secondary loop-regen-btn"
              x-show="!setupBlocked()"
              @click="regenerateLearningLoopIndex()"
              :disabled="learningIndexButtonDisabled()"
              x-text="learningIndexButtonLabel()"
            ></button>
          </div>

          <div x-show="learningLoopReady()">
            <div class="loop-status-row">
              <span class="pill-dot" :class="learningPillTone()"></span>
              <span
                class="loop-status-value"
                :class="learningPillTone()"
                x-text="learningPillValue()"
              ></span>
              <span
                class="loop-status-detail"
                x-text="learningLoopStatusDetail()"
              ></span>
            </div>

            <div
              class="loop-index-list"
              x-show="learningIndexRows().length > 0"
            >
              <template
                x-for="entry in learningIndexRows()"
                :key="entry.bucket"
              >
                <div class="loop-index-row" :title="entry.indexPath">
                  <span class="loop-index-bucket" x-text="entry.bucket"></span>
                  <div class="loop-stat-bar">
                    <div
                      class="loop-stat-fill"
                      :class="learningBarTone(entry)"
                      :style="{ width: learningBarWidth(entry) }"
                    ></div>
                  </div>
                  <span
                    class="loop-index-count"
                    x-text="entry.entryCount"
                  ></span>
                  <span
                    class="learning-index-chip"
                    :class="'is-' + entry.state"
                    x-text="learningIndexStateLabel(entry.state)"
                  ></span>
                </div>
              </template>
            </div>

            <div
              class="loop-meta"
              x-show="learningOldest()"
              x-text="'Oldest review: ' + learningOldest()"
            ></div>

            <div
              class="loop-error"
              x-show="indexRegenerateError"
              x-text="indexRegenerateError"
            ></div>
          </div>

          <div class="loop-na" x-show="!learningLoopReady()">
            <div class="loop-na-mark">NA</div>
            <p x-text="learningLoopNaText()"></p>
          </div>
        </article>
      </section>

      <div
        class="gf-footer"
        style="text-align: center; font-size: 11px; padding: 12px 0"
      >
        Built by
        <a
          href="https://www.blundergoat.com"
          target="_blank"
          class="gf-footer-link"
          >BlunderGOAT</a
        >
        ·
        <span x-text="dashboardVersion ? `v${dashboardVersion}` : ''"></span>
      </div>
    </div>
  </div>
</div>
