import { ChangeDetectorRef, Component, Input, ViewEncapsulation, inject } from '@angular/core';
import { CommonModule } from '@angular/common';
import { MJButtonDirective } from '@memberjunction/ng-ui-components';
import { MJNotificationService } from '@memberjunction/ng-notifications';
import { UUIDsEqual } from '@memberjunction/global';
import { PredictiveStudioControlExperimentSessionOperation, } from '@memberjunction/core-entities';
import { deriveLeaderboard, groupIterationsToKanban, } from '../predictive-studio.view-models';
import { PSConfirmModalComponent } from './ps-confirm-modal.component';
import * as i0 from "@angular/core";
import * as i1 from "@angular/common";
const _c0 = a0 => ({ c: a0 });
const _forTrack0 = ($index, $item) => $item.rank;
const _forTrack1 = ($index, $item) => $item.iteration;
const _forTrack2 = ($index, $item) => $item.label;
function PSExperimentsComponent_Conditional_1_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 2)(1, "span", 4);
    i0.ɵɵelement(2, "i", 5);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(3, "h3");
    i0.ɵɵtext(4, "No experiment sessions yet");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(5, "p");
    i0.ɵɵtext(6, "Launch an experiment to watch the Model Dev Agent search algorithms and feature sets in waves. Running and completed iterations will appear here with a live leaderboard.");
    i0.ɵɵelementEnd()();
} }
function PSExperimentsComponent_Conditional_2_Conditional_12_Template(rf, ctx) { if (rf & 1) {
    const _r1 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "button", 32);
    i0.ɵɵlistener("click", function PSExperimentsComponent_Conditional_2_Conditional_12_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r1); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.requestControl("pause")); });
    i0.ɵɵelement(1, "i", 33);
    i0.ɵɵtext(2, " Pause");
    i0.ɵɵelementEnd();
} }
function PSExperimentsComponent_Conditional_2_Conditional_13_Template(rf, ctx) { if (rf & 1) {
    const _r3 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "button", 34);
    i0.ɵɵlistener("click", function PSExperimentsComponent_Conditional_2_Conditional_13_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r3); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.requestControl("resume")); });
    i0.ɵɵelement(1, "i", 35);
    i0.ɵɵtext(2, " Resume");
    i0.ɵɵelementEnd();
} }
function PSExperimentsComponent_Conditional_2_Conditional_14_Template(rf, ctx) { if (rf & 1) {
    const _r4 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "button", 36);
    i0.ɵɵlistener("click", function PSExperimentsComponent_Conditional_2_Conditional_14_Template_button_click_0_listener() { i0.ɵɵrestoreView(_r4); const ctx_r1 = i0.ɵɵnextContext(2); return i0.ɵɵresetView(ctx_r1.requestControl("cancel")); });
    i0.ɵɵelement(1, "i", 37);
    i0.ɵɵtext(2, " Cancel");
    i0.ɵɵelementEnd();
} }
function PSExperimentsComponent_Conditional_2_Conditional_23_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "span", 7);
    i0.ɵɵtext(1, "No scored iterations yet.");
    i0.ɵɵelementEnd();
} }
function PSExperimentsComponent_Conditional_2_For_25_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 38)(1, "span", 39);
    i0.ɵɵtext(2);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(3, "span", 40);
    i0.ɵɵelement(4, "i");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(5, "div")(6, "div", 41);
    i0.ɵɵtext(7);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(8, "div", 42);
    i0.ɵɵtext(9);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(10, "span", 43);
    i0.ɵɵtext(11);
    i0.ɵɵpipe(12, "number");
    i0.ɵɵelementEnd()();
} if (rf & 2) {
    const lp_r5 = ctx.$implicit;
    i0.ɵɵclassProp("best", lp_r5.best)("pruned", lp_r5.pruned);
    i0.ɵɵadvance();
    i0.ɵɵclassProp("gold", lp_r5.best);
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(lp_r5.rank);
    i0.ɵɵadvance();
    i0.ɵɵstyleProp("background", lp_r5.algorithmColor);
    i0.ɵɵadvance();
    i0.ɵɵclassMap(lp_r5.algorithmIcon);
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate(lp_r5.algorithm);
    i0.ɵɵadvance(2);
    i0.ɵɵtextInterpolate(lp_r5.features);
    i0.ɵɵadvance();
    i0.ɵɵclassProp("win", lp_r5.best);
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(12, 16, lp_r5.auc, "1.3-3"));
} }
function PSExperimentsComponent_Conditional_2_Conditional_26_For_3_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 45)(1, "div", 46)(2, "span", 47);
    i0.ɵɵtext(3);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(4, "div", 48)(5, "div", 49);
    i0.ɵɵtext(6);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(7, "div", 50)(8, "strong");
    i0.ɵɵtext(9);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(10, "span", 51);
    i0.ɵɵtext(11);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(12, "div", 52);
    i0.ɵɵelement(13, "span");
    i0.ɵɵelementEnd()()();
} if (rf & 2) {
    const b_r6 = ctx.$implicit;
    i0.ɵɵadvance();
    i0.ɵɵstyleProp("--ps-p", b_r6.fillPct)("--ps-gauge-color", b_r6.color);
    i0.ɵɵadvance(2);
    i0.ɵɵtextInterpolate(b_r6.centerText);
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate(b_r6.label);
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate(b_r6.value);
    i0.ɵɵadvance(2);
    i0.ɵɵtextInterpolate1("/ ", b_r6.cap);
    i0.ɵɵadvance(2);
    i0.ɵɵstyleProp("width", b_r6.fillPct, "%")("background", b_r6.color);
} }
function PSExperimentsComponent_Conditional_2_Conditional_26_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 20)(1, "div", 44);
    i0.ɵɵrepeaterCreate(2, PSExperimentsComponent_Conditional_2_Conditional_26_For_3_Template, 14, 12, "div", 45, _forTrack2);
    i0.ɵɵelementEnd()();
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext(2);
    i0.ɵɵadvance(2);
    i0.ɵɵrepeater(ctx_r1.budget);
} }
function PSExperimentsComponent_Conditional_2_For_37_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementContainer(0, 27);
} if (rf & 2) {
    const c_r7 = ctx.$implicit;
    i0.ɵɵnextContext();
    const iterCard_r8 = i0.ɵɵreference(62);
    i0.ɵɵproperty("ngTemplateOutlet", iterCard_r8)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, c_r7));
} }
function PSExperimentsComponent_Conditional_2_Conditional_38_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "span", 7);
    i0.ɵɵtext(1, "No running iterations.");
    i0.ɵɵelementEnd();
} }
function PSExperimentsComponent_Conditional_2_For_48_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementContainer(0, 27);
} if (rf & 2) {
    const c_r9 = ctx.$implicit;
    i0.ɵɵnextContext();
    const iterCard_r8 = i0.ɵɵreference(62);
    i0.ɵɵproperty("ngTemplateOutlet", iterCard_r8)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, c_r9));
} }
function PSExperimentsComponent_Conditional_2_Conditional_49_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "span", 7);
    i0.ɵɵtext(1, "No completed iterations.");
    i0.ɵɵelementEnd();
} }
function PSExperimentsComponent_Conditional_2_For_59_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementContainer(0, 27);
} if (rf & 2) {
    const c_r10 = ctx.$implicit;
    i0.ɵɵnextContext();
    const iterCard_r8 = i0.ɵɵreference(62);
    i0.ɵɵproperty("ngTemplateOutlet", iterCard_r8)("ngTemplateOutletContext", i0.ɵɵpureFunction1(2, _c0, c_r10));
} }
function PSExperimentsComponent_Conditional_2_Conditional_60_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "span", 7);
    i0.ɵɵtext(1, "Nothing pruned.");
    i0.ɵɵelementEnd();
} }
function PSExperimentsComponent_Conditional_2_ng_template_61_For_14_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "span", 57);
    i0.ɵɵtext(1);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const f_r11 = ctx.$implicit;
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(f_r11);
} }
function PSExperimentsComponent_Conditional_2_ng_template_61_Conditional_15_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 58)(1, "div", 63);
    i0.ɵɵelement(2, "span");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(3, "div", 64)(4, "span", 51);
    i0.ɵɵtext(5);
    i0.ɵɵelementEnd()()();
} if (rf & 2) {
    const c_r12 = i0.ɵɵnextContext().c;
    i0.ɵɵadvance(2);
    i0.ɵɵstyleProp("width", c_r12.progress, "%");
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate(c_r12.progressDetail);
} }
function PSExperimentsComponent_Conditional_2_ng_template_61_Conditional_16_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 59)(1, "span", 65);
    i0.ɵɵtext(2);
    i0.ɵɵpipe(3, "number");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(4, "span", 66);
    i0.ɵɵtext(5);
    i0.ɵɵelementEnd()();
} if (rf & 2) {
    const c_r12 = i0.ɵɵnextContext().c;
    i0.ɵɵadvance();
    i0.ɵɵclassProp("green", c_r12.status === "Best");
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(i0.ɵɵpipeBind2(3, 4, c_r12.score, "1.3-3"));
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate1("score \u00B7 ", c_r12.scoreDelta);
} }
function PSExperimentsComponent_Conditional_2_ng_template_61_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 53)(1, "div", 54)(2, "span", 40);
    i0.ɵɵelement(3, "i");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(4, "div")(5, "div", 41);
    i0.ɵɵtext(6);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(7, "div", 55);
    i0.ɵɵtext(8);
    i0.ɵɵelementEnd()();
    i0.ɵɵelement(9, "span", 10);
    i0.ɵɵelementStart(10, "span", 8);
    i0.ɵɵtext(11);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(12, "div", 56);
    i0.ɵɵrepeaterCreate(13, PSExperimentsComponent_Conditional_2_ng_template_61_For_14_Template, 2, 1, "span", 57, i0.ɵɵrepeaterTrackByIdentity);
    i0.ɵɵelementEnd();
    i0.ɵɵconditionalCreate(15, PSExperimentsComponent_Conditional_2_ng_template_61_Conditional_15_Template, 6, 3, "div", 58)(16, PSExperimentsComponent_Conditional_2_ng_template_61_Conditional_16_Template, 6, 7, "div", 59);
    i0.ɵɵelementStart(17, "div", 60);
    i0.ɵɵelement(18, "i", 61);
    i0.ɵɵelementStart(19, "span", 62);
    i0.ɵɵtext(20);
    i0.ɵɵelementEnd()()();
} if (rf & 2) {
    const c_r12 = ctx.c;
    const ctx_r1 = i0.ɵɵnextContext(2);
    i0.ɵɵclassProp("best", c_r12.status === "Best")("running", c_r12.status === "Running")("pruned", c_r12.status === "Pruned");
    i0.ɵɵadvance(2);
    i0.ɵɵstyleProp("background", c_r12.algorithmColor);
    i0.ɵɵadvance();
    i0.ɵɵclassMap(c_r12.algorithmIcon);
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate(c_r12.algorithm);
    i0.ɵɵadvance(2);
    i0.ɵɵtextInterpolate(c_r12.iteration);
    i0.ɵɵadvance(2);
    i0.ɵɵclassMap(ctx_r1.statusBadgeClass(c_r12.status));
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate(ctx_r1.statusLabel(c_r12.status));
    i0.ɵɵadvance(2);
    i0.ɵɵrepeater(c_r12.features);
    i0.ɵɵadvance(2);
    i0.ɵɵconditional(c_r12.status === "Running" ? 15 : 16);
    i0.ɵɵadvance(5);
    i0.ɵɵtextInterpolate(c_r12.rationale);
} }
function PSExperimentsComponent_Conditional_2_Template(rf, ctx) { if (rf & 1) {
    i0.ɵɵelementStart(0, "div", 6)(1, "div")(2, "div", 7);
    i0.ɵɵtext(3, "Experiment session");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(4, "h2");
    i0.ɵɵtext(5);
    i0.ɵɵelementStart(6, "span", 8);
    i0.ɵɵelement(7, "span", 9);
    i0.ɵɵtext(8);
    i0.ɵɵelementEnd()()();
    i0.ɵɵelement(9, "span", 10);
    i0.ɵɵelementStart(10, "span", 7);
    i0.ɵɵtext(11);
    i0.ɵɵelementEnd();
    i0.ɵɵconditionalCreate(12, PSExperimentsComponent_Conditional_2_Conditional_12_Template, 3, 0, "button", 11);
    i0.ɵɵconditionalCreate(13, PSExperimentsComponent_Conditional_2_Conditional_13_Template, 3, 0, "button", 12);
    i0.ɵɵconditionalCreate(14, PSExperimentsComponent_Conditional_2_Conditional_14_Template, 3, 0, "button", 13);
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(15, "div", 14)(16, "div", 15)(17, "div", 16)(18, "div", 17);
    i0.ɵɵelement(19, "i", 18);
    i0.ɵɵtext(20, " Leaderboard");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(21, "div", 7);
    i0.ɵɵtext(22);
    i0.ɵɵelementEnd()();
    i0.ɵɵconditionalCreate(23, PSExperimentsComponent_Conditional_2_Conditional_23_Template, 2, 0, "span", 7);
    i0.ɵɵrepeaterCreate(24, PSExperimentsComponent_Conditional_2_For_25_Template, 13, 19, "div", 19, _forTrack0);
    i0.ɵɵelementEnd()();
    i0.ɵɵconditionalCreate(26, PSExperimentsComponent_Conditional_2_Conditional_26_Template, 4, 0, "div", 20);
    i0.ɵɵelementStart(27, "div", 21)(28, "div", 22)(29, "div", 23);
    i0.ɵɵelement(30, "i", 24);
    i0.ɵɵelementStart(31, "h3");
    i0.ɵɵtext(32, "Running");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(33, "span", 25);
    i0.ɵɵtext(34);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(35, "div", 26);
    i0.ɵɵrepeaterCreate(36, PSExperimentsComponent_Conditional_2_For_37_Template, 1, 4, "ng-container", 27, _forTrack1);
    i0.ɵɵconditionalCreate(38, PSExperimentsComponent_Conditional_2_Conditional_38_Template, 2, 0, "span", 7);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(39, "div", 28)(40, "div", 23);
    i0.ɵɵelement(41, "i", 29);
    i0.ɵɵelementStart(42, "h3");
    i0.ɵɵtext(43, "Completed");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(44, "span", 25);
    i0.ɵɵtext(45);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(46, "div", 26);
    i0.ɵɵrepeaterCreate(47, PSExperimentsComponent_Conditional_2_For_48_Template, 1, 4, "ng-container", 27, _forTrack1);
    i0.ɵɵconditionalCreate(49, PSExperimentsComponent_Conditional_2_Conditional_49_Template, 2, 0, "span", 7);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(50, "div", 30)(51, "div", 23);
    i0.ɵɵelement(52, "i", 31);
    i0.ɵɵelementStart(53, "h3");
    i0.ɵɵtext(54, "Pruned");
    i0.ɵɵelementEnd();
    i0.ɵɵelementStart(55, "span", 25);
    i0.ɵɵtext(56);
    i0.ɵɵelementEnd()();
    i0.ɵɵelementStart(57, "div", 26);
    i0.ɵɵrepeaterCreate(58, PSExperimentsComponent_Conditional_2_For_59_Template, 1, 4, "ng-container", 27, _forTrack1);
    i0.ɵɵconditionalCreate(60, PSExperimentsComponent_Conditional_2_Conditional_60_Template, 2, 0, "span", 7);
    i0.ɵɵelementEnd()()();
    i0.ɵɵtemplate(61, PSExperimentsComponent_Conditional_2_ng_template_61_Template, 21, 17, "ng-template", null, 0, i0.ɵɵtemplateRefExtractor);
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext();
    i0.ɵɵadvance(5);
    i0.ɵɵtextInterpolate1("", ctx_r1.session.Name, " ");
    i0.ɵɵadvance();
    i0.ɵɵclassMap(ctx_r1.sessionBadgeClass);
    i0.ɵɵadvance();
    i0.ɵɵstyleProp("background", ctx_r1.sessionDotColor);
    i0.ɵɵadvance();
    i0.ɵɵtextInterpolate1(" ", ctx_r1.session.Status);
    i0.ɵɵadvance(3);
    i0.ɵɵtextInterpolate(ctx_r1.iterationCountLabel);
    i0.ɵɵadvance();
    i0.ɵɵconditional(ctx_r1.canPause ? 12 : -1);
    i0.ɵɵadvance();
    i0.ɵɵconditional(ctx_r1.canResume ? 13 : -1);
    i0.ɵɵadvance();
    i0.ɵɵconditional(ctx_r1.canCancel ? 14 : -1);
    i0.ɵɵadvance(8);
    i0.ɵɵtextInterpolate1("", ctx_r1.leaderboard.length, " scored \u00B7 by metric");
    i0.ɵɵadvance();
    i0.ɵɵconditional(ctx_r1.leaderboard.length === 0 ? 23 : -1);
    i0.ɵɵadvance();
    i0.ɵɵrepeater(ctx_r1.leaderboard);
    i0.ɵɵadvance(2);
    i0.ɵɵconditional(ctx_r1.budget.length > 0 ? 26 : -1);
    i0.ɵɵadvance(8);
    i0.ɵɵtextInterpolate(ctx_r1.kanban.running.length);
    i0.ɵɵadvance(2);
    i0.ɵɵrepeater(ctx_r1.kanban.running);
    i0.ɵɵadvance(2);
    i0.ɵɵconditional(ctx_r1.kanban.running.length === 0 ? 38 : -1);
    i0.ɵɵadvance(7);
    i0.ɵɵtextInterpolate(ctx_r1.kanban.completed.length);
    i0.ɵɵadvance(2);
    i0.ɵɵrepeater(ctx_r1.kanban.completed);
    i0.ɵɵadvance(2);
    i0.ɵɵconditional(ctx_r1.kanban.completed.length === 0 ? 49 : -1);
    i0.ɵɵadvance(7);
    i0.ɵɵtextInterpolate(ctx_r1.kanban.pruned.length);
    i0.ɵɵadvance(2);
    i0.ɵɵrepeater(ctx_r1.kanban.pruned);
    i0.ɵɵadvance(2);
    i0.ɵɵconditional(ctx_r1.kanban.pruned.length === 0 ? 60 : -1);
} }
function PSExperimentsComponent_Conditional_3_Template(rf, ctx) { if (rf & 1) {
    const _r13 = i0.ɵɵgetCurrentView();
    i0.ɵɵelementStart(0, "ps-confirm-modal", 67);
    i0.ɵɵlistener("confirmed", function PSExperimentsComponent_Conditional_3_Template_ps_confirm_modal_confirmed_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.confirmControl()); })("cancelled", function PSExperimentsComponent_Conditional_3_Template_ps_confirm_modal_cancelled_0_listener() { i0.ɵɵrestoreView(_r13); const ctx_r1 = i0.ɵɵnextContext(); return i0.ɵɵresetView(ctx_r1.cancelControl()); });
    i0.ɵɵelement(1, "div", 68);
    i0.ɵɵelementEnd();
} if (rf & 2) {
    const ctx_r1 = i0.ɵɵnextContext();
    i0.ɵɵproperty("title", ctx_r1.pendingTitle)("icon", ctx_r1.pendingIcon)("confirmIcon", ctx_r1.pendingIcon)("confirmLabel", ctx_r1.pendingConfirmLabel)("variant", ctx_r1.pendingAction === "cancel" ? "danger" : "warn")("busy", ctx_r1.busy);
    i0.ɵɵadvance();
    i0.ɵɵproperty("innerHTML", ctx_r1.pendingMessage, i0.ɵɵsanitizeHtml);
} }
/**
 * Experiments panel: a kanban of iteration cards in Running / Completed / Pruned columns, a leaderboard
 * strip ranked by score, and budget gauges — all live against `MJ: Experiment Sessions` + their
 * `MJ: Experiment Session Iterations`:
 *
 * - The **active session** is the first Running session, else the most-recently-created one.
 * - The **kanban** + **leaderboard** are derived from that session's iterations (grouped by status,
 *   ranked by score) via the pure {@link groupIterationsToKanban} / {@link deriveLeaderboard} helpers.
 * - **Budget gauges** combine the session's budget JSON caps with actual iteration spend (compute
 *   cost, iteration count).
 * - **Pause / Cancel** call the {@link PredictiveStudioControlExperimentSessionOperation} Remote Op
 *   behind a confirmation; on success the engine refreshes.
 *
 * Empty state when there are no sessions. 100% entity-agnostic.
 */
