<?php
$userId = $auth->requireAuth();

// Validation Workflow — the main Strategy editor/declaration tool belongs
// to the established-edge workflow, same as Reports/Trader Profile. Safe
// for the graduation-prefill redirect (?graduated_from=) specifically:
// ValidationService::graduate() already flips workflow_state to 'main'
// BEFORE redirecting here, so by the time this page is ever reached with
// that param, the check below is already false.
// 2026-08-17: this exact 4-line block was independently duplicated across
// reports.php/strategy.php/trader-profile.php/journal.php — now the single
// shared ValidationService::gateMainWorkflowOnly() implementation instead.
ValidationService::gateMainWorkflowOnly($userId, $db);

// ── Read-only reference mode ───────────────────────────────────────
// Reached via Strategies' "Forgot strategy?" link
// (/traderalign/strategy?strategy_id=X&mode=readonly&back_account_id=Y) —
// opens this same editor page, but locked: no save, no delete, no archive,
// no accidental modifications. See loadStrategyReadonly()/lockReadonlyUI()
// in the script block below. Ownership of $readonlyStrategyId is verified
// by the existing /api/strategy/load endpoint (403s on another user's
// strategy) — nothing extra is needed here.
$readonlyMode = ($_GET['mode'] ?? '') === 'readonly' && !empty($_GET['strategy_id']);
$readonlyStrategyId = $readonlyMode ? $_GET['strategy_id'] : null;
$readonlyBackAccountId = $_GET['back_account_id'] ?? null;
$readonlyBackUrl = '/traderalign/strategies'
    . ($readonlyBackAccountId ? ('?account_id=' . urlencode($readonlyBackAccountId)) : '');

// ── Validation Workflow graduation prefill ────────────────────────
// Reached via journal-validation.php's ("Validation Tracker") graduate
// button, which already ran ValidationService::graduate() BEFORE
// redirecting here — by this point the strategy/trades are already real
// (is_validation=0), so this only ever reads already-committed history,
// never mutates anything. Ownership + provenance are both verified
// server-side (never trust the query param alone): the strategy must
// belong to this user, must currently be non-validation, and must appear
// in this user's own onboarding_context.graduations audit trail — a
// crafted ?graduated_from= for a strategy that was never actually
// graduated (or belongs to someone else) silently gets no prefill at all.
$validationPrefill = null;
$validationEvidence = null;
$validationEdgeVerdict = null;
$graduatedFromStrategyId = $_GET['graduated_from'] ?? null;
if ($graduatedFromStrategyId) {
    $gRows = $db->raw(
        "SELECT id, name, current_version_id, is_validation
         FROM strategies WHERE id = :sid AND user_id = :uid AND deleted_at IS NULL",
        [':sid' => $graduatedFromStrategyId, ':uid' => $userId]
    );
    $gStrategy = $gRows[0] ?? null;
    $graduatedProvenanceOk = false;
    if ($gStrategy && (int)($gStrategy['is_validation'] ?? 1) === 0) {
        $gProfile = $db->selectById('user_profiles', $userId, 'user_id');
        $gCtx = json_decode($gProfile['onboarding_context'] ?? '{}', true) ?: [];
        foreach (($gCtx['graduations'] ?? []) as $g) {
            if (($g['strategy_id'] ?? null) === $graduatedFromStrategyId) { $graduatedProvenanceOk = true; break; }
        }
    }
    if ($gStrategy && $graduatedProvenanceOk && !empty($gStrategy['current_version_id'])) {
        // Reliably-derivable fields only (spec §15) — never inventing a
        // value, never guessing anything the trade history can't establish.
        $validationEvidence = ValidationService::getPostGraduationMetrics($userId, $gStrategy['current_version_id']);
        $validationPrefill = [
            'name' => $gStrategy['name'],
            'win_rate' => $validationEvidence['win_rate'] !== null ? round($validationEvidence['win_rate'] * 100, 1) : null,
            'avg_r_multiple' => $validationEvidence['avg_r_multiple'],
        ];
        // Same classification the Validation Tracker's own graduation CTA
        // already uses (ValidationService::evaluateEdge() — see the
        // 2026-08-12 edge-warning pass) — reused here, not re-derived, so
        // a strategy can never read as "demonstrated" on one page and
        // "not demonstrated" on another. Drives both the recommendation
        // banner below and the modal's copy (see the JS block further
        // down) — a trader arriving here should either proceed with real
        // confidence or get a clear, honest caution, never a generic
        // "create your strategy" prompt that implies nothing was already
        // tested.
        $validationEdgeVerdict = ValidationService::evaluateEdge($validationEvidence);
    }
}

