===== DIFF /home/yeff/public_html/devon/panel/assets/css/panel.css <-> /home/yeff/public_html/devon/panel/_restore_layout/20260325_190044/panel.css.current ===== --- /home/yeff/public_html/devon/panel/_restore_layout/20260325_190044/panel.css.current 2026-03-23 13:31:11.312648930 -0300 +++ /home/yeff/public_html/devon/panel/assets/css/panel.css 2026-04-09 08:12:21.523371410 -0300 @@ -1,205 +1,162 @@ -:root{ - --bg:#071427; - --bg2:#0b1d39; - --panel:#0d2142; - --panel2:#0f2850; - --line:rgba(133,161,210,.18); - --text:#eef4ff; - --muted:#9db0d2; - --blue:#5aa2ff; - --green:#18c58f; - --red:#ff646e; - --amber:#ffbf53; - --violet:#8a7dff; - --radius:22px; - --shadow:0 18px 42px rgba(0,0,0,.26); -} - -*{box-sizing:border-box} -html,body{margin:0;padding:0;background:linear-gradient(180deg,var(--bg),#08101f);color:var(--text);font:14px/1.45 Inter,system-ui,-apple-system,Segoe UI,Roboto,Arial,sans-serif} -button{font:inherit} -pre{margin:0} - -.op-shell{ - min-height:100vh; - display:grid; - grid-template-columns:300px minmax(0,1fr) 420px; - gap:20px; - padding:20px; -} - -.op-sidebar,.card,.drawer-card{ - background:linear-gradient(180deg,var(--panel),var(--bg2)); - border:1px solid var(--line); - border-radius:var(--radius); - box-shadow:var(--shadow); -} - -.op-sidebar{padding:18px;position:sticky;top:20px;height:calc(100vh - 40px);overflow:auto} -.brand{display:flex;align-items:center;gap:12px;padding:6px 4px 16px} -.brand-dot{width:14px;height:14px;border-radius:999px;background:#ffb000;box-shadow:0 0 0 4px rgba(255,176,0,.12)} -.brand strong{display:block;font-size:32px;line-height:1} -.brand span{display:block;color:var(--muted);margin-top:4px} - -.side-block + .side-block{margin-top:20px} -.side-label{color:#9db0d2;text-transform:uppercase;font-size:12px;letter-spacing:.12em;margin-bottom:12px} -.pill-row{display:flex;flex-wrap:wrap;gap:8px} -.pill,.badge{ - display:inline-flex;align-items:center;justify-content:center; - min-height:34px;padding:0 12px;border-radius:999px; - border:1px solid var(--line);background:rgba(255,255,255,.04);color:var(--text);font-weight:700 -} -.pill.pass,.badge.pass{border-color:rgba(24,197,143,.35);color:#8ff2cf;background:rgba(24,197,143,.12)} -.pill.fail,.badge.fail{border-color:rgba(255,100,110,.35);color:#ffb2b8;background:rgba(255,100,110,.12)} -.pill.missing,.badge.missing{border-color:rgba(255,191,83,.35);color:#ffd99a;background:rgba(255,191,83,.12)} -.pill.running,.badge.running{border-color:rgba(90,162,255,.35);color:#b9d6ff;background:rgba(90,162,255,.12)} -.pill.pending,.badge.pending{border-color:rgba(138,125,255,.35);color:#cec8ff;background:rgba(138,125,255,.12)} -.badge-blue{border-color:rgba(90,162,255,.35);color:#b9d6ff;background:rgba(90,162,255,.12)} -.badge-violet{border-color:rgba(138,125,255,.35);color:#cec8ff;background:rgba(138,125,255,.12)} - -.stage-nav{display:flex;flex-direction:column;gap:10px} -.stage-btn{ - width:100%;text-align:left;border:1px solid var(--line);background:rgba(255,255,255,.02); - color:var(--text);border-radius:18px;padding:14px 14px;cursor:pointer; - display:flex;align-items:center;justify-content:space-between;gap:10px -} -.stage-btn:hover,.stage-btn.active{background:rgba(90,162,255,.12);border-color:rgba(90,162,255,.3)} -.stage-btn small{display:block;color:var(--muted);font-size:12px} - -.op-main{min-width:0} -.hero{ - display:flex;align-items:flex-start;justify-content:space-between;gap:16px; - padding:14px 4px 20px -} -.eyebrow{font-size:12px;letter-spacing:.14em;color:#8eb5ff;text-transform:uppercase;margin-bottom:8px} -.hero h1{margin:0 0 8px;font-size:42px;line-height:1.05} -.hero p{margin:0;color:var(--muted);font-size:16px} -.hero-actions{display:flex;flex-wrap:wrap;gap:10px} -.btn{ - border:1px solid var(--line);border-radius:16px;padding:12px 16px;cursor:pointer; - background:rgba(255,255,255,.04);color:var(--text);font-weight:700 -} -.btn-primary{background:linear-gradient(180deg,#4f93ff,#3272df);border-color:transparent} -.btn-secondary:hover{background:rgba(255,255,255,.08)} - -.layer-grid, -.top-grid{ - display:grid; - grid-template-columns:repeat(2,minmax(0,1fr)); - gap:18px; - margin-bottom:18px; -} -.top-grid{grid-template-columns:repeat(3,minmax(0,1fr))} -.runtime-grid{ - display:grid; - grid-template-columns:repeat(3,minmax(0,1fr)); - gap:18px; - margin-bottom:18px; -} -.workspace-grid{ - display:grid; - grid-template-columns:minmax(0,1.08fr) minmax(0,1fr); - gap:18px; -} -.card{padding:18px;min-width:0} -.card-top{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:14px} -.card-title{font-size:12px;letter-spacing:.12em;color:#9db0d2;text-transform:uppercase} -.stat-card h2{margin:0 0 8px;font-size:30px} -.muted{color:var(--muted)} - -.layer-list,.step-list{list-style:none;padding:0;margin:0} -.layer-list li,.step-list li{ - display:flex;align-items:center;justify-content:space-between;gap:12px; - padding:10px 0;border-top:1px solid rgba(255,255,255,.06) -} -.layer-list li:first-child,.step-list li:first-child{border-top:0} - -.donut-wrap{display:flex;align-items:center;justify-content:center;min-height:168px} -.donut{width:170px;height:170px;display:grid;place-items:center;position:relative} -.donut svg{width:170px;height:170px;transform:rotate(-90deg)} -.donut-center{ - position:absolute;display:flex;flex-direction:column;align-items:center;justify-content:center; - text-align:center -} -.donut-center strong{font-size:30px;line-height:1} -.donut-center span{font-size:12px;color:var(--muted);margin-top:6px} -.step-state{font-size:11px;text-transform:uppercase;letter-spacing:.08em;color:#ffd99a} - -.mini-metric-grid{ - display:grid; - grid-template-columns:repeat(2,minmax(0,1fr)); - gap:12px; -} -.metric-box{ - border:1px solid var(--line); - border-radius:16px; - padding:14px; - background:rgba(255,255,255,.025) -} -.metric-box .metric-label{ - color:var(--muted); - text-transform:uppercase; - letter-spacing:.08em; - font-size:11px; - margin-bottom:8px -} -.metric-box .metric-value{ - font-size:22px; - font-weight:800 -} -.metric-box .metric-sub{ - font-size:12px; - color:var(--muted); - margin-top:6px -} - -.pipeline-board{display:flex;flex-direction:column;gap:10px;max-height:320px;overflow:auto;padding-right:4px} -.pipeline-item{ - border:1px solid var(--line); - border-radius:16px; - padding:14px; - background:rgba(255,255,255,.025) -} -.pipeline-item h4{margin:0 0 8px;font-size:16px} -.pipeline-item p{margin:0 0 10px;color:var(--muted)} -.pipeline-kv{display:flex;flex-wrap:wrap;gap:8px} - -.subcategory-grid{ - display:grid; - grid-template-columns:repeat(2,minmax(0,1fr)); - gap:14px; -} -.subcard{ - border:1px solid var(--line);border-radius:18px;padding:14px;background:rgba(255,255,255,.025) -} -.subcard h3{margin:0 0 10px;font-size:18px;line-height:1.2} -.sub-meta{display:flex;align-items:center;justify-content:space-between;gap:10px;margin-bottom:10px} -.sub-stats{display:flex;flex-wrap:wrap;gap:8px;margin-top:10px} - -.row-table{display:flex;flex-direction:column;gap:10px;max-height:calc(100vh - 340px);overflow:auto;padding-right:4px} -.row-item{ - border:1px solid var(--line);border-radius:16px;padding:14px;background:rgba(255,255,255,.025);cursor:pointer -} -.row-item h4{margin:0 0 8px;font-size:17px} -.row-item p{margin:0 0 10px;color:var(--muted)} -.row-kv{display:flex;flex-wrap:wrap;gap:8px} - -.op-drawer{position:sticky;top:20px;height:calc(100vh - 40px)} -.drawer-card{height:100%;padding:18px;overflow:auto} -.json-viewer{ - background:#07111f;border:1px solid var(--line);border-radius:18px;padding:16px; - color:#bfd3f6;white-space:pre-wrap;word-break:break-word;min-height:calc(100% - 44px) -} - -@media (max-width: 1480px){ - .op-shell{grid-template-columns:280px minmax(0,1fr)} - .op-drawer{grid-column:1 / -1;position:relative;top:auto;height:auto} -} -@media (max-width: 1180px){ - .layer-grid,.top-grid,.runtime-grid,.workspace-grid,.subcategory-grid{grid-template-columns:1fr} -} -@media (max-width: 1080px){ - .op-shell{grid-template-columns:1fr} - .op-sidebar,.op-drawer{position:relative;top:auto;height:auto} - .hero{flex-direction:column} -} +/* Devon Operator Panel — panel.css v20260409 */ +:root { + --bg0:#0c1117;--bg1:#111820;--bg2:#141e2e;--bg3:#0e1520; + --border:rgba(255,255,255,0.07);--border2:rgba(255,255,255,0.04); + --text0:#dde3ef;--text1:#9aafc2;--text2:#5a6e82;--text3:#334455; + --blue:#2563eb;--blue-lt:#60a5fa; + --violet:#7c3aed;--violet-lt:#a78bfa; + --green:#22c55e;--amber:#f59e0b;--red:#f87171; + --mono:'IBM Plex Mono',monospace;--sans:'IBM Plex Sans',sans-serif; +} +*{box-sizing:border-box;margin:0;padding:0} +html,body{height:100%;overflow:hidden;background:var(--bg0);font-family:var(--sans);color:var(--text0);font-size:13px} + +/* SHELL */ +#dp-shell{display:flex;height:100vh;overflow:hidden} + +/* LEFT */ +#dp-left{width:238px;flex-shrink:0;background:var(--bg1);border-right:1px solid var(--border);display:flex;flex-direction:column;overflow:hidden} +#dp-brand{padding:14px 12px;border-bottom:1px solid var(--border);display:flex;align-items:center;gap:10px;flex-shrink:0} +#dp-logo{height:22px;width:auto;object-fit:contain} +#dp-brand-name{font-size:13px;font-weight:600;color:#e8ecf5} +#dp-brand-sub{font-size:8px;color:var(--text3);letter-spacing:1px;text-transform:uppercase;margin-top:2px} +.tree-label{font-size:8px;color:var(--text3);letter-spacing:1.2px;text-transform:uppercase;padding:12px 12px 4px;font-weight:500;flex-shrink:0;font-family:var(--mono)} +#dp-tree{flex:1;overflow-y:auto;padding-bottom:8px} +#dp-tree::-webkit-scrollbar{width:3px} +#dp-tree::-webkit-scrollbar-thumb{background:var(--border);border-radius:2px} + +/* PHASE */ +.ph-row{display:flex;align-items:center;gap:6px;padding:5px 10px 5px 8px;cursor:pointer;border-left:2px solid transparent;transition:background 0.1s;user-select:none} +.ph-row:hover{background:rgba(255,255,255,0.03)} +.ph-row.ph-active{background:rgba(37,99,235,0.07);border-left-color:var(--blue)} +.ph-arrow{font-size:9px;color:var(--text3);width:12px;flex-shrink:0} +.ph-arrow.open{color:var(--text2)} +.ph-num{font-family:var(--mono);font-size:9px;color:var(--text3);width:18px;flex-shrink:0} +.ph-row.ph-active .ph-num{color:var(--blue)} +.ph-name{font-size:10px;color:var(--text2);flex:1;line-height:1.3} +.ph-row.ph-active .ph-name{color:var(--blue-lt)} +.ph-dot{width:5px;height:5px;border-radius:50%;flex-shrink:0} + +/* CATEGORY */ +.cat-row{display:flex;align-items:center;gap:6px;padding:3px 10px 3px 24px;cursor:pointer;border-left:2px solid transparent;transition:background 0.1s;margin-left:6px;user-select:none} +.cat-row:hover{background:rgba(255,255,255,0.02)} +.cat-row.cat-active{background:rgba(37,99,235,0.06);border-left-color:rgba(37,99,235,0.4)} +.cat-arrow{font-size:8px;color:var(--text3);width:10px;flex-shrink:0} +.cat-arrow.open{color:var(--text2)} +.cat-name{font-size:10px;color:#445566;flex:1;line-height:1.3} +.cat-row.cat-active .cat-name{color:#7ab4cc} +.cat-dot{width:4px;height:4px;border-radius:50%;flex-shrink:0} + +/* BUCKET */ +.bk-row{display:flex;align-items:center;gap:6px;padding:2px 10px 2px 38px;cursor:pointer;margin-left:6px;border-left:2px solid transparent;user-select:none} +.bk-row:hover{background:rgba(255,255,255,0.015)} ===== DIFF /home/yeff/public_html/devon/panel/assets/js/panel.js <-> /home/yeff/public_html/devon/panel/_restore_layout/20260325_190044/panel.js.current ===== --- /home/yeff/public_html/devon/panel/_restore_layout/20260325_190044/panel.js.current 2026-03-25 18:11:23.802640494 -0300 +++ /home/yeff/public_html/devon/panel/assets/js/panel.js 2026-04-09 08:12:45.118922299 -0300 @@ -1,250 +1,331 @@ -(function () { - const DATA_BASE = "data/"; +'use strict'; - const els = { - globalPills: document.getElementById("global-pills"), - stageNav: document.getElementById("stage-nav"), - heroTitle: document.getElementById("hero-title"), - heroSubtitle: document.getElementById("hero-subtitle"), - stageOrderBadge: document.getElementById("stage-order-badge"), - selectedStageName: document.getElementById("selected-stage-name"), - selectedStageDesc: document.getElementById("selected-stage-desc"), - selectedStageTotal: document.getElementById("selected-stage-total"), - selectedStageDonut: document.getElementById("selected-stage-donut"), - selectedRuntimeBadge: document.getElementById("selected-runtime-badge"), - selectedPipelineSteps: document.getElementById("selected-pipeline-steps"), - hostStatusBadge: document.getElementById("host-status-badge"), - dockerStatusBadge: document.getElementById("docker-status-badge"), - hostRuntimeGrid: document.getElementById("host-runtime-grid"), - dockerRuntimeGrid: document.getElementById("docker-runtime-grid"), - pipelineRuntimeCount: document.getElementById("pipeline-runtime-count"), - pipelineRuntimeBoard: document.getElementById("pipeline-runtime-board"), - subcatCount: document.getElementById("subcat-count"), - subcategoryGrid: document.getElementById("subcategory-grid"), - rowCount: document.getElementById("row-count"), - rowTable: document.getElementById("row-table"), - drawerLabel: document.getElementById("drawer-label"), - jsonViewer: document.getElementById("json-viewer"), - btnOpenManifest: document.getElementById("btn-open-manifest"), - btnOpenContract: document.getElementById("btn-open-contract"), - btnOpenHost: document.getElementById("btn-open-host"), - btnOpenDocker: document.getElementById("btn-open-docker"), - btnOpenRuntime: document.getElementById("btn-open-runtime"), - dataViewerModal: document.getElementById("data-viewer-modal"), - btnCloseViewerModal: document.getElementById("btn-close-viewer-modal") - }; - - const state = { - manifest: null, - dataContract: null, - contentIndex: null, - matrix: null, - pipelines: null, - hostRuntime: null, - dockerRuntime: null, - runtimeStatus: null, - selectedStage: null - }; - - function openDataViewerModal() { - if (!els.dataViewerModal) return; - if (typeof els.dataViewerModal.showModal === "function") { - if (!els.dataViewerModal.open) els.dataViewerModal.showModal(); - return; - } - els.dataViewerModal.setAttribute("open", "open"); - } - - function closeDataViewerModal() { - if (!els.dataViewerModal) return; - if (typeof els.dataViewerModal.close === "function" && els.dataViewerModal.open) { - els.dataViewerModal.close(); - return; - } - els.dataViewerModal.removeAttribute("open"); - } - - function safeUpper(v) { - return String(v || "MISSING").toUpperCase(); - } - - function getBadgeClass(status) { - const s = safeUpper(status); - if (s === "PASS") return "pass"; - if (s === "FAIL") return "fail"; - if (s === "RUNNING") return "running"; - if (s === "PENDING") return "pending"; - return "missing"; - } - const FILE_ALIASES = { - "host_runtime.json": ["panel_host_runtime.json"], - "docker_runtime.json": ["panel_docker_runtime.json"], - "runtime_status.json": ["panel_pipeline_runtime.json", "panel_runtime_status.json"] - }; - - function buildJsonCandidates(file) { - const aliases = FILE_ALIASES[file] || []; - const raw = [file].concat(aliases); - const out = []; - raw.forEach(function (name) { - out.push(DATA_BASE + name); - out.push(name); - }); - return Array.from(new Set(out)); +const BUCKETS = [ + 'prerequisites', + 'installation', + 'configuration', + 'validation', + 'observable_evidence', + 'failure_modes_recovery', + 'completion_promotion' +]; + +const BUCKET_DESC = { + prerequisites: 'Required conditions, blockers and hard dependencies', + installation: 'File and artifact installation steps', + configuration: 'Configuration and binding steps', + validation: 'Validation gates and pass/fail criteria', + observable_evidence: 'Filesystem and runtime observable evidence', + failure_modes_recovery:'Known failure modes and recovery actions', + completion_promotion: 'Done criteria and promotion gate' +}; + +const G = { + phases: [], cats: [], data: {}, + openPhases: new Set(), openCats: new Set(), + sel: { phaseId: null, catId: null, bucket: null } +}; + +async function init() { + try { + const [hub, host, docker, runtime, progress] = await Promise.all([ + fetch('data/hub_index.json').then(r => r.json()), + fetch('data/host_runtime.json').then(r => r.json()).catch(() => null), + fetch('data/docker_runtime.json').then(r => r.json()).catch(() => null), + fetch('data/runtime_status.json').then(r => r.json()).catch(() => null), + fetch('data/project_progress.json').then(r => r.json()).catch(() => null) + ]); + G.phases = hub.phases || []; + G.cats = hub.categories || []; + G.data = { host, docker, runtime, progress }; + renderTree(); + renderDetail(); + renderFooter(); + } catch (e) { + document.getElementById('dp-tree').innerHTML = + '