export class PSExperimentsComponent {
    engine;
    /** Provider to route the control Remote Op + engine refresh through (multi-provider correctness). */
    provider = null;
    /** Acting user for the engine refresh after a mutation. */
    currentUser = null;
    cdr = inject(ChangeDetectorRef);
    notifications = inject(MJNotificationService);
    /** The currently-displayed session ID (first Running, else most recent). */
    sessionId = '';
    kanban = { running: [], completed: [], pruned: [] };
    leaderboard = [];
    budget = [];
    /** Pending control action awaiting confirmation (null when no modal is open). */
    pendingAction = null;
    /** Remote Op in flight. */
    busy = false;
    ngOnInit() {
        this.selectActiveSession();
        this.rebuild();
    }
    // ---- active session selection ----
    /** Pick the most relevant session to display: first Running, else the most-recently-created. */
    selectActiveSession() {
        const sessions = this.engine?.Sessions ?? [];
        const running = sessions.find((s) => s.Status === 'Running');
        // Sessions are loaded OrderBy '__mj_CreatedAt DESC', so index 0 is the most recent.
        this.sessionId = (running ?? sessions[0])?.ID ?? '';
    }
    get session() {
        return this.engine?.Sessions.find((s) => UUIDsEqual(s.ID, this.sessionId));
    }
    get iterationCountLabel() {
        const total = this.kanban.running.length + this.kanban.completed.length + this.kanban.pruned.length;
        return `${total} iteration${total === 1 ? '' : 's'}`;
    }
    // ---- derivations ----
    rebuild() {
        if (!this.sessionId) {
            this.kanban = { running: [], completed: [], pruned: [] };
            this.leaderboard = [];
            this.budget = [];
            return;
        }
        const rows = this.engine.IterationRowsForSession(this.sessionId);
        this.kanban = groupIterationsToKanban(rows);
        this.leaderboard = deriveLeaderboard(rows);
        this.budget = this.buildBudget(rows);
    }
    /** Build the budget gauges from the session's budget JSON caps + actual iteration spend. */
    buildBudget(rows) {
        const session = this.session;
        if (!session)
            return [];
        const budgetJson = this.parseBudget(session.Budget);
        const gauges = [];
        const spentCost = rows.reduce((sum, r) => sum + (r.ComputeCost ?? 0), 0);
        const maxCost = budgetJson.maxComputeCost;
        if (maxCost != null && maxCost > 0) {
            gauges.push(this.gauge('Compute cost', spentCost, maxCost, 'var(--ps-gauge-cost)', (v) => `$${v.toFixed(0)}`, `$${maxCost.toFixed(0)} cap`));
        }
        const iterations = rows.length;
        const maxIterations = budgetJson.maxIterations;
        if (maxIterations != null && maxIterations > 0) {
            gauges.push(this.gauge('Iterations', iterations, maxIterations, 'var(--ps-gauge-iterations)', (v) => `${v}`, `${maxIterations} trials`));
        }
        return gauges;
    }
    /** Construct a single gauge VM (fill clamped to 0..100). */
    gauge(label, value, cap, color, fmt, capLabel) {
        const fillPct = Math.max(0, Math.min(100, Math.round((value / cap) * 100)));
        return { label, fillPct, centerText: `${fillPct}%`, value: fmt(value), cap: capLabel, color };
    }
    /** Tolerant parse of the session's budget JSON (accepts a few common key spellings). */
    parseBudget(json) {
        if (!json)
            return { maxComputeCost: null, maxIterations: null };
        try {
            const parsed = JSON.parse(json);
            const num = (...keys) => {
                for (const k of keys) {
                    const v = parsed[k];
                    if (typeof v === 'number' && Number.isFinite(v))
                        return v;
                }
                return null;
            };
            return {
                maxComputeCost: num('maxComputeCost', 'maxCost', 'computeBudget'),
                maxIterations: num('maxIterations', 'maxTrials', 'iterationBudget'),
            };
        }
        catch {
            return { maxComputeCost: null, maxIterations: null };
        }
    }
    // ---- session status chrome ----
    get sessionBadgeClass() {
        switch (this.session?.Status) {
            case 'Running': return 'green';
            case 'Paused': return 'amber';
            case 'Cancelled': return 'red';
            case 'Completed': return 'blue';
            default: return 'gray';
        }
    }
    get sessionDotColor() {
        switch (this.session?.Status) {
            case 'Running': return 'var(--mj-status-success)';
            case 'Paused': return 'var(--mj-status-warning)';
            case 'Cancelled': return 'var(--mj-status-error)';
            default: return 'var(--mj-text-muted)';
        }
    }
    statusBadgeClass(status) {
        switch (status) {
            case 'Best': return 'green';
            case 'Completed': return 'gray';
            case 'AwaitingApproval': return 'amber';
            case 'Pruned': return 'red';
            case 'Running': return 'blue';
        }
    }
    statusLabel(status) {
        switch (status) {
            case 'Best': return 'Best';
            case 'AwaitingApproval': return 'Awaiting approval';
            default: return status;
        }
    }
    // ---- control availability ----
    get canPause() {
        return this.session?.Status === 'Running';
    }
    get canResume() {
        return this.session?.Status === 'Paused';
    }
    get canCancel() {
        const s = this.session?.Status;
        return s === 'Running' || s === 'Paused' || s === 'AwaitingApproval';
    }
    // ---- control flow (Remote Op) ----
    requestControl(action) {
        if (!this.session)
            return;
        this.pendingAction = action;
    }
    cancelControl() {
        if (this.busy)
            return;
        this.pendingAction = null;
    }
    get pendingTitle() {
        switch (this.pendingAction) {
            case 'pause': return 'Pause experiment';
            case 'resume': return 'Resume experiment';
            case 'cancel': return 'Cancel experiment';
            default: return '';
        }
    }
    get pendingIcon() {
        switch (this.pendingAction) {
            case 'pause': return 'fa-solid fa-pause';
            case 'resume': return 'fa-solid fa-play';
            case 'cancel': return 'fa-solid fa-stop';
            default: return 'fa-solid fa-check';
        }
    }
    get pendingConfirmLabel() {
        switch (this.pendingAction) {
            case 'pause': return 'Pause';
            case 'resume': return 'Resume';
            case 'cancel': return 'Cancel run';
            default: return 'Confirm';
        }
    }
    get pendingMessage() {
        const name = escapeHtml(this.session?.Name ?? 'this session');
        switch (this.pendingAction) {
            case 'pause':
                return `Pause <strong>${name}</strong>? The orchestrator stops at the next wave checkpoint; in-flight iterations finish. You can resume later.`;
            case 'resume':
                return `Resume <strong>${name}</strong>? The orchestrator continues searching from where it paused.`;
            case 'cancel':
                return `Cancel <strong>${name}</strong>? This stops the search at the next checkpoint. Completed iterations and the leaderboard are kept, but the session cannot be resumed.`;
            default:
                return '';
        }
    }
    /** Run the control Remote Op, then refresh the engine + close on success. */
    async confirmControl() {
        if (!this.pendingAction || !this.session || this.busy)
            return;
        this.busy = true;
        const action = this.pendingAction;
        const sessionId = this.session.ID;
        const name = this.session.Name;
        try {
            const op = new PredictiveStudioControlExperimentSessionOperation();
            const result = await op.Execute({ sessionId, action }, { provider: this.provider ?? undefined, user: this.currentUser ?? undefined });
            if (result.Success) {
                this.notifications.CreateSimpleNotification(`${name} → ${result.Output?.status ?? action}`, 'success', 3500);
                await this.refreshAfterMutation();
                this.pendingAction = null;
            }
            else {
                this.notifications.CreateSimpleNotification(result.ErrorMessage || `Could not ${action} ${name}.`, 'error', 5000);
            }
        }
        catch (e) {
            this.notifications.CreateSimpleNotification(`${action} failed: ${e instanceof Error ? e.message : String(e)}`, 'error', 5000);
        }
        finally {
            this.busy = false;
            this.cdr.detectChanges();
        }
    }
    /** Force-refresh the engine's cached sessions/iterations, then rebuild. */
    async refreshAfterMutation() {
        await this.engine.Config(true, this.currentUser ?? undefined, this.provider ?? undefined);
        this.selectActiveSession();
        this.rebuild();
        this.cdr.detectChanges();
    }
    static ɵfac = function PSExperimentsComponent_Factory(__ngFactoryType__) { return new (__ngFactoryType__ || PSExperimentsComponent)(); };
    static ɵcmp = /*@__PURE__*/ i0.ɵɵdefineComponent({ type: PSExperimentsComponent, selectors: [["ps-experiments"]], inputs: { engine: "engine", provider: "provider", currentUser: "currentUser" }, decls: 4, vars: 2, consts: [["iterCard", ""], ["data-testid", "ps-experiments-panel", 1, "ps-panel", "ps-experiments"], ["data-testid", "ps-experiments-empty", 1, "ps-empty"], [3, "title", "icon", "confirmIcon", "confirmLabel", "variant", "busy"], [1, "ps-empty-ico"], [1, "fa-solid", "fa-flask"], [1, "sess-head"], [1, "ps-small", "ps-muted"], [1, "ps-badge"], [1, "ps-dot"], [1, "ps-spacer"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-experiments-pause"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-experiments-resume"], ["mjButton", "", "variant", "danger", "size", "sm", "data-testid", "ps-experiments-cancel"], ["data-testid", "ps-experiments-leaderboard", 1, "ps-card"], [1, "ps-card-body", "lead-strip"], [1, "lead-lbl"], [1, "t"], [1, "fa-solid", "fa-trophy", 2, "color", "var(--mj-status-warning)"], [1, "lp", 3, "best", "pruned"], [1, "ps-card"], ["data-testid", "ps-experiments-kanban", 1, "kanban"], ["data-testid", "ps-kanban-col-running", 1, "kcol", "run"], [1, "kcol-head"], [1, "fa-solid", "fa-spinner"], [1, "cnt"], [1, "kbody"], [3, "ngTemplateOutlet", "ngTemplateOutletContext"], ["data-testid", "ps-kanban-col-completed", 1, "kcol", "done"], [1, "fa-solid", "fa-circle-check"], ["data-testid", "ps-kanban-col-pruned", 1, "kcol", "prune"], [1, "fa-solid", "fa-scissors"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-experiments-pause", 3, "click"], [1, "fa-solid", "fa-pause"], ["mjButton", "", "variant", "secondary", "size", "sm", "data-testid", "ps-experiments-resume", 3, "click"], [1, "fa-solid", "fa-play"], ["mjButton", "", "variant", "danger", "size", "sm", "data-testid", "ps-experiments-cancel", 3, "click"], [1, "fa-solid", "fa-stop"], [1, "lp"], [1, "ps-rank"], [1, "algo-ic"], [1, "nm"], [1, "fs", "ps-muted", "ps-small"], [1, "auc"], [1, "ps-card-body", "budget-rail"], [1, "bud"], [1, "ps-gauge"], [1, "g-val"], [2, "flex", "1"], [1, "ps-section-title"], [1, "b-val"], [1, "ps-muted", "ps-small"], [1, "ps-bar", 2, "margin-top", "6px", "max-width", "150px"], [1, "icard"], [1, "ic-top"], [1, "it", "ps-muted", "ps-small"], [1, "feat-chips"], [1, "ps-tag"], [1, "ic-prog"], [1, "ic-score"], [1, "rationale"], [1, "fa-solid", "fa-robot"], [1, "ps-small"], [1, "ps-bar", "run"], [1, "meta"], [1, "v"], [1, "lbl", "ps-muted", "ps-small"], [3, "confirmed", "cancelled", "title", "icon", "confirmIcon", "confirmLabel", "variant", "busy"], [3, "innerHTML"]], template: function PSExperimentsComponent_Template(rf, ctx) { if (rf & 1) {
            i0.ɵɵelementStart(0, "div", 1);
            i0.ɵɵconditionalCreate(1, PSExperimentsComponent_Conditional_1_Template, 7, 0, "div", 2)(2, PSExperimentsComponent_Conditional_2_Template, 63, 19);
            i0.ɵɵconditionalCreate(3, PSExperimentsComponent_Conditional_3_Template, 2, 7, "ps-confirm-modal", 3);
            i0.ɵɵelementEnd();
        } if (rf & 2) {
            i0.ɵɵadvance();
            i0.ɵɵconditional(!ctx.session ? 1 : 2);
            i0.ɵɵadvance(2);
            i0.ɵɵconditional(ctx.pendingAction ? 3 : -1);
        } }, dependencies: [CommonModule, i1.NgTemplateOutlet, MJButtonDirective, PSConfirmModalComponent, i1.DecimalPipe], styles: ["/* ============================================================================\n   Predictive Studio \u2014 shared panel styles (design-token compliant)\n   Maps the mockup design system onto MemberJunction semantic --mj-* tokens.\n   Loaded by every PS panel component (styleUrls) under ViewEncapsulation.None,\n   so the class names are global within the PS dashboard subtree.\n   No hardcoded colors except the intentional categorical node/algorithm palette\n   (declared once as --ps-* custom props below) which must stay distinct across\n   light/dark to remain readable as diagram accents.\n   ============================================================================ */\n\n/* Categorical accents for DAG node types + algorithm chips. These are\n   data-visualization colors that must remain distinct regardless of theme\n   (allowed exception #3 in the design-token rules). */\n.ps-panel {\n  --ps-node-source: #6b7280;\n  --ps-node-feature: #2050c8;\n  --ps-node-embedding: #7b3ff0;\n  --ps-node-target: #1f9d57;\n  --ps-node-algorithm: #d98213;\n  /* budget-gauge categorical accents (reuse the node palette so light/dark stay distinct) */\n  --ps-gauge-cost: var(--ps-node-algorithm);\n  --ps-gauge-iterations: var(--ps-node-feature);\n}\n\n.ps-panel {\n  display: block;\n  height: 100%;\n}\n\n/* ---- generic layout helpers ---- */\n.ps-row { display: flex; gap: 16px; }\n.ps-col { display: flex; flex-direction: column; gap: 16px; }\n.ps-wrap { flex-wrap: wrap; }\n.ps-spacer { flex: 1; }\n.ps-muted { color: var(--mj-text-muted); }\n.ps-small { font-size: 12.5px; }\n.ps-mono { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-section-title {\n  font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n  color: var(--mj-text-muted); margin: 4px 0 2px; font-weight: 700;\n}\n\n/* ---- cards ---- */\n.ps-card {\n  background: var(--mj-bg-surface);\n  border: 1px solid var(--mj-border-default);\n  border-radius: 10px;\n  box-shadow: var(--mj-shadow-sm);\n  overflow: hidden;\n}\n.ps-card-head {\n  display: flex; align-items: center; gap: 10px;\n  padding: 14px 16px; border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-card-head h3 { font-size: 14.5px; margin: 0; font-weight: 650; color: var(--mj-text-primary); }\n.ps-card-body { padding: 16px; }\n\n/* ---- KPI tiles ---- */\n.ps-kpi {\n  background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n  border-radius: 10px; padding: 16px 18px; box-shadow: var(--mj-shadow-sm);\n}\n.ps-kpi .label { font-size: 12px; color: var(--mj-text-muted); font-weight: 600; }\n.ps-kpi .val { font-size: 26px; font-weight: 720; letter-spacing: -.02em; margin-top: 2px; color: var(--mj-text-primary); }\n\n/* ---- badges ---- */\n.ps-badge {\n  display: inline-flex; align-items: center; gap: 5px;\n  padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 650; line-height: 1.7;\n}\n.ps-badge.gray { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.ps-badge.blue { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.ps-badge.green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.ps-badge.amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-badge.red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }\n\n/* recommendation-level chips (the ranking matrix payoff) */\n.ps-lvl {\n  display: inline-flex; align-items: center; justify-content: center;\n  min-width: 92px; padding: 4px 10px; border-radius: 7px;\n  font-weight: 650; font-size: 11.5px; color: var(--mj-text-inverse);\n}\n.ps-lvl-Primary { background: var(--mj-status-success); }\n.ps-lvl-Strong { background: var(--mj-status-info); }\n.ps-lvl-Viable { background: var(--mj-status-warning); }\n.ps-lvl-Weak { background: var(--mj-text-disabled); }\n.ps-lvl-NotRecommended { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n/* ---- tags ---- */\n.ps-tag {\n  display: inline-block; padding: 2px 8px; border-radius: 6px;\n  background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n  font-size: 11.5px; font-weight: 600;\n}\n.ps-tag.muted { opacity: .6; }\n.ps-divider { height: 1px; background: var(--mj-border-subtle); margin: 8px 0; }\n\n/* ---- tables ---- */\n.ps-table { width: 100%; border-collapse: collapse; font-size: 13px; }\n.ps-table th {\n  text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;\n  color: var(--mj-text-muted); font-weight: 700; padding: 9px 12px;\n  border-bottom: 1px solid var(--mj-border-default);\n}\n.ps-table td { padding: 11px 12px; border-bottom: 1px solid var(--mj-border-subtle); color: var(--mj-text-primary); }\n.ps-table tr:hover td { background: var(--mj-bg-surface-hover); }\n.ps-table .num { text-align: right; font-variant-numeric: tabular-nums; }\n\n.ps-rank {\n  width: 22px; height: 22px; border-radius: 6px; background: var(--mj-bg-surface-sunken);\n  display: inline-grid; place-items: center; font-weight: 700; font-size: 11.5px; color: var(--mj-text-secondary);\n}\n.ps-rank.gold { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n\n/* ---- progress bars ---- */\n.ps-bar { height: 8px; border-radius: 999px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--mj-brand-primary); }\n.ps-bar.warn > span { background: var(--mj-status-warning); }\n.ps-bar.run > span { background: var(--mj-brand-primary); }\n\n.ps-fbar { display: grid; grid-template-columns: 150px 1fr 48px; align-items: center; gap: 10px; padding: 5px 0; }\n.ps-fbar .track { height: 14px; border-radius: 5px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-fbar .track > span { display: block; height: 100%; background: var(--mj-brand-primary); }\n.ps-fbar .track > span.warn { background: var(--mj-status-warning); }\n.ps-fbar .name { color: var(--mj-text-secondary); }\n\n/* gauge */\n.ps-gauge {\n  position: relative; width: 64px; height: 64px; border-radius: 50%; flex: 0 0 auto;\n  background: conic-gradient(var(--ps-gauge-color, var(--mj-brand-primary)) calc(var(--ps-p, 40) * 1%), var(--mj-bg-surface-sunken) 0);\n  display: grid; place-items: center;\n}\n.ps-gauge::after { content: ''; position: absolute; inset: 9px; background: var(--mj-bg-surface); border-radius: 50%; }\n.ps-gauge .g-val { position: relative; font-weight: 720; font-size: 14px; color: var(--mj-text-primary); }\n\n/* warning / info callouts */\n.ps-callout { display: flex; gap: 11px; padding: 12px 14px; border-radius: 10px; border: 1px solid; }\n.ps-callout.warn { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); color: var(--mj-status-warning-text); }\n.ps-callout.info { background: var(--mj-status-info-bg); border-color: var(--mj-status-info-border); color: var(--mj-status-info-text); }\n.ps-callout.success { background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); color: var(--mj-status-success-text); }\n.ps-callout i { font-size: 16px; margin-top: 1px; }\n\n/* lifecycle stepper */\n.ps-stepper { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.ps-step { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.ps-step .pip {\n  width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--mj-border-strong);\n  display: grid; place-items: center; font-size: 11px;\n}\n.ps-step.done { color: var(--mj-status-success-text); }\n.ps-step.done .pip { background: var(--mj-status-success); border-color: var(--mj-status-success); color: var(--mj-text-inverse); }\n.ps-step.curr { color: var(--mj-brand-primary); }\n.ps-step.curr .pip { border-color: var(--mj-brand-primary); color: var(--mj-brand-primary); }\n.ps-step .ln { width: 26px; height: 2px; background: var(--mj-border-strong); }\n\n/* ---- DAG flow canvas ---- */\n.ps-flow {\n  position: relative;\n  background:\n    linear-gradient(var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n    linear-gradient(90deg, var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n    var(--mj-bg-surface-card);\n  border: 1px solid var(--mj-border-default); border-radius: 10px;\n  min-height: 620px; overflow: hidden;\n}\n.ps-node {\n  position: absolute; width: 190px; background: var(--mj-bg-surface);\n  border: 1px solid var(--mj-border-strong); border-left-width: 3px; border-radius: 10px;\n  box-shadow: var(--mj-shadow-sm); cursor: pointer;\n}\n.ps-node .nh {\n  display: flex; align-items: center; gap: 8px; padding: 9px 11px;\n  border-bottom: 1px solid var(--mj-border-subtle); font-weight: 650; font-size: 12.5px; color: var(--mj-text-primary);\n}\n.ps-node .nh i.tile {\n  width: 24px; height: 24px; border-radius: 6px; display: grid; place-items: center;\n  color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-node .nh .ps-tag { margin-left: auto; }\n.ps-node .nb { padding: 9px 11px; font-size: 12px; color: var(--mj-text-secondary); }\n.ps-node .nb-row { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; }\n.ps-node .nb-row .k { color: var(--mj-text-muted); }\n.ps-node.src { border-left-color: var(--ps-node-source); }\n.ps-node.src .nh i.tile { background: var(--ps-node-source); }\n.ps-node.feat { border-left-color: var(--ps-node-feature); }\n.ps-node.feat .nh i.tile { background: var(--ps-node-feature); }\n.ps-node.emb { border-left-color: var(--ps-node-embedding); }\n.ps-node.emb .nh i.tile { background: var(--ps-node-embedding); }\n.ps-node.target { border-left-color: var(--ps-node-target); }\n.ps-node.target .nh i.tile { background: var(--ps-node-target); }\n.ps-node.algo { border-left-color: var(--ps-node-algorithm); }\n.ps-node.algo .nh i.tile { background: var(--ps-node-algorithm); }\n.ps-node.output { border-left-color: var(--mj-status-success); }\n.ps-node.output .nh i.tile { background: var(--mj-status-success); }\n.ps-node.selected {\n  border-color: var(--mj-brand-primary);\n  box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.ps-node .port {\n  position: absolute; width: 11px; height: 11px; border-radius: 50%;\n  background: var(--mj-bg-surface); border: 2px solid var(--mj-brand-primary);\n  top: 50%; transform: translateY(-50%);\n}\n.ps-node .port.in { left: -6px; }\n.ps-node .port.out { right: -6px; }\nsvg.ps-edges { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }\nsvg.ps-edges path { stroke: color-mix(in srgb, var(--mj-brand-primary) 45%, transparent); stroke-width: 2; fill: none; }\n\n/* palette chips */\n.ps-pchip {\n  display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 8px;\n  border: 1px dashed var(--mj-border-strong); background: var(--mj-bg-surface);\n  font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); cursor: grab;\n}\n.ps-pchip i { font-size: 12px; color: var(--mj-text-inverse); width: 20px; height: 20px; border-radius: 5px; display: grid; place-items: center; }\n.ps-pchip.s i { background: var(--ps-node-source); }\n.ps-pchip.f i { background: var(--ps-node-feature); }\n.ps-pchip.e i { background: var(--ps-node-embedding); }\n.ps-pchip.t i { background: var(--ps-node-target); }\n.ps-pchip.a i { background: var(--ps-node-algorithm); }\n\n/* segmented control */\n.ps-seg { display: inline-flex; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.ps-seg button {\n  border: none; background: var(--mj-bg-surface); color: var(--mj-text-secondary);\n  padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer;\n  border-right: 1px solid var(--mj-border-default);\n}\n.ps-seg button:last-child { border-right: none; }\n.ps-seg button.on { background: var(--mj-brand-primary); color: var(--mj-text-inverse); }\n\n/* field control */\n.ps-field { margin-bottom: 14px; }\n.ps-field > label {\n  display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;\n  color: var(--mj-text-muted); font-weight: 700; margin-bottom: 6px;\n}\n.ps-input {\n  width: 100%; padding: 8px 10px; border: 1px solid var(--mj-border-default);\n  border-radius: 6px; font-size: 13px; background: var(--mj-bg-surface); color: var(--mj-text-primary);\n  box-sizing: border-box;\n}\n.ps-input:focus { outline: none; border-color: var(--mj-brand-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); }\n\n/* loading container */\n.ps-loading { display: flex; align-items: center; justify-content: center; padding: 60px 0; }\n\n/* ---- empty / prompt states ---- */\n.ps-empty {\n  display: flex; flex-direction: column; align-items: center; justify-content: center;\n  text-align: center; gap: 10px; padding: 56px 24px; color: var(--mj-text-muted);\n}\n.ps-empty .ps-empty-ico {\n  width: 60px; height: 60px; border-radius: 16px; display: grid; place-items: center;\n  background: var(--mj-bg-surface-sunken); color: var(--mj-text-disabled); font-size: 24px;\n}\n.ps-empty h3 { margin: 4px 0 0; font-size: 16px; font-weight: 650; color: var(--mj-text-secondary); }\n.ps-empty p { margin: 0; max-width: 420px; font-size: 13px; line-height: 1.5; }\n\n/* ---- confirm modal ---- */\n.ps-modal-backdrop {\n  position: fixed; inset: 0; z-index: 1000;\n  background: var(--mj-bg-overlay);\n  display: flex; align-items: center; justify-content: center; padding: 24px;\n}\n.ps-modal {\n  width: 100%; max-width: 480px; background: var(--mj-bg-surface);\n  border: 1px solid var(--mj-border-default); border-radius: 14px;\n  box-shadow: var(--mj-shadow-lg, var(--mj-shadow-sm)); overflow: hidden;\n}\n.ps-modal-head {\n  display: flex; align-items: center; gap: 12px; padding: 18px 20px;\n  border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-modal-head .ico {\n  width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;\n  font-size: 16px; flex: 0 0 auto;\n  background: var(--mj-status-info-bg); color: var(--mj-status-info-text);\n}\n.ps-modal-head.warn .ico { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-modal-head.danger .ico { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-modal-head h3 { margin: 0; font-size: 15.5px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-modal-body { padding: 18px 20px; font-size: 13.5px; line-height: 1.55; color: var(--mj-text-secondary); }\n.ps-modal-body .ps-field { margin-top: 14px; margin-bottom: 0; }\n.ps-modal-foot {\n  display: flex; align-items: center; gap: 10px; padding: 14px 20px;\n  border-top: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card);\n}\n.ps-modal-foot .ps-spacer { flex: 1; }\n", ".ps-experiments { display: flex; flex-direction: column; gap: 16px; }\n\n.ps-experiments .sess-head { display: flex; align-items: center; gap: 12px; }\n.ps-experiments .sess-head h2 { font-size: 18px; color: var(--mj-text-primary); display: flex; align-items: center; gap: 10px; }\n\n/* leaderboard strip */\n.ps-experiments .lead-strip { display: flex; gap: 10px; align-items: center; overflow-x: auto; }\n.ps-experiments .lead-lbl { padding-right: 14px; border-right: 1px solid var(--mj-border-default); flex: 0 0 auto; }\n.ps-experiments .lead-lbl .t { display: flex; align-items: center; gap: 7px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-experiments .lp {\n  display: flex; align-items: center; gap: 9px; flex: 0 0 auto; padding: 8px 12px;\n  border: 1px solid var(--mj-border-default); border-radius: 9px; background: var(--mj-bg-surface);\n}\n.ps-experiments .lp.best { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); }\n.ps-experiments .lp.pruned { opacity: .55; }\n.ps-experiments .algo-ic {\n  width: 26px; height: 26px; border-radius: 7px; display: grid; place-items: center;\n  color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-experiments .lp .nm { font-size: 12.5px; font-weight: 600; color: var(--mj-text-primary); }\n.ps-experiments .lp .auc { font-weight: 740; font-variant-numeric: tabular-nums; color: var(--mj-text-primary); }\n.ps-experiments .lp .auc.win { color: var(--mj-status-success-text); }\n\n/* budget rail */\n.ps-experiments .budget-rail { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }\n@media (max-width: 880px) { .ps-experiments .budget-rail { grid-template-columns: 1fr; } }\n.ps-experiments .bud { display: flex; align-items: center; gap: 13px; }\n.ps-experiments .b-val { font-size: 15px; color: var(--mj-text-primary); margin-top: 2px; }\n\n/* kanban */\n.ps-experiments .kanban { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; align-items: start; }\n@media (max-width: 980px) { .ps-experiments .kanban { grid-template-columns: 1fr; } }\n.ps-experiments .kcol { background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 10px; overflow: hidden; }\n.ps-experiments .kcol-head {\n  display: flex; align-items: center; gap: 9px; padding: 12px 14px; border-bottom: 1px solid var(--mj-border-subtle);\n  font-weight: 650; color: var(--mj-text-primary);\n}\n.ps-experiments .kcol-head h3 { font-size: 13.5px; margin: 0; flex: 1; }\n.ps-experiments .kcol.run .kcol-head { border-top: 3px solid var(--mj-brand-primary); }\n.ps-experiments .kcol.done .kcol-head { border-top: 3px solid var(--mj-status-success); }\n.ps-experiments .kcol.prune .kcol-head { border-top: 3px solid var(--mj-text-disabled); }\n.ps-experiments .kcol.run .kcol-head i { color: var(--mj-brand-primary); }\n.ps-experiments .kcol.done .kcol-head i { color: var(--mj-status-success); }\n.ps-experiments .kcol.prune .kcol-head i { color: var(--mj-text-muted); }\n.ps-experiments .cnt {\n  background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n  border-radius: 999px; padding: 1px 9px; font-size: 12px; font-weight: 700;\n}\n.ps-experiments .kbody { padding: 11px; display: flex; flex-direction: column; gap: 11px; }\n\n.ps-experiments .icard {\n  border: 1px solid var(--mj-border-default); border-radius: 9px; padding: 11px;\n  background: var(--mj-bg-surface-card); display: flex; flex-direction: column; gap: 9px;\n}\n.ps-experiments .icard.running { border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-border-default)); }\n.ps-experiments .icard.best { border-left: 3px solid var(--mj-status-warning); }\n.ps-experiments .icard.pruned { opacity: .78; }\n.ps-experiments .ic-top { display: flex; align-items: center; gap: 9px; }\n.ps-experiments .ic-top .algo-ic { width: 30px; height: 30px; }\n.ps-experiments .ic-top .nm { font-weight: 600; color: var(--mj-text-primary); font-size: 13px; }\n.ps-experiments .feat-chips { display: flex; gap: 6px; flex-wrap: wrap; }\n.ps-experiments .ic-prog .meta { display: flex; justify-content: space-between; margin-top: 5px; }\n.ps-experiments .ic-score { display: flex; align-items: baseline; gap: 8px; }\n.ps-experiments .ic-score .v { font-size: 21px; font-weight: 720; color: var(--mj-text-primary); font-variant-numeric: tabular-nums; }\n.ps-experiments .ic-score .v.green { color: var(--mj-status-success-text); }\n.ps-experiments .rationale {\n  display: flex; gap: 8px; padding-top: 8px; border-top: 1px solid var(--mj-border-subtle); color: var(--mj-text-secondary);\n}\n.ps-experiments .rationale i { color: var(--mj-brand-primary); margin-top: 2px; }\n"], encapsulation: 2 });
}
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassMetadata(PSExperimentsComponent, [{
        type: Component,
        args: [{ standalone: true, selector: 'ps-experiments', imports: [CommonModule, MJButtonDirective, PSConfirmModalComponent], encapsulation: ViewEncapsulation.None, template: `
    <div class="ps-panel ps-experiments" data-testid="ps-experiments-panel">
      @if (!session) {
        <div class="ps-empty" data-testid="ps-experiments-empty">
          <span class="ps-empty-ico"><i class="fa-solid fa-flask"></i></span>
          <h3>No experiment sessions yet</h3>
          <p>Launch an experiment to watch the Model Dev Agent search algorithms and feature sets in waves. Running and completed iterations will appear here with a live leaderboard.</p>
        </div>
      } @else {
        <!-- session header strip -->
        <div class="sess-head">
          <div>
            <div class="ps-small ps-muted">Experiment session</div>
            <h2>{{ session.Name }} <span class="ps-badge" [class]="sessionBadgeClass"><span class="ps-dot" [style.background]="sessionDotColor"></span> {{ session.Status }}</span></h2>
          </div>
          <span class="ps-spacer"></span>
          <span class="ps-small ps-muted">{{ iterationCountLabel }}</span>
          @if (canPause) {
            <button mjButton variant="secondary" size="sm" data-testid="ps-experiments-pause" (click)="requestControl('pause')"><i class="fa-solid fa-pause"></i> Pause</button>
          }
          @if (canResume) {
            <button mjButton variant="secondary" size="sm" data-testid="ps-experiments-resume" (click)="requestControl('resume')"><i class="fa-solid fa-play"></i> Resume</button>
          }
          @if (canCancel) {
            <button mjButton variant="danger" size="sm" data-testid="ps-experiments-cancel" (click)="requestControl('cancel')"><i class="fa-solid fa-stop"></i> Cancel</button>
          }
        </div>

        <!-- Leaderboard strip -->
        <div class="ps-card" data-testid="ps-experiments-leaderboard">
          <div class="ps-card-body lead-strip">
            <div class="lead-lbl">
              <div class="t"><i class="fa-solid fa-trophy" style="color:var(--mj-status-warning)"></i> Leaderboard</div>
              <div class="ps-small ps-muted">{{ leaderboard.length }} scored · by metric</div>
            </div>
            @if (leaderboard.length === 0) {
              <span class="ps-small ps-muted">No scored iterations yet.</span>
            }
            @for (lp of leaderboard; track lp.rank) {
              <div class="lp" [class.best]="lp.best" [class.pruned]="lp.pruned">
                <span class="ps-rank" [class.gold]="lp.best">{{ lp.rank }}</span>
                <span class="algo-ic" [style.background]="lp.algorithmColor"><i [class]="lp.algorithmIcon"></i></span>
                <div><div class="nm">{{ lp.algorithm }}</div><div class="fs ps-muted ps-small">{{ lp.features }}</div></div>
                <span class="auc" [class.win]="lp.best">{{ lp.auc | number: '1.3-3' }}</span>
              </div>
            }
          </div>
        </div>

        <!-- Budget rail -->
        @if (budget.length > 0) {
          <div class="ps-card">
            <div class="ps-card-body budget-rail">
              @for (b of budget; track b.label) {
                <div class="bud">
                  <div class="ps-gauge" [style.--ps-p]="b.fillPct" [style.--ps-gauge-color]="b.color">
                    <span class="g-val">{{ b.centerText }}</span>
                  </div>
                  <div style="flex:1">
                    <div class="ps-section-title">{{ b.label }}</div>
                    <div class="b-val"><strong>{{ b.value }}</strong> <span class="ps-muted ps-small">/ {{ b.cap }}</span></div>
                    <div class="ps-bar" style="margin-top:6px;max-width:150px"><span [style.width.%]="b.fillPct" [style.background]="b.color"></span></div>
                  </div>
                </div>
              }
            </div>
          </div>
        }

        <!-- Kanban -->
        <div class="kanban" data-testid="ps-experiments-kanban">
          <div class="kcol run" data-testid="ps-kanban-col-running">
            <div class="kcol-head"><i class="fa-solid fa-spinner"></i><h3>Running</h3><span class="cnt">{{ kanban.running.length }}</span></div>
            <div class="kbody">
              @for (c of kanban.running; track c.iteration) {
                <ng-container [ngTemplateOutlet]="iterCard" [ngTemplateOutletContext]="{ c: c }"></ng-container>
              }
              @if (kanban.running.length === 0) { <span class="ps-small ps-muted">No running iterations.</span> }
            </div>
          </div>
          <div class="kcol done" data-testid="ps-kanban-col-completed">
            <div class="kcol-head"><i class="fa-solid fa-circle-check"></i><h3>Completed</h3><span class="cnt">{{ kanban.completed.length }}</span></div>
            <div class="kbody">
              @for (c of kanban.completed; track c.iteration) {
                <ng-container [ngTemplateOutlet]="iterCard" [ngTemplateOutletContext]="{ c: c }"></ng-container>
              }
              @if (kanban.completed.length === 0) { <span class="ps-small ps-muted">No completed iterations.</span> }
            </div>
          </div>
          <div class="kcol prune" data-testid="ps-kanban-col-pruned">
            <div class="kcol-head"><i class="fa-solid fa-scissors"></i><h3>Pruned</h3><span class="cnt">{{ kanban.pruned.length }}</span></div>
            <div class="kbody">
              @for (c of kanban.pruned; track c.iteration) {
                <ng-container [ngTemplateOutlet]="iterCard" [ngTemplateOutletContext]="{ c: c }"></ng-container>
              }
              @if (kanban.pruned.length === 0) { <span class="ps-small ps-muted">Nothing pruned.</span> }
            </div>
          </div>
        </div>

        <ng-template #iterCard let-c="c">
          <div class="icard" [class.best]="c.status === 'Best'" [class.running]="c.status === 'Running'" [class.pruned]="c.status === 'Pruned'">
            <div class="ic-top">
              <span class="algo-ic" [style.background]="c.algorithmColor"><i [class]="c.algorithmIcon"></i></span>
              <div><div class="nm">{{ c.algorithm }}</div><div class="it ps-muted ps-small">{{ c.iteration }}</div></div>
              <span class="ps-spacer"></span>
              <span class="ps-badge" [class]="statusBadgeClass(c.status)">{{ statusLabel(c.status) }}</span>
            </div>
            <div class="feat-chips">
              @for (f of c.features; track f) { <span class="ps-tag">{{ f }}</span> }
            </div>
            @if (c.status === 'Running') {
              <div class="ic-prog">
                <div class="ps-bar run"><span [style.width.%]="c.progress"></span></div>
                <div class="meta"><span class="ps-muted ps-small">{{ c.progressDetail }}</span></div>
              </div>
            } @else {
              <div class="ic-score">
                <span class="v" [class.green]="c.status === 'Best'">{{ c.score | number: '1.3-3' }}</span>
                <span class="lbl ps-muted ps-small">score · {{ c.scoreDelta }}</span>
              </div>
            }
            <div class="rationale"><i class="fa-solid fa-robot"></i><span class="ps-small">{{ c.rationale }}</span></div>
          </div>
        </ng-template>
      }

      @if (pendingAction) {
        <ps-confirm-modal
          [title]="pendingTitle"
          [icon]="pendingIcon"
          [confirmIcon]="pendingIcon"
          [confirmLabel]="pendingConfirmLabel"
          [variant]="pendingAction === 'cancel' ? 'danger' : 'warn'"
          [busy]="busy"
          (confirmed)="confirmControl()"
          (cancelled)="cancelControl()">
          <div [innerHTML]="pendingMessage"></div>
        </ps-confirm-modal>
      }
    </div>
  `, styles: ["/* ============================================================================\n   Predictive Studio \u2014 shared panel styles (design-token compliant)\n   Maps the mockup design system onto MemberJunction semantic --mj-* tokens.\n   Loaded by every PS panel component (styleUrls) under ViewEncapsulation.None,\n   so the class names are global within the PS dashboard subtree.\n   No hardcoded colors except the intentional categorical node/algorithm palette\n   (declared once as --ps-* custom props below) which must stay distinct across\n   light/dark to remain readable as diagram accents.\n   ============================================================================ */\n\n/* Categorical accents for DAG node types + algorithm chips. These are\n   data-visualization colors that must remain distinct regardless of theme\n   (allowed exception #3 in the design-token rules). */\n.ps-panel {\n  --ps-node-source: #6b7280;\n  --ps-node-feature: #2050c8;\n  --ps-node-embedding: #7b3ff0;\n  --ps-node-target: #1f9d57;\n  --ps-node-algorithm: #d98213;\n  /* budget-gauge categorical accents (reuse the node palette so light/dark stay distinct) */\n  --ps-gauge-cost: var(--ps-node-algorithm);\n  --ps-gauge-iterations: var(--ps-node-feature);\n}\n\n.ps-panel {\n  display: block;\n  height: 100%;\n}\n\n/* ---- generic layout helpers ---- */\n.ps-row { display: flex; gap: 16px; }\n.ps-col { display: flex; flex-direction: column; gap: 16px; }\n.ps-wrap { flex-wrap: wrap; }\n.ps-spacer { flex: 1; }\n.ps-muted { color: var(--mj-text-muted); }\n.ps-small { font-size: 12.5px; }\n.ps-mono { font-family: ui-monospace, 'SF Mono', Menlo, Consolas, monospace; font-size: 12.5px; }\n.ps-section-title {\n  font-size: 12px; text-transform: uppercase; letter-spacing: .06em;\n  color: var(--mj-text-muted); margin: 4px 0 2px; font-weight: 700;\n}\n\n/* ---- cards ---- */\n.ps-card {\n  background: var(--mj-bg-surface);\n  border: 1px solid var(--mj-border-default);\n  border-radius: 10px;\n  box-shadow: var(--mj-shadow-sm);\n  overflow: hidden;\n}\n.ps-card-head {\n  display: flex; align-items: center; gap: 10px;\n  padding: 14px 16px; border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-card-head h3 { font-size: 14.5px; margin: 0; font-weight: 650; color: var(--mj-text-primary); }\n.ps-card-body { padding: 16px; }\n\n/* ---- KPI tiles ---- */\n.ps-kpi {\n  background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default);\n  border-radius: 10px; padding: 16px 18px; box-shadow: var(--mj-shadow-sm);\n}\n.ps-kpi .label { font-size: 12px; color: var(--mj-text-muted); font-weight: 600; }\n.ps-kpi .val { font-size: 26px; font-weight: 720; letter-spacing: -.02em; margin-top: 2px; color: var(--mj-text-primary); }\n\n/* ---- badges ---- */\n.ps-badge {\n  display: inline-flex; align-items: center; gap: 5px;\n  padding: 2px 9px; border-radius: 999px; font-size: 11.5px; font-weight: 650; line-height: 1.7;\n}\n.ps-badge.gray { background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary); }\n.ps-badge.blue { background: var(--mj-status-info-bg); color: var(--mj-status-info-text); }\n.ps-badge.green { background: var(--mj-status-success-bg); color: var(--mj-status-success-text); }\n.ps-badge.amber { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-badge.red { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-dot { width: 7px; height: 7px; border-radius: 50%; display: inline-block; }\n\n/* recommendation-level chips (the ranking matrix payoff) */\n.ps-lvl {\n  display: inline-flex; align-items: center; justify-content: center;\n  min-width: 92px; padding: 4px 10px; border-radius: 7px;\n  font-weight: 650; font-size: 11.5px; color: var(--mj-text-inverse);\n}\n.ps-lvl-Primary { background: var(--mj-status-success); }\n.ps-lvl-Strong { background: var(--mj-status-info); }\n.ps-lvl-Viable { background: var(--mj-status-warning); }\n.ps-lvl-Weak { background: var(--mj-text-disabled); }\n.ps-lvl-NotRecommended { background: var(--mj-bg-surface-sunken); color: var(--mj-text-muted); }\n\n/* ---- tags ---- */\n.ps-tag {\n  display: inline-block; padding: 2px 8px; border-radius: 6px;\n  background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n  font-size: 11.5px; font-weight: 600;\n}\n.ps-tag.muted { opacity: .6; }\n.ps-divider { height: 1px; background: var(--mj-border-subtle); margin: 8px 0; }\n\n/* ---- tables ---- */\n.ps-table { width: 100%; border-collapse: collapse; font-size: 13px; }\n.ps-table th {\n  text-align: left; font-size: 11.5px; text-transform: uppercase; letter-spacing: .04em;\n  color: var(--mj-text-muted); font-weight: 700; padding: 9px 12px;\n  border-bottom: 1px solid var(--mj-border-default);\n}\n.ps-table td { padding: 11px 12px; border-bottom: 1px solid var(--mj-border-subtle); color: var(--mj-text-primary); }\n.ps-table tr:hover td { background: var(--mj-bg-surface-hover); }\n.ps-table .num { text-align: right; font-variant-numeric: tabular-nums; }\n\n.ps-rank {\n  width: 22px; height: 22px; border-radius: 6px; background: var(--mj-bg-surface-sunken);\n  display: inline-grid; place-items: center; font-weight: 700; font-size: 11.5px; color: var(--mj-text-secondary);\n}\n.ps-rank.gold { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n\n/* ---- progress bars ---- */\n.ps-bar { height: 8px; border-radius: 999px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-bar > span { display: block; height: 100%; border-radius: 999px; background: var(--mj-brand-primary); }\n.ps-bar.warn > span { background: var(--mj-status-warning); }\n.ps-bar.run > span { background: var(--mj-brand-primary); }\n\n.ps-fbar { display: grid; grid-template-columns: 150px 1fr 48px; align-items: center; gap: 10px; padding: 5px 0; }\n.ps-fbar .track { height: 14px; border-radius: 5px; background: var(--mj-bg-surface-sunken); overflow: hidden; }\n.ps-fbar .track > span { display: block; height: 100%; background: var(--mj-brand-primary); }\n.ps-fbar .track > span.warn { background: var(--mj-status-warning); }\n.ps-fbar .name { color: var(--mj-text-secondary); }\n\n/* gauge */\n.ps-gauge {\n  position: relative; width: 64px; height: 64px; border-radius: 50%; flex: 0 0 auto;\n  background: conic-gradient(var(--ps-gauge-color, var(--mj-brand-primary)) calc(var(--ps-p, 40) * 1%), var(--mj-bg-surface-sunken) 0);\n  display: grid; place-items: center;\n}\n.ps-gauge::after { content: ''; position: absolute; inset: 9px; background: var(--mj-bg-surface); border-radius: 50%; }\n.ps-gauge .g-val { position: relative; font-weight: 720; font-size: 14px; color: var(--mj-text-primary); }\n\n/* warning / info callouts */\n.ps-callout { display: flex; gap: 11px; padding: 12px 14px; border-radius: 10px; border: 1px solid; }\n.ps-callout.warn { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); color: var(--mj-status-warning-text); }\n.ps-callout.info { background: var(--mj-status-info-bg); border-color: var(--mj-status-info-border); color: var(--mj-status-info-text); }\n.ps-callout.success { background: var(--mj-status-success-bg); border-color: var(--mj-status-success-border); color: var(--mj-status-success-text); }\n.ps-callout i { font-size: 16px; margin-top: 1px; }\n\n/* lifecycle stepper */\n.ps-stepper { display: flex; align-items: center; gap: 6px; flex-wrap: wrap; }\n.ps-step { display: flex; align-items: center; gap: 6px; font-size: 12px; font-weight: 600; color: var(--mj-text-muted); }\n.ps-step .pip {\n  width: 22px; height: 22px; border-radius: 50%; border: 2px solid var(--mj-border-strong);\n  display: grid; place-items: center; font-size: 11px;\n}\n.ps-step.done { color: var(--mj-status-success-text); }\n.ps-step.done .pip { background: var(--mj-status-success); border-color: var(--mj-status-success); color: var(--mj-text-inverse); }\n.ps-step.curr { color: var(--mj-brand-primary); }\n.ps-step.curr .pip { border-color: var(--mj-brand-primary); color: var(--mj-brand-primary); }\n.ps-step .ln { width: 26px; height: 2px; background: var(--mj-border-strong); }\n\n/* ---- DAG flow canvas ---- */\n.ps-flow {\n  position: relative;\n  background:\n    linear-gradient(var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n    linear-gradient(90deg, var(--mj-border-subtle) 1px, transparent 1px) 0 0 / 22px 22px,\n    var(--mj-bg-surface-card);\n  border: 1px solid var(--mj-border-default); border-radius: 10px;\n  min-height: 620px; overflow: hidden;\n}\n.ps-node {\n  position: absolute; width: 190px; background: var(--mj-bg-surface);\n  border: 1px solid var(--mj-border-strong); border-left-width: 3px; border-radius: 10px;\n  box-shadow: var(--mj-shadow-sm); cursor: pointer;\n}\n.ps-node .nh {\n  display: flex; align-items: center; gap: 8px; padding: 9px 11px;\n  border-bottom: 1px solid var(--mj-border-subtle); font-weight: 650; font-size: 12.5px; color: var(--mj-text-primary);\n}\n.ps-node .nh i.tile {\n  width: 24px; height: 24px; border-radius: 6px; display: grid; place-items: center;\n  color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-node .nh .ps-tag { margin-left: auto; }\n.ps-node .nb { padding: 9px 11px; font-size: 12px; color: var(--mj-text-secondary); }\n.ps-node .nb-row { display: flex; justify-content: space-between; gap: 8px; padding: 2px 0; }\n.ps-node .nb-row .k { color: var(--mj-text-muted); }\n.ps-node.src { border-left-color: var(--ps-node-source); }\n.ps-node.src .nh i.tile { background: var(--ps-node-source); }\n.ps-node.feat { border-left-color: var(--ps-node-feature); }\n.ps-node.feat .nh i.tile { background: var(--ps-node-feature); }\n.ps-node.emb { border-left-color: var(--ps-node-embedding); }\n.ps-node.emb .nh i.tile { background: var(--ps-node-embedding); }\n.ps-node.target { border-left-color: var(--ps-node-target); }\n.ps-node.target .nh i.tile { background: var(--ps-node-target); }\n.ps-node.algo { border-left-color: var(--ps-node-algorithm); }\n.ps-node.algo .nh i.tile { background: var(--ps-node-algorithm); }\n.ps-node.output { border-left-color: var(--mj-status-success); }\n.ps-node.output .nh i.tile { background: var(--mj-status-success); }\n.ps-node.selected {\n  border-color: var(--mj-brand-primary);\n  box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 18%, transparent);\n}\n.ps-node .port {\n  position: absolute; width: 11px; height: 11px; border-radius: 50%;\n  background: var(--mj-bg-surface); border: 2px solid var(--mj-brand-primary);\n  top: 50%; transform: translateY(-50%);\n}\n.ps-node .port.in { left: -6px; }\n.ps-node .port.out { right: -6px; }\nsvg.ps-edges { position: absolute; inset: 0; width: 100%; height: 100%; pointer-events: none; }\nsvg.ps-edges path { stroke: color-mix(in srgb, var(--mj-brand-primary) 45%, transparent); stroke-width: 2; fill: none; }\n\n/* palette chips */\n.ps-pchip {\n  display: inline-flex; align-items: center; gap: 7px; padding: 6px 11px; border-radius: 8px;\n  border: 1px dashed var(--mj-border-strong); background: var(--mj-bg-surface);\n  font-size: 12.5px; font-weight: 600; color: var(--mj-text-secondary); cursor: grab;\n}\n.ps-pchip i { font-size: 12px; color: var(--mj-text-inverse); width: 20px; height: 20px; border-radius: 5px; display: grid; place-items: center; }\n.ps-pchip.s i { background: var(--ps-node-source); }\n.ps-pchip.f i { background: var(--ps-node-feature); }\n.ps-pchip.e i { background: var(--ps-node-embedding); }\n.ps-pchip.t i { background: var(--ps-node-target); }\n.ps-pchip.a i { background: var(--ps-node-algorithm); }\n\n/* segmented control */\n.ps-seg { display: inline-flex; border: 1px solid var(--mj-border-default); border-radius: 8px; overflow: hidden; }\n.ps-seg button {\n  border: none; background: var(--mj-bg-surface); color: var(--mj-text-secondary);\n  padding: 6px 12px; font-size: 12.5px; font-weight: 600; cursor: pointer;\n  border-right: 1px solid var(--mj-border-default);\n}\n.ps-seg button:last-child { border-right: none; }\n.ps-seg button.on { background: var(--mj-brand-primary); color: var(--mj-text-inverse); }\n\n/* field control */\n.ps-field { margin-bottom: 14px; }\n.ps-field > label {\n  display: block; font-size: 11px; text-transform: uppercase; letter-spacing: .04em;\n  color: var(--mj-text-muted); font-weight: 700; margin-bottom: 6px;\n}\n.ps-input {\n  width: 100%; padding: 8px 10px; border: 1px solid var(--mj-border-default);\n  border-radius: 6px; font-size: 13px; background: var(--mj-bg-surface); color: var(--mj-text-primary);\n  box-sizing: border-box;\n}\n.ps-input:focus { outline: none; border-color: var(--mj-brand-primary); box-shadow: 0 0 0 3px color-mix(in srgb, var(--mj-brand-primary) 12%, transparent); }\n\n/* loading container */\n.ps-loading { display: flex; align-items: center; justify-content: center; padding: 60px 0; }\n\n/* ---- empty / prompt states ---- */\n.ps-empty {\n  display: flex; flex-direction: column; align-items: center; justify-content: center;\n  text-align: center; gap: 10px; padding: 56px 24px; color: var(--mj-text-muted);\n}\n.ps-empty .ps-empty-ico {\n  width: 60px; height: 60px; border-radius: 16px; display: grid; place-items: center;\n  background: var(--mj-bg-surface-sunken); color: var(--mj-text-disabled); font-size: 24px;\n}\n.ps-empty h3 { margin: 4px 0 0; font-size: 16px; font-weight: 650; color: var(--mj-text-secondary); }\n.ps-empty p { margin: 0; max-width: 420px; font-size: 13px; line-height: 1.5; }\n\n/* ---- confirm modal ---- */\n.ps-modal-backdrop {\n  position: fixed; inset: 0; z-index: 1000;\n  background: var(--mj-bg-overlay);\n  display: flex; align-items: center; justify-content: center; padding: 24px;\n}\n.ps-modal {\n  width: 100%; max-width: 480px; background: var(--mj-bg-surface);\n  border: 1px solid var(--mj-border-default); border-radius: 14px;\n  box-shadow: var(--mj-shadow-lg, var(--mj-shadow-sm)); overflow: hidden;\n}\n.ps-modal-head {\n  display: flex; align-items: center; gap: 12px; padding: 18px 20px;\n  border-bottom: 1px solid var(--mj-border-subtle);\n}\n.ps-modal-head .ico {\n  width: 38px; height: 38px; border-radius: 10px; display: grid; place-items: center;\n  font-size: 16px; flex: 0 0 auto;\n  background: var(--mj-status-info-bg); color: var(--mj-status-info-text);\n}\n.ps-modal-head.warn .ico { background: var(--mj-status-warning-bg); color: var(--mj-status-warning-text); }\n.ps-modal-head.danger .ico { background: var(--mj-status-error-bg); color: var(--mj-status-error-text); }\n.ps-modal-head h3 { margin: 0; font-size: 15.5px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-modal-body { padding: 18px 20px; font-size: 13.5px; line-height: 1.55; color: var(--mj-text-secondary); }\n.ps-modal-body .ps-field { margin-top: 14px; margin-bottom: 0; }\n.ps-modal-foot {\n  display: flex; align-items: center; gap: 10px; padding: 14px 20px;\n  border-top: 1px solid var(--mj-border-subtle); background: var(--mj-bg-surface-card);\n}\n.ps-modal-foot .ps-spacer { flex: 1; }\n", ".ps-experiments { display: flex; flex-direction: column; gap: 16px; }\n\n.ps-experiments .sess-head { display: flex; align-items: center; gap: 12px; }\n.ps-experiments .sess-head h2 { font-size: 18px; color: var(--mj-text-primary); display: flex; align-items: center; gap: 10px; }\n\n/* leaderboard strip */\n.ps-experiments .lead-strip { display: flex; gap: 10px; align-items: center; overflow-x: auto; }\n.ps-experiments .lead-lbl { padding-right: 14px; border-right: 1px solid var(--mj-border-default); flex: 0 0 auto; }\n.ps-experiments .lead-lbl .t { display: flex; align-items: center; gap: 7px; font-weight: 650; color: var(--mj-text-primary); }\n.ps-experiments .lp {\n  display: flex; align-items: center; gap: 9px; flex: 0 0 auto; padding: 8px 12px;\n  border: 1px solid var(--mj-border-default); border-radius: 9px; background: var(--mj-bg-surface);\n}\n.ps-experiments .lp.best { background: var(--mj-status-warning-bg); border-color: var(--mj-status-warning-border); }\n.ps-experiments .lp.pruned { opacity: .55; }\n.ps-experiments .algo-ic {\n  width: 26px; height: 26px; border-radius: 7px; display: grid; place-items: center;\n  color: var(--mj-text-inverse); font-size: 12px; flex: 0 0 auto;\n}\n.ps-experiments .lp .nm { font-size: 12.5px; font-weight: 600; color: var(--mj-text-primary); }\n.ps-experiments .lp .auc { font-weight: 740; font-variant-numeric: tabular-nums; color: var(--mj-text-primary); }\n.ps-experiments .lp .auc.win { color: var(--mj-status-success-text); }\n\n/* budget rail */\n.ps-experiments .budget-rail { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; }\n@media (max-width: 880px) { .ps-experiments .budget-rail { grid-template-columns: 1fr; } }\n.ps-experiments .bud { display: flex; align-items: center; gap: 13px; }\n.ps-experiments .b-val { font-size: 15px; color: var(--mj-text-primary); margin-top: 2px; }\n\n/* kanban */\n.ps-experiments .kanban { display: grid; grid-template-columns: repeat(3, 1fr); gap: 16px; align-items: start; }\n@media (max-width: 980px) { .ps-experiments .kanban { grid-template-columns: 1fr; } }\n.ps-experiments .kcol { background: var(--mj-bg-surface); border: 1px solid var(--mj-border-default); border-radius: 10px; overflow: hidden; }\n.ps-experiments .kcol-head {\n  display: flex; align-items: center; gap: 9px; padding: 12px 14px; border-bottom: 1px solid var(--mj-border-subtle);\n  font-weight: 650; color: var(--mj-text-primary);\n}\n.ps-experiments .kcol-head h3 { font-size: 13.5px; margin: 0; flex: 1; }\n.ps-experiments .kcol.run .kcol-head { border-top: 3px solid var(--mj-brand-primary); }\n.ps-experiments .kcol.done .kcol-head { border-top: 3px solid var(--mj-status-success); }\n.ps-experiments .kcol.prune .kcol-head { border-top: 3px solid var(--mj-text-disabled); }\n.ps-experiments .kcol.run .kcol-head i { color: var(--mj-brand-primary); }\n.ps-experiments .kcol.done .kcol-head i { color: var(--mj-status-success); }\n.ps-experiments .kcol.prune .kcol-head i { color: var(--mj-text-muted); }\n.ps-experiments .cnt {\n  background: var(--mj-bg-surface-sunken); color: var(--mj-text-secondary);\n  border-radius: 999px; padding: 1px 9px; font-size: 12px; font-weight: 700;\n}\n.ps-experiments .kbody { padding: 11px; display: flex; flex-direction: column; gap: 11px; }\n\n.ps-experiments .icard {\n  border: 1px solid var(--mj-border-default); border-radius: 9px; padding: 11px;\n  background: var(--mj-bg-surface-card); display: flex; flex-direction: column; gap: 9px;\n}\n.ps-experiments .icard.running { border-color: color-mix(in srgb, var(--mj-brand-primary) 40%, var(--mj-border-default)); }\n.ps-experiments .icard.best { border-left: 3px solid var(--mj-status-warning); }\n.ps-experiments .icard.pruned { opacity: .78; }\n.ps-experiments .ic-top { display: flex; align-items: center; gap: 9px; }\n.ps-experiments .ic-top .algo-ic { width: 30px; height: 30px; }\n.ps-experiments .ic-top .nm { font-weight: 600; color: var(--mj-text-primary); font-size: 13px; }\n.ps-experiments .feat-chips { display: flex; gap: 6px; flex-wrap: wrap; }\n.ps-experiments .ic-prog .meta { display: flex; justify-content: space-between; margin-top: 5px; }\n.ps-experiments .ic-score { display: flex; align-items: baseline; gap: 8px; }\n.ps-experiments .ic-score .v { font-size: 21px; font-weight: 720; color: var(--mj-text-primary); font-variant-numeric: tabular-nums; }\n.ps-experiments .ic-score .v.green { color: var(--mj-status-success-text); }\n.ps-experiments .rationale {\n  display: flex; gap: 8px; padding-top: 8px; border-top: 1px solid var(--mj-border-subtle); color: var(--mj-text-secondary);\n}\n.ps-experiments .rationale i { color: var(--mj-brand-primary); margin-top: 2px; }\n"] }]
    }], null, { engine: [{
            type: Input
        }], provider: [{
            type: Input
        }], currentUser: [{
            type: Input
        }] }); })();
(() => { (typeof ngDevMode === "undefined" || ngDevMode) && i0.ɵsetClassDebugInfo(PSExperimentsComponent, { className: "PSExperimentsComponent", filePath: "src/PredictiveStudio/components/ps-experiments.component.ts", lineNumber: 195 }); })();
/** Minimal HTML-escape for interpolating session names into the modal's innerHTML message. */
function escapeHtml(value) {
    return value
        .replace(/&/g, '&amp;')
        .replace(/</g, '&lt;')
        .replace(/>/g, '&gt;')
        .replace(/"/g, '&quot;');
}
//# sourceMappingURL=ps-experiments.component.js.map