// ── Strategy health counts (for cap warnings) ─────────────────────
// Scoped to real (non-validation) strategies only — this page (Strategy
// Builder) is being redesigned around the persistent-edge/Strategy Change
// Event model (TRADERALIGN STRATEGY BUSINESS RULES.docx). Validation/
// practice strategies (is_validation = 1) are a separate, not-yet-
// redesigned domain (their own dedicated wizard is strategy-validation.php)
// and are deliberately excluded from every query on this page, not just
// hidden in the UI, so this page can never write a Strategy Change Event
// against one.
$healthStats = $db->raw("
    SELECT
        COUNT(*) AS total_active,
        SUM(CASE WHEN trade_count < 10 OR trade_count IS NULL THEN 1 ELSE 0 END) AS low_activity_count,
        SUM(CASE WHEN days_since_last > 30 OR days_since_last IS NULL THEN 1 ELSE 0 END) AS stale_count
    FROM (
        SELECT
            s.id,
            COUNT(t.id) AS trade_count,
            DATEDIFF(NOW(), MAX(t.closed_at)) AS days_since_last
        FROM strategies s
        LEFT JOIN strategy_versions sv ON sv.strategy_id = s.id
        LEFT JOIN trades t ON t.strategy_version_id = sv.id AND t.status = 'closed' AND t.deleted_at IS NULL
        WHERE s.user_id = :uid AND s.is_active = 1 AND s.deleted_at IS NULL
          AND (s.is_validation = 0 OR s.is_validation IS NULL)
        GROUP BY s.id
    ) sub
", [':uid' => $userId]);

$totalActiveStrategies = (int)($healthStats[0]['total_active'] ?? 0);
$lowActivityCount = (int)($healthStats[0]['low_activity_count'] ?? 0);
$staleCount = (int)($healthStats[0]['stale_count'] ?? 0);

// Encode for JavaScript
$strategyHealthJson = json_encode([
    'totalActive' => $totalActiveStrategies,
    'lowActivityCount' => $lowActivityCount,
    'staleCount' => $staleCount,
]);

// ── All active strategies for the search dropdown ─────────────────
// change_count feeds a plain "N changes" badge — replaces the old "vN"
// badge (business rules §13: version numbers must never be user-facing).
$allUserStrategies = $db->raw("
    SELECT s.id, s.name, s.trading_style, s.current_version_id,
           (SELECT COUNT(*) FROM checklist_items ci WHERE ci.strategy_version_id = sv.id) AS item_count,
           (SELECT COUNT(*) FROM strategy_change_events sce WHERE sce.strategy_id = s.id) AS change_count
    FROM strategies s
    JOIN strategy_versions sv ON sv.id = s.current_version_id
    WHERE s.user_id = :uid AND s.is_active = 1 AND s.deleted_at IS NULL
      AND (s.is_validation = 0 OR s.is_validation IS NULL)
    ORDER BY s.created_at DESC
", [':uid' => $userId]);

$allStrategiesJson = json_encode($allUserStrategies);
?>
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Strategy - TraderAlign</title>
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&family=JetBrains+Mono:wght@400;500;600&display=swap" rel="stylesheet">
<link rel="stylesheet" href="/traderalign/assets/tokens.css">
<link rel="icon" type="image/png" sizes="32x32" href="/traderalign/assets/favicon/favicon-32.png">
    <link rel="icon" type="image/png" sizes="16x16" href="/traderalign/assets/favicon/favicon-16.png">
    <link rel="apple-touch-icon" sizes="180x180" href="/traderalign/assets/favicon/apple-touch-icon.png">
    <link rel="shortcut icon" href="/traderalign/assets/favicon/favicon.ico">
<link rel="stylesheet" href="/traderalign/assets/css/brand.css">

<style>
.dash-layout{display:flex;min-height:100vh}
.sidebar{width:4rem;background:var(--sidebar);border-right:1px solid var(--sidebar-border);display:flex;flex-direction:column;align-items:center;padding-top:1rem;gap:.25rem;position:fixed;top:0;left:0;bottom:0;z-index:40}
.sidebar a{display:flex;align-items:center;justify-content:center;width:2.75rem;height:2.75rem;border-radius:var(--radius-md);color:var(--foreground-dim);transition:background var(--t-fast),color var(--t-fast);position:relative}
.sidebar a:hover{background:var(--background-surface);color:var(--foreground)}
.sidebar a.active{background:var(--background-surface);color:var(--sidebar-primary)}
.sidebar a .tt{position:absolute;left:3.5rem;background:var(--popover);color:var(--foreground);font-size:.75rem;padding:.25rem .625rem;border-radius:var(--radius-sm);white-space:nowrap;pointer-events:none;opacity:0;transition:opacity var(--t-fast)}
.sidebar a:hover .tt{opacity:1}
.main{margin-left:4rem;flex:1;padding:2rem}
body{background:var(--background);margin:0}

/* ===== Strategy Styles ===== */
.strat-container{padding:0 0 40px 0;max-width:960px}
.control-card{background:var(--background-elevated);border:1px solid var(--border);border-radius:var(--radius-xl);padding:16px 22px;margin-bottom:20px;display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap}
.control-card .cc-left{display:flex;align-items:center;gap:8px}
.control-card .cc-divider{width:1px;height:24px;background:var(--border)}
.strat-tab{padding:8px 16px;border-radius:var(--radius-full);font-size:13px;font-weight:600;color:var(--foreground-dim);transition:all .2s ease;background:none;border:none;cursor:pointer;font-family:var(--font-sans);white-space:nowrap}
.strat-tab:hover{color:var(--foreground);background:var(--background-surface)}
.strat-tab.active{background:var(--primary);color:#fff}

.strat-rail{display:none}

/* Strategy card in list */
.strat-list-card{background:var(--background-elevated);border:1px solid var(--border);border-radius:var(--radius-lg);padding:16px 20px;margin-bottom:10px;display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap;transition:border-color .2s}
.strat-list-card:hover{border-color:color-mix(in srgb,var(--primary) 25%,transparent)}
.strat-list-card .slc-info{display:flex;flex-direction:column;gap:4px}
.strat-list-card .slc-name{font-weight:700;color:var(--foreground);font-size:14px}
.strat-list-card .slc-meta{font-size:11px;color:var(--foreground-dim)}
.strat-list-card .slc-actions{display:flex;gap:8px;align-items:center}
.btn-archive{display:inline-flex;align-items:center;gap:4px;padding:6px 14px;border-radius:var(--radius-full);font-size:11px;font-weight:600;color:var(--foreground-dim);background:transparent;border:1px solid var(--border);cursor:pointer;transition:all .2s;font-family:var(--font-sans)}
.btn-archive:hover{color:var(--negative);border-color:var(--negative);background:color-mix(in srgb,var(--negative) 8%,transparent)}

.premium-card{background:var(--background-elevated);border:1px solid var(--border);border-radius:var(--radius-xl);padding:28px 32px;margin-bottom:20px;position:relative;overflow:hidden}
.premium-card::after{content:'';position:absolute;top:0;right:0;width:200px;height:200px;background:radial-gradient(circle,color-mix(in srgb,var(--primary) 3%,transparent),transparent 70%);pointer-events:none}
.premium-card .pc-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:6px;position:relative;z-index:1}
.premium-card .pc-head h2{font-size:18px;font-weight:700;color:var(--foreground);letter-spacing:-.01em}
.premium-card .pc-subtitle{font-size:12px;color:var(--foreground-dim);margin-bottom:18px;position:relative;z-index:1}

.prompt-card{background:var(--background-elevated);border:1px solid var(--border);border-left:3px solid transparent;border-radius:var(--radius-lg);padding:24px 28px;margin:0;position:relative;overflow:hidden;cursor:pointer;transition:all .2s ease}
.prompt-card:hover{transform:translateY(-2px);box-shadow:0 8px 24px rgba(0,0,0,.2)}
.prompt-card::after{content:'';position:absolute;top:0;left:0;width:100%;height:100%;background:radial-gradient(ellipse at top left,color-mix(in srgb,var(--primary) 4%,transparent),transparent 70%);pointer-events:none;z-index:0}
.prompt-card>*{position:relative;z-index:1}
.prompt-card.new-strat::before{content:'';position:absolute;top:0;left:0;width:3px;height:100%;z-index:1;background:var(--positive);animation:greenFlow 4s ease-in-out infinite}
@keyframes greenFlow{0%,100%{box-shadow:0 0 8px color-mix(in srgb,var(--positive) 45%,transparent),0 0 22px color-mix(in srgb,var(--positive) 18%,transparent)}33%{box-shadow:0 0 8px color-mix(in srgb,#10b981 45%,transparent),0 0 22px color-mix(in srgb,#10b981 18%,transparent)}66%{box-shadow:0 0 8px color-mix(in srgb,#34d399 45%,transparent),0 0 22px color-mix(in srgb,#34d399 18%,transparent)}}
.prompt-card.refine-strat::before{content:'';position:absolute;top:0;left:0;width:3px;height:100%;z-index:1;background:var(--primary);animation:blueFlow 5s ease-in-out infinite}
@keyframes blueFlow{0%,100%{box-shadow:0 0 8px color-mix(in srgb,var(--primary) 45%,transparent),0 0 22px color-mix(in srgb,var(--primary) 18%,transparent)}50%{box-shadow:0 0 8px color-mix(in srgb,#818cf8 45%,transparent),0 0 22px color-mix(in srgb,#818cf8 18%,transparent)}}
.prompt-card .pr-icon{font-size:26px;margin-bottom:8px}
.prompt-card .pr-title{font-size:1.05rem;font-weight:700;color:var(--foreground);margin-bottom:4px;display:flex;align-items:center;gap:8px;flex-wrap:wrap}
.prompt-card .pr-desc{font-size:.82rem;color:var(--foreground-dim);line-height:1.6;max-width:540px}
.pr-ver-badge{font-size:10px;font-weight:600;padding:3px 9px;border-radius:var(--radius-full);background:color-mix(in srgb,var(--primary) 15%,transparent);color:var(--primary);white-space:nowrap}

/* ── Strategy search dropdown ─────────────────────── */
.search-wrap{position:relative;margin-bottom:14px}
.search-wrap input{width:100%;padding:11px 14px;font-size:14px;background:var(--background-surface);border:1px solid var(--border);border-radius:var(--radius-md);color:var(--foreground);font-family:var(--font-sans);outline:none;transition:border-color .15s}
.search-wrap input:focus{border-color:var(--ring);box-shadow:0 0 0 3px color-mix(in srgb,var(--ring) 15%,transparent)}
.search-drop{position:absolute;top:100%;left:0;right:0;background:var(--popover);border:1px solid var(--border);border-radius:var(--radius-md);max-height:280px;overflow:auto;z-index:30;display:none;box-shadow:0 8px 24px rgba(0,0,0,.3);margin-top:4px}
.search-drop.show{display:block}
.search-opt{padding:10px 14px;cursor:pointer;display:flex;align-items:center;justify-content:space-between;gap:12px;color:var(--foreground);transition:background .12s;border-bottom:1px solid color-mix(in srgb,var(--border) 30%,transparent)}
.search-opt:last-child{border-bottom:none}
.search-opt:hover,.search-opt.hi{background:color-mix(in srgb,var(--primary) 10%,transparent)}
.search-opt .so-left{display:flex;flex-direction:column;gap:2px}
.search-opt .so-name{font-weight:600;font-size:13px}
.search-opt .so-meta{font-size:10px;color:var(--foreground-dim)}
.search-opt .so-right{display:flex;align-items:center;gap:6px;flex-shrink:0}
.search-opt .so-style{font-size:9px;text-transform:uppercase;letter-spacing:.5px;color:var(--foreground-dim);background:var(--background-surface);padding:2px 7px;border-radius:var(--radius-full)}
.search-opt .so-count{font-family:var(--font-mono);font-size:10px;color:var(--foreground-dim)}

.mgmt-card{background:var(--background-elevated);border:1px solid var(--border);border-radius:var(--radius-xl);overflow:hidden;margin-bottom:20px}
.mgmt-card .mgmt-section{padding:20px 22px}
.mgmt-card .mgmt-section+.mgmt-section{border-top:1px solid var(--border)}
.mgmt-card .mgmt-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:14px}
.mgmt-card .mgmt-head h3{font-size:13px;font-weight:700;color:var(--foreground);text-transform:uppercase;letter-spacing:.5px;display:flex;align-items:center;gap:8px}
.mgmt-card .mgmt-head h3 .dot{width:8px;height:8px;border-radius:50%}
.mgmt-card .mgmt-head h3 .dot.green{background:var(--positive);box-shadow:0 0 8px color-mix(in srgb,var(--positive) 40%,transparent)}
.mgmt-card .mgmt-head h3 .dot.blue{background:var(--primary);box-shadow:0 0 8px color-mix(in srgb,var(--primary) 40%,transparent)}

.modal-overlay{display:none;position:fixed;inset:0;background:rgba(0,0,0,.65);z-index:200;align-items:center;justify-content:center;padding:20px}
.modal-overlay.show{display:flex}
.modal-box{background:var(--background-elevated);border:1px solid var(--border);border-radius:var(--radius-xl);padding:28px 32px;max-width:480px;width:100%;animation:modalIn .25s ease}
@keyframes modalIn{from{opacity:0;transform:scale(.95) translateY(8px)}to{opacity:1;transform:scale(1) translateY(0)}}
.modal-box h2{font-size:1.1rem;font-weight:700;color:var(--foreground);margin-bottom:6px}
.modal-box .modal-desc{font-size:.82rem;color:var(--foreground-dim);margin-bottom:16px;line-height:1.5}
.modal-box input{width:100%;padding:10px 12px;font-size:14px;background:var(--background-surface);border:1px solid var(--border);border-radius:var(--radius-md);color:var(--foreground);font-family:var(--font-sans);outline:none;margin-bottom:6px}
.modal-box input:focus{border-color:var(--primary);box-shadow:0 0 0 3px color-mix(in srgb,var(--primary) 15%,transparent)}
.modal-box .modal-err{color:var(--negative);font-size:11px;margin-bottom:12px;display:none}
.modal-box .modal-err.show{display:block}
.modal-box .modal-actions{display:flex;gap:10px;justify-content:flex-end}
.modal-box .existing-info{display:flex;flex-direction:column;gap:8px;margin-bottom:14px;padding:10px 14px;background:var(--background-surface);border-radius:var(--radius-md);border-left:3px solid var(--primary)}
.modal-box .existing-info .ei-row{display:flex;align-items:center;gap:8px;font-size:12px}
.modal-box .existing-info .ei-label{font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:var(--foreground-dim);min-width:80px}
.modal-box .existing-info .ei-value{color:var(--foreground);font-weight:600}
.modal-box .existing-info .ei-ver{font-family:var(--font-mono);font-size:10px;color:var(--primary);background:color-mix(in srgb,var(--primary) 18%,transparent);padding:2px 8px;border-radius:var(--radius-full)}

/* Cap warning modal styles */
.cap-warning-box{background:var(--background-elevated);border:1px solid var(--border);border-radius:var(--radius-xl);padding:28px 32px;max-width:520px;width:100%;animation:modalIn .25s ease}
.cap-warning-box h2{font-size:1.1rem;font-weight:700;color:var(--foreground);margin-bottom:10px}
.cap-warning-box .cap-message{font-size:.84rem;color:var(--foreground-dim);line-height:1.6;margin-bottom:18px}
.cap-warning-box .cap-stats{display:flex;gap:16px;margin-bottom:18px;flex-wrap:wrap}
.cap-warning-box .cap-stat{background:var(--background-surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:12px 16px;text-align:center;min-width:80px;flex:1}
.cap-warning-box .cap-stat .cs-value{font-family:var(--font-mono);font-size:1.3rem;font-weight:700;color:var(--foreground)}
.cap-warning-box .cap-stat .cs-label{font-size:10px;text-transform:uppercase;letter-spacing:.5px;color:var(--foreground-dim);margin-top:2px}
.cap-warning-box .cap-actions{display:flex;gap:10px;justify-content:flex-end}

.btn-revert{display:inline-flex;align-items:center;gap:6px;padding:10px 18px;border-radius:var(--radius-lg);font-size:13px;font-weight:500;color:var(--foreground-dim);background:var(--background-surface);border:1px solid var(--border);cursor:pointer;transition:all .2s ease;font-family:var(--font-sans)}
.btn-revert:hover{color:var(--foreground);border-color:var(--foreground-dim);background:var(--background-elevated)}
.btn-save{display:inline-flex;align-items:center;gap:8px;padding:10px 22px;border-radius:var(--radius-lg);font-size:13px;font-weight:600;color:#fff;background:var(--primary);border:1px solid var(--primary);cursor:pointer;transition:all .2s ease;font-family:var(--font-sans);box-shadow:0 2px 8px color-mix(in srgb,var(--primary) 30%,transparent)}
.btn-save:hover{opacity:.9;transform:translateY(-1px)}
.btn-save:active{transform:translateY(0)}
.btn-continue{display:inline-flex;align-items:center;gap:8px;padding:10px 22px;border-radius:var(--radius-lg);font-size:13px;font-weight:600;color:#fff;background:var(--warning);border:1px solid var(--warning);cursor:pointer;transition:all .2s ease;font-family:var(--font-sans)}
.btn-continue:hover{opacity:.9}
.btn-analytics{display:inline-flex;align-items:center;gap:8px;padding:10px 22px;border-radius:var(--radius-lg);font-size:13px;font-weight:600;color:var(--primary);background:transparent;border:1px solid var(--primary);cursor:pointer;transition:all .2s ease;font-family:var(--font-sans);text-decoration:none}
.btn-analytics:hover{background:color-mix(in srgb,var(--primary) 10%,transparent)}

.field.required label::after{content:' *';color:var(--negative);font-weight:700}
.field.highlight-empty input{border-color:var(--negative);animation:shake .4s ease}
@keyframes shake{0%,100%{transform:translateX(0)}25%{transform:translateX(-4px)}75%{transform:translateX(4px)}}

.edge-grid{display:grid;grid-template-columns:1fr 1fr;gap:14px;position:relative;z-index:1}
.edge-card{background:var(--background-surface);border:1px solid var(--border);border-radius:var(--radius-lg);padding:18px 20px;transition:all .2s ease;position:relative;overflow:hidden}
.edge-card:hover{border-color:color-mix(in srgb,var(--primary) 30%,transparent);box-shadow:0 4px 16px rgba(0,0,0,.15)}
.edge-card::before{content:'';position:absolute;top:0;left:0;width:3px;height:100%;border-radius:3px 0 0 3px}
.edge-card.setup::before{background:var(--primary)}.edge-card.entry::before{background:var(--positive)}
.edge-card.risk::before{background:var(--warning)}.edge-card.execution::before{background:#a78bfa}
.edge-card .ec-icon{font-size:18px;margin-bottom:6px}
.edge-card .ec-label{font-size:11px;text-transform:uppercase;letter-spacing:.8px;color:var(--foreground-dim);font-weight:700;margin-bottom:10px}
.edge-card .ec-list{display:flex;flex-direction:column;gap:5px}
.edge-card .ec-item{display:flex;gap:5px;align-items:center}
.edge-card .ec-item input{flex:1;font-size:12px;padding:6px 9px;background:var(--background);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--foreground);font-family:var(--font-sans);outline:none;transition:border-color .15s}
.edge-card .ec-item input:focus{border-color:var(--ring)}
.edge-card .ec-item .x{color:var(--foreground-dim);cursor:pointer;font-size:13px;padding:4px 6px;border-radius:var(--radius-sm);background:none;border:none;line-height:1}
.edge-card .ec-item .x:hover{color:var(--destructive);background:var(--background)}
.edge-card .ec-add{font-size:11px;color:var(--primary);margin-top:8px;font-weight:600;background:none;border:none;cursor:pointer;font-family:var(--font-sans)}
.edge-card .ec-empty{font-size:11px;color:var(--foreground-dim);opacity:.5;font-style:italic;padding:2px 0}

.cat-row{background:var(--background-surface);border:1px solid var(--border);border-radius:var(--radius-lg);padding:16px 18px;margin-bottom:10px;transition:border-color .2s ease}
.cat-row:hover{border-color:color-mix(in srgb,var(--primary) 20%,transparent)}
.cat-row .cr-head{display:flex;align-items:center;gap:10px;margin-bottom:6px}
.cat-row .cr-badge{font-size:10px;text-transform:uppercase;letter-spacing:.8px;font-weight:700;padding:3px 9px;border-radius:var(--radius-full);flex-shrink:0}
.cat-setup{background:color-mix(in srgb,var(--primary) 18%,transparent);color:var(--primary)}
.cat-entry{background:color-mix(in srgb,var(--positive) 18%,transparent);color:var(--positive)}
.cat-risk{background:color-mix(in srgb,var(--warning) 18%,transparent);color:var(--warning)}
.cat-execution{background:color-mix(in srgb,#a78bfa 18%,transparent);color:#a78bfa}
.cat-row .cr-items{display:flex;flex-direction:column;gap:5px}
.cat-row .ci-row{display:flex;gap:8px;align-items:flex-start}
.cat-row .ci-row input{flex:1;font-size:12px;padding:7px 9px;background:var(--background);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--foreground);font-family:var(--font-sans);outline:none}
.cat-row .ci-row input:focus{border-color:var(--ring)}
.cat-row .ci-hint{margin-top:3px}
.cat-row .ci-hint input{font-size:11px;padding:5px 8px;background:var(--background);border:1px solid var(--border);border-radius:var(--radius-sm);color:var(--foreground);width:100%;outline:none}
.cat-row .req-tog{display:flex;align-items:center;gap:4px;font-size:10px;color:var(--foreground-dim);cursor:pointer;white-space:nowrap;padding-top:8px;user-select:none}
.cat-row .req-tog .sw{width:26px;height:15px;border-radius:var(--radius-full);background:var(--background);border:1px solid var(--border);position:relative;transition:all .2s}
.cat-row .req-tog .sw::after{content:"";position:absolute;top:1.5px;left:2px;width:11px;height:11px;border-radius:50%;background:var(--foreground-dim);transition:all .2s}
.cat-row .req-tog.on .sw{background:color-mix(in srgb,var(--primary) 25%,transparent);border-color:var(--primary)}
.cat-row .req-tog.on .sw::after{left:13px;background:var(--primary)}
.cat-row .ci-x{color:var(--foreground-dim);cursor:pointer;font-size:14px;padding:7px 5px;background:none;border:none;line-height:1}
.cat-row .ci-x:hover{color:var(--destructive)}
.cat-row .cr-add{font-size:11px;color:var(--primary);margin-top:6px;font-weight:600;background:none;border:none;cursor:pointer;font-family:var(--font-sans)}
.cat-empty{font-size:11px;color:var(--foreground-dim);opacity:.6;padding:6px 0;font-style:italic;line-height:1.5}

.help-toggle{display:inline-flex;align-items:center;gap:4px;font-size:10px;color:var(--foreground-dim);cursor:pointer;background:none;border:none;font-family:var(--font-sans);padding:2px 4px;transition:color .15s;user-select:none}
.help-toggle:hover{color:var(--foreground-muted)}
.help-toggle .arrow{display:inline-block;transition:transform .2s ease;font-size:8px}
.help-toggle.open .arrow{transform:rotate(90deg)}
.help-content{display:none;margin-top:6px;font-size:11px;color:var(--foreground-dim);line-height:1.6;padding:8px 10px;background:var(--background-deep);border:1px dashed var(--border);border-radius:var(--radius-sm)}
.help-content.show{display:block}

.mode-row{display:flex;gap:8px;margin:12px 0;flex-wrap:wrap}
.mode-btn{padding:7px 14px;border-radius:var(--radius-full);font-size:12px;font-weight:600;color:var(--foreground-dim);border:1px solid var(--border);background:none;cursor:pointer;transition:all .2s;font-family:var(--font-sans)}
.mode-btn.on{background:var(--primary);color:#fff;border-color:var(--primary)}
.mode-btn:disabled{opacity:.35;cursor:not-allowed}
.ai-box{background:var(--background-deep);border:1px dashed color-mix(in srgb,var(--primary) 30%,transparent);border-radius:var(--radius-md);padding:16px;margin-top:10px}
.ai-status{font-size:11px;color:var(--primary);margin-top:8px;display:none}
.diff-row{background:var(--background-elevated);border:1px solid var(--border);border-radius:var(--radius-sm);padding:10px;margin-top:8px}
.diff-row .old{color:var(--foreground-dim);text-decoration:line-through;font-size:12px}
.diff-row .new{color:var(--foreground);font-size:12.5px;margin-top:2px}
.diff-actions{display:flex;gap:6px;margin-top:6px}

.tick-card{background:var(--background-surface);border:1px solid var(--border);border-radius:var(--radius-md);padding:14px 16px;margin-bottom:8px;cursor:pointer;transition:all .2s;display:flex;gap:12px;align-items:flex-start}
.tick-card:hover{border-color:var(--primary);transform:translateY(-1px)}
.tick-card.ticked{background:color-mix(in srgb,var(--positive) 6%,transparent);border-color:color-mix(in srgb,var(--positive) 35%,transparent)}
.tick-box{width:20px;height:20px;border-radius:6px;border:2px solid var(--border);flex-shrink:0;margin-top:1px;display:flex;align-items:center;justify-content:center;transition:all .2s}
.tick-card.ticked .tick-box{background:var(--positive);border-color:var(--positive)}
.tick-box svg{opacity:0;transition:all .2s;width:10px;height:10px}
.tick-card.ticked .tick-box svg{opacity:1}
.tick-text{font-size:13.5px;font-weight:500;color:var(--foreground)}
.tick-card.ticked .tick-text{color:var(--foreground-dim);text-decoration:line-through;text-decoration-color:color-mix(in srgb,var(--foreground-dim) 30%,transparent)}
.tick-pill{font-size:9px;text-transform:uppercase;letter-spacing:.5px;font-weight:700;padding:2px 6px;border-radius:var(--radius-full);margin-left:6px}
.tick-req{background:color-mix(in srgb,var(--warning) 15%,transparent);color:var(--warning)}
.tick-opt{background:var(--background);color:var(--foreground-dim)}

.gatebar{background:var(--background-elevated);border:1px solid var(--border);border-radius:var(--radius-xl);padding:16px 22px;display:flex;align-items:center;gap:14px;position:sticky;bottom:16px;margin-top:16px;box-shadow:0 -4px 20px rgba(0,0,0,.15);flex-wrap:wrap}
.gatebar .stat{font-size:13px;color:var(--foreground-dim)}
.gatebar .stat b{color:var(--foreground);font-family:var(--font-mono)}
.gate-warn{font-size:11px;color:var(--warning)}
.spacer{flex:1}
.prog-bar{height:5px;border-radius:var(--radius-full);background:var(--background-surface);overflow:hidden;margin-top:8px}
.prog-bar i{display:block;height:100%;background:linear-gradient(90deg,var(--positive),#10b981);border-radius:var(--radius-full);transition:width .4s ease}

.save-bar{display:flex;align-items:center;justify-content:flex-end;gap:12px;margin:20px 0 40px;position:relative;z-index:1}

.g2{display:grid;grid-template-columns:1fr 1fr;gap:14px}
.g3{display:grid;grid-template-columns:1fr 1fr 1fr;gap:14px}
.field{margin-bottom:14px;position:relative;z-index:1}
.field label{display:block;font-size:10px;text-transform:uppercase;letter-spacing:.7px;color:var(--foreground-dim);margin-bottom:4px;font-weight:600}
.field input,.field select{font-family:var(--font-sans);font-size:13px;color:var(--foreground);background:var(--background-surface);border:1px solid var(--border);border-radius:var(--radius-sm);padding:9px 11px;width:100%;outline:none;transition:border-color .15s}
.field input:focus,.field select:focus{border-color:var(--ring);box-shadow:0 0 0 3px color-mix(in srgb,var(--ring) 15%,transparent)}
.field .err{color:var(--destructive);font-size:10px;margin-top:3px;display:none}
.field.invalid input{border-color:var(--destructive)}
.field.invalid .err{display:block}

.chips{display:flex;flex-wrap:wrap;gap:5px;margin-top:6px}
.chip{display:inline-flex;align-items:center;gap:5px;padding:4px 10px;border-radius:var(--radius-full);font-size:11px;background:color-mix(in srgb,var(--primary) 15%,transparent);color:var(--primary);border:1px solid color-mix(in srgb,var(--primary) 25%,transparent)}
.chip b{cursor:pointer;opacity:.5;font-weight:700}
.chip b:hover{opacity:1}
.picker{display:flex;flex-wrap:wrap;gap:5px;margin-top:6px}
.pick{padding:5px 10px;border-radius:var(--radius-full);font-size:11px;color:var(--foreground-dim);border:1px solid var(--border);background:none;cursor:pointer;transition:all .15s}
.pick:hover{color:var(--foreground);border-color:var(--primary)}
.pick.on{background:color-mix(in srgb,var(--primary) 15%,transparent);color:var(--primary);border-color:var(--primary)}
.instr-search{position:relative}
.instr-drop{position:absolute;top:100%;left:0;right:0;background:var(--popover);border:1px solid var(--border);border-radius:var(--radius-sm);max-height:200px;overflow:auto;z-index:20;display:none;box-shadow:0 8px 24px rgba(0,0,0,.3);margin-top:4px}
.instr-drop.show{display:block}
.instr-opt{padding:7px 10px;font-size:12px;cursor:pointer;display:flex;justify-content:space-between;color:var(--foreground)}
.instr-opt:hover,.instr-opt.hi{background:color-mix(in srgb,var(--primary) 12%,transparent)}
.instr-opt .cat{font-size:9px;color:var(--foreground-dim);text-transform:uppercase}

.toast{position:fixed;top:80px;left:50%;transform:translateX(-50%);background:var(--popover);border:1px solid var(--border);color:var(--foreground);padding:10px 18px;border-radius:var(--radius-full);font-size:13px;z-index:999;opacity:0;transition:opacity .2s;pointer-events:none}
.toast.show{opacity:1}

@media(max-width:768px){.edge-grid,.g2,.g3{grid-template-columns:1fr}.control-card{flex-direction:column;align-items:flex-start}.save-bar{flex-wrap:wrap}.premium-card,.prompt-card{padding:20px 18px}.main{padding:1rem}}

/* ── Read-only reference mode ("Forgot strategy?") ──────────────────
   #stratContent gets pointer-events:none so nothing inside the rendered
   form/checklist builder is clickable — no save, no delete, no archive, no
   accidental edits — regardless of what buttons/inputs the JS state machine
   renders inside it. Inputs/textareas/selects are also .disabled via JS
   (lockReadonlyUI()) as a second layer, so keyboard focus can't type into
   them either. The Build/Checklist tabs are hidden outright — irrelevant
   to a pure reference view. */
.readonly-banner{display:none;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;background:color-mix(in srgb,var(--primary) 10%,transparent);border:1px solid color-mix(in srgb,var(--primary) 30%,transparent);border-radius:var(--radius-lg);padding:.75rem 1.1rem;margin-bottom:1.25rem;font-size:.85rem;color:var(--foreground)}
.readonly-banner strong{color:var(--primary)}
body.readonly-mode .readonly-banner{display:flex}
body.readonly-mode .control-card{display:none}
body.readonly-mode #stratContent{pointer-events:none}
body.readonly-mode #stratContent .btn-save{display:none!important}
</style>
</head>
<body class="dash-layout<?= $readonlyMode ? ' readonly-mode' : '' ?>">

<?php require __DIR__ . '/sidebar.php'; ?>

<main class="main">

<div class="readonly-banner" id="readonlyBanner">
  <span>📖 <strong>Reference View: Read Only.</strong> This shows your strategy's declared setup, edge, and checklist. Editing happens in Strategy Builder. Nothing here can be changed or saved.</span>
  <a href="<?= htmlspecialchars($readonlyBackUrl) ?>" class="btn btn-outline btn-md" style="flex-shrink:0">← Back</a>
</div>

<?php if ($validationEvidence):
    $validationEdgeOk = $validationEdgeVerdict['demonstrated'] ?? null; // true / false / null (no trades)
    $validationAccentColor = $validationEdgeOk === false ? 'var(--warning)' : 'var(--positive)';
?>
<div style="background:var(--background-elevated);border:1px solid color-mix(in srgb,<?= $validationAccentColor ?> 30%,transparent);border-radius:var(--radius-xl);padding:1.25rem 1.5rem;margin-bottom:1.25rem">
  <div style="font-size:.95rem;font-weight:700;color:<?= $validationAccentColor ?>;margin-bottom:.35rem">🎓 Validation Evidence: <?= htmlspecialchars($validationPrefill['name']) ?></div>
  <p style="font-size:.78rem;color:var(--foreground-dim);line-height:1.5;margin-bottom:.85rem">
    This strategy graduated from the Validation Workflow. Win rate and average R below have been pre-filled into your declaration where the form has a matching field. Review and complete the rest below. Everything else here is shown for reference only; it isn't stored as part of your strategy declaration.
  </p>
  <?php if ($validationEdgeOk === true): ?>
  <div style="background:color-mix(in srgb,var(--positive) 10%,transparent);border:1px solid color-mix(in srgb,var(--positive) 30%,transparent);border-radius:var(--radius-md);padding:.7rem .9rem;font-size:.8rem;color:var(--foreground);line-height:1.5;margin-bottom:1rem">
    ✅ Your validation results show a real, positive edge — expectancy and profit factor both support this strategy. You can bring it into your main workflow with confidence.
  </div>
  <?php elseif ($validationEdgeOk === false): ?>
  <div style="background:color-mix(in srgb,var(--warning) 10%,transparent);border:1px solid color-mix(in srgb,var(--warning) 30%,transparent);border-radius:var(--radius-md);padding:.7rem .9rem;font-size:.8rem;color:var(--foreground);line-height:1.5;margin-bottom:1rem">
    ⚠️ Your results suggest that this strategy may not currently provide a profitable edge. We recommend reviewing and improving the strategy before continuing. You can continue validating it if you believe the edge can be improved, seek mentorship, or discard it and develop a stronger approach.
  </div>
  <?php endif; ?>
  <div style="display:grid;grid-template-columns:repeat(auto-fit,minmax(110px,1fr));gap:.75rem;font-family:var(--font-mono)">
    <div><div style="font-size:.6rem;text-transform:uppercase;letter-spacing:.08em;color:var(--foreground-dim)">Trade Count</div><div style="font-size:1rem;font-weight:700"><?= (int)($validationEvidence['total_trades'] ?? 0) ?></div></div>
    <div><div style="font-size:.6rem;text-transform:uppercase;letter-spacing:.08em;color:var(--foreground-dim)">Win Rate</div><div style="font-size:1rem;font-weight:700"><?= $validationPrefill['win_rate'] !== null ? $validationPrefill['win_rate'] . '%' : '-' ?></div></div>
    <div><div style="font-size:.6rem;text-transform:uppercase;letter-spacing:.08em;color:var(--foreground-dim)">Avg R</div><div style="font-size:1rem;font-weight:700"><?= $validationPrefill['avg_r_multiple'] !== null ? number_format($validationPrefill['avg_r_multiple'], 2) . 'R' : '-' ?></div></div>
    <div><div style="font-size:.6rem;text-transform:uppercase;letter-spacing:.08em;color:var(--foreground-dim)">Expectancy</div><div style="font-size:1rem;font-weight:700"><?= number_format((float)($validationEvidence['expectancy'] ?? 0), 2) ?></div></div>
    <div><div style="font-size:.6rem;text-transform:uppercase;letter-spacing:.08em;color:var(--foreground-dim)">Profit Factor</div><div style="font-size:1rem;font-weight:700"><?= $validationEvidence['profit_factor'] !== null ? number_format($validationEvidence['profit_factor'], 2) : '-' ?></div></div>
    <div><div style="font-size:.6rem;text-transform:uppercase;letter-spacing:.08em;color:var(--foreground-dim)">Wins</div><div style="font-size:1rem;font-weight:700;color:var(--positive)"><?= (int)($validationEvidence['win_count'] ?? 0) ?></div></div>
    <div><div style="font-size:.6rem;text-transform:uppercase;letter-spacing:.08em;color:var(--foreground-dim)">Losses</div><div style="font-size:1rem;font-weight:700;color:var(--negative)"><?= (int)($validationEvidence['loss_count'] ?? 0) ?></div></div>
    <div><div style="font-size:.6rem;text-transform:uppercase;letter-spacing:.08em;color:var(--foreground-dim)">Breakevens</div><div style="font-size:1rem;font-weight:700"><?= (int)($validationEvidence['breakeven_count'] ?? 0) ?></div></div>
  </div>
</div>
<?php endif; ?>

<div class="toast" id="toast"></div>

<!-- Strategy Name Modal -->
<div class="modal-overlay" id="nameModal">
  <div class="modal-box">
    <h2 id="modalTitle"></h2>
    <p class="modal-desc" id="modalDesc"></p>
    <div id="modalExisting" style="display:none"></div>
    <input type="text" id="modalNameInput" placeholder="" maxlength="80" onkeydown="if(event.key==='Enter')confirmName()">
    <div class="modal-err" id="modalErr">Please enter a strategy name.</div>
    <div class="modal-actions">
      <button class="btn-revert" onclick="closeNameModal()">Cancel</button>
      <button class="btn-save" id="modalConfirmBtn" onclick="confirmName()"></button>
    </div>
  </div>
</div>

<!-- Cap Warning Modal -->
<div class="modal-overlay" id="capWarningModal">
  <div class="cap-warning-box">
    <h2 id="capWarningTitle">⚠️ Strategy Cap Warning</h2>
    <div class="cap-message" id="capWarningMessage"></div>
    <div class="cap-stats" id="capWarningStats"></div>
    <div class="cap-actions" id="capWarningActions"></div>
  </div>
</div>

<div class="strat-container">
  <div class="control-card">
    <div class="cc-left">
      <button class="strat-tab active" id="tab-build" onclick="setView('build')">Build Strategy</button>
      <div class="cc-divider"></div>
      <button class="strat-tab" id="tab-tick" onclick="setView('tick')">Pre-Trade Checklist</button>
    </div>
  </div>
  <div id="stratContent"></div>
</div>

</main>

<script>
// ── Strategy health data from server ──────────────────────────────
var strategyHealth = <?= $strategyHealthJson ?>;
var allStrategies = <?= $allStrategiesJson ?>;
const READONLY_MODE = <?= json_encode($readonlyMode) ?>;
const READONLY_STRATEGY_ID = <?= json_encode($readonlyStrategyId) ?>;
// Validation Workflow graduation prefill (null unless ?graduated_from=
// resolved to a real, provenance-verified graduated strategy — see PHP
// above). Only ever applied ONCE, to the very next brand-new strategy the
// modal creates — see confirmName()'s applyValidationPrefillOnce check.
const VALIDATION_PREFILL = <?= json_encode($validationPrefill) ?>;
// true/false/null — same ValidationService::evaluateEdge() verdict the
// Evidence card's recommendation banner above is built from. Drives
// openNewStrategyModal()'s copy for the graduation auto-open only; a
// normal manual "+ New Strategy" click never reads this.
const VALIDATION_EDGE_DEMONSTRATED = <?= json_encode($validationEdgeVerdict['demonstrated'] ?? null) ?>;

function getCapLevel() {
    var total = strategyHealth.totalActive;
    if (total >= 25) return 'hard_cap';
    if (total >= 20) return 'near_limit';
    if (total >= 10) return 'moderate';
    if (total >= 5) return 'light';
    return 'open';
}

function getCapWarningMessage() {
    var total = strategyHealth.totalActive;
    var low = strategyHealth.lowActivityCount;
    var stale = strategyHealth.staleCount;
    var level = getCapLevel();
    
    switch (level) {
        case 'hard_cap':
            return 'Maximum 25 active strategies reached. ' + low + ' of your strategies have fewer than 5 trades. Archive an inactive strategy before creating a new one.';
        case 'near_limit':
            return total + ' active strategies, approaching the limit of 25. ' + low + ' are low-activity. ' + stale + ' are stale. Archive unused strategies to make room.';
        case 'moderate':
            return total + ' active strategies. ' + low + ' have fewer than 10 trades. ' + stale + ' haven\'t been traded in 30+ days. Behavioural tracking works best with focus.';
        case 'light':
            return 'You have ' + total + ' active strategies. ' + low + ' have fewer than 10 trades. Consider focusing on fewer, well-tested edges.';
        default:
            return null;
    }
}

function showCapWarning(callback) {
    var level = getCapLevel();
    var total = strategyHealth.totalActive;
    var low = strategyHealth.lowActivityCount;
    var stale = strategyHealth.staleCount;
    
    var msg = getCapWarningMessage();
    if (!msg) {
        callback();
        return;
    }
    
    document.getElementById('capWarningTitle').textContent = 
        level === 'hard_cap' ? '🚫 Strategy Limit Reached' : '⚠️ Strategy Cap Warning';
    document.getElementById('capWarningMessage').textContent = msg;
    
    document.getElementById('capWarningStats').innerHTML = 
        '<div class="cap-stat"><div class="cs-value">' + total + '</div><div class="cs-label">Active Strategies</div></div>' +
        '<div class="cap-stat"><div class="cs-value" style="color:var(--warning)">' + low + '</div><div class="cs-label">Low Activity</div></div>' +
        '<div class="cap-stat"><div class="cs-value" style="color:var(--negative)">' + stale + '</div><div class="cs-label">Stale</div></div>';
    
    var actionsHtml = '<button class="btn-revert" onclick="closeCapWarning()">Cancel</button>';
    
    if (level === 'hard_cap') {
        actionsHtml += '<a href="/traderalign/reports" class="btn-analytics">View Analytics →</a>';
    } else {
        actionsHtml += '<button class="btn-continue" onclick="closeCapWarning();callback()">Continue Anyway</button>';
    }
    
    document.getElementById('capWarningActions').innerHTML = actionsHtml;
    document.getElementById('capWarningModal').classList.add('show');
}

function closeCapWarning() {
    document.getElementById('capWarningModal').classList.remove('show');
}

const INSTRUMENTS=[{s:'EURUSD',cat:'major'},{s:'GBPUSD',cat:'major'},{s:'AUDUSD',cat:'major'},{s:'NZDUSD',cat:'major'},{s:'USDJPY',cat:'major'},{s:'USDCAD',cat:'major'},{s:'USDCHF',cat:'major'},{s:'EURJPY',cat:'cross'},{s:'GBPJPY',cat:'cross'},{s:'CADJPY',cat:'cross'},{s:'AUDJPY',cat:'cross'},{s:'NZDJPY',cat:'cross'},{s:'CHFJPY',cat:'cross'},{s:'AUDCAD',cat:'cross'},{s:'EURCAD',cat:'cross'},{s:'GBPCAD',cat:'cross'},{s:'NZDCAD',cat:'cross'},{s:'EURGBP',cat:'cross'},{s:'GBPAUD',cat:'cross'},{s:'EURAUD',cat:'cross'},{s:'AUDNZD',cat:'cross'},{s:'GBPNZD',cat:'cross'},{s:'EURNZD',cat:'cross'},{s:'EURCHF',cat:'cross'},{s:'GBPCHF',cat:'cross'},{s:'AUDCHF',cat:'cross'},{s:'CADCHF',cat:'cross'},{s:'NZDCHF',cat:'cross'},{s:'XAUUSD',cat:'metal'},{s:'XAGUSD',cat:'metal'},{s:'XPTUSD',cat:'metal'},{s:'XPDUSD',cat:'metal'},{s:'US30',cat:'index'},{s:'US500',cat:'index'},{s:'US100',cat:'index'},{s:'UK100',cat:'index'},{s:'GER40',cat:'index'},{s:'AUS200',cat:'index'},{s:'COFFEE',cat:'commodity'},{s:'COCOA',cat:'commodity'},{s:'SUGAR',cat:'commodity'},{s:'CORN',cat:'commodity'},{s:'WHEAT',cat:'commodity'},{s:'COTTON',cat:'commodity'},{s:'USOIL',cat:'commodity'},{s:'UKOIL',cat:'commodity'},{s:'NATGAS',cat:'commodity'},{s:'BTCUSD',cat:'crypto'},{s:'ETHUSD',cat:'crypto'},{s:'AAPL',cat:'stock'},{s:'TSLA',cat:'stock'},{s:'NVDA',cat:'stock'},{s:'AMZN',cat:'stock'},{s:'GOOGL',cat:'stock'},{s:'MSFT',cat:'stock'},{s:'META',cat:'stock'}];
const SESSIONS=[{name:'Sydney',win:'21:00-06:00 UTC'},{name:'Tokyo',win:'23:00-08:00 UTC'},{name:'London',win:'07:00-16:00 UTC'},{name:'New York',win:'12:00-21:00 UTC'}];
// Canonical timeframe list (2026-07-27, item 2) — sourced server-side from
// src/RenderHelpers.php's timeframeOptions(), the single source of truth
// also used by Draft Resolution's actual_timeframe field and the
// Calculator's planned_timeframe field, so this set can never drift.
const TIMEFRAMES=<?= json_encode(timeframeOptions()) ?>;
const CATEGORIES=['setup','entry','risk','execution'];
const STYLE_HOURS={scalper:4,day_trader:'eod',swing:168,position:720,default:24};

let state={view:'build',strategies:[],activeId:null,editingVersion:null,authMode:'manual',aiProposal:null,tick:null,pendingRefine:null,pendingNew:false,hasUnsavedWork:false,searchQuery:'',searchHi:-1,searchResults:[],applyValidationPrefillOnce:false};
const uuid=()=>'xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx'.replace(/[xy]/g,c=>{const r=Math.random()*16|0;return(c==='x'?r:(r&0x3|0x8)).toString(16);});
const now=()=>new Date().toISOString();
function blankVersion(vn){return{id:uuid(),version_number:vn||1,polished_by:'manual',polish_history:[],backtested_win_rate:null,backtested_avg_rr:null,max_risk_per_trade_pct:1,max_losing_streak:3,max_trades_per_day:null,max_trades_per_week:null,instruments_traded:[],timeframes_traded:[],session_preference:[],setup_criteria:[],entry_triggers:[],sl_rules:[],tp_rules:[],move_to_be_rule:'',checklist_items:[],created_at:now()};}
function blankItem(cat){return{id:uuid(),category:cat,position:0,raw_text:'',polished_text:'',verification_hint:'',is_required:true};}

const $=s=>document.querySelector(s);
function toast(m){const t=$('#toast');t.textContent=m;t.classList.add('show');clearTimeout(t._);t._=setTimeout(()=>t.classList.remove('show'),2200);}
function activeStrategy(){return state.strategies.find(s=>s.id===state.activeId);}
function currentVersion(){const s=activeStrategy();return s?s.versions.find(v=>v.id===s.current_version_id):null;}
function render(){state.view==='build'?renderBuild():renderTick();}
function setView(v){state.view=v;$('#tab-build').classList.toggle('active',v==='build');$('#tab-tick').classList.toggle('active',v==='tick');render();}
function esc(s){return(s||'').replace(/[&<>"]/g,c=>({'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;'}[c]));}
function helpToggle(id){const el=document.getElementById(id);el.classList.toggle('show');const btn=el.previousElementSibling;if(btn)btn.classList.toggle('open',el.classList.contains('show'));}
function H(id,label,text){return`<button class="help-toggle" onclick="helpToggle('${id}')"><span class="arrow">▶</span> ${label}</button><div class="help-content" id="${id}">${text}</div>`;}
function hasUnsavedStrategy(){return state.activeId&&state.editingVersion&&isDirty();}

// ── Archive strategy ────────────────────────────────────────────────
function archiveStrategy(strategyId, event) {
    if (event) event.stopPropagation();
    if (!confirm('Archive this strategy? This action cannot be undone.')) return;
    
    fetch('/traderalign/api/strategy/save', {
        method: 'POST',
        headers: {'Content-Type': 'application/json'},
        body: JSON.stringify({
            action: 'archive',
            strategy_id: strategyId
        })
    }).then(function(r) { return r.json(); })
    .then(function(d) {
        if (d.success) {
            state.strategies = state.strategies.filter(function(s) { return s.id !== strategyId; });
            if (state.activeId === strategyId) {
                state.activeId = null;
                state.editingVersion = null;
                state.hasUnsavedWork = false;
            }
            allStrategies = allStrategies.filter(function(s) { return s.id !== strategyId; });
            refreshHealthStats();
            toast('Strategy archived');
            render();
        } else {
            toast('Failed to archive strategy');
        }
    }).catch(function() {
        toast('Network error, try again');
    });
}

function refreshHealthStats() {
    fetch('/traderalign/api/strategy/health')
        .then(function(r) { return r.json(); })
        .then(function(d) {
            if (d) {
                strategyHealth.totalActive = d.totalActive || 0;
                strategyHealth.lowActivityCount = d.lowActivityCount || 0;
                strategyHealth.staleCount = d.staleCount || 0;
            }
        })
        .catch(function() {});
}

// ── Change history — TRADERALIGN STRATEGY BUSINESS RULES.docx §20/§21 ──
// A strategy's real, recorded evolution: one entry per save that changed
// something, each showing exactly which field(s) moved from what to what.
// Narrated from real data (api/strategy/changes.php), never a hardcoded
// sentence — the doc is explicit that this must be data-driven.
function fmtHistVal(v) {
    if (v === null || v === undefined || v === '') return '(not set)';
    try { var d = JSON.parse(v); if (Array.isArray(d)) return d.length ? d.join(', ') : '(none)'; } catch (e) {}
    return v;
}
function toggleChangeHistory(strategyId, event) {
    if (event) event.stopPropagation();
    var panel = document.getElementById('hist-' + strategyId);
    if (!panel) return;
    if (panel.style.display !== 'none') { panel.style.display = 'none'; return; }
    panel.style.display = 'block';
    panel.innerHTML = '<div style="font-size:12px;color:var(--foreground-dim)">Loading change history…</div>';
    fetch('/traderalign/api/strategy/changes?strategy_id=' + strategyId)
        .then(function(r) { return r.json(); })
        .then(function(d) {
            if (d.error || !d.events) { panel.innerHTML = '<div style="font-size:12px;color:var(--foreground-dim)">Could not load change history.</div>'; return; }
            if (!d.events.length) { panel.innerHTML = '<div style="font-size:12px;color:var(--foreground-dim)">No changes recorded yet.</div>'; return; }
            panel.innerHTML = '<div style="font-size:12px;color:var(--foreground);margin-bottom:8px;font-weight:500">' + esc(d.narration) + '</div>' +
                d.events.map(function(e) {
                    var when = new Date(e.changed_at).toLocaleDateString(undefined, { year: 'numeric', month: 'short', day: 'numeric' });
                    var fieldsHtml = e.fields.map(function(f) {
                        return '<div style="font-size:11.5px;color:var(--foreground-dim);padding:2px 0"><b style="color:var(--foreground)">' + esc(f.label) + ':</b> ' + esc(fmtHistVal(f.previous)) + ' → ' + esc(fmtHistVal(f.new)) + '</div>';
                    }).join('');
                    return '<div style="padding:8px 0;border-top:1px dashed var(--border)"><div style="font-size:11px;font-weight:600;color:var(--foreground-dim);margin-bottom:4px">' + when + '</div>' + fieldsHtml + '</div>';
                }).join('');
        })
        .catch(function() { panel.innerHTML = '<div style="font-size:12px;color:var(--foreground-dim)">Could not load change history.</div>'; });
}

// ── Strategy creation ───────────────────────────────────────────────
function openNewStrategyModal(){
  if(hasUnsavedStrategy()){toast('Save or discard your current strategy first');return;}
  
  showCapWarning(function() {
    state.pendingNew=true;state.pendingRefine=null;
    // A trader arriving here straight from graduating out of Validation
    // has already proven (or, per VALIDATION_EDGE_DEMONSTRATED===false,
    // NOT proven) their edge — this modal must never advertise "Create
    // New Strategy" to them, since the intended next step is saving what
    // they already validated, not being prompted to start from scratch.
    // A normal manual "+ New Strategy" click (applyValidationPrefillOnce
    // false/never set) keeps the original copy unchanged.
    var isGraduationSave = !!(VALIDATION_PREFILL && state.applyValidationPrefillOnce);
    if (isGraduationSave) {
      $('#modalTitle').textContent='🎓 Save Your Validated Strategy';
      $('#modalDesc').textContent = (VALIDATION_EDGE_DEMONSTRATED === false)
        ? 'Your validation results are still weak for this strategy — review the recommendation above before continuing. Give it a name to save it here and keep refining it, or close this and validate further first.'
        : 'Save your validated strategy and continue developing your edge. Give it a name below to bring it into your main workflow.';
      $('#modalConfirmBtn').textContent='Save Strategy';
    } else {
      $('#modalTitle').textContent='🆕 Create New Strategy';
      $('#modalDesc').textContent='Give your strategy a meaningful name that describes your edge.';
      $('#modalConfirmBtn').textContent='Create Strategy';
    }
    $('#modalExisting').style.display='none';
    $('#modalNameInput').value=(VALIDATION_PREFILL&&state.applyValidationPrefillOnce)?(VALIDATION_PREFILL.name||''):'';
    $('#modalNameInput').placeholder='e.g. London Breakout, Asian Range Fade';
    $('#modalErr').classList.remove('show');
    $('#nameModal').classList.add('show');
    setTimeout(function(){ $('#modalNameInput').focus(); },200);
  });
}

function confirmName(){
  const name=$('#modalNameInput').value.trim();
  if(!name){$('#modalErr').classList.add('show');$('#modalNameInput').focus();return;}
  closeNameModal();
  if(state.pendingRefine){
    // Editing an EXISTING strategy — per TRADERALIGN STRATEGY BUSINESS
    // RULES.docx §2/§7: this never creates a new Strategy or a new
    // declaration row. It opens the strategy's own single, real version
    // for in-place editing; saveVersion() below writes to that same row
    // and records a Strategy Change Event for whatever actually changed.
    const s=state.strategies.find(x=>x.id===state.pendingRefine);if(s){
      const cv=s.versions.find(v=>v.id===s.current_version_id)||s.versions[s.versions.length-1];
      if(name!==s.name)s.name=name;state.activeId=s.id;state.editingVersion=cv?JSON.parse(JSON.stringify(cv)):blankVersion(1);
      state.authMode='manual';state.aiProposal=null;state.hasUnsavedWork=true;
      toast('Editing '+esc(s.name)+', changes save to this strategy directly');
    }
  }else{
    const v=blankVersion(1);
    // Validation Workflow graduation prefill — applied ONCE, only to this
    // literal next brand-new strategy, only into fields that are still at
    // blankVersion()'s own defaults (never overwrites something the
    // trader already typed — there's nothing to overwrite yet here since
    // v was just created, but the null-checks stay as a clear, explicit
    // guarantee, not just an implicit one). Cleared immediately after use
    // so a later "+ New Strategy" click never re-applies it.
    if(VALIDATION_PREFILL&&state.applyValidationPrefillOnce){
      if(v.backtested_win_rate==null&&VALIDATION_PREFILL.win_rate!=null)v.backtested_win_rate=VALIDATION_PREFILL.win_rate;
      if(v.backtested_avg_rr==null&&VALIDATION_PREFILL.avg_r_multiple!=null)v.backtested_avg_rr=VALIDATION_PREFILL.avg_r_multiple;
      state.applyValidationPrefillOnce=false;
    }
    const s={id:uuid(),name:name,description:'',trading_style:'day_trader',is_active:true,current_version_id:v.id,versions:[v],created_at:now()};
    state.strategies.push(s);state.activeId=s.id;state.editingVersion=JSON.parse(JSON.stringify(v));
    state.authMode='manual';state.aiProposal=null;state.hasUnsavedWork=true;
    toast('Strategy created, fill in the details below');
  }
  setView('build');
}

function closeNameModal(){$('#nameModal').classList.remove('show');state.pendingNew=false;state.pendingRefine=null;}

// ── Search for existing strategy to update ──────────────────────────
function onSearchInput(val) {
    state.searchQuery = val.trim().toLowerCase();
    state.searchHi = -1;
    var drop = document.getElementById('searchDrop');
    if (!state.searchQuery) {
        state.searchResults = [];
        drop.classList.remove('show');
        drop.innerHTML = '';
        return;
    }
    state.searchResults = allStrategies.filter(function(s) {
        return s.name.toLowerCase().indexOf(state.searchQuery) !== -1;
    });
    drop.innerHTML = state.searchResults.length
        ? state.searchResults.map(function(s, i) {
            var styleLabel = (s.trading_style || 'day_trader').replace(/_/g, ' ');
            var changeBadge = s.change_count ? ('<span class="pr-ver-badge">' + s.change_count + ' change' + (s.change_count === 1 ? '' : 's') + '</span>') : '';
            return '<div class="search-opt" onclick="selectExistingStrategy(\'' + s.id + '\')" data-idx="' + i + '">' +
                '<div class="so-left">' +
                    '<div class="so-name">' + esc(s.name) + ' ' + changeBadge + '</div>' +
                    '<div class="so-meta">' + styleLabel + '</div>' +
                '</div>' +
                '<div class="so-right">' +
                    '<span class="so-style">' + styleLabel + '</span>' +
                    '<span class="so-count">' + (s.item_count || 0) + ' items</span>' +
                '</div>' +
            '</div>';
        }).join('')
        : '<div class="search-opt" style="color:var(--foreground-dim);cursor:default">No matching strategies</div>';
    drop.classList.add('show');
}

function onSearchKey(e) {
    if (!state.searchResults.length) return;
    if (e.key === 'ArrowDown') {
        state.searchHi = Math.min(state.searchHi + 1, state.searchResults.length - 1);
        e.preventDefault();
    } else if (e.key === 'ArrowUp') {
        state.searchHi = Math.max(state.searchHi - 1, 0);
        e.preventDefault();
    } else if (e.key === 'Enter') {
        if (state.searchHi >= 0 && state.searchResults[state.searchHi]) {
            selectExistingStrategy(state.searchResults[state.searchHi].id);
        } else if (state.searchResults[0]) {
            selectExistingStrategy(state.searchResults[0].id);
        }
        e.preventDefault();
        return;
    }
    var children = document.querySelectorAll('#searchDrop .search-opt');
    children.forEach(function(c, i) { c.classList.toggle('hi', i === state.searchHi); });
}

function selectExistingStrategy(strategyId) {
    var drop = document.getElementById('searchDrop');
    drop.classList.remove('show');
    state.searchResults = [];
    state.searchQuery = '';
    document.getElementById('existingSearchInput').value = '';
    
    if (hasUnsavedStrategy()) { toast('Save or discard your current strategy first'); return; }

    // Fetch full strategy data with debug logging
    console.log('Loading strategy:', strategyId);
    fetch('/traderalign/api/strategy/load?id=' + strategyId)
        .then(function(r) { 
            console.log('Response status:', r.status);
            if (!r.ok) throw new Error('HTTP ' + r.status);
            return r.json();
        })
        .then(function(data) {
            console.log('Loaded data:', data);
            
            if (data.error) {
                toast('Failed to load strategy data: ' + data.error);
                return;
            }
            if (!data.strategy) {
                toast('Failed to load strategy data: No strategy in response');
                return;
            }
            
            var s = data.strategy;
            var v = data.version;
            var items = data.checklist_items || [];
            
            // Build the version object. version_number is carried through
            // purely as internal row metadata (the DB column is NOT NULL) —
            // it is never incremented on edit and never shown to the user
            // anywhere (TRADERALIGN STRATEGY BUSINESS RULES.docx §13).
            var versionObj = {
                id: v.id,
                strategy_id: s.id,
                version_number: v.version_number,
                polished_by: v.polished_by || 'manual',
                polish_history: v.polish_history || [],
                backtested_win_rate: v.backtested_win_rate,
                backtested_avg_rr: v.backtested_avg_rr,
                max_risk_per_trade_pct: v.max_risk_per_trade_pct || 1,
                max_losing_streak: v.max_losing_streak || 3,
                max_trades_per_day: v.max_trades_per_day,
                max_trades_per_week: v.max_trades_per_week,
                instruments_traded: v.instruments_traded || [],
                timeframes_traded: v.timeframes_traded || [],
                session_preference: v.session_preference || [],
                setup_criteria: v.setup_criteria || [],
                entry_triggers: v.entry_triggers || [],
                sl_rules: v.sl_rules || [],
                tp_rules: v.tp_rules || [],
                move_to_be_rule: v.move_to_be_rule || '',
                checklist_items: items.map(function(it) {
                    return {
                        id: it.id || uuid(),
                        category: it.category,
                        position: it.position || 0,
                        raw_text: it.raw_text || '',
                        polished_text: it.polished_text || '',
                        verification_hint: it.verification_hint || '',
                        is_required: it.is_required !== false
                    };
                }),
                created_at: v.created_at || now()
            };
            
            // Editing this strategy in place (TRADERALIGN STRATEGY BUSINESS
            // RULES.docx §2/§7/§10) — the strategy has exactly ONE real
            // declaration row, identified by versionObj.id (the server's own
            // strategy.current_version_id, always). Whether or not this
            // strategy was already loaded into local state, we always end up
            // editing that same row's real, freshly-fetched data — never a
            // clone with a new id/version number.
            var existing = state.strategies.find(function(x) { return x.id === s.id; });
            if (existing) {
                existing.name = s.name;
                existing.description = s.description || '';
                existing.trading_style = s.trading_style || 'day_trader';
                existing.current_version_id = versionObj.id;
                existing.versions = [versionObj];
            } else {
                var newS = {
                    id: s.id,
                    name: s.name,
                    description: s.description || '',
                    trading_style: s.trading_style || 'day_trader',
                    is_active: true,
                    current_version_id: versionObj.id,
                    versions: [versionObj],
                    created_at: s.created_at || now()
                };
                state.strategies.push(newS);
            }
            state.activeId = s.id;
            state.editingVersion = JSON.parse(JSON.stringify(versionObj));
            state.authMode = 'manual';
            state.aiProposal = null;
            state.hasUnsavedWork = true;
            toast('Editing ' + esc(s.name) + ', changes save to this strategy directly');
            setView('build');
        })
        .catch(function(err) {
            console.error('Fetch error:', err);
            toast('Failed to load strategy data, check console');
        });
}

function selectStrategy(id){
  if(hasUnsavedStrategy()){toast('Save or discard your current strategy first');return;}
  state.activeId=id;const cv=currentVersion();state.editingVersion=cv?JSON.parse(JSON.stringify(cv)):blankVersion(1);
  state.aiProposal=null;state.hasUnsavedWork=false;render();
}

function renderBuild(){
  const c=$('#stratContent');const s=activeStrategy();
  if(!s){
    const hasStrategies=state.strategies.length>0;
    const styleLabels={scalper:'Scalper',day_trader:'Day Trader',swing:'Swing',position:'Position'};
    
    var strategyListHtml = '';
    if (hasStrategies) {
        strategyListHtml = '<div class="mgmt-section"><div class="mgmt-head"><h3><span class="dot blue"></span> Your Active Strategies</h3></div>' +
            state.strategies.map(function(strat, i) {
                var cv = strat.versions.find(function(v) { return v.id === strat.current_version_id; }) || strat.versions[strat.versions.length-1];
                var itemCount = cv ? cv.checklist_items.length : 0;
                // change_count comes from the server-fetched allStrategies list
                // (api/strategy/save.php's real strategy_change_events count) —
                // a real "how many times has this strategy evolved" indicator,
                // never a version number (business rules §13).
                var srcEntry = allStrategies.find(function(a) { return a.id === strat.id; });
                var changeCount = srcEntry ? (srcEntry.change_count || 0) : 0;
                var changeBadge = changeCount
                    ? '<button type="button" class="btn-archive" style="border-color:color-mix(in srgb,var(--primary) 30%,var(--border));color:var(--primary)" onclick="event.stopPropagation();toggleChangeHistory(\'' + strat.id + '\', event)">🕓 ' + changeCount + ' change' + (changeCount === 1 ? '' : 's') + '</button>'
                    : '';
                return '<div class="strat-list-card" style="flex-direction:column;align-items:stretch">' +
                    '<div style="display:flex;align-items:center;justify-content:space-between;gap:14px;flex-wrap:wrap">' +
                    '<div class="slc-info">' +
                        '<div class="slc-name">' + esc(strat.name || 'Untitled') + '</div>' +
                        '<div class="slc-meta">' + (styleLabels[strat.trading_style] || strat.trading_style) + ' · ' + itemCount + ' checklist items</div>' +
                    '</div>' +
                    '<div class="slc-actions">' +
                        changeBadge +
                        '<button class="btn btn-primary btn-sm" onclick="event.stopPropagation();selectExistingStrategy(\'' + strat.id + '\')">Edit</button>' +
                        '<button class="btn-archive" onclick="archiveStrategy(\'' + strat.id + '\', event)">📦 Archive</button>' +
                    '</div>' +
                    '</div>' +
                    '<div id="hist-' + strat.id + '" style="display:none;margin-top:10px;padding-top:10px;border-top:1px solid var(--border)"></div>' +
                '</div>';
            }).join('') +
        '</div>';
    }
    
    c.innerHTML=`<div class="mgmt-card">
      <div class="mgmt-section">
        <div class="mgmt-head"><h3><span class="dot green"></span> Create New Strategy</h3></div>
        <div class="prompt-card new-strat" onclick="openNewStrategyModal()">
          <div class="pr-icon">🆕</div>
          <div class="pr-title">Start a New Strategy</div>
          <div class="pr-desc">Create a brand new strategy from scratch. Declare your edge, author your checklist, and gate every trade with a defined process.</div>
        </div>
      </div>
      <div class="mgmt-section">
        <div class="mgmt-head"><h3><span class="dot blue"></span> Edit Existing Strategy</h3></div>
        <div style="font-size:.82rem;color:var(--foreground-dim);line-height:1.6;margin-bottom:10px">Search for a strategy to edit and refine its current edge.</div>
        <div class="search-wrap">
          <input type="text" id="existingSearchInput" placeholder="Search your strategies by name…" oninput="onSearchInput(this.value)" onkeydown="onSearchKey(event)" autocomplete="off">
          <div class="search-drop" id="searchDrop"></div>
        </div>
      </div>
      ${strategyListHtml}
    </div>`;return;
  }
  const v=state.editingVersion;

  const cv=currentVersion();
  const html=`
  <div class="premium-card">
    <div class="pc-head"><h2>📐 Strategy Identity</h2>${cv?`<button type="button" class="btn-archive" style="border-color:color-mix(in srgb,var(--primary) 30%,var(--border));color:var(--primary)" onclick="toggleChangeHistory('${s.id}',event)">🕓 Change History</button>`:''}</div>
    ${cv?`<div id="hist-${s.id}" style="display:none;margin-bottom:14px;padding:10px 14px;background:var(--background-surface);border-radius:var(--radius-md)"></div>`:''}
    <div class="pc-subtitle">Name your strategy and choose the trading style that sets your draft expiry window. This is the ONE persistent declaration for this strategy: saving updates it in place and records what changed, it never creates another strategy.</div>
    ${H('help-strat','How trading style affects expiry','<b>Scalper</b> = 4 hours · <b>Day Trader</b> = end of day · <b>Swing</b> = 7 days · <b>Position</b> = 30 days.')}
    <div class="g2" style="margin-top:12px">
      <div class="field required"><label>Strategy name</label><input id="f_name" value="${esc(s.name)}" placeholder="e.g. London Breakout, Asian Range Fade" oninput="updS('name',this.value)"></div>
      <div class="field required"><label>Trading style</label><select id="f_style" onchange="updS('trading_style',this.value)">${['scalper','day_trader','swing','position'].map(x=>`<option value="${x}" ${s.trading_style===x?'selected':''}>${x.replace('_',' ')}</option>`).join('')}</select></div>
    </div>
    <div class="field"><label>Description <span style="font-weight:400;text-transform:none;opacity:.6">(optional)</span></label><input value="${esc(s.description)}" placeholder="One sentence that captures what this edge is about" oninput="updS('description',this.value)"></div>
  </div>
  <div class="premium-card">
    <div class="pc-head"><h2>📊 Declared Edge</h2></div>
    <div class="pc-subtitle">Quantitative boundaries you commit to. Every trade is measured against these caps.</div>
    <div class="g3">${NF('backtested_win_rate','Win rate %','58',v.backtested_win_rate,true)}${NF('backtested_avg_rr','Avg Reward per $1 Risked','1.8',v.backtested_avg_rr,true)}${NF('max_risk_per_trade_pct','Max risk/trade %','1',v.max_risk_per_trade_pct,true)}${NF('max_losing_streak','Max losing streak','3',v.max_losing_streak,true)}${NF('max_trades_per_day','Max trades/day','5',v.max_trades_per_day,true)}${NF('max_trades_per_week','Max trades/week','20',v.max_trades_per_week,true)}</div>
    <div class="field required" style="margin-top:12px"><label>Instruments traded *</label><div class="instr-search"><input id="instrInput" placeholder="Search instruments…" oninput="instrSearch(this.value)" onkeydown="instrKey(event)" autocomplete="off"><div class="instr-drop" id="instrDrop"></div></div><div class="chips" id="instrChips"></div><div class="err" id="err_instruments_traded"></div></div>
    <div class="field required"><label>Timeframes traded *</label><div class="picker">${TIMEFRAMES.map(tf=>`<button class="pick ${v.timeframes_traded.includes(tf)?'on':''}" onclick="toggleTimeframe('${tf}')">${tf}</button>`).join('')}</div><div class="err" id="err_timeframes_traded"></div></div>
    <div class="field required"><label>Session preference *</label><div class="picker">${SESSIONS.map(se=>`<button class="pick ${v.session_preference.includes(se.name)?'on':''}" onclick="toggleSession('${se.name}')">${se.name}</button>`).join('')}</div><div class="err" id="err_session_preference"></div></div>
  </div>
  <div class="premium-card">
    <div class="pc-head"><h2>⚙️ Edge Rules</h2></div>
    <div class="pc-subtitle">Qualitative rules that define how you trade. Write each rule as a single, verifiable statement.</div>
    <div class="edge-grid">${edgeCard('setup_criteria','📋','Setup criteria','setup','Market conditions that must exist before you look for an entry.','Price above 200 EMA · London session active · Daily trend direction matches')}${edgeCard('entry_triggers','🎯','Entry triggers','entry','The exact signals that tell you to execute.','Bullish engulfing on M5 · Break above Asian range high')}${edgeCard('sl_rules','🛑','Stop-loss rules','risk','Where your stop goes: invalidation points, not arbitrary.','5 pips below recent swing low · Below demand zone')}${edgeCard('tp_rules','🏁','Take-profit rules','execution','Profit targets at logical levels.','Most recent swing high · Next liquidity level')}</div>
    <div class="field" style="margin-top:16px"><label>Move-to-breakeven rule</label><input value="${esc(v.move_to_be_rule)}" placeholder="e.g. Move SL to entry when price reaches +1R" oninput="updV('move_to_be_rule',this.value)"></div>
  </div>
  <div class="premium-card">
    <div class="pc-head"><h2>✅ Checklist Authoring</h2></div>
    <div class="pc-subtitle">Turn your edge rules into a tickable pre-trade checklist.</div>
    <div class="mode-row"><button class="mode-btn ${state.authMode==='manual'?'on':''}" onclick="setMode('manual')">✍️ Manual</button><button class="mode-btn ${state.authMode==='polish'?'on':''}" onclick="setMode('polish')">✨ AI Polish</button><button class="mode-btn ${state.authMode==='ai_first'?'on':''}" onclick="setMode('ai_first')">🤖 AI-First</button></div>
    ${state.authMode==='polish'?`<div class="ai-box"><div style="font-weight:600;margin-bottom:6px;color:var(--foreground)">Polish with Colex</div>${H('help-pol','How it works','Colex rewords your checklist items. You review every change before saving.')}<button class="btn btn-primary btn-sm" style="margin-top:8px" onclick="runPolish()">Polish ${v.checklist_items.length} items</button><div class="ai-status" id="aiStatus"></div><div id="aiDiff"></div></div>`:''}
    ${state.authMode==='ai_first'?`<div class="ai-box"><div style="font-weight:600;margin-bottom:6px;color:var(--foreground)">AI-First Authoring</div>${H('help-aif','How it works','Paste your rules. Colex decomposes them into a structured checklist.')}<textarea id="aiFirstInput" style="margin-top:6px;min-height:80px" placeholder="Paste your rules…"></textarea><button class="btn btn-primary btn-sm" style="margin-top:8px" onclick="runAiFirst()">Decompose</button><div class="ai-status" id="aiStatus"></div><div id="aiDiff"></div></div>`:''}
    <div style="margin-top:16px">${checklistSection(v)}</div>
  </div>
  <div class="save-bar">
    <button class="btn-revert" onclick="revertVersion()">↩ Revert</button>
    <button class="btn-save" onclick="saveVersion()">💾 Save Strategy</button>
  </div>`;

  c.innerHTML=html;
  renderInstrChips();
}

function NF(key,label,ph,val,required){const reqClass=required?' required':'';return`<div class="field${reqClass}" id="fld_${key}"><label>${label}</label><input type="number" step="any" value="${val??''}" placeholder="${ph}" oninput="updNum('${key}',this.value)"><div class="err" id="err_${key}"></div></div>`;}
function edgeCard(key,icon,label,accentClass,purpose,examples){const v=state.editingVersion;const arr=v[key]||[];const helpId='help-'+key;const items=arr.map((r,i)=>`<div class="ec-item"><input value="${esc(r)}" oninput="updRule('${key}',${i},this.value)" placeholder="Add rule…"><button class="x" onclick="delRule('${key}',${i})">✕</button></div>`).join('');return`<div class="edge-card ${accentClass}"><div class="ec-icon">${icon}</div><div class="ec-label">${label} ${H(helpId,'?','<b>Purpose:</b> '+purpose+'<br><br><b>Examples:</b><br>'+examples)}</div><div class="ec-list">${items||'<div class="ec-empty">No rules yet</div>'}</div><button class="ec-add" onclick="addRule('${key}')">+ Add rule</button></div>`;}
function checklistSection(v){const guide={setup:{t:'The market environment matches your strategy, verify before looking for entry signals.',eg:'e.g. "Price above 200 EMA", "London session active", "Daily trend direction matches"'},entry:{t:'The actual entry signal has appeared, your trigger fired, time to act.',eg:'e.g. "Bullish engulfing on M5", "Price broke above Asian range and retested"'},risk:{t:'Position sizing, stop placement, risk parameters, all within declared caps.',eg:'e.g. "Position size 1% or less", "SL below recent swing low with spread"'},execution:{t:'Final verification before placing the order: your last line of defence.',eg:'e.g. "TP levels set on platform", "SL and TP match calculator output"'}};const byCat=c=>v.checklist_items.filter(i=>i.category===c).sort((a,b)=>a.position-b.position);return CATEGORIES.map(cat=>{const g=guide[cat];const items=byCat(cat);const hid='hcat-'+cat;return`<div class="cat-row"><div class="cr-head"><span class="cr-badge cat-${cat}">${cat}</span>${H(hid,'What is this?',g.t)}<button class="cr-add" style="margin-left:auto" onclick="addItem('${cat}')">+ Item</button></div><div class="cr-items">${items.length?items.map(it=>`<div class="ci-row"><input value="${esc(it.polished_text||it.raw_text)}" placeholder="What must be true?" oninput="updItem('${it.id}','text',this.value)"><div class="req-tog ${it.is_required?'on':''}" onclick="updItem('${it.id}','req',null)"><span class="sw"></span>Req</div><button class="ci-x" onclick="delItem('${it.id}')">✕</button></div><div class="ci-hint"><input value="${esc(it.verification_hint)}" placeholder="Verification hint (optional)" oninput="updItem('${it.id}','hint',this.value)"></div>`).join(''):`<div class="cat-empty">${g.eg}</div>`}</div></div>`;}).join('');}

function renderTick(){
  const c=$('#stratContent');const s=activeStrategy();const v=currentVersion();
  if(!s||!v||!v.checklist_items.length){c.innerHTML='<div style="text-align:center;padding:60px 20px;color:var(--foreground-dim)"><div style="font-size:40px;margin-bottom:12px">📋</div><h3 style="color:var(--foreground);margin-bottom:6px;font-size:16px">No checklist items yet</h3><p style="font-size:13px;max-width:340px;margin:0 auto;line-height:1.5">Build and save a strategy with checklist items first.</p></div>';return;}
  if(!state.tick||state.tick.versionId!==v.id){state.tick={versionId:v.id,ticked:new Set(),lifecycleId:null};}
  const t=state.tick;const items=v.checklist_items.slice().sort((a,b)=>CATEGORIES.indexOf(a.category)-CATEGORIES.indexOf(b.category)||a.position-b.position);
  const required=items.filter(i=>i.is_required);const reqTicked=required.filter(i=>t.ticked.has(i.id)).length;
  const tickedPct=items.length?Math.round([...t.ticked].filter(id=>items.find(i=>i.id===id)).length/items.length*100):0;
  c.innerHTML=`<div class="premium-card"><div class="pc-head"><h2>📋 ${esc(s.name)}</h2></div><div class="pc-subtitle">Tick what's true. ${required.length} required, ${items.length-required.length} optional.</div><div class="prog-bar"><i style="width:${tickedPct}%"></i></div></div>${items.map(it=>`<div class="tick-card ${t.ticked.has(it.id)?'ticked':''}" onclick="toggleTick('${it.id}')"><div class="tick-box"><svg viewBox="0 0 12 12"><path d="M2 6.5L5 9.5L10 3" stroke="#0A0A0B" stroke-width="2" fill="none" stroke-linecap="round" stroke-linejoin="round"/></svg></div><div><div class="tick-text">${esc(it.polished_text||it.raw_text)}<span class="tick-pill ${it.is_required?'tick-req':'tick-opt'}">${it.is_required?'required':'optional'}</span></div></div></div>`).join('')}<div class="gatebar"><div class="stat">Checklist <b>${tickedPct}%</b> · Required <b>${reqTicked}/${required.length}</b></div><div class="spacer"></div>${reqTicked<required.length?`<div class="gate-warn">⚠ ${required.length-reqTicked} required unticked</div>`:''}<button class="btn btn-primary" onclick="proceedToCalculator()">Proceed to Calculator →</button></div>`;
}
function toggleTick(id){const t=state.tick;t.ticked.has(id)?t.ticked.delete(id):t.ticked.add(id);renderTick();}
function proceedToCalculator(){const s=activeStrategy();const v=currentVersion();const t=state.tick;const items=v.checklist_items;const required=items.filter(i=>i.is_required).map(i=>i.id);const ticked=[...t.ticked].filter(id=>items.find(i=>i.id===id));const tickedPct=items.length?+(ticked.length/items.length*100).toFixed(2):0;const lifecycleId=uuid();const hrs=STYLE_HOURS[s.trading_style]||STYLE_HOURS.default;let expires;if(hrs==='eod'){const d=new Date();d.setUTCHours(23,59,59,0);expires=d.toISOString();}else{expires=new Date(Date.now()+hrs*3600*1000).toISOString();}const result={trade_lifecycle_id:lifecycleId,strategy_version_id:v.id,items_ticked:ticked,items_required:required,ticked_pct:tickedPct,status:'pending_calculator',ticked_at:now(),expires_at:expires};try{sessionStorage.setItem('trade_lifecycle_id',lifecycleId);sessionStorage.setItem('strategy_version_id',v.id);}catch(e){}fetch('/traderalign/api/checklist/save',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(result)}).catch(function(){});toast('Opening Calculator…');setTimeout(function(){window.location.href='/traderalign/calculator';},1200);}

function updS(k,val){activeStrategy()[k]=val;}
function updV(k,val){state.editingVersion[k]=val;}
function updNum(k,val){state.editingVersion[k]=val===''?null:parseFloat(val);validateField(k);}
function updRule(key,i,val){state.editingVersion[key][i]=val;}
function addRule(key){state.editingVersion[key].push('');render();}
function delRule(key,i){state.editingVersion[key].splice(i,1);render();}
function toggleSession(name){const a=state.editingVersion.session_preference;const i=a.indexOf(name);i>=0?a.splice(i,1):a.push(name);render();}
function toggleTimeframe(name){const a=state.editingVersion.timeframes_traded;const i=a.indexOf(name);i>=0?a.splice(i,1):a.push(name);render();}
function addItem(cat){const v=state.editingVersion;const it=blankItem(cat);it.position=v.checklist_items.filter(x=>x.category===cat).length;v.checklist_items.push(it);render();}
function updItem(id,field,val){const it=state.editingVersion.checklist_items.find(x=>x.id===id);if(!it)return;if(field==='text'){it.raw_text=val;it.polished_text=val;}else if(field==='hint'){it.verification_hint=val;}else if(field==='req'){it.is_required=!it.is_required;render();}}
function delItem(id){state.editingVersion.checklist_items=state.editingVersion.checklist_items.filter(x=>x.id!==id);render();}

let instrHi=-1,instrMatches=[];
function instrSearch(q){q=q.trim().toUpperCase().replace(/[^A-Z0-9]/g,'');const drop=$('#instrDrop');const sel=state.editingVersion.instruments_traded;if(!q){drop.classList.remove('show');return;}instrMatches=INSTRUMENTS.filter(i=>i.s.includes(q)&&!sel.includes(i.s)).slice(0,10);instrHi=-1;drop.innerHTML=instrMatches.length?instrMatches.map((m,i)=>`<div class="instr-opt" onclick="addInstr('${m.s}')"><span>${m.s}</span><span class="cat">${m.cat}</span></div>`).join(''):'<div class="instr-opt" style="color:var(--foreground-dim)">No match</div>';drop.classList.add('show');}
function instrKey(e){if(!instrMatches.length)return;if(e.key==='ArrowDown'){instrHi=Math.min(instrHi+1,instrMatches.length-1);e.preventDefault();}else if(e.key==='ArrowUp'){instrHi=Math.max(instrHi-1,0);e.preventDefault();}else if(e.key==='Enter'){if(instrHi>=0)addInstr(instrMatches[instrHi].s);else if(instrMatches[0])addInstr(instrMatches[0].s);e.preventDefault();return;}[...$('#instrDrop').children].forEach((c,i)=>c.classList.toggle('hi',i===instrHi));}
function addInstr(sym){const sel=state.editingVersion.instruments_traded;if(!sel.includes(sym))sel.push(sym);$('#instrInput').value='';$('#instrDrop').classList.remove('show');instrMatches=[];renderInstrChips();}
function delInstr(sym){state.editingVersion.instruments_traded=state.editingVersion.instruments_traded.filter(s=>s!==sym);renderInstrChips();}
function renderInstrChips(){const el=$('#instrChips');if(el)el.innerHTML=state.editingVersion.instruments_traded.map(s=>`<span class="chip">${s} <b onclick="delInstr('${s}')">✕</b></span>`).join('');}

const REQUIRED_FIELDS=['f_name','f_style'];
const RULES={backtested_win_rate:v=>v!=null&&v>0&&v<=100,backtested_avg_rr:v=>v!=null&&v>0,max_risk_per_trade_pct:v=>v!=null&&v>0&&v<=10,max_losing_streak:v=>v!=null&&Number.isInteger(v)&&v>0,max_trades_per_day:v=>v!=null&&v>0,max_trades_per_week:v=>v!=null&&v>0};
function validateField(k){if(!(k in RULES))return true;const ok=RULES[k](state.editingVersion[k]);const fld=$('#fld_'+k);if(fld){fld.classList.toggle('invalid',!ok);$('#err_'+k).textContent=ok?'':'Out of range';}return ok;}
function validateEdgeFields(){
  const v=state.editingVersion;
  let valid=true;
  
  // Validate instruments_traded
  const instrFld=$('#err_instruments_traded');
  if(!v.instruments_traded||v.instruments_traded.length===0){
    if(instrFld){instrFld.textContent='At least one instrument required';instrFld.parentElement.classList.add('invalid');}
    valid=false;
  }else{
    if(instrFld){instrFld.textContent='';instrFld.parentElement.classList.remove('invalid');}
  }
  
  // Validate session_preference
  const sessFld=$('#err_session_preference');
  if(!v.session_preference||v.session_preference.length===0){
    if(sessFld){sessFld.textContent='At least one session required';sessFld.parentElement.classList.add('invalid');}
    valid=false;
  }else{
    if(sessFld){sessFld.textContent='';sessFld.parentElement.classList.remove('invalid');}
  }

  // Validate timeframes_traded (2026-07-27, item 2 — now mandatory
  // alongside instruments_traded, same pattern)
  const tfFld=$('#err_timeframes_traded');
  if(!v.timeframes_traded||v.timeframes_traded.length===0){
    if(tfFld){tfFld.textContent='At least one timeframe required';tfFld.parentElement.classList.add('invalid');}
    valid=false;
  }else{
    if(tfFld){tfFld.textContent='';tfFld.parentElement.classList.remove('invalid');}
  }

  return valid;
}
function validateAll(){let ok=true;const s=activeStrategy();REQUIRED_FIELDS.forEach(fid=>{const el=document.getElementById(fid);if(el&&!el.value.trim()){el.classList.add('highlight-empty');setTimeout(function(){el.classList.remove('highlight-empty');},500);ok=false;}});if(!s||!s.name.trim()){toast('Strategy name is required');ok=false;}if(!s.trading_style){toast('Trading style is required');ok=false;}Object.keys(RULES).forEach(k=>{if(!validateField(k))ok=false;});if(!validateEdgeFields()){toast('All edge declaration fields are required. The edge snapshot must be complete.');ok=false;}if(state.editingVersion.checklist_items.filter(i=>i.is_required&&(i.polished_text||i.raw_text).trim()).length<1){toast('Add at least one required checklist item');ok=false;}return ok;}
function isDirty(){const cv=currentVersion();return cv&&JSON.stringify(stripV(cv))!==JSON.stringify(stripV(state.editingVersion));}
function stripV(v){const{id,version_number,created_at,polish_history,...rest}=v;return rest;}
function revertVersion(){const cv=currentVersion();state.editingVersion=cv?JSON.parse(JSON.stringify(cv)):blankVersion(1);state.aiProposal=null;state.hasUnsavedWork=false;render();toast('Reverted');}
// saveVersion() — TRADERALIGN STRATEGY BUSINESS RULES.docx §2/§7/§33.
// Editing an existing strategy NEVER creates a new declaration row — the
// edited data is written into the strategy's own real version id in
// place, and the server (api/strategy/save.php) records a Strategy Change
// Event for whatever actually changed. A brand-new strategy (no current
// version yet) still gets its one real row created here, same as before —
// that's creation, not an edit.
function saveVersion(){
  if(!validateAll())return;
  const s=activeStrategy();const cv=currentVersion();const edited=state.editingVersion;
  edited.checklist_items=edited.checklist_items.filter(i=>(i.polished_text||i.raw_text).trim());
  edited.checklist_items.forEach(it=>{if(!it.polished_text)it.polished_text=it.raw_text;});
  edited.polished_by=state.authMode==='polish'?'hybrid_ai':state.authMode==='ai_first'?'ai_first':'manual';
  const wasDirty=cv&&isDirty();
  if(!cv){
    // First-ever save for a brand new strategy — its one real row.
    edited.checklist_items.forEach(it=>{if(!it.id)it.id=uuid();});
  }
  // Sync local state's version entry to the real, edited data being saved.
  // A strategy has exactly one version entry in local state now, always —
  // real bug fixed here in the same pass: the old code only ever pushed a
  // NEW-strategy's edited version if its id wasn't already in s.versions,
  // but confirmName() had already pushed a still-blank placeholder under
  // that exact same id, so the check silently skipped the real, edited
  // data and buildPayload() below would have sent the stale blank version
  // to the server on a brand new strategy's first save.
  s.current_version_id=edited.id;
  s.versions=[JSON.parse(JSON.stringify(edited))];
  state.hasUnsavedWork=false;
  const payload=buildPayload();payload.action=cv?'update':'create';
  fetch('/traderalign/api/strategy/save',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(payload)})
    .then(r=>r.json())
    .then(d=>{
      if(!d.success){toast('Save failed, try again');return;}
      if(!cv){toast('Strategy created');}
      else if(!wasDirty){toast('No changes to save');}
      else if(d.changes_recorded>0){toast(esc(s.name)+' updated, '+d.changes_recorded+' change'+(d.changes_recorded===1?'':'s')+' recorded');}
      else{toast('Strategy saved');}
    })
    .catch(function(){toast('Network error, changes may not have saved');});
  render();
}
function buildPayload(){const s=activeStrategy();const v=currentVersion()||state.editingVersion;return{strategy:{id:s.id,name:s.name,description:s.description,trading_style:s.trading_style,is_active:s.is_active,current_version_id:s.current_version_id},strategy_version:{id:v.id,strategy_id:s.id,version_number:v.version_number,backtested_win_rate:v.backtested_win_rate,backtested_avg_rr:v.backtested_avg_rr,max_risk_per_trade_pct:v.max_risk_per_trade_pct,max_losing_streak:v.max_losing_streak,max_trades_per_day:v.max_trades_per_day,max_trades_per_week:v.max_trades_per_week,instruments_traded:v.instruments_traded,timeframes_traded:v.timeframes_traded,session_preference:v.session_preference,setup_criteria:v.setup_criteria.filter(Boolean),entry_triggers:v.entry_triggers.filter(Boolean),sl_rules:v.sl_rules.filter(Boolean),tp_rules:v.tp_rules.filter(Boolean),move_to_be_rule:v.move_to_be_rule,polished_by:v.polished_by,created_at:v.created_at},checklist_items:v.checklist_items.map((it,idx)=>({id:it.id,strategy_version_id:v.id,category:it.category,position:idx,raw_text:it.raw_text,polished_text:it.polished_text,verification_hint:it.verification_hint||null,is_required:it.is_required}))};}

// callColexAssist() — real, server-side, authenticated call to Colex
// (2026-08-10, Alignex→Colex rebrand cleanup). Replaces the old
// callAlignex(), which called Anthropic's API directly from this
// client-side JS with no API key anywhere in the request — meaning it
// failed every single time it was invoked. The server (api/colex/
// assist.php) now builds the same system/user prompts this file used
// to build itself, holds the real API key, and applies the same
// allowance gate Colex chat already uses — this function just sends the
// task + the trader's own raw data and gets real JSON back.
async function callColexAssist(task,payload){const r=await fetch('/traderalign/api/colex/assist',{method:'POST',headers:{'Content-Type':'application/json'},body:JSON.stringify(Object.assign({task:task},payload))});const d=await r.json();if(!d.success)throw new Error(d.error||'Colex unavailable.');return d;}
function aiStatus(m,s=true){const e=$('#aiStatus');if(e){e.style.display=s?'block':'none';e.textContent=m;}}
async function runPolish(){const v=state.editingVersion;const items=v.checklist_items.filter(i=>(i.raw_text||'').trim());if(!items.length){toast('Add checklist items first');return;}aiStatus('Colex is polishing…');try{const o=await callColexAssist('polish',{items:items.map(i=>({id:i.id,category:i.category,raw_text:i.raw_text}))});state.aiProposal={type:'polish',items:o.items||[]};aiStatus('',false);renderDiff();}catch(e){aiStatus('Colex unavailable.');}}
function renderDiff(){const v=state.editingVersion;const p=state.aiProposal;if(!p)return;$('#aiDiff').innerHTML=`<div style="font-size:11px;color:var(--foreground-dim);margin:8px 0">Review before saving.</div>${p.items.map(x=>{const o=v.checklist_items.find(i=>i.id===x.id);if(!o)return'';return`<div class="diff-row"><div class="old">${esc(o.raw_text)}</div><div class="new">${esc(x.polished_text)}</div><div class="diff-actions"><button class="btn btn-primary btn-sm" onclick="acceptDiff('${x.id}')">Accept</button><button class="btn btn-outline btn-sm" onclick="rejectDiff('${x.id}')">Keep mine</button></div></div>`;}).join('')}<button class="btn btn-outline btn-sm" style="margin-top:6px" onclick="acceptAllDiffs()">Accept all</button>`;}
function acceptDiff(id){const p=state.aiProposal.items.find(x=>x.id===id);const it=state.editingVersion.checklist_items.find(i=>i.id===id);if(p&&it){it.polished_text=p.polished_text;it.verification_hint=p.verification_hint||it.verification_hint;}}
function rejectDiff(id){const d=document.querySelector(`.diff-row[data-id="${id}"]`);if(d)d.style.opacity=.4;}
function acceptAllDiffs(){state.aiProposal.items.forEach(p=>acceptDiff(p.id));toast('All accepted');render();}
async function runAiFirst(){const txt=$('#aiFirstInput').value.trim();if(!txt){toast('Paste your rules first');return;}aiStatus('Decomposing…');try{const o=await callColexAssist('ai_first',{rules_text:txt});const v=state.editingVersion;(o.checklist_items||[]).forEach(c=>{if(!CATEGORIES.includes(c.category))return;const it=blankItem(c.category);it.raw_text=c.polished_text;it.polished_text=c.polished_text;it.verification_hint=c.verification_hint||'';it.is_required=c.is_required!==false;it.position=v.checklist_items.filter(x=>x.category===c.category).length;v.checklist_items.push(it);});const e=o.edge||{};if(e.max_risk_per_trade_pct!=null)v.max_risk_per_trade_pct=e.max_risk_per_trade_pct;if(e.max_losing_streak!=null)v.max_losing_streak=e.max_losing_streak;if(e.max_trades_per_day!=null)v.max_trades_per_day=e.max_trades_per_day;(e.instruments||[]).forEach(s=>{const u=s.toUpperCase().replace(/[^A-Z0-9]/g,'');if(INSTRUMENTS.find(x=>x.s===u)&&!v.instruments_traded.includes(u))v.instruments_traded.push(u);});(e.sessions||[]).forEach(s=>{const m=SESSIONS.find(x=>x.name.toLowerCase()===s.toLowerCase());if(m&&!v.session_preference.includes(m.name))v.session_preference.push(m.name);});aiStatus('Review and save below.');render();}catch(e){aiStatus('Colex unavailable.');}}

// ── Read-only reference-view loader ─────────────────────────────────
// Adapted from selectExistingStrategy() above, but deliberately skips its
// hasUnsavedStrategy()/tier-authoring guards — those exist to protect
// SAVING, and this mode can never save (pointer-events:none + disabled
// inputs, see lockReadonlyUI() and the .readonly-mode CSS above), so
// viewing your own strategy read-only must never be gated behind an
// authoring tier.
function loadStrategyReadonly(strategyId) {
    fetch('/traderalign/api/strategy/load?id=' + strategyId)
        .then(function(r) { if (!r.ok) throw new Error('HTTP ' + r.status); return r.json(); })
        .then(function(data) {
            if (data.error || !data.strategy) { toast('Failed to load strategy for reference view'); return; }
            var s = data.strategy, v = data.version, items = data.checklist_items || [];
            var versionObj = {
                id: v.id, strategy_id: s.id, version_number: v.version_number,
                polished_by: v.polished_by || 'manual', polish_history: v.polish_history || [],
                backtested_win_rate: v.backtested_win_rate, backtested_avg_rr: v.backtested_avg_rr,
                max_risk_per_trade_pct: v.max_risk_per_trade_pct || 1, max_losing_streak: v.max_losing_streak || 3,
                max_trades_per_day: v.max_trades_per_day, max_trades_per_week: v.max_trades_per_week,
                instruments_traded: v.instruments_traded || [], timeframes_traded: v.timeframes_traded || [],
                session_preference: v.session_preference || [], setup_criteria: v.setup_criteria || [],
                entry_triggers: v.entry_triggers || [], sl_rules: v.sl_rules || [], tp_rules: v.tp_rules || [],
                move_to_be_rule: v.move_to_be_rule || '',
                checklist_items: items.map(function(it) {
                    return { id: it.id || uuid(), category: it.category, position: it.position || 0,
                             raw_text: it.raw_text || '', polished_text: it.polished_text || '',
                             verification_hint: it.verification_hint || '', is_required: it.is_required !== false };
                }),
                created_at: v.created_at || now()
            };
            var newS = { id: s.id, name: s.name, description: s.description || '', trading_style: s.trading_style || 'day_trader',
                         is_active: true, current_version_id: versionObj.id, versions: [versionObj], created_at: s.created_at || now() };
            state.strategies = [newS];
            state.activeId = newS.id;
            state.editingVersion = JSON.parse(JSON.stringify(versionObj));
            state.authMode = 'manual';
            state.aiProposal = null;
            state.hasUnsavedWork = false;
            setView('build');
            lockReadonlyUI();
        })
        .catch(function(err) {
            console.error('Readonly load failed:', err);
            toast('Failed to load strategy, check console');
        });
}

function lockReadonlyUI() {
    document.body.classList.add('readonly-mode');
    var content = document.getElementById('stratContent');
    if (content) {
        content.querySelectorAll('input, textarea, select').forEach(function(el) {
            el.disabled = true;
            el.readOnly = true;
        });
    }
}

if (READONLY_MODE && READONLY_STRATEGY_ID) {
    loadStrategyReadonly(READONLY_STRATEGY_ID);
} else {
    render();
    if (VALIDATION_PREFILL) {
        // Land the graduating trader straight into the save-your-validated-
        // strategy modal, pre-named after their validation strategy,
        // instead of an empty list — openNewStrategyModal() itself reads
        // applyValidationPrefillOnce (still true here) both to pre-fill
        // the name input and to swap in the graduation-specific copy.
        state.applyValidationPrefillOnce = true;
        openNewStrategyModal();
    }
}
</script>

</body>
</html>