spytial-core 6.4.1 → 6.5.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +1 -1
- package/dist/browser/spytial-core-complete.css +1 -1
- package/dist/browser/spytial-core-complete.css.map +1 -1
- package/dist/browser/spytial-core-complete.global.js +1 -1
- package/dist/cli/spytial-check.js +1 -1
- package/dist/components/react-component-integration.css +1 -1
- package/dist/components/react-component-integration.css.map +1 -1
- package/dist/components/react-component-integration.d.ts +8 -3
- package/dist/components/react-component-integration.global.js +79 -79
- package/dist/components/react-component-integration.global.js.map +1 -1
- package/dist/esm/index.mjs +1 -1
- package/dist/react.css +24 -7
- package/dist/react.mjs +11 -8
- package/dist/react.mjs.map +1 -1
- package/dist/types/components/ErrorMessageModal/ErrorMessageContainer.d.ts +2 -0
- package/dist/types/components/ErrorMessageModal/ErrorMessageModal.d.ts +2 -0
- package/dist/types/react-component-integration.d.ts +8 -3
- package/docs/spytial-language.json +1 -1
- package/docs/spytial-spec.schema.json +2 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -52,7 +52,7 @@ CDN:
|
|
|
52
52
|
|
|
53
53
|
That is the only script tag you need. The bundle carries its own d3 v4 and WebCola, and it will not replace a `window.d3` your page already has.
|
|
54
54
|
|
|
55
|
-
For reproducibility, pin a version (e.g. `spytial-core@6.
|
|
55
|
+
For reproducibility, pin a version (e.g. `spytial-core@6.5.0`).
|
|
56
56
|
|
|
57
57
|
---
|
|
58
58
|
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
.error-card{min-width:320px;max-width:100%}#error-message-modal{border-radius:.5rem;border:2px var(--bs-danger) solid}.constraint-item.highlight-source{background-color:#ffc10759;border-radius:4px}.constraint-item.highlight-diagram{background-color:#ffc107b3;border-radius:4px}.constraint-relationship-table{width:100%;margin-bottom:1rem}.constraint-columns{display:flex;gap:0;max-height:45vh;min-height:5rem;overflow:hidden;resize:vertical}.constraint-column{flex:1 1 0;min-width:0;min-height:0;display:flex;flex-direction:column;border:1px solid #dee2e6}.constraint-column+.constraint-column{border-left:none}.constraint-column-header{flex:0 0 auto;font-weight:600;padding:.5rem;background:#f8f9fa;border-bottom:1px solid #dee2e6}.constraint-column-body{flex:1 1 auto;min-height:0;overflow:auto}.constraint-relationship-table .constraint-item{padding:.5rem;border-bottom:1px solid #eee}.constraint-relationship-table .constraint-item:last-child{border-bottom:none}code>code,code>pre{border:1px solid var(--bs-code-color);padding:.2em .4em;border-radius:4px}.error-modal-header{gap:.5rem}.error-modal-toggle{background:transparent;border:
|
|
1
|
+
.error-card{min-width:320px;max-width:100%}#error-message-modal{border-radius:.5rem;border:2px var(--bs-danger) solid}.constraint-item.highlight-source{background-color:#ffc10759;border-radius:4px}.constraint-item.highlight-diagram{background-color:#ffc107b3;border-radius:4px}.constraint-relationship-table{width:100%;margin-bottom:1rem}.constraint-columns{display:flex;gap:0;max-height:45vh;min-height:5rem;overflow:hidden;resize:vertical}.constraint-column{flex:1 1 0;min-width:0;min-height:0;display:flex;flex-direction:column;border:1px solid #dee2e6}.constraint-column+.constraint-column{border-left:none}.constraint-column-header{flex:0 0 auto;font-weight:600;padding:.5rem;background:#f8f9fa;border-bottom:1px solid #dee2e6}.constraint-column-body{flex:1 1 auto;min-height:0;overflow:auto}.constraint-relationship-table .constraint-item{padding:.5rem;border-bottom:1px solid #eee}.constraint-relationship-table .constraint-item:last-child{border-bottom:none}code>code,code>pre{border:1px solid var(--bs-code-color);padding:.2em .4em;border-radius:4px}.error-modal-header{gap:.5rem}.error-modal-toggle{display:inline-flex;align-items:center;gap:.35rem;min-height:2rem;background:transparent;border:1px solid currentColor;border-radius:.375rem;color:var(--bs-danger);font:inherit;font-size:.875rem;font-weight:600;line-height:1.2;padding:.25rem .5rem;cursor:pointer}.error-modal-toggle:hover{background:color-mix(in srgb,var(--bs-danger) 10%,transparent)}.error-modal-toggle:focus-visible{outline:2px solid currentColor;outline-offset:2px}.error-modal-chevron{flex:none;transition:transform .15s ease}.error-modal-toggle[aria-expanded=false] .error-modal-chevron{transform:rotate(-90deg)}
|
|
2
2
|
/*# sourceMappingURL=spytial-core-complete.css.map */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../src/components/ErrorMessageModal/ErrorMessageModal.css"],"sourcesContent":[".error-card {\n min-width: 320px;\n max-width: 100%;\n}\n\n#error-message-modal {\n border-radius: 0.5rem;\n border: 2px var(--bs-danger) solid;\n}\n\n/* Source constraint highlight - lighter yellow */\n.constraint-item.highlight-source {\n background-color: rgba(255, 193, 7, 0.35);\n border-radius: 4px;\n}\n\n/* Diagram element highlight - darker yellow */\n.constraint-item.highlight-diagram {\n background-color: rgba(255, 193, 7, 0.7);\n border-radius: 4px;\n}\n\n.constraint-relationship-table {\n width: 100%;\n margin-bottom: 1rem;\n}\n\n/*\n * Two independently-scrolling columns inside one resizable region.\n * - resize: vertical gives a drag handle to tune height (larger/smaller/taller)\n * - max-height caps the default so a long conflict list can't cover the screen\n * (and is the drag ceiling); min-height is the drag floor\n * - overflow: hidden is required for `resize`; each column body scrolls itself,\n * which is what lets a hovered item stay put while its correspondence in the\n * OTHER column scrolls into view\n */\n.constraint-columns {\n display: flex;\n gap: 0;\n max-height: 45vh;\n min-height: 5rem;\n overflow: hidden;\n resize: vertical;\n}\n\n.constraint-column {\n flex: 1 1 0;\n min-width: 0;\n min-height: 0;\n display: flex;\n flex-direction: column;\n border: 1px solid #dee2e6;\n}\n\n/* Collapse the seam between the two adjacent columns */\n.constraint-column + .constraint-column {\n border-left: none;\n}\n\n.constraint-column-header {\n flex: 0 0 auto;\n font-weight: 600;\n padding: 0.5rem;\n background: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\n}\n\n/* The independent per-column scroll container (both axes: wide constraint\n * text scrolls within the column instead of widening the whole modal). */\n.constraint-column-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n}\n\n.constraint-relationship-table .constraint-item {\n padding: 0.5rem;\n border-bottom: 1px solid #eee;\n}\n\n.constraint-relationship-table .constraint-item:last-child {\n border-bottom: none;\n}\n\ncode > code, code > pre {\n border: 1px solid var(--bs-code-color);\n padding: 0.2em 0.4em;\n border-radius: 4px;\n}\n\n/* Collapse/expand header bar */\n.error-modal-header {\n gap: 0.5rem;\n}\n\n.error-modal-toggle {\n background: transparent;\n border:
|
|
1
|
+
{"version":3,"sources":["../../src/components/ErrorMessageModal/ErrorMessageModal.css"],"sourcesContent":[".error-card {\n min-width: 320px;\n max-width: 100%;\n}\n\n#error-message-modal {\n border-radius: 0.5rem;\n border: 2px var(--bs-danger) solid;\n}\n\n/* Source constraint highlight - lighter yellow */\n.constraint-item.highlight-source {\n background-color: rgba(255, 193, 7, 0.35);\n border-radius: 4px;\n}\n\n/* Diagram element highlight - darker yellow */\n.constraint-item.highlight-diagram {\n background-color: rgba(255, 193, 7, 0.7);\n border-radius: 4px;\n}\n\n.constraint-relationship-table {\n width: 100%;\n margin-bottom: 1rem;\n}\n\n/*\n * Two independently-scrolling columns inside one resizable region.\n * - resize: vertical gives a drag handle to tune height (larger/smaller/taller)\n * - max-height caps the default so a long conflict list can't cover the screen\n * (and is the drag ceiling); min-height is the drag floor\n * - overflow: hidden is required for `resize`; each column body scrolls itself,\n * which is what lets a hovered item stay put while its correspondence in the\n * OTHER column scrolls into view\n */\n.constraint-columns {\n display: flex;\n gap: 0;\n max-height: 45vh;\n min-height: 5rem;\n overflow: hidden;\n resize: vertical;\n}\n\n.constraint-column {\n flex: 1 1 0;\n min-width: 0;\n min-height: 0;\n display: flex;\n flex-direction: column;\n border: 1px solid #dee2e6;\n}\n\n/* Collapse the seam between the two adjacent columns */\n.constraint-column + .constraint-column {\n border-left: none;\n}\n\n.constraint-column-header {\n flex: 0 0 auto;\n font-weight: 600;\n padding: 0.5rem;\n background: #f8f9fa;\n border-bottom: 1px solid #dee2e6;\n}\n\n/* The independent per-column scroll container (both axes: wide constraint\n * text scrolls within the column instead of widening the whole modal). */\n.constraint-column-body {\n flex: 1 1 auto;\n min-height: 0;\n overflow: auto;\n}\n\n.constraint-relationship-table .constraint-item {\n padding: 0.5rem;\n border-bottom: 1px solid #eee;\n}\n\n.constraint-relationship-table .constraint-item:last-child {\n border-bottom: none;\n}\n\ncode > code, code > pre {\n border: 1px solid var(--bs-code-color);\n padding: 0.2em 0.4em;\n border-radius: 4px;\n}\n\n/* Collapse/expand header bar */\n.error-modal-header {\n gap: 0.5rem;\n}\n\n.error-modal-toggle {\n display: inline-flex;\n align-items: center;\n gap: 0.35rem;\n min-height: 2rem;\n background: transparent;\n border: 1px solid currentColor;\n border-radius: 0.375rem;\n color: var(--bs-danger);\n font: inherit;\n font-size: 0.875rem;\n font-weight: 600;\n line-height: 1.2;\n padding: 0.25rem 0.5rem;\n cursor: pointer;\n}\n\n.error-modal-toggle:hover {\n background: color-mix(in srgb, var(--bs-danger) 10%, transparent);\n}\n\n.error-modal-toggle:focus-visible {\n outline: 2px solid currentColor;\n outline-offset: 2px;\n}\n\n.error-modal-chevron {\n flex: none;\n transition: transform 150ms ease;\n}\n\n.error-modal-toggle[aria-expanded=\"false\"] .error-modal-chevron {\n transform: rotate(-90deg);\n}\n"],"mappings":"AAAA,CAAC,WACG,UAAW,MACX,UAAW,IACf,CAEA,CAAC,oBALD,cAMmB,MACf,OAAQ,IAAI,IAAI,aAAa,KACjC,CAGA,CAAC,eAAe,CAAC,iBACb,iBAAkB,UAZtB,cAamB,GACnB,CAGA,CANC,eAMe,CAAC,kBACb,iBAAkB,UAlBtB,cAmBmB,GACnB,CAEA,CAAC,8BACG,MAAO,KACP,cAAe,IACnB,CAWA,CAAC,mBACG,QAAS,KACT,IAAK,EACL,WAAY,KACZ,WAAY,KACZ,SAAU,OACV,OAAQ,QACZ,CAEA,CAAC,kBACG,KAAM,EAAE,EAAE,EACV,UAAW,EACX,WAAY,EACZ,QAAS,KACT,eAAgB,OAChB,OAAQ,IAAI,MAAM,OACtB,CAGA,CAVC,iBAUkB,CAAE,CAVpB,kBAWG,YAAa,IACjB,CAEA,CAAC,yBACG,KAAM,EAAE,EAAE,KACV,YAAa,IA7DjB,QA8Da,MACT,WAAY,QACZ,cAAe,IAAI,MAAM,OAC7B,CAIA,CAAC,uBACG,KAAM,EAAE,EAAE,KACV,WAAY,EACZ,SAAU,IACd,CAEA,CArDC,8BAqD8B,CAhE9B,gBAXD,QA4Ea,MACT,cAAe,IAAI,MAAM,IAC7B,CAEA,CA1DC,8BA0D8B,CArE9B,eAqE8C,YAC3C,cAAe,IACnB,CAEA,IAAK,CAAE,KAAM,IAAK,CAAE,IAChB,OAAQ,IAAI,MAAM,IAAI,iBArF1B,QAsFa,KAAM,KAtFnB,cAuFmB,GACnB,CAGA,CAAC,mBACG,IAAK,KACT,CAEA,CAAC,mBACG,QAAS,YACT,YAAa,OACb,IAAK,OACL,WAAY,KACZ,WAAY,YACZ,OAAQ,IAAI,MAAM,aArGtB,cAsGmB,QACf,MAAO,IAAI,aACX,KAAM,QACN,UAAW,QACX,YAAa,IACb,YAAa,IA3GjB,QA4Ga,OAAQ,MACjB,OAAQ,OACZ,CAEA,CAjBC,kBAiBkB,OACf,WAAY,UAAU,GAAG,IAAI,CAAE,IAAI,aAAa,GAAG,CAAE,YACzD,CAEA,CArBC,kBAqBkB,eACf,QAAS,IAAI,MAAM,aACnB,eAAgB,GACpB,CAEA,CAAC,oBACG,KAAM,KACN,WAAY,UAAU,KAAM,IAChC,CAEA,CA/BC,kBA+BkB,CAAC,qBAAuB,CAL1C,oBAMG,UAAW,OAAO,OACtB","names":[]}
|
|
@@ -1644,7 +1644,7 @@ ${i}`}removeAtom(e){this.alloyInstance=FO(this.alloyInstance,e),this.emitEvent({
|
|
|
1644
1644
|
`).trim()}function H0t(t,e={}){let{includeBuiltInTypes:n=false,includeTypeHierarchy:s=true}=e,i=t.getTypes(),r=NT(t.getRelations()),o=n?i:i.filter(c=>!c.isBuiltin),a=[];for(let c of o){if(a.push(`CREATE TABLE ${c.id} (`),a.push(" id VARCHAR PRIMARY KEY"),s&&c.types.length>1){let m=c.types[1];a.push(` -- extends ${m}`);}a.push(");"),a.push("");}for(let c of r)if(c.types.length!==0&&!(!n&&c.types.every(m=>{let v=i.find(g=>g.id===m);return v&&v.isBuiltin}))){a.push(`CREATE TABLE ${c.name} (`);for(let m=0;m<c.types.length;m++){let v=c.types[m],g=m===0?"source":m===1?"target":`arg${m}`,l=o.some(u=>u.id===v)?` REFERENCES ${v}(id)`:"";a.push(` ${g}_${v} VARCHAR${l}${m<c.types.length-1?",":""}`);}a.push(");"),a.push("");}return a.join(`
|
|
1645
1645
|
`).trim()}function q0t(t,e={}){let{includeBuiltInTypes:n=false}=e,s=t.getTypes(),i=t.getRelations(),r=n?s:s.filter(a=>!a.isBuiltin),o=[];o.push("Types:");for(let a of r){let c=a.atoms.length,m=a.isBuiltin?" (built-in)":"",v=a.types.length>1?` extends ${a.types.slice(1).join(", ")}`:"";o.push(`- ${a.id}${v} (${c} atom${c!==1?"s":""})${m}`);}o.push(""),o.push("Relations:");for(let a of i){if(!n&&a.types.every(v=>{let g=s.find(l=>l.id===v);return g&&g.isBuiltin}))continue;let c=a.tuples.length,m=a.types.length>0?a.types.join(" -> "):"untyped";o.push(`- ${a.name}: ${m} (${c} tuple${c!==1?"s":""})`);}return o.join(`
|
|
1646
1646
|
`)}Ay();o1();kf();kf();nT();wN();I0();var E1=Ys(Sw());my();I0();var z0t=E1.synthesizeSelector?E1:E1.default,{synthesizeSelector:$0t,synthesizeBinaryRelation:V0t,synthesizeSelectorWithWhy:Y0t,synthesizeBinaryRelationWithWhy:W0t}=z0t;function X0t(t){return t instanceof exports.SGraphQueryEvaluator}function Q0t(t,e=3){let n=t.map(s=>({atoms:new Set(s.atoms),datum:dd(s.dataInstance)}));return $0t(n,e)}function J0t(t,e=3){let n=t.map(s=>({pairs:new Set(s.pairs),datum:dd(s.dataInstance)}));return V0t(n,e)}function Z0t(t,e=3){let n=t.map(s=>({atoms:new Set(s.atoms),datum:dd(s.dataInstance)}));return Y0t(n,e)}function tvt(t,e=3){let n=t.map(s=>({pairs:new Set(s.pairs),datum:dd(s.dataInstance)}));return W0t(n,e)}function evt(t,e){return e.map(n=>`${n}(${t})`).join(`
|
|
1647
|
-
`)}function rvt(t,e){return `align ${e}(${t})`}function nvt(t,e){return `color ${e}(${t})`}var HN=class extends Error{constructor(e){super(e),this.name="SelectorSynthesisError";}};var qN=class{constructor(){this.currentError=null;this.errorCallbacks=[];}setError(e){this.currentError=e,this.notifyCallbacks();}clearError(){this.currentError=null,this.notifyCallbacks();}getCurrentError(){return this.currentError}onErrorChange(e){this.errorCallbacks.push(e);}hasError(){return this.currentError!==null}notifyCallbacks(){this.errorCallbacks.forEach(e=>e(this.currentError));}};qE();Ay();I0();FE();var ivt=800,ovt=600;async function Sj(t,e,n={}){let s=n.figWidth??ivt,i=n.figHeight??ovt,r=new exports.SGraphQueryEvaluator;r.initialize({sourceData:e});let o=new exports.LayoutInstance(t,r,0,true),{layout:a}=o.generateLayout(e),c,m=null;if(n.policy&&n.prevInstance&&n.currInstance){let f={priorState:n.priorPositions??{positions:[],transform:{k:1,x:0,y:0}},prevInstance:n.prevInstance,currInstance:n.currInstance,spec:t},p=n.policy.apply(f);p.effectivePriorState&&(c={priorPositions:p.effectivePriorState,lockUnconstrainedNodes:p.useReducedIterations},m={positions:p.effectivePriorState.positions.map(x=>({...x})),transform:{...p.effectivePriorState.transform}});}else n.priorPositions&&(c={priorPositions:n.priorPositions,lockUnconstrainedNodes:n.lockUnconstrainedNodes??false});let g=await new exports.WebColaTranslator().translate(a,s,i,c);new(Iy()).Layout().linkDistance(150).convergenceThreshold(.1).avoidOverlaps(true).handleDisconnected(true).nodes(g.colaNodes).groups(g.groups).links(g.colaEdges).constraints(g.colaConstraints).size([g.FIG_WIDTH,g.FIG_HEIGHT]).start(0,10,20,1);let u={positions:g.colaNodes.map(h=>({id:h.id,x:h.x??0,y:h.y??0})),transform:{k:1,x:0,y:0}},d=a.edges.map(h=>({source:h.source.id,target:h.target.id,rel:h.relationName}));return {positions:u,edges:d,constraints:a.constraints,nodes:g.colaNodes,groups:g.groups,seed:m}}Rl();var fG=Ys(hG());Rl();function _S(t,e){if(t.positions.length===0)return {positions:[],transform:{...t.transform}};let n=new Map(t.positions.map(c=>[c.id,{x:c.x,y:c.y}])),s=new Set(n.keys());for(let c of e)ii(c)?(s.add(c.left.id),s.add(c.right.id)):ni(c)?(s.add(c.top.id),s.add(c.bottom.id)):Fn(c)&&(s.add(c.node1.id),s.add(c.node2.id));let i=new OE,r=new Map,o=new Map;for(let c of s)r.set(c,new Bf),o.set(c,new Bf);for(let c of e)if(ii(c)){let m=r.get(c.left.id),v=r.get(c.right.id);i.addConstraint(new vc(m.plus(c.minDistance??0),da.Le,v,vs.required));}else if(ni(c)){let m=o.get(c.top.id),v=o.get(c.bottom.id);i.addConstraint(new vc(m.plus(c.minDistance??0),da.Le,v,vs.required));}else if(Fn(c)){let m=c.axis==="x"?r.get(c.node1.id):o.get(c.node1.id),v=c.axis==="x"?r.get(c.node2.id):o.get(c.node2.id);i.addConstraint(new vc(m,da.Eq,v,vs.required));}for(let[c,m]of n)i.addEditVariable(r.get(c),vs.weak),i.addEditVariable(o.get(c),vs.weak),i.suggestValue(r.get(c),m.x),i.suggestValue(o.get(c),m.y);return i.updateVariables(),{positions:t.positions.map(c=>({id:c.id,x:r.get(c.id).value(),y:o.get(c.id).value()})),transform:{...t.transform}}}function pG(t,e,n={}){if(t.positions.length<2)return {positions:t.positions.map(g=>({...g})),transform:{...t.transform}};let s=n.iterations??30,i=n.figWidth??800,r=n.figHeight??600,o=new Map;t.positions.forEach((g,l)=>o.set(g.id,l));let a=t.positions.map((g,l)=>({index:l,id:g.id,x:g.x,y:g.y})),c=[];for(let g=0;g<a.length;g++)for(let l=g+1;l<a.length;l++){let u=a[g].x-a[l].x,d=a[g].y-a[l].y,h=Math.hypot(u,d);h>0&&c.push({source:g,target:l,length:h});}let m=[];for(let g of e)if(ii(g)){let l=o.get(g.left.id),u=o.get(g.right.id);l!==void 0&&u!==void 0&&m.push({type:"separation",axis:"x",left:l,right:u,gap:g.minDistance??0});}else if(ni(g)){let l=o.get(g.top.id),u=o.get(g.bottom.id);l!==void 0&&u!==void 0&&m.push({type:"separation",axis:"y",left:l,right:u,gap:g.minDistance??0});}else if(Fn(g)){let l=o.get(g.node1.id),u=o.get(g.node2.id);l!==void 0&&u!==void 0&&m.push({type:"separation",axis:g.axis,left:l,right:u,gap:0,equality:true});}return new fG.Layout().convergenceThreshold(.01).avoidOverlaps(false).handleDisconnected(false).nodes(a).links(c).linkDistance(g=>g.length).constraints(m).size([i,r]).start(s,0,0,0),{positions:a.map(g=>({id:g.id,x:g.x,y:g.y})),transform:{...t.transform}}}var dG=t=>`${t.source}->${t.target}#${t.rel}`,xs=t=>{let e=new Map,n=Number.isFinite(t.transform?.k)&&t.transform.k>0?t.transform.k:1,s=Number.isFinite(t.transform?.x)?t.transform.x:0,i=Number.isFinite(t.transform?.y)?t.transform.y:0;for(let r of t.positions)e.set(r.id,{x:r.x*n+s,y:r.y*n+i});return e};function bS(t,e,n){let s=xs(t),i=xs(e),r=0;for(let[o,a]of i){if(!s.has(o)||n&&!n.has(o))continue;let c=s.get(o),m=a.x-c.x,v=a.y-c.y;r+=m*m+v*v;}return r}function yG(t,e,n,s,i){let r=xs(t),o=xs(n),a=new Set(e.map(dG)),c=0;for(let m of s){if(!a.has(dG(m))||i&&(!i.has(m.source)||!i.has(m.target)))continue;let v=r.get(m.source),g=r.get(m.target),l=o.get(m.source),u=o.get(m.target);if(!v||!g||!l||!u)continue;let d=g.x-v.x,h=g.y-v.y,f=u.x-l.x,p=u.y-l.y,x=f-d,b=p-h;c+=x*x+b*b;}return c}function TS(t,e,n){let s=xs(t),i=xs(e),r=[];for(let a of e.positions)s.has(a.id)&&(n&&!n.has(a.id)||r.push(a.id));let o=0;for(let a=0;a<r.length;a++){let c=i.get(r[a]),m=s.get(r[a]);for(let v=a+1;v<r.length;v++){let g=i.get(r[v]),l=s.get(r[v]),u=Math.hypot(g.x-c.x,g.y-c.y),d=Math.hypot(l.x-m.x,l.y-m.y),h=u-d;o+=h*h;}}return o}function gG(t){return t.length===0?null:t.reduce((e,n)=>e+n,0)/t.length}function mG(t,e,n){let s=xs(t),i=xs(e),r=[],o=[];for(let[v,g]of i){let l=s.get(v);if(!l)continue;let u=Math.hypot(g.x-l.x,g.y-l.y);n.has(v)?r.push(u):o.push(u);}let a=null;if(r.length>0&&o.length>0){let v=0;for(let g of r)for(let l of o)g>l?v+=1:g===l&&(v+=.5);a=v/(r.length*o.length);}let c=new Set,m=new Set;for(let[v]of i)s.has(v)&&(n.has(v)?c.add(v):m.add(v));return {auc:a,changedMeanDrift:gG(r),stableMeanDrift:gG(o),changedPositional:c.size>0?bS(t,e,c):null,stablePositional:m.size>0?bS(t,e,m):null,changedPairwiseDistance:c.size>=2?TS(t,e,c):null,stablePairwiseDistance:m.size>=2?TS(t,e,m):null,changedCount:r.length,stableCount:o.length}}function gxt(t,e,n){let s=t.visualWidth??t.width??100,i=e.visualWidth??e.width??100,r=s/2+i/2+n,o=Math.min(Math.max(s,i)*.1,20);return r+o}function yxt(t,e,n){let s=t.visualHeight??t.height??60,i=e.visualHeight??e.height??60,r=s/2+i/2+n,o=Math.min(Math.max(s,i)*.1,15);return r+o}function vG(t,e,n=5){let s=new Map(e.map(o=>[o.id,o])),i=0,r=0;for(let o of t)if(ii(o)){let a=s.get(o.left.id),c=s.get(o.right.id);if(!a||!c)continue;let m=gxt(a,c,o.minDistance),v=(c.x??0)-(a.x??0);i+=1,v+n>=m&&(r+=1);}else if(ni(o)){let a=s.get(o.top.id),c=s.get(o.bottom.id);if(!a||!c)continue;let m=yxt(a,c,o.minDistance),v=(c.y??0)-(a.y??0);i+=1,v+n>=m&&(r+=1);}else if(Fn(o)){let a=s.get(o.node1.id),c=s.get(o.node2.id);if(!a||!c)continue;let m=o.axis==="x"?a.x??0:a.y??0,v=o.axis==="x"?c.x??0:c.y??0;i+=1,Math.abs(m-v)<=n&&(r+=1);}return i===0?1:r/i}function xG(t,e,n=.5){let s=xs(t),i=xs(e),r=new Set;for(let[o,a]of i){let c=s.get(o);c&&Math.abs(a.x-c.x)<=n&&Math.abs(a.y-c.y)<=n&&r.add(o);}return r}function mxt(t,e,n,s){if(t.x===n.x&&t.y===n.y||t.x===s.x&&t.y===s.y||e.x===n.x&&e.y===n.y||e.x===s.x&&e.y===s.y)return false;let i=(m,v,g)=>(v.x-m.x)*(g.y-m.y)-(v.y-m.y)*(g.x-m.x),r=i(n,s,t),o=i(n,s,e),a=i(t,e,n),c=i(t,e,s);return (r>0&&o<0||r<0&&o>0)&&(a>0&&c<0||a<0&&c>0)}function _G(t,e,n){let s=xs(t),i=xs(e),r=[];for(let[c]of i)s.has(c)&&(n&&!n.has(c)||r.push(c));if(r.sort(),r.length<2)return null;let o=0,a=0;for(let c=0;c<r.length;c++){let m=s.get(r[c]),v=i.get(r[c]);for(let g=c+1;g<r.length;g++){let l=s.get(r[g]),u=i.get(r[g]),d=m.x<l.x&&v.x<u.x||m.x>l.x&&v.x>u.x||m.x===l.x&&v.x===u.x,h=m.y<l.y&&v.y<u.y||m.y>l.y&&v.y>u.y||m.y===l.y&&v.y===u.y;d&&h&&(o+=1),a+=1;}}return a===0?null:o/a}function bG(t,e,n=3,s){let i=xs(t),r=xs(e),o=[];for(let[v]of r)i.has(v)&&(s&&!s.has(v)||o.push(v));if(o.sort(),o.length<n+1)return null;let a=(v,g)=>{let l=v.get(g),u=[];for(let d of o){if(d===g)continue;let h=v.get(d);u.push({id:d,d:Math.hypot(h.x-l.x,h.y-l.y)});}return u.sort((d,h)=>d.d-h.d||d.id.localeCompare(h.id)),new Set(u.slice(0,n).map(d=>d.id))},c=0,m=0;for(let v of o){let g=a(i,v),l=a(r,v),u=new Set([...g,...l]);if(u.size===0)continue;let d=0;for(let h of g)l.has(h)&&(d+=1);c+=d/u.size,m+=1;}return m===0?null:c/m}function ES(t,e){let n=xs(t),s=[];for(let r of e){let o=n.get(r.source),a=n.get(r.target);!o||!a||s.push({a:o,b:a});}let i=0;for(let r=0;r<s.length;r++)for(let o=r+1;o<s.length;o++)mxt(s[r].a,s[r].b,s[o].a,s[o].b)&&(i+=1);return i}function TG(t,e,n,s){return Math.abs(ES(n,s)-ES(t,e))}function EG(t,e,n){let s=xs(t),i=xs(e),r=0,o=0,a=0;for(let c of n){let m=s.get(c),v=i.get(c);if(!m||!v)continue;let g=v.x-m.x,l=v.y-m.y,u=Math.hypot(g,l);u!==0&&(r+=g/u,o+=l/u,a+=1);}return a===0?null:Math.hypot(r,o)/a}function SG(t,e,n,s=5){let i=xs(t),r=xs(e),o=0,a=0;for(let c of n){let m=i.get(c),v=r.get(c);!m||!v||(o+=1,Math.hypot(v.x-m.x,v.y-m.y)<=s&&(a+=1));}return o===0?null:a/o}function OG(t,e){if(t.positions.length===0)return 0;let n=_S(t,e),s=new Map(n.positions.map(r=>[r.id,r])),i=0;for(let r of t.positions){let o=s.get(r.id);o&&(i+=Math.hypot(o.x-r.x,o.y-r.y));}return i}var y2="2026-09-18",m2={note:"`languageVersion` is the date the language last changed (YYYY-MM-DD). If it has not moved since the manifest you generated against, nothing you emit needs revisiting. `spytialCoreVersion` records which release produced this file.",deprecations:"A deprecated form keeps parsing and keeps its meaning while it is listed in `deprecations`, and each entry names its replacement and the rewrite to apply. Removal is signalled by `languageVersion` moving, not by the `spytialCoreVersion` major: a removed form leaves this manifest and becomes a parse error, so check `languageVersion` before assuming a spec you generated earlier still parses."},vxt={name:"textStyle",description:"Styling for a label. Reused by every form that renders text \u2014 an atom's own label, attribute and tag lines, edge labels, and a group label.",fields:[{name:"size",type:"enum",values:["small","normal","large"],enforcement:"value-ignored",default:"normal",description:"Font-size tier relative to the node label: `large` renders bigger than the label, `normal` smaller, `small` smaller still."},{name:"color",type:"color",description:"Any CSS color. Unset inherits the node label color, so dark mode still adapts."}]},xxt={name:"lineStyle",description:"Styling for an edge's drawn line. Reused by edgeStyle, inferredEdge, and a group's addEdge connector.",fields:[{name:"color",type:"color",description:"Any CSS color."},{name:"pattern",type:"enum",values:["solid","dashed","dotted"],enforcement:"value-ignored",description:"Dash pattern of the line."},{name:"weight",type:"number",exclusiveMinimum:0,enforcement:"value-ignored",description:"Line thickness in pixels. Must be > 0; a non-positive or non-numeric weight is dropped."},{name:"highlight",type:"color",description:"A wider, translucent underlay drawn beneath the line. Orthogonal to color and pattern."}]},_xt={name:"fillStyle",description:"An atom's interior fill. Opt-in: the default look is unfilled, with only the border and label marking the node.",fields:[{name:"color",type:"color",description:"Any CSS color."}]},bxt={name:"borderStyle",description:"An atom's outline.",fields:[{name:"color",type:"color",description:"Any CSS color."},{name:"width",type:"number",exclusiveMinimum:0,enforcement:"value-ignored",description:"Outline thickness in pixels. Must be > 0; anything else is dropped."}]},Txt={name:"iconStyle",description:"An icon drawn on an atom. Every leaf is optional, including `path`, so a supertype rule can supply the icon and a subtype rule tune only its opacity.",fields:[{name:"path",type:"icon-path",description:"A bundled icon name (`person`), an icon-pack reference (`bi:person-fill`), a URL, or a path. Resolved to a concrete URL or data URI at parse time. An iconStyle with no path draws nothing."},{name:"placement",type:"enum",values:["full","badge"],enforcement:"value-ignored",default:"full",description:"`full` \u2014 the icon occupies the box, which stays transparent unless a fillStyle.color is given. `badge` \u2014 a small marker in the top-right corner, secondary to the label."},{name:"opacity",type:"number",minimum:0,maximum:1,enforcement:"value-ignored",default:1,description:"Alpha in [0,1]. Out-of-range values are dropped rather than clamped. Fade a `full` icon to use it as a watermark behind the label."}]},AG=[vxt,xxt,_xt,bxt,Txt],$u=(t,e)=>({name:t,type:"block",block:t,description:e}),Ky=t=>[{arity:"unary",minColumns:1,maxColumns:1,meaning:t}],Ext={arity:"binary",minColumns:2,maxColumns:2,meaning:"Each tuple is one (first, last) pair, and the constraint applies to it."},Sxt={arity:"n-ary",minColumns:3,meaning:"Accepted: the pair is the tuple's first and last atom. The columns between are ignored."},v2=[Ext,Sxt],SS={name:"selector",type:"selector",arity:"unary",accepts:Ky("The set of source atoms the directive is narrowed to."),description:"Apply only to edges whose source atom is in this set. Omit to apply to every source atom."},OS={name:"filter",type:"selector",arity:"n-ary",accepts:[{arity:"n-ary",minColumns:2,meaning:"A tuple matches on its first and last atom, so a longer tuple filters the same relation ends a pair would. A unary result matches nothing \u2014 the directive is then scoped to no tuples at all."}],description:"Apply only to the (source, target, \u2026) tuples this selector returns. Use it to scope a directive to part of a relation, e.g. only the tuples whose value is True."},Oxt={id:"orientation",yamlKey:"orientation",label:"Orientation",description:"Place the two ends of each selected tuple relative to one another.",sections:["constraints"],valueShape:"mapping",supportsHold:true,fields:[{name:"selector",type:"selector",arity:"binary",accepts:v2,required:true,enforcement:"parse-error",description:"Returns (source, target) pairs. The constraint applies to each pair."},{name:"directions",type:"enum-list",values:["above","below","left","right","directlyAbove","directlyBelow","directlyLeft","directlyRight"],required:true,enforcement:"parse-error",listRules:{atMostOneOf:[["above","below"],["left","right"]],narrowsListTo:{directlyAbove:["above","directlyAbove"],directlyBelow:["below","directlyBelow"],directlyLeft:["left","directlyLeft"],directlyRight:["right","directlyRight"]}},description:"Where the TARGET sits relative to the SOURCE. `directions: [above]` on selector `parent` places each tuple's target above its source. The `directly*` variants additionally enforce axis alignment.",note:"The direction is target-relative-to-source. Getting this backwards is the most common spec bug \u2014 transpose the selector (`~parent`) rather than flipping the direction if the relation reads the other way."}],example:{selector:"parent",directions:["above"]},note:"Contradictory direction sets are rejected at parse time: `above` with `below`, `left` with `right`, and a `directly*` variant combined with anything other than its own non-direct counterpart. Values outside the listed set are NOT rejected \u2014 they parse and then match nothing."},Axt={id:"cyclic",yamlKey:"cyclic",label:"Cyclic",description:"Arrange the selected atoms around the perimeter of a circle, in the order the selector defines.",sections:["constraints"],valueShape:"mapping",supportsHold:true,fields:[{name:"selector",type:"selector",arity:"binary",accepts:v2,required:true,enforcement:"parse-error",description:'Returns (a, b) pairs meaning "b follows a around the circle".'},{name:"direction",type:"enum",values:["clockwise","counterclockwise"],default:"clockwise",enforcement:"unchecked",description:"Which way the cycle runs."}],example:{selector:"nextState",direction:"clockwise"},note:"Two cyclic constraints on the same selector with different directions is a parse error. An unrecognized direction string is not rejected at parse time."},wxt={id:"align",yamlKey:"align",label:"Align",description:"Put the selected atoms on a shared horizontal or vertical line.",sections:["constraints"],valueShape:"mapping",supportsHold:true,fields:[{name:"selector",type:"selector",arity:"binary",accepts:v2,required:true,enforcement:"parse-error",description:"Returns the pairs of atoms to align with one another."},{name:"direction",type:"enum",values:["horizontal","vertical"],required:true,enforcement:"parse-error",description:"`horizontal` gives the atoms a shared Y coordinate; `vertical` a shared X coordinate. An unrecognized value is a parse error."}],example:{selector:"siblings",direction:"horizontal"}},Cxt={id:"group",yamlKey:"group",label:"Group (by selector)",description:"Draw a hull around a set of atoms. For tuples (a, b), (a, c), \u2026 the group is keyed by `a` and contains {b, c, \u2026}.",sections:["constraints"],valueShape:"mapping",discriminator:{field:"field",present:false},supportsHold:true,fields:[{name:"selector",type:"selector",arity:"binary",accepts:[{arity:"binary",minColumns:2,maxColumns:2,meaning:"One group per distinct first atom: the first column is the key, the last the members. The group is named `<name>[<key>]`, which is what a keyed `inferredEdge` `draw` end attaches to."},{arity:"n-ary",minColumns:3,meaning:"As binary \u2014 the key is the tuple's first atom and the member its last, ignoring the columns between."},{arity:"unary",minColumns:1,maxColumns:1,meaning:"One single group holding every selected atom, with no key. It is named `<name>` with no `[key]` suffix, and a `draw` end naming it attaches there whatever the end's atom is."}],required:true,enforcement:"unchecked",description:"First column is the group key, second the members. A unary selector builds a single unkeyed group.",note:"A `group` with neither `selector` nor `field` is silently dropped \u2014 it matches neither grouping form. That is the one case where omitting this field is not an error but a no-op."},{name:"name",type:"string",required:true,enforcement:"parse-error",description:"Display name on the group, and the handle an `inferredEdge` `draw` endpoint refers to. Keyed captions use `<name>[<key label>]`, adding the key ID only to distinguish duplicate captions. Required unless the constraint is negated (`hold: never`), where a name is generated."},{name:"addEdge",type:"enum",values:["none","togroup","fromgroup"],default:"none",enforcement:"value-ignored",description:"Draw a connector between the group key and the group: `togroup` points key \u2192 group, `fromgroup` points group \u2192 key, `none` draws nothing.",alternativeForm:{type:"block",description:"Block form also styles the connector, which is an edge and so takes the shared edge blocks: `{ points: <direction>, lineStyle: {\u2026}, textStyle: {\u2026} }`.",fields:[{name:"points",type:"enum",values:["none","togroup","fromgroup"],default:"none",description:"The connector direction \u2014 the same value the bare string form carries."},$u("lineStyle","The connector's line."),$u("textStyle","The connector's label.")]},note:"The legacy boolean `true` is still accepted and means `togroup`."},{name:"showLabel",type:"boolean",default:true,description:"Whether the group caption and its background pill are drawn. The group hull remains visible."},$u("textStyle","The group's own label. Only `color` applies today \u2014 group labels auto-fit their box, so `size` is reserved.")],example:{selector:"Team.members",name:"Team"}},Nxt={id:"size",yamlKey:"size",label:"Size",description:"Set the width and height of matching nodes, in pixels.",sections:["constraints"],deprecatedSections:["directives"],sectionDeprecation:{reason:"Size fixes a node's geometry, which is what the layout solves over \u2014 not presentation layered on a solved layout. It is a constraint. The directives section still accepts it, identically, behind a deprecation warning.",warningSpecType:"size"},valueShape:"mapping",supportsHold:false,fields:[{name:"width",type:"number",required:true,enforcement:"parse-error",exclusiveMinimum:0,description:"Node width in pixels. Required, and must be a number greater than 0."},{name:"height",type:"number",required:true,enforcement:"parse-error",exclusiveMinimum:0,description:"Node height in pixels. Required, and must be a number greater than 0."},{name:"selector",type:"selector",arity:"unary",accepts:Ky("The nodes to resize."),description:"Which nodes to resize. Omit to resize every node."}],example:{selector:"ImportantNode",width:150,height:80},note:"`hold: never` is not supported and is silently ignored."},Rxt={id:"hideAtom",yamlKey:"hideAtom",label:"Hide atom",description:"Remove matching atoms from the diagram.",sections:["constraints"],deprecatedSections:["directives"],sectionDeprecation:{reason:"Hiding an atom changes what the layout has to place, and can make a spec unsatisfiable against the other constraints \u2014 it is a constraint, not presentation. The directives section still accepts it, identically, behind a deprecation warning.",warningSpecType:"hideAtom"},valueShape:"mapping",supportsHold:false,fields:[{name:"selector",type:"selector",arity:"unary",accepts:Ky("The atoms to hide."),required:true,enforcement:"unchecked",description:"Which atoms to hide."}],example:{selector:"HelperNode"},note:"`hold: never` is not supported and is silently ignored. Hiding an atom that a layout constraint places, or that a group contains, makes the spec unsatisfiable: the layout reports a hidden-node conflict and draws a counterfactual with the conflicting atoms outlined. Hiding a keyed group's key is fine \u2014 the key is not inside the group."},Lxt={id:"flag",yamlKey:"flag",label:"Flag",description:"Toggle a whole-diagram rendering behaviour.",sections:["directives"],valueShape:"scalar",supportsHold:false,fields:[{name:"flag",type:"enum",values:["hideDisconnected","hideDisconnectedBuiltIns"],required:true,enforcement:"unchecked",description:"`hideDisconnected` hides every atom with no edges; `hideDisconnectedBuiltIns` hides only the disconnected built-in atoms (Int, String, \u2026). Any other value is silently ignored."}],example:{flag:"hideDisconnectedBuiltIns"},note:"Written as a bare scalar: `- flag: hideDisconnected`, not a mapping."},Ixt={id:"atomStyle",yamlKey:"atomStyle",label:"Atom style",description:"Style matching atoms. An atom is a composite of an interior fill, an outline, an icon, and its label, so each is its own block.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"selector",type:"selector",arity:"unary",accepts:Ky("The atoms this rule styles."),description:"Which atoms to style. Omit to style every atom."},$u("fillStyle","The node's interior fill."),$u("borderStyle","The node's outline."),$u("iconStyle","An icon drawn on the node."),$u("textStyle","The node's own label."),{name:"showLabel",type:"boolean",default:true,description:"Whether the atom's label is drawn. Independent of the icon: `iconStyle.placement` controls the icon's geometry, this controls the label."}],example:{selector:"Person",borderStyle:{color:"#0369a1"}},note:"Rules compose: a supertype selector already returns subtype atoms, so a `Node` rule and a `RedNode` rule both apply to a RedNode atom and their set properties gap-fill each other. Two rules setting the SAME property to DIFFERENT values is a hard error at layout time \u2014 styles never silently override."},Dxt={id:"edgeStyle",yamlKey:"edgeStyle",label:"Edge style",description:"Style the edges of a relation: the drawn line, the label, and visibility.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"field",type:"relation",required:true,enforcement:"unchecked",description:"The relation whose edges this styles."},SS,OS,$u("lineStyle","The drawn line."),$u("textStyle","The edge label."),{name:"showLabel",type:"boolean",default:true,description:"Whether the edge label is drawn."},{name:"hidden",type:"boolean",default:false,description:"Hide the edge entirely while keeping the relation in the data."}],example:{field:"parent",lineStyle:{color:"blue",pattern:"dashed"}},note:"Like atomStyle, overlapping rules compose and a genuine disagreement is an error rather than a silent override."},Pxt={id:"attribute",yamlKey:"attribute",label:"Attribute",description:"Render a relation as a key-value line on its source node instead of as an edge.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"field",type:"relation",required:true,enforcement:"unchecked",description:"The relation to fold into the source node. Its edges are removed from the graph."},{...SS,description:"Apply only to these source atoms. Omit to apply to every source atom."},OS,$u("textStyle","This attribute line's own styling.")],example:{field:"age",selector:"Person"},note:"Multiple targets for the same source become a list. Unlike `tag`, this removes the edge."},kxt={id:"tag",yamlKey:"tag",label:"Tag",description:"Add a computed key-value line to matching nodes, without touching the graph structure.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"toTag",type:"selector",arity:"unary",accepts:Ky("The atoms that receive the tag."),required:true,enforcement:"unchecked",description:"Which atoms receive the tag."},{name:"name",type:"string",required:true,enforcement:"unchecked",description:"The literal label shown before the value; this field is not a selector."},{name:"value",type:"selector",arity:"n-ary",accepts:[{arity:"n-ary",minColumns:2,meaning:"One line per tuple whose first atom is the tagged atom: the last column is the value and any columns between become one comma-separated key tuple, as `name[k1,k2]: value`. A binary result is the plain `name: value` case."},{arity:"unary",minColumns:1,maxColumns:1,meaning:'A membership tag: an atom in the result is tagged with its own label, as `name: <label>`. The value carries no more than "this atom is in the set".'}],required:true,enforcement:"unchecked",description:"Evaluated once; each tuple is attached to the tagged atom in its first column. A binary result shows as `name: value`; a longer tuple shows one line per tuple, as `name[k1,k2]: value`. A unary result tags each selected atom with its own label."},$u("textStyle","This tag line's own styling.")],example:{toTag:"Person",name:"age",value:"age"},note:"Unlike `attribute`, tags do not remove edges."},Mxt={id:"hideField",yamlKey:"hideField",label:"Hide field",description:"Hide a relation's edges.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"field",type:"relation",required:true,enforcement:"unchecked",description:"The relation to hide."},SS,{...OS,description:"Hide only the tuples this selector returns."}],example:{field:"internal"}},Kxt={id:"inferredEdge",yamlKey:"inferredEdge",label:"Inferred edge",description:"Draw an edge that is not in the data, computed from a selector.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"name",type:"string",required:true,enforcement:"unchecked",description:"The label drawn on the edge."},{name:"selector",type:"selector",arity:"binary",accepts:[{arity:"binary",minColumns:2,maxColumns:2,meaning:"One edge per tuple, from its first atom to its last."},{arity:"n-ary",minColumns:3,meaning:"One edge from the tuple's first atom to its last. Unlike the constraints, the columns between are not discarded: their labels are appended to the edge label as `<name>[m1,m2]`."},{arity:"unary",minColumns:1,maxColumns:1,requires:"draw",meaning:"One edge per atom, the atom feeding both ends \u2014 the shape `draw: _ -> <group>` needs, connecting each atom to its own group. Without `draw` a unary selector draws nothing at all: the engine reads this field as tuples, and single-atom tuples are dropped before any edge is made."}],required:true,enforcement:"unchecked",description:"Returns the (source, target) pairs to connect. May be unary when `draw` is given \u2014 the single atom then feeds both ends."},{name:"draw",type:"string",enforcement:"parse-error",pattern:"^\\s*[^\\s](?:(?!->)[\\s\\S])*->(?:(?!->)[\\s\\S])*[^\\s]\\s*$",description:"Reinterpret what each end attaches to, as `<end> -> <end>`. Each end is `_` (the atom itself, the default) or the name of a `group` constraint, in which case the end attaches to that group's hull. The left end applies to the first atom of each tuple, the right end to the last.",note:"Parsed strictly: a value that is not a string, or that does not contain exactly one `->`, is a parse error. A group name that no `group` constraint defines is not \u2014 it raises a warning (code `unresolved-reference`, specType `inferredEdge`) and the edge is skipped at layout time, so a fragment that names a group defined in another fragment still parses. `draw` never reorders \u2014 transpose the selector (`~connected`) to flip an edge."},$u("lineStyle","The drawn line."),$u("textStyle","The edge label."),{name:"color",type:"color",description:"Legacy inline line color.",deprecated:{replacedBy:"lineStyle.color"}},{name:"style",type:"enum",values:["solid","dashed","dotted"],description:"Legacy inline dash pattern.",deprecated:{replacedBy:"lineStyle.pattern"}},{name:"weight",type:"number",exclusiveMinimum:0,description:"Legacy inline line thickness.",deprecated:{replacedBy:"lineStyle.weight"}},{name:"highlight",type:"color",description:"Legacy inline highlight underlay.",deprecated:{replacedBy:"lineStyle.highlight"}}],example:{name:"reachable",selector:"^parent",lineStyle:{color:"gray",pattern:"dotted"}},note:"Using any of the legacy inline `color`/`style`/`weight`/`highlight` keys raises a deprecation warning with specType `inferredEdge`. The block form wins when both are given. If an end's atom keys no group of that name in a given instance, that one edge is skipped with a console warning \u2014 data-dependent, not a spec error."},Fxt={id:"icon",yamlKey:"icon",label:"Icon",description:"Assign an icon to matching atoms.",sections:["directives"],valueShape:"mapping",supportsHold:false,deprecated:{replacedBy:"atomStyle",reason:"The single `showLabels` boolean drove label visibility and icon geometry at once. atomStyle splits those into two independent knobs, which is what makes a faded watermark, or a hidden label with no icon, expressible.",mapping:{path:"iconStyle.path",selector:"selector","showLabels: false":"showLabel: false + iconStyle.placement: full","showLabels: true":"showLabel: true + iconStyle.placement: badge"},warningSpecType:"icon"},fields:[{name:"selector",type:"selector",arity:"unary",accepts:Ky("The atoms that get the icon."),required:true,enforcement:"unchecked",description:'Which atoms get the icon. Omitting it drops the directive entirely \u2014 it never means "every atom".'},{name:"path",type:"icon-path",required:true,enforcement:"unchecked",description:"Bundled name, icon-pack reference, URL, or path. Omitting it drops the directive."},{name:"showLabels",type:"boolean",default:false,description:"Whether the atom's label is drawn alongside the icon."}],example:{selector:"Person",path:"person",showLabels:true}},Bxt={id:"atomColor",yamlKey:"atomColor",label:"Atom color",description:"Set the color of matching atoms.",sections:["directives"],valueShape:"mapping",supportsHold:false,deprecated:{replacedBy:"atomStyle",reason:"atomStyle expresses the same recolor and also reaches the fill, the icon, and the label. The rewrite is border-preserving, so an existing diagram is unchanged.",mapping:{value:"borderStyle.color",selector:"selector"},warningSpecType:"atomColor"},fields:[{name:"value",type:"color",required:true,enforcement:"unchecked",description:"Any CSS color. Applies to the node's outline, not its fill."},{name:"selector",type:"selector",arity:"unary",accepts:Ky("The atoms to recolor."),required:true,enforcement:"unchecked",description:'Which atoms to recolor. Omitting it drops the directive \u2014 it never means "every atom".'}],example:{selector:"Person",value:"#ff5733"}},Uxt={id:"edgeColor",yamlKey:"edgeColor",label:"Edge color",description:"Style a relation's edges with flat, inline keys.",sections:["directives"],valueShape:"mapping",supportsHold:false,deprecated:{replacedBy:"edgeStyle",reason:"edgeStyle groups the same knobs into the shared lineStyle/textStyle blocks that every other form uses.",mapping:{value:"lineStyle.color",style:"lineStyle.pattern",weight:"lineStyle.weight",highlight:"lineStyle.highlight",field:"field",selector:"selector",filter:"filter",showLabel:"showLabel",hidden:"hidden"},warningSpecType:"edgeColor"},fields:[{name:"field",type:"relation",required:true,enforcement:"unchecked",description:"The relation whose edges this styles."},{name:"value",type:"color",required:true,enforcement:"unchecked",description:"Line color."},SS,OS,{name:"style",type:"enum",values:["solid","dashed","dotted"],enforcement:"value-ignored",description:"Dash pattern. Trimmed and lowercased before matching, unlike `lineStyle.pattern`."},{name:"weight",type:"number",exclusiveMinimum:0,enforcement:"value-ignored",description:"Line thickness in pixels."},{name:"highlight",type:"color",description:"A wider, translucent underlay beneath the line."},{name:"showLabel",type:"boolean",default:true,description:"Whether the edge label is drawn."},{name:"hidden",type:"boolean",default:false,description:"Hide the edge entirely."}],example:{field:"parent",value:"blue"}},jd=[Oxt,Axt,wxt,Cxt,Nxt,Rxt,Lxt,Ixt,Dxt,Pxt,kxt,Mxt,Kxt,Fxt,Bxt,Uxt],jxt={field:"source",fields:[{name:"text",type:"string",required:true,enforcement:"value-ignored",description:"The rule exactly as its author wrote it in the host surface \u2014 a Python decorator, a Rust attribute, a Forge annotation. Shown (escaped, as code) in conflict reports and warnings in place of the engine\u2019s own description of the rule. A missing or empty `text` makes the whole `source` block ignored."},{name:"location",type:"string",description:"Where the rule was written, e.g. `tree.py:12`. Appended to the displayed text."}],supportedBy:jd.filter(t=>t.valueShape!=="scalar").map(t=>t.id),displayedBy:["orientation","cyclic","align","group","hideAtom"],note:"For generators only \u2014 hand-written YAML needs no `source`, because there the YAML is the author\u2019s text. Accepted on every block-bodied item so a generator can stamp it uniformly. The engine carries and displays it for the forms that appear in conflict reports (the `displayedBy` list: the layout constraints and `hideAtom`); on the rest it parses and is ignored. Duplicate rules de-duplicate to one entry, which keeps the first provided source."},Gxt={field:"hold",values:["always","never"],default:"always",supportedBy:jd.filter(t=>t.supportsHold).map(t=>t.id),note:"`hold: never` negates a constraint: it asserts the relationship must not hold. Only the value `never` has an effect \u2014 `always`, any other string, and an absent field all mean the positive constraint. Double negation is not supported. `size` and `hideAtom` accept the key syntactically but ignore it."},Hxt={sections:["constraints","directives"],unknownKeys:"ignored",sectionShape:"list",notes:["Both sections are optional; an empty document is valid and yields an empty spec.","Each section must be a YAML list of single-key mappings. A section written as a mapping instead of a list is ignored wholesale, without an error.","Unrecognized top-level keys, unrecognized list items, and unrecognized fields inside a known item are all ignored silently. Nothing in the parser will tell you about a typo \u2014 validate against this manifest first.","`size` and `hideAtom` are constraints. Both are still accepted among the directives, with identical meaning, but that placement is deprecated and warns \u2014 emit them under `constraints`. Each item lists where to write it in `sections`, and any tolerated-but-deprecated placement in `deprecatedSections`.","Duplicate constraints (same selector and same parameters) are de-duplicated at parse time.","Parsing returns advisory `warnings` alongside the spec. Each carries a `code` (currently `deprecated`) and a `specType` naming the form, so a consumer can surface them without matching prose.","Every block-bodied item accepts an optional `source` block carrying the rule as its author wrote it in the host surface; conflict reports cite that text instead of the engine\u2019s own rendering. See the top-level `source` entry for the block\u2019s shape and which items display it.","The old group-by-field shape, `group: { field, groupOn, addToGroup }`, is removed. It is a parse error, not a silently ignored key, so an old spec fails loudly instead of losing its grouping. Write a `group` whose binary `selector` has the key in its first column and the members in its second; over `worksIn: Employee -> Department`, `groupOn: 1` / `addToGroup: 0` becomes `selector: ~worksIn` plus a `name`, and `groupOn: 0` / `addToGroup: 1` becomes `selector: worksIn`."]},qxt=[...jd.filter(t=>t.deprecated).map(t=>({id:t.id,kind:"item",path:t.yamlKey,...t.deprecated})),...jd.filter(t=>t.deprecatedSections?.length).flatMap(t=>t.deprecatedSections.map(e=>({id:`${t.id}@${e}`,kind:"placement",path:`${e}[].${t.yamlKey}`,replacedBy:`${t.sections[0]}[].${t.yamlKey}`,reason:t.sectionDeprecation.reason,mapping:{[`${e}[].${t.yamlKey}`]:`${t.sections[0]}[].${t.yamlKey}`},warningSpecType:t.sectionDeprecation.warningSpecType}))),...jd.flatMap(t=>t.fields.filter(e=>e.deprecated).map(e=>({id:`${t.id}.${e.name}`,kind:"field",path:`${t.yamlKey}.${e.name}`,replacedBy:`${t.yamlKey}.${e.deprecated.replacedBy}`,reason:e.deprecated.reason??`Superseded by ${e.deprecated.replacedBy}.`,mapping:{[e.name]:e.deprecated.replacedBy},warningSpecType:t.yamlKey})))],zxt={reference:"https://github.com/sidprasad/spytial-core/blob/main/docs/YAML_SPECIFICATION.md",constraints:"https://sidprasad.github.io/spytial-core/#/constraints",directives:"https://sidprasad.github.io/spytial-core/#/directives",selectors:"https://sidprasad.github.io/spytial-core/#/selectors",jsonSchema:"https://cdn.jsdelivr.net/gh/sidprasad/spytial-core@main/docs/spytial-spec.schema.json",manifest:"https://cdn.jsdelivr.net/gh/sidprasad/spytial-core@main/docs/spytial-language.json"};function wG(t){return {language:"spytial-layout-spec",languageVersion:y2,spytialCoreVersion:t,versioning:m2,document:Hxt,hold:Gxt,source:jxt,blocks:AG,items:jd,deprecations:qxt,documentation:zxt}}function CG(){return jd}function NG(t){return jd.find(e=>e.id===t)}function RG(){return AG}var $xt="https://json-schema.org/draft/2020-12/schema",Vxt=t=>`urn:spytial:layout-spec-schema:${t}`,LG={selector:"string",relation:"string",string:"string",color:"string","icon-path":"string",number:"number",integer:"integer",boolean:"boolean"};function IG(t){let e=[t.description];if(t.arity){let n=a=>a.maxColumns===void 0?`${a.minColumns}+ columns`:a.maxColumns===1?"1 column":`${a.maxColumns} columns`,s=t.accepts??[],i=s.find(a=>a.arity===t.arity),r=s.filter(a=>a!==i),o=i?`${t.arity} \u2014 ${n(i)}`:t.arity;e.push(r.length>0?`Selector arity: ${o} (also accepted: ${r.map(a=>a.requires?`${n(a)}, with \`${a.requires}\``:n(a)).join("; ")}).`:`Selector arity: ${o}.`);}return t.default!==void 0&&e.push(`Default when omitted: ${JSON.stringify(t.default)}.`),t.deprecated&&e.push(`Deprecated \u2014 use \`${t.deprecated.replacedBy}\` instead.`),t.note&&e.push(t.note),e.join(" ")}function PG(t){let e={description:IG(t)};switch(t.deprecated&&(e.deprecated=true),t.type){case "enum":e.type="string",e.enum=[...t.values??[]];break;case "enum-list":{e.type="array",e.minItems=1,e.items={type:"string",enum:[...t.values??[]]};let n=[];for(let s of t.listRules?.atMostOneOf??[])n.push({not:{allOf:s.map(i=>({contains:{const:i}}))},description:`At most one of: ${s.join(", ")}.`});for(let[s,i]of Object.entries(t.listRules?.narrowsListTo??{}))n.push({if:{contains:{const:s}},then:{items:{enum:[...i]}},description:`With \`${s}\`, the only other value allowed is ${i.filter(r=>r!==s).join(", ")}.`});n.length>0&&(e.allOf=n);break}case "block":t.block?e.$ref=`#/$defs/${t.block}`:Object.assign(e,P1(t.fields??[]));break;default:{let n=LG[t.type];n&&(e.type=n),n==="string"&&t.required&&(e.minLength=1),t.pattern!==void 0&&(e.pattern=t.pattern);break}}if(t.exclusiveMinimum!==void 0&&(e.exclusiveMinimum=t.exclusiveMinimum),t.minimum!==void 0&&(e.minimum=t.minimum),t.maximum!==void 0&&(e.maximum=t.maximum),t.alternativeForm){let n={...e};delete n.description;let s=t.alternativeForm.type==="block"?{...P1(t.alternativeForm.fields??[]),description:t.alternativeForm.description}:{type:LG[t.alternativeForm.type]??"string"};return {description:IG(t),oneOf:[n,s,{const:true,deprecated:true,description:"Legacy spelling of `togroup`."}]}}return e}function P1(t){let e={};for(let i of t)e[i.name]=PG(i);let n=t.filter(i=>i.required).map(i=>i.name),s={type:"object",properties:e,additionalProperties:false};return n.length>0&&(s.required=n),s}function Yxt(t,e){let n=P1(t.fields);if(t.supportsHold&&(n.properties.hold={type:"string",enum:["always","never"],description:"Negation. `never` asserts the constraint must not hold; `always` (the default) is the positive form."}),e.source.supportedBy.includes(t.id)&&(n.properties.source={$ref:"#/$defs/source",description:e.source.displayedBy.includes(t.id)?"The rule as its author wrote it in the host surface. Cited in conflict reports in place of the engine\u2019s own rendering.":"The rule as its author wrote it in the host surface. Accepted here for uniform generation; not displayed for this item today."}),t.discriminator)if(t.discriminator.present){let s=new Set([...n.required??[],t.discriminator.field]);n.required=[...s];}else n.not={required:[t.discriminator.field]};return t.id==="group"&&(n.required=(n.required??[]).filter(s=>s!=="name"),n.required.length===0&&delete n.required,n.allOf=[{if:{not:{properties:{hold:{const:"never"}},required:["hold"]}},then:{required:["name"]}}]),n}function Wxt(t,e){let n=t.valueShape==="scalar"?PG(t.fields[0]):Yxt(t,e),s={title:t.label,description:t.deprecated?`${t.description} DEPRECATED \u2014 use \`${t.deprecated.replacedBy}\` instead. ${t.deprecated.reason}`:t.description,type:"object",properties:{[t.yamlKey]:n},required:[t.yamlKey],additionalProperties:false};return t.deprecated&&(s.deprecated=true),s}function DG(t,e){let n=t.items.filter(i=>i.sections.includes(e)),s=t.items.filter(i=>i.deprecatedSections?.includes(e));return {type:["array","null"],description:e==="constraints"?"Structural layout: where nodes end up relative to one another.":"Presentation: how nodes and edges look, and what is shown at all.",items:{oneOf:[...n.map(i=>({$ref:`#/$defs/${x2(i)}`})),...s.map(i=>({$ref:`#/$defs/${x2(i)}`,deprecated:true,description:`\`${i.yamlKey}\` here is deprecated \u2014 write it under \`${i.sections[0]}\`. ${i.sectionDeprecation.reason}`}))]}}}function x2(t){return t.id.replace(/\./g,"_")}function kG(t){let e={};for(let n of t.blocks)e[n.name]={description:n.description,...P1(n.fields)};e.source={description:t.source.note,...P1(t.source.fields)};for(let n of t.items)e[x2(n)]=Wxt(n,t);return {$schema:$xt,$id:Vxt(t.languageVersion),title:"Spytial layout specification",description:`A Spytial spec: constraints (structural layout) and directives (presentation). Spec language ${t.languageVersion}, from spytial-core ${t.spytialCoreVersion}. This schema is stricter than the engine parser, which silently ignores anything it does not recognize \u2014 validating here is how a misspelled key or an out-of-range value gets caught at all. Fetch it from https://cdn.jsdelivr.net/gh/sidprasad/spytial-core@<tag>/docs/spytial-spec.schema.json; pin a tag, since the @main path is overwritten each release.`,"x-spytial-language-version":t.languageVersion,"x-spytial-core-version":t.spytialCoreVersion,type:"object",properties:{constraints:DG(t,"constraints"),directives:DG(t,"directives")},additionalProperties:false,$defs:e}}var Xxt=b2.default??b2,Qxt=T2.default??T2;if(typeof window<"u"){let t=window;t.d3||(t.d3=Xxt),t.cola||(t.cola=Qxt),Promise.resolve().then(()=>(QE(),$U)).then(({WebColaCnDGraph:e})=>(typeof customElements<"u"&&!customElements.get("webcola-cnd-graph")&&customElements.define("webcola-cnd-graph",e),Promise.resolve().then(()=>(LN(),YU)).then(({StructuredInputGraph:n})=>{typeof customElements<"u"&&!customElements.get("structured-input-graph")&&customElements.define("structured-input-graph",n);}))).catch(console.error);}var Jxt="6.4.1",_2=class{constructor(e={}){this.config={debug:false,version:Jxt,...e};}init(){this.config.debug;}getConfig(){return {...this.config}}updateConfig(e){this.config={...this.config,...e};}},l4t=t=>new _2(t);/*! Bundled license information:
|
|
1647
|
+
`)}function rvt(t,e){return `align ${e}(${t})`}function nvt(t,e){return `color ${e}(${t})`}var HN=class extends Error{constructor(e){super(e),this.name="SelectorSynthesisError";}};var qN=class{constructor(){this.currentError=null;this.errorCallbacks=[];}setError(e){this.currentError=e,this.notifyCallbacks();}clearError(){this.currentError=null,this.notifyCallbacks();}getCurrentError(){return this.currentError}onErrorChange(e){this.errorCallbacks.push(e);}hasError(){return this.currentError!==null}notifyCallbacks(){this.errorCallbacks.forEach(e=>e(this.currentError));}};qE();Ay();I0();FE();var ivt=800,ovt=600;async function Sj(t,e,n={}){let s=n.figWidth??ivt,i=n.figHeight??ovt,r=new exports.SGraphQueryEvaluator;r.initialize({sourceData:e});let o=new exports.LayoutInstance(t,r,0,true),{layout:a}=o.generateLayout(e),c,m=null;if(n.policy&&n.prevInstance&&n.currInstance){let f={priorState:n.priorPositions??{positions:[],transform:{k:1,x:0,y:0}},prevInstance:n.prevInstance,currInstance:n.currInstance,spec:t},p=n.policy.apply(f);p.effectivePriorState&&(c={priorPositions:p.effectivePriorState,lockUnconstrainedNodes:p.useReducedIterations},m={positions:p.effectivePriorState.positions.map(x=>({...x})),transform:{...p.effectivePriorState.transform}});}else n.priorPositions&&(c={priorPositions:n.priorPositions,lockUnconstrainedNodes:n.lockUnconstrainedNodes??false});let g=await new exports.WebColaTranslator().translate(a,s,i,c);new(Iy()).Layout().linkDistance(150).convergenceThreshold(.1).avoidOverlaps(true).handleDisconnected(true).nodes(g.colaNodes).groups(g.groups).links(g.colaEdges).constraints(g.colaConstraints).size([g.FIG_WIDTH,g.FIG_HEIGHT]).start(0,10,20,1);let u={positions:g.colaNodes.map(h=>({id:h.id,x:h.x??0,y:h.y??0})),transform:{k:1,x:0,y:0}},d=a.edges.map(h=>({source:h.source.id,target:h.target.id,rel:h.relationName}));return {positions:u,edges:d,constraints:a.constraints,nodes:g.colaNodes,groups:g.groups,seed:m}}Rl();var fG=Ys(hG());Rl();function _S(t,e){if(t.positions.length===0)return {positions:[],transform:{...t.transform}};let n=new Map(t.positions.map(c=>[c.id,{x:c.x,y:c.y}])),s=new Set(n.keys());for(let c of e)ii(c)?(s.add(c.left.id),s.add(c.right.id)):ni(c)?(s.add(c.top.id),s.add(c.bottom.id)):Fn(c)&&(s.add(c.node1.id),s.add(c.node2.id));let i=new OE,r=new Map,o=new Map;for(let c of s)r.set(c,new Bf),o.set(c,new Bf);for(let c of e)if(ii(c)){let m=r.get(c.left.id),v=r.get(c.right.id);i.addConstraint(new vc(m.plus(c.minDistance??0),da.Le,v,vs.required));}else if(ni(c)){let m=o.get(c.top.id),v=o.get(c.bottom.id);i.addConstraint(new vc(m.plus(c.minDistance??0),da.Le,v,vs.required));}else if(Fn(c)){let m=c.axis==="x"?r.get(c.node1.id):o.get(c.node1.id),v=c.axis==="x"?r.get(c.node2.id):o.get(c.node2.id);i.addConstraint(new vc(m,da.Eq,v,vs.required));}for(let[c,m]of n)i.addEditVariable(r.get(c),vs.weak),i.addEditVariable(o.get(c),vs.weak),i.suggestValue(r.get(c),m.x),i.suggestValue(o.get(c),m.y);return i.updateVariables(),{positions:t.positions.map(c=>({id:c.id,x:r.get(c.id).value(),y:o.get(c.id).value()})),transform:{...t.transform}}}function pG(t,e,n={}){if(t.positions.length<2)return {positions:t.positions.map(g=>({...g})),transform:{...t.transform}};let s=n.iterations??30,i=n.figWidth??800,r=n.figHeight??600,o=new Map;t.positions.forEach((g,l)=>o.set(g.id,l));let a=t.positions.map((g,l)=>({index:l,id:g.id,x:g.x,y:g.y})),c=[];for(let g=0;g<a.length;g++)for(let l=g+1;l<a.length;l++){let u=a[g].x-a[l].x,d=a[g].y-a[l].y,h=Math.hypot(u,d);h>0&&c.push({source:g,target:l,length:h});}let m=[];for(let g of e)if(ii(g)){let l=o.get(g.left.id),u=o.get(g.right.id);l!==void 0&&u!==void 0&&m.push({type:"separation",axis:"x",left:l,right:u,gap:g.minDistance??0});}else if(ni(g)){let l=o.get(g.top.id),u=o.get(g.bottom.id);l!==void 0&&u!==void 0&&m.push({type:"separation",axis:"y",left:l,right:u,gap:g.minDistance??0});}else if(Fn(g)){let l=o.get(g.node1.id),u=o.get(g.node2.id);l!==void 0&&u!==void 0&&m.push({type:"separation",axis:g.axis,left:l,right:u,gap:0,equality:true});}return new fG.Layout().convergenceThreshold(.01).avoidOverlaps(false).handleDisconnected(false).nodes(a).links(c).linkDistance(g=>g.length).constraints(m).size([i,r]).start(s,0,0,0),{positions:a.map(g=>({id:g.id,x:g.x,y:g.y})),transform:{...t.transform}}}var dG=t=>`${t.source}->${t.target}#${t.rel}`,xs=t=>{let e=new Map,n=Number.isFinite(t.transform?.k)&&t.transform.k>0?t.transform.k:1,s=Number.isFinite(t.transform?.x)?t.transform.x:0,i=Number.isFinite(t.transform?.y)?t.transform.y:0;for(let r of t.positions)e.set(r.id,{x:r.x*n+s,y:r.y*n+i});return e};function bS(t,e,n){let s=xs(t),i=xs(e),r=0;for(let[o,a]of i){if(!s.has(o)||n&&!n.has(o))continue;let c=s.get(o),m=a.x-c.x,v=a.y-c.y;r+=m*m+v*v;}return r}function yG(t,e,n,s,i){let r=xs(t),o=xs(n),a=new Set(e.map(dG)),c=0;for(let m of s){if(!a.has(dG(m))||i&&(!i.has(m.source)||!i.has(m.target)))continue;let v=r.get(m.source),g=r.get(m.target),l=o.get(m.source),u=o.get(m.target);if(!v||!g||!l||!u)continue;let d=g.x-v.x,h=g.y-v.y,f=u.x-l.x,p=u.y-l.y,x=f-d,b=p-h;c+=x*x+b*b;}return c}function TS(t,e,n){let s=xs(t),i=xs(e),r=[];for(let a of e.positions)s.has(a.id)&&(n&&!n.has(a.id)||r.push(a.id));let o=0;for(let a=0;a<r.length;a++){let c=i.get(r[a]),m=s.get(r[a]);for(let v=a+1;v<r.length;v++){let g=i.get(r[v]),l=s.get(r[v]),u=Math.hypot(g.x-c.x,g.y-c.y),d=Math.hypot(l.x-m.x,l.y-m.y),h=u-d;o+=h*h;}}return o}function gG(t){return t.length===0?null:t.reduce((e,n)=>e+n,0)/t.length}function mG(t,e,n){let s=xs(t),i=xs(e),r=[],o=[];for(let[v,g]of i){let l=s.get(v);if(!l)continue;let u=Math.hypot(g.x-l.x,g.y-l.y);n.has(v)?r.push(u):o.push(u);}let a=null;if(r.length>0&&o.length>0){let v=0;for(let g of r)for(let l of o)g>l?v+=1:g===l&&(v+=.5);a=v/(r.length*o.length);}let c=new Set,m=new Set;for(let[v]of i)s.has(v)&&(n.has(v)?c.add(v):m.add(v));return {auc:a,changedMeanDrift:gG(r),stableMeanDrift:gG(o),changedPositional:c.size>0?bS(t,e,c):null,stablePositional:m.size>0?bS(t,e,m):null,changedPairwiseDistance:c.size>=2?TS(t,e,c):null,stablePairwiseDistance:m.size>=2?TS(t,e,m):null,changedCount:r.length,stableCount:o.length}}function gxt(t,e,n){let s=t.visualWidth??t.width??100,i=e.visualWidth??e.width??100,r=s/2+i/2+n,o=Math.min(Math.max(s,i)*.1,20);return r+o}function yxt(t,e,n){let s=t.visualHeight??t.height??60,i=e.visualHeight??e.height??60,r=s/2+i/2+n,o=Math.min(Math.max(s,i)*.1,15);return r+o}function vG(t,e,n=5){let s=new Map(e.map(o=>[o.id,o])),i=0,r=0;for(let o of t)if(ii(o)){let a=s.get(o.left.id),c=s.get(o.right.id);if(!a||!c)continue;let m=gxt(a,c,o.minDistance),v=(c.x??0)-(a.x??0);i+=1,v+n>=m&&(r+=1);}else if(ni(o)){let a=s.get(o.top.id),c=s.get(o.bottom.id);if(!a||!c)continue;let m=yxt(a,c,o.minDistance),v=(c.y??0)-(a.y??0);i+=1,v+n>=m&&(r+=1);}else if(Fn(o)){let a=s.get(o.node1.id),c=s.get(o.node2.id);if(!a||!c)continue;let m=o.axis==="x"?a.x??0:a.y??0,v=o.axis==="x"?c.x??0:c.y??0;i+=1,Math.abs(m-v)<=n&&(r+=1);}return i===0?1:r/i}function xG(t,e,n=.5){let s=xs(t),i=xs(e),r=new Set;for(let[o,a]of i){let c=s.get(o);c&&Math.abs(a.x-c.x)<=n&&Math.abs(a.y-c.y)<=n&&r.add(o);}return r}function mxt(t,e,n,s){if(t.x===n.x&&t.y===n.y||t.x===s.x&&t.y===s.y||e.x===n.x&&e.y===n.y||e.x===s.x&&e.y===s.y)return false;let i=(m,v,g)=>(v.x-m.x)*(g.y-m.y)-(v.y-m.y)*(g.x-m.x),r=i(n,s,t),o=i(n,s,e),a=i(t,e,n),c=i(t,e,s);return (r>0&&o<0||r<0&&o>0)&&(a>0&&c<0||a<0&&c>0)}function _G(t,e,n){let s=xs(t),i=xs(e),r=[];for(let[c]of i)s.has(c)&&(n&&!n.has(c)||r.push(c));if(r.sort(),r.length<2)return null;let o=0,a=0;for(let c=0;c<r.length;c++){let m=s.get(r[c]),v=i.get(r[c]);for(let g=c+1;g<r.length;g++){let l=s.get(r[g]),u=i.get(r[g]),d=m.x<l.x&&v.x<u.x||m.x>l.x&&v.x>u.x||m.x===l.x&&v.x===u.x,h=m.y<l.y&&v.y<u.y||m.y>l.y&&v.y>u.y||m.y===l.y&&v.y===u.y;d&&h&&(o+=1),a+=1;}}return a===0?null:o/a}function bG(t,e,n=3,s){let i=xs(t),r=xs(e),o=[];for(let[v]of r)i.has(v)&&(s&&!s.has(v)||o.push(v));if(o.sort(),o.length<n+1)return null;let a=(v,g)=>{let l=v.get(g),u=[];for(let d of o){if(d===g)continue;let h=v.get(d);u.push({id:d,d:Math.hypot(h.x-l.x,h.y-l.y)});}return u.sort((d,h)=>d.d-h.d||d.id.localeCompare(h.id)),new Set(u.slice(0,n).map(d=>d.id))},c=0,m=0;for(let v of o){let g=a(i,v),l=a(r,v),u=new Set([...g,...l]);if(u.size===0)continue;let d=0;for(let h of g)l.has(h)&&(d+=1);c+=d/u.size,m+=1;}return m===0?null:c/m}function ES(t,e){let n=xs(t),s=[];for(let r of e){let o=n.get(r.source),a=n.get(r.target);!o||!a||s.push({a:o,b:a});}let i=0;for(let r=0;r<s.length;r++)for(let o=r+1;o<s.length;o++)mxt(s[r].a,s[r].b,s[o].a,s[o].b)&&(i+=1);return i}function TG(t,e,n,s){return Math.abs(ES(n,s)-ES(t,e))}function EG(t,e,n){let s=xs(t),i=xs(e),r=0,o=0,a=0;for(let c of n){let m=s.get(c),v=i.get(c);if(!m||!v)continue;let g=v.x-m.x,l=v.y-m.y,u=Math.hypot(g,l);u!==0&&(r+=g/u,o+=l/u,a+=1);}return a===0?null:Math.hypot(r,o)/a}function SG(t,e,n,s=5){let i=xs(t),r=xs(e),o=0,a=0;for(let c of n){let m=i.get(c),v=r.get(c);!m||!v||(o+=1,Math.hypot(v.x-m.x,v.y-m.y)<=s&&(a+=1));}return o===0?null:a/o}function OG(t,e){if(t.positions.length===0)return 0;let n=_S(t,e),s=new Map(n.positions.map(r=>[r.id,r])),i=0;for(let r of t.positions){let o=s.get(r.id);o&&(i+=Math.hypot(o.x-r.x,o.y-r.y));}return i}var y2="2026-09-18",m2={note:"`languageVersion` is the date the language last changed (YYYY-MM-DD). If it has not moved since the manifest you generated against, nothing you emit needs revisiting. `spytialCoreVersion` records which release produced this file.",deprecations:"A deprecated form keeps parsing and keeps its meaning while it is listed in `deprecations`, and each entry names its replacement and the rewrite to apply. Removal is signalled by `languageVersion` moving, not by the `spytialCoreVersion` major: a removed form leaves this manifest and becomes a parse error, so check `languageVersion` before assuming a spec you generated earlier still parses."},vxt={name:"textStyle",description:"Styling for a label. Reused by every form that renders text \u2014 an atom's own label, attribute and tag lines, edge labels, and a group label.",fields:[{name:"size",type:"enum",values:["small","normal","large"],enforcement:"value-ignored",default:"normal",description:"Font-size tier relative to the node label: `large` renders bigger than the label, `normal` smaller, `small` smaller still."},{name:"color",type:"color",description:"Any CSS color. Unset inherits the node label color, so dark mode still adapts."}]},xxt={name:"lineStyle",description:"Styling for an edge's drawn line. Reused by edgeStyle, inferredEdge, and a group's addEdge connector.",fields:[{name:"color",type:"color",description:"Any CSS color."},{name:"pattern",type:"enum",values:["solid","dashed","dotted"],enforcement:"value-ignored",description:"Dash pattern of the line."},{name:"weight",type:"number",exclusiveMinimum:0,enforcement:"value-ignored",description:"Line thickness in pixels. Must be > 0; a non-positive or non-numeric weight is dropped."},{name:"highlight",type:"color",description:"A wider, translucent underlay drawn beneath the line. Orthogonal to color and pattern."}]},_xt={name:"fillStyle",description:"An atom's interior fill. Opt-in: the default look is unfilled, with only the border and label marking the node.",fields:[{name:"color",type:"color",description:"Any CSS color."}]},bxt={name:"borderStyle",description:"An atom's outline.",fields:[{name:"color",type:"color",description:"Any CSS color."},{name:"width",type:"number",exclusiveMinimum:0,enforcement:"value-ignored",description:"Outline thickness in pixels. Must be > 0; anything else is dropped."}]},Txt={name:"iconStyle",description:"An icon drawn on an atom. Every leaf is optional, including `path`, so a supertype rule can supply the icon and a subtype rule tune only its opacity.",fields:[{name:"path",type:"icon-path",description:"A bundled icon name (`person`), an icon-pack reference (`bi:person-fill`), a URL, or a path. Resolved to a concrete URL or data URI at parse time. An iconStyle with no path draws nothing."},{name:"placement",type:"enum",values:["full","badge"],enforcement:"value-ignored",default:"full",description:"`full` \u2014 the icon occupies the box, which stays transparent unless a fillStyle.color is given. `badge` \u2014 a small marker in the top-right corner, secondary to the label."},{name:"opacity",type:"number",minimum:0,maximum:1,enforcement:"value-ignored",default:1,description:"Alpha in [0,1]. Out-of-range values are dropped rather than clamped. Fade a `full` icon to use it as a watermark behind the label."}]},AG=[vxt,xxt,_xt,bxt,Txt],$u=(t,e)=>({name:t,type:"block",block:t,description:e}),Ky=t=>[{arity:"unary",minColumns:1,maxColumns:1,meaning:t}],Ext={arity:"binary",minColumns:2,maxColumns:2,meaning:"Each tuple is one (first, last) pair, and the constraint applies to it."},Sxt={arity:"n-ary",minColumns:3,meaning:"Accepted: the pair is the tuple's first and last atom. The columns between are ignored."},v2=[Ext,Sxt],SS={name:"selector",type:"selector",arity:"unary",accepts:Ky("The set of source atoms the directive is narrowed to."),description:"Apply only to edges whose source atom is in this set. Omit to apply to every source atom."},OS={name:"filter",type:"selector",arity:"n-ary",accepts:[{arity:"n-ary",minColumns:2,meaning:"A tuple matches on its first and last atom, so a longer tuple filters the same relation ends a pair would. A unary result matches nothing \u2014 the directive is then scoped to no tuples at all."}],description:"Apply only to the (source, target, \u2026) tuples this selector returns. Use it to scope a directive to part of a relation, e.g. only the tuples whose value is True."},Oxt={id:"orientation",yamlKey:"orientation",label:"Orientation",description:"Place the two ends of each selected tuple relative to one another.",sections:["constraints"],valueShape:"mapping",supportsHold:true,fields:[{name:"selector",type:"selector",arity:"binary",accepts:v2,required:true,enforcement:"parse-error",description:"Returns (source, target) pairs. The constraint applies to each pair."},{name:"directions",type:"enum-list",values:["above","below","left","right","directlyAbove","directlyBelow","directlyLeft","directlyRight"],required:true,enforcement:"parse-error",listRules:{atMostOneOf:[["above","below"],["left","right"]],narrowsListTo:{directlyAbove:["above","directlyAbove"],directlyBelow:["below","directlyBelow"],directlyLeft:["left","directlyLeft"],directlyRight:["right","directlyRight"]}},description:"Where the TARGET sits relative to the SOURCE. `directions: [above]` on selector `parent` places each tuple's target above its source. The `directly*` variants additionally enforce axis alignment.",note:"The direction is target-relative-to-source. Getting this backwards is the most common spec bug \u2014 transpose the selector (`~parent`) rather than flipping the direction if the relation reads the other way."}],example:{selector:"parent",directions:["above"]},note:"Contradictory direction sets are rejected at parse time: `above` with `below`, `left` with `right`, and a `directly*` variant combined with anything other than its own non-direct counterpart. Values outside the listed set are NOT rejected \u2014 they parse and then match nothing."},Axt={id:"cyclic",yamlKey:"cyclic",label:"Cyclic",description:"Arrange the selected atoms around the perimeter of a circle, in the order the selector defines.",sections:["constraints"],valueShape:"mapping",supportsHold:true,fields:[{name:"selector",type:"selector",arity:"binary",accepts:v2,required:true,enforcement:"parse-error",description:'Returns (a, b) pairs meaning "b follows a around the circle".'},{name:"direction",type:"enum",values:["clockwise","counterclockwise"],default:"clockwise",enforcement:"unchecked",description:"Which way the cycle runs."}],example:{selector:"nextState",direction:"clockwise"},note:"Two cyclic constraints on the same selector with different directions is a parse error. An unrecognized direction string is not rejected at parse time."},wxt={id:"align",yamlKey:"align",label:"Align",description:"Put the selected atoms on a shared horizontal or vertical line.",sections:["constraints"],valueShape:"mapping",supportsHold:true,fields:[{name:"selector",type:"selector",arity:"binary",accepts:v2,required:true,enforcement:"parse-error",description:"Returns the pairs of atoms to align with one another."},{name:"direction",type:"enum",values:["horizontal","vertical"],required:true,enforcement:"parse-error",description:"`horizontal` gives the atoms a shared Y coordinate; `vertical` a shared X coordinate. An unrecognized value is a parse error."}],example:{selector:"siblings",direction:"horizontal"}},Cxt={id:"group",yamlKey:"group",label:"Group (by selector)",description:"Draw a hull around a set of atoms. For tuples (a, b), (a, c), \u2026 the group is keyed by `a` and contains {b, c, \u2026}.",sections:["constraints"],valueShape:"mapping",discriminator:{field:"field",present:false},supportsHold:true,fields:[{name:"selector",type:"selector",arity:"binary",accepts:[{arity:"binary",minColumns:2,maxColumns:2,meaning:"One group per distinct first atom: the first column is the key, the last the members. The group is named `<name>[<key>]`, which is what a keyed `inferredEdge` `draw` end attaches to."},{arity:"n-ary",minColumns:3,meaning:"As binary \u2014 the key is the tuple's first atom and the member its last, ignoring the columns between."},{arity:"unary",minColumns:1,maxColumns:1,meaning:"One single group holding every selected atom, with no key. It is named `<name>` with no `[key]` suffix, and a `draw` end naming it attaches there whatever the end's atom is."}],required:true,enforcement:"unchecked",description:"First column is the group key, second the members. A unary selector builds a single unkeyed group.",note:"A `group` with neither `selector` nor `field` is silently dropped \u2014 it matches neither grouping form. That is the one case where omitting this field is not an error but a no-op."},{name:"name",type:"string",required:true,enforcement:"parse-error",description:"Display name on the group, and the handle an `inferredEdge` `draw` endpoint refers to. Keyed captions use `<name>[<key label>]`, adding the key ID only to distinguish duplicate captions. Required unless the constraint is negated (`hold: never`), where a name is generated."},{name:"addEdge",type:"enum",values:["none","togroup","fromgroup"],default:"none",enforcement:"value-ignored",description:"Draw a connector between the group key and the group: `togroup` points key \u2192 group, `fromgroup` points group \u2192 key, `none` draws nothing.",alternativeForm:{type:"block",description:"Block form also styles the connector, which is an edge and so takes the shared edge blocks: `{ points: <direction>, lineStyle: {\u2026}, textStyle: {\u2026} }`.",fields:[{name:"points",type:"enum",values:["none","togroup","fromgroup"],default:"none",description:"The connector direction \u2014 the same value the bare string form carries."},$u("lineStyle","The connector's line."),$u("textStyle","The connector's label.")]},note:"The legacy boolean `true` is still accepted and means `togroup`."},{name:"showLabel",type:"boolean",default:true,description:"Whether the group caption and its background pill are drawn. The group hull remains visible."},$u("textStyle","The group's own label. Only `color` applies today \u2014 group labels auto-fit their box, so `size` is reserved.")],example:{selector:"Team.members",name:"Team"}},Nxt={id:"size",yamlKey:"size",label:"Size",description:"Set the width and height of matching nodes, in pixels.",sections:["constraints"],deprecatedSections:["directives"],sectionDeprecation:{reason:"Size fixes a node's geometry, which is what the layout solves over \u2014 not presentation layered on a solved layout. It is a constraint. The directives section still accepts it, identically, behind a deprecation warning.",warningSpecType:"size"},valueShape:"mapping",supportsHold:false,fields:[{name:"width",type:"number",required:true,enforcement:"parse-error",exclusiveMinimum:0,description:"Node width in pixels. Required, and must be a number greater than 0."},{name:"height",type:"number",required:true,enforcement:"parse-error",exclusiveMinimum:0,description:"Node height in pixels. Required, and must be a number greater than 0."},{name:"selector",type:"selector",arity:"unary",accepts:Ky("The nodes to resize."),description:"Which nodes to resize. Omit to resize every node."}],example:{selector:"ImportantNode",width:150,height:80},note:"`hold: never` is not supported and is silently ignored."},Rxt={id:"hideAtom",yamlKey:"hideAtom",label:"Hide atom",description:"Remove matching atoms from the diagram.",sections:["constraints"],deprecatedSections:["directives"],sectionDeprecation:{reason:"Hiding an atom changes what the layout has to place, and can make a spec unsatisfiable against the other constraints \u2014 it is a constraint, not presentation. The directives section still accepts it, identically, behind a deprecation warning.",warningSpecType:"hideAtom"},valueShape:"mapping",supportsHold:false,fields:[{name:"selector",type:"selector",arity:"unary",accepts:Ky("The atoms to hide."),required:true,enforcement:"unchecked",description:"Which atoms to hide."}],example:{selector:"HelperNode"},note:"`hold: never` is not supported and is silently ignored. Hiding an atom that a layout constraint places, or that a group contains, makes the spec unsatisfiable: the layout reports a hidden-node conflict and draws a counterfactual with the conflicting atoms outlined. Hiding a keyed group's key is fine \u2014 the key is not inside the group."},Lxt={id:"flag",yamlKey:"flag",label:"Flag",description:"Toggle a whole-diagram rendering behaviour.",sections:["directives"],valueShape:"scalar",supportsHold:false,fields:[{name:"flag",type:"enum",values:["hideDisconnected","hideDisconnectedBuiltIns"],required:true,enforcement:"unchecked",description:"`hideDisconnected` hides every atom with no edges; `hideDisconnectedBuiltIns` hides only the disconnected built-in atoms (Int, String, \u2026). Any other value is silently ignored."}],example:{flag:"hideDisconnectedBuiltIns"},note:"Written as a bare scalar: `- flag: hideDisconnected`, not a mapping."},Ixt={id:"atomStyle",yamlKey:"atomStyle",label:"Atom style",description:"Style matching atoms. An atom is a composite of an interior fill, an outline, an icon, and its label, so each is its own block.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"selector",type:"selector",arity:"unary",accepts:Ky("The atoms this rule styles."),description:"Which atoms to style. Omit to style every atom."},$u("fillStyle","The node's interior fill."),$u("borderStyle","The node's outline."),$u("iconStyle","An icon drawn on the node."),$u("textStyle","The node's own label."),{name:"showLabel",type:"boolean",default:true,description:"Whether the atom's label is drawn. Independent of the icon: `iconStyle.placement` controls the icon's geometry, this controls the label."}],example:{selector:"Person",borderStyle:{color:"#0369a1"}},note:"Rules compose: a supertype selector already returns subtype atoms, so a `Node` rule and a `RedNode` rule both apply to a RedNode atom and their set properties gap-fill each other. Two rules setting the SAME property to DIFFERENT values is a hard error at layout time \u2014 styles never silently override."},Dxt={id:"edgeStyle",yamlKey:"edgeStyle",label:"Edge style",description:"Style the edges of a relation: the drawn line, the label, and visibility.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"field",type:"relation",required:true,enforcement:"unchecked",description:"The relation whose edges this styles."},SS,OS,$u("lineStyle","The drawn line."),$u("textStyle","The edge label."),{name:"showLabel",type:"boolean",default:true,description:"Whether the edge label is drawn."},{name:"hidden",type:"boolean",default:false,description:"Hide the edge entirely while keeping the relation in the data."}],example:{field:"parent",lineStyle:{color:"blue",pattern:"dashed"}},note:"Like atomStyle, overlapping rules compose and a genuine disagreement is an error rather than a silent override."},Pxt={id:"attribute",yamlKey:"attribute",label:"Attribute",description:"Render a relation as a key-value line on its source node instead of as an edge.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"field",type:"relation",required:true,enforcement:"unchecked",description:"The relation to fold into the source node. Its edges are removed from the graph."},{...SS,description:"Apply only to these source atoms. Omit to apply to every source atom."},OS,$u("textStyle","This attribute line's own styling.")],example:{field:"age",selector:"Person"},note:"Multiple targets for the same source become a list. Unlike `tag`, this removes the edge."},kxt={id:"tag",yamlKey:"tag",label:"Tag",description:"Add a computed key-value line to matching nodes, without touching the graph structure.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"toTag",type:"selector",arity:"unary",accepts:Ky("The atoms that receive the tag."),required:true,enforcement:"unchecked",description:"Which atoms receive the tag."},{name:"name",type:"string",required:true,enforcement:"unchecked",description:"The literal label shown before the value; this field is not a selector."},{name:"value",type:"selector",arity:"n-ary",accepts:[{arity:"n-ary",minColumns:2,meaning:"One line per tuple whose first atom is the tagged atom: the last column is the value and any columns between become one comma-separated key tuple, as `name[k1,k2]: value`. A binary result is the plain `name: value` case."},{arity:"unary",minColumns:1,maxColumns:1,meaning:'A membership tag: an atom in the result is tagged with its own label, as `name: <label>`. The value carries no more than "this atom is in the set".'}],required:true,enforcement:"unchecked",description:"Evaluated once; each tuple is attached to the tagged atom in its first column. A binary result shows as `name: value`; a longer tuple shows one line per tuple, as `name[k1,k2]: value`. A unary result tags each selected atom with its own label."},$u("textStyle","This tag line's own styling.")],example:{toTag:"Person",name:"age",value:"age"},note:"Unlike `attribute`, tags do not remove edges."},Mxt={id:"hideField",yamlKey:"hideField",label:"Hide field",description:"Hide a relation's edges.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"field",type:"relation",required:true,enforcement:"unchecked",description:"The relation to hide."},SS,{...OS,description:"Hide only the tuples this selector returns."}],example:{field:"internal"}},Kxt={id:"inferredEdge",yamlKey:"inferredEdge",label:"Inferred edge",description:"Draw an edge that is not in the data, computed from a selector.",sections:["directives"],valueShape:"mapping",supportsHold:false,fields:[{name:"name",type:"string",required:true,enforcement:"unchecked",description:"The label drawn on the edge."},{name:"selector",type:"selector",arity:"binary",accepts:[{arity:"binary",minColumns:2,maxColumns:2,meaning:"One edge per tuple, from its first atom to its last."},{arity:"n-ary",minColumns:3,meaning:"One edge from the tuple's first atom to its last. Unlike the constraints, the columns between are not discarded: their labels are appended to the edge label as `<name>[m1,m2]`."},{arity:"unary",minColumns:1,maxColumns:1,requires:"draw",meaning:"One edge per atom, the atom feeding both ends \u2014 the shape `draw: _ -> <group>` needs, connecting each atom to its own group. Without `draw` a unary selector draws nothing at all: the engine reads this field as tuples, and single-atom tuples are dropped before any edge is made."}],required:true,enforcement:"unchecked",description:"Returns the (source, target) pairs to connect. May be unary when `draw` is given \u2014 the single atom then feeds both ends."},{name:"draw",type:"string",enforcement:"parse-error",pattern:"^\\s*[^\\s](?:(?!->)[\\s\\S])*->(?:(?!->)[\\s\\S])*[^\\s]\\s*$",description:"Reinterpret what each end attaches to, as `<end> -> <end>`. Each end is `_` (the atom itself, the default) or the name of a `group` constraint, in which case the end attaches to that group's hull. The left end applies to the first atom of each tuple, the right end to the last.",note:"Parsed strictly: a value that is not a string, or that does not contain exactly one `->`, is a parse error. A group name that no `group` constraint defines is not \u2014 it raises a warning (code `unresolved-reference`, specType `inferredEdge`) and the edge is skipped at layout time, so a fragment that names a group defined in another fragment still parses. `draw` never reorders \u2014 transpose the selector (`~connected`) to flip an edge."},$u("lineStyle","The drawn line."),$u("textStyle","The edge label."),{name:"color",type:"color",description:"Legacy inline line color.",deprecated:{replacedBy:"lineStyle.color"}},{name:"style",type:"enum",values:["solid","dashed","dotted"],description:"Legacy inline dash pattern.",deprecated:{replacedBy:"lineStyle.pattern"}},{name:"weight",type:"number",exclusiveMinimum:0,description:"Legacy inline line thickness.",deprecated:{replacedBy:"lineStyle.weight"}},{name:"highlight",type:"color",description:"Legacy inline highlight underlay.",deprecated:{replacedBy:"lineStyle.highlight"}}],example:{name:"reachable",selector:"^parent",lineStyle:{color:"gray",pattern:"dotted"}},note:"Using any of the legacy inline `color`/`style`/`weight`/`highlight` keys raises a deprecation warning with specType `inferredEdge`. The block form wins when both are given. If an end's atom keys no group of that name in a given instance, that one edge is skipped with a console warning \u2014 data-dependent, not a spec error."},Fxt={id:"icon",yamlKey:"icon",label:"Icon",description:"Assign an icon to matching atoms.",sections:["directives"],valueShape:"mapping",supportsHold:false,deprecated:{replacedBy:"atomStyle",reason:"The single `showLabels` boolean drove label visibility and icon geometry at once. atomStyle splits those into two independent knobs, which is what makes a faded watermark, or a hidden label with no icon, expressible.",mapping:{path:"iconStyle.path",selector:"selector","showLabels: false":"showLabel: false + iconStyle.placement: full","showLabels: true":"showLabel: true + iconStyle.placement: badge"},warningSpecType:"icon"},fields:[{name:"selector",type:"selector",arity:"unary",accepts:Ky("The atoms that get the icon."),required:true,enforcement:"unchecked",description:'Which atoms get the icon. Omitting it drops the directive entirely \u2014 it never means "every atom".'},{name:"path",type:"icon-path",required:true,enforcement:"unchecked",description:"Bundled name, icon-pack reference, URL, or path. Omitting it drops the directive."},{name:"showLabels",type:"boolean",default:false,description:"Whether the atom's label is drawn alongside the icon."}],example:{selector:"Person",path:"person",showLabels:true}},Bxt={id:"atomColor",yamlKey:"atomColor",label:"Atom color",description:"Set the color of matching atoms.",sections:["directives"],valueShape:"mapping",supportsHold:false,deprecated:{replacedBy:"atomStyle",reason:"atomStyle expresses the same recolor and also reaches the fill, the icon, and the label. The rewrite is border-preserving, so an existing diagram is unchanged.",mapping:{value:"borderStyle.color",selector:"selector"},warningSpecType:"atomColor"},fields:[{name:"value",type:"color",required:true,enforcement:"unchecked",description:"Any CSS color. Applies to the node's outline, not its fill."},{name:"selector",type:"selector",arity:"unary",accepts:Ky("The atoms to recolor."),required:true,enforcement:"unchecked",description:'Which atoms to recolor. Omitting it drops the directive \u2014 it never means "every atom".'}],example:{selector:"Person",value:"#ff5733"}},Uxt={id:"edgeColor",yamlKey:"edgeColor",label:"Edge color",description:"Style a relation's edges with flat, inline keys.",sections:["directives"],valueShape:"mapping",supportsHold:false,deprecated:{replacedBy:"edgeStyle",reason:"edgeStyle groups the same knobs into the shared lineStyle/textStyle blocks that every other form uses.",mapping:{value:"lineStyle.color",style:"lineStyle.pattern",weight:"lineStyle.weight",highlight:"lineStyle.highlight",field:"field",selector:"selector",filter:"filter",showLabel:"showLabel",hidden:"hidden"},warningSpecType:"edgeColor"},fields:[{name:"field",type:"relation",required:true,enforcement:"unchecked",description:"The relation whose edges this styles."},{name:"value",type:"color",required:true,enforcement:"unchecked",description:"Line color."},SS,OS,{name:"style",type:"enum",values:["solid","dashed","dotted"],enforcement:"value-ignored",description:"Dash pattern. Trimmed and lowercased before matching, unlike `lineStyle.pattern`."},{name:"weight",type:"number",exclusiveMinimum:0,enforcement:"value-ignored",description:"Line thickness in pixels."},{name:"highlight",type:"color",description:"A wider, translucent underlay beneath the line."},{name:"showLabel",type:"boolean",default:true,description:"Whether the edge label is drawn."},{name:"hidden",type:"boolean",default:false,description:"Hide the edge entirely."}],example:{field:"parent",value:"blue"}},jd=[Oxt,Axt,wxt,Cxt,Nxt,Rxt,Lxt,Ixt,Dxt,Pxt,kxt,Mxt,Kxt,Fxt,Bxt,Uxt],jxt={field:"source",fields:[{name:"text",type:"string",required:true,enforcement:"value-ignored",description:"The rule exactly as its author wrote it in the host surface \u2014 a Python decorator, a Rust attribute, a Forge annotation. Shown (escaped, as code) in conflict reports and warnings in place of the engine\u2019s own description of the rule. A missing or empty `text` makes the whole `source` block ignored."},{name:"location",type:"string",description:"Where the rule was written, e.g. `tree.py:12`. Appended to the displayed text."}],supportedBy:jd.filter(t=>t.valueShape!=="scalar").map(t=>t.id),displayedBy:["orientation","cyclic","align","group","hideAtom"],note:"For generators only \u2014 hand-written YAML needs no `source`, because there the YAML is the author\u2019s text. Accepted on every block-bodied item so a generator can stamp it uniformly. The engine carries and displays it for the forms that appear in conflict reports (the `displayedBy` list: the layout constraints and `hideAtom`); on the rest it parses and is ignored. Duplicate rules de-duplicate to one entry, which keeps the first provided source."},Gxt={field:"hold",values:["always","never"],default:"always",supportedBy:jd.filter(t=>t.supportsHold).map(t=>t.id),note:"`hold: never` negates a constraint: it asserts the relationship must not hold. Only the value `never` has an effect \u2014 `always`, any other string, and an absent field all mean the positive constraint. Double negation is not supported. `size` and `hideAtom` accept the key syntactically but ignore it."},Hxt={sections:["constraints","directives"],unknownKeys:"ignored",sectionShape:"list",notes:["Both sections are optional; an empty document is valid and yields an empty spec.","Each section must be a YAML list of single-key mappings. A section written as a mapping instead of a list is ignored wholesale, without an error.","Unrecognized top-level keys, unrecognized list items, and unrecognized fields inside a known item are all ignored silently. Nothing in the parser will tell you about a typo \u2014 validate against this manifest first.","`size` and `hideAtom` are constraints. Both are still accepted among the directives, with identical meaning, but that placement is deprecated and warns \u2014 emit them under `constraints`. Each item lists where to write it in `sections`, and any tolerated-but-deprecated placement in `deprecatedSections`.","Duplicate constraints (same selector and same parameters) are de-duplicated at parse time.","Parsing returns advisory `warnings` alongside the spec. Each carries a `code` (currently `deprecated`) and a `specType` naming the form, so a consumer can surface them without matching prose.","Every block-bodied item accepts an optional `source` block carrying the rule as its author wrote it in the host surface; conflict reports cite that text instead of the engine\u2019s own rendering. See the top-level `source` entry for the block\u2019s shape and which items display it.","The old group-by-field shape, `group: { field, groupOn, addToGroup }`, is removed. It is a parse error, not a silently ignored key, so an old spec fails loudly instead of losing its grouping. Write a `group` whose binary `selector` has the key in its first column and the members in its second; over `worksIn: Employee -> Department`, `groupOn: 1` / `addToGroup: 0` becomes `selector: ~worksIn` plus a `name`, and `groupOn: 0` / `addToGroup: 1` becomes `selector: worksIn`."]},qxt=[...jd.filter(t=>t.deprecated).map(t=>({id:t.id,kind:"item",path:t.yamlKey,...t.deprecated})),...jd.filter(t=>t.deprecatedSections?.length).flatMap(t=>t.deprecatedSections.map(e=>({id:`${t.id}@${e}`,kind:"placement",path:`${e}[].${t.yamlKey}`,replacedBy:`${t.sections[0]}[].${t.yamlKey}`,reason:t.sectionDeprecation.reason,mapping:{[`${e}[].${t.yamlKey}`]:`${t.sections[0]}[].${t.yamlKey}`},warningSpecType:t.sectionDeprecation.warningSpecType}))),...jd.flatMap(t=>t.fields.filter(e=>e.deprecated).map(e=>({id:`${t.id}.${e.name}`,kind:"field",path:`${t.yamlKey}.${e.name}`,replacedBy:`${t.yamlKey}.${e.deprecated.replacedBy}`,reason:e.deprecated.reason??`Superseded by ${e.deprecated.replacedBy}.`,mapping:{[e.name]:e.deprecated.replacedBy},warningSpecType:t.yamlKey})))],zxt={reference:"https://github.com/sidprasad/spytial-core/blob/main/docs/YAML_SPECIFICATION.md",constraints:"https://sidprasad.github.io/spytial-core/#/constraints",directives:"https://sidprasad.github.io/spytial-core/#/directives",selectors:"https://sidprasad.github.io/spytial-core/#/selectors",jsonSchema:"https://cdn.jsdelivr.net/gh/sidprasad/spytial-core@main/docs/spytial-spec.schema.json",manifest:"https://cdn.jsdelivr.net/gh/sidprasad/spytial-core@main/docs/spytial-language.json"};function wG(t){return {language:"spytial-layout-spec",languageVersion:y2,spytialCoreVersion:t,versioning:m2,document:Hxt,hold:Gxt,source:jxt,blocks:AG,items:jd,deprecations:qxt,documentation:zxt}}function CG(){return jd}function NG(t){return jd.find(e=>e.id===t)}function RG(){return AG}var $xt="https://json-schema.org/draft/2020-12/schema",Vxt=t=>`urn:spytial:layout-spec-schema:${t}`,LG={selector:"string",relation:"string",string:"string",color:"string","icon-path":"string",number:"number",integer:"integer",boolean:"boolean"};function IG(t){let e=[t.description];if(t.arity){let n=a=>a.maxColumns===void 0?`${a.minColumns}+ columns`:a.maxColumns===1?"1 column":`${a.maxColumns} columns`,s=t.accepts??[],i=s.find(a=>a.arity===t.arity),r=s.filter(a=>a!==i),o=i?`${t.arity} \u2014 ${n(i)}`:t.arity;e.push(r.length>0?`Selector arity: ${o} (also accepted: ${r.map(a=>a.requires?`${n(a)}, with \`${a.requires}\``:n(a)).join("; ")}).`:`Selector arity: ${o}.`);}return t.default!==void 0&&e.push(`Default when omitted: ${JSON.stringify(t.default)}.`),t.deprecated&&e.push(`Deprecated \u2014 use \`${t.deprecated.replacedBy}\` instead.`),t.note&&e.push(t.note),e.join(" ")}function PG(t){let e={description:IG(t)};switch(t.deprecated&&(e.deprecated=true),t.type){case "enum":e.type="string",e.enum=[...t.values??[]];break;case "enum-list":{e.type="array",e.minItems=1,e.items={type:"string",enum:[...t.values??[]]};let n=[];for(let s of t.listRules?.atMostOneOf??[])n.push({not:{allOf:s.map(i=>({contains:{const:i}}))},description:`At most one of: ${s.join(", ")}.`});for(let[s,i]of Object.entries(t.listRules?.narrowsListTo??{}))n.push({if:{contains:{const:s}},then:{items:{enum:[...i]}},description:`With \`${s}\`, the only other value allowed is ${i.filter(r=>r!==s).join(", ")}.`});n.length>0&&(e.allOf=n);break}case "block":t.block?e.$ref=`#/$defs/${t.block}`:Object.assign(e,P1(t.fields??[]));break;default:{let n=LG[t.type];n&&(e.type=n),n==="string"&&t.required&&(e.minLength=1),t.pattern!==void 0&&(e.pattern=t.pattern);break}}if(t.exclusiveMinimum!==void 0&&(e.exclusiveMinimum=t.exclusiveMinimum),t.minimum!==void 0&&(e.minimum=t.minimum),t.maximum!==void 0&&(e.maximum=t.maximum),t.alternativeForm){let n={...e};delete n.description;let s=t.alternativeForm.type==="block"?{...P1(t.alternativeForm.fields??[]),description:t.alternativeForm.description}:{type:LG[t.alternativeForm.type]??"string"};return {description:IG(t),oneOf:[n,s,{const:true,deprecated:true,description:"Legacy spelling of `togroup`."}]}}return e}function P1(t){let e={};for(let i of t)e[i.name]=PG(i);let n=t.filter(i=>i.required).map(i=>i.name),s={type:"object",properties:e,additionalProperties:false};return n.length>0&&(s.required=n),s}function Yxt(t,e){let n=P1(t.fields);if(t.supportsHold&&(n.properties.hold={type:"string",enum:["always","never"],description:"Negation. `never` asserts the constraint must not hold; `always` (the default) is the positive form."}),e.source.supportedBy.includes(t.id)&&(n.properties.source={$ref:"#/$defs/source",description:e.source.displayedBy.includes(t.id)?"The rule as its author wrote it in the host surface. Cited in conflict reports in place of the engine\u2019s own rendering.":"The rule as its author wrote it in the host surface. Accepted here for uniform generation; not displayed for this item today."}),t.discriminator)if(t.discriminator.present){let s=new Set([...n.required??[],t.discriminator.field]);n.required=[...s];}else n.not={required:[t.discriminator.field]};return t.id==="group"&&(n.required=(n.required??[]).filter(s=>s!=="name"),n.required.length===0&&delete n.required,n.allOf=[{if:{not:{properties:{hold:{const:"never"}},required:["hold"]}},then:{required:["name"]}}]),n}function Wxt(t,e){let n=t.valueShape==="scalar"?PG(t.fields[0]):Yxt(t,e),s={title:t.label,description:t.deprecated?`${t.description} DEPRECATED \u2014 use \`${t.deprecated.replacedBy}\` instead. ${t.deprecated.reason}`:t.description,type:"object",properties:{[t.yamlKey]:n},required:[t.yamlKey],additionalProperties:false};return t.deprecated&&(s.deprecated=true),s}function DG(t,e){let n=t.items.filter(i=>i.sections.includes(e)),s=t.items.filter(i=>i.deprecatedSections?.includes(e));return {type:["array","null"],description:e==="constraints"?"Structural layout: where nodes end up relative to one another.":"Presentation: how nodes and edges look, and what is shown at all.",items:{oneOf:[...n.map(i=>({$ref:`#/$defs/${x2(i)}`})),...s.map(i=>({$ref:`#/$defs/${x2(i)}`,deprecated:true,description:`\`${i.yamlKey}\` here is deprecated \u2014 write it under \`${i.sections[0]}\`. ${i.sectionDeprecation.reason}`}))]}}}function x2(t){return t.id.replace(/\./g,"_")}function kG(t){let e={};for(let n of t.blocks)e[n.name]={description:n.description,...P1(n.fields)};e.source={description:t.source.note,...P1(t.source.fields)};for(let n of t.items)e[x2(n)]=Wxt(n,t);return {$schema:$xt,$id:Vxt(t.languageVersion),title:"Spytial layout specification",description:`A Spytial spec: constraints (structural layout) and directives (presentation). Spec language ${t.languageVersion}, from spytial-core ${t.spytialCoreVersion}. This schema is stricter than the engine parser, which silently ignores anything it does not recognize \u2014 validating here is how a misspelled key or an out-of-range value gets caught at all. Fetch it from https://cdn.jsdelivr.net/gh/sidprasad/spytial-core@<tag>/docs/spytial-spec.schema.json; pin a tag, since the @main path is overwritten each release.`,"x-spytial-language-version":t.languageVersion,"x-spytial-core-version":t.spytialCoreVersion,type:"object",properties:{constraints:DG(t,"constraints"),directives:DG(t,"directives")},additionalProperties:false,$defs:e}}var Xxt=b2.default??b2,Qxt=T2.default??T2;if(typeof window<"u"){let t=window;t.d3||(t.d3=Xxt),t.cola||(t.cola=Qxt),Promise.resolve().then(()=>(QE(),$U)).then(({WebColaCnDGraph:e})=>(typeof customElements<"u"&&!customElements.get("webcola-cnd-graph")&&customElements.define("webcola-cnd-graph",e),Promise.resolve().then(()=>(LN(),YU)).then(({StructuredInputGraph:n})=>{typeof customElements<"u"&&!customElements.get("structured-input-graph")&&customElements.define("structured-input-graph",n);}))).catch(console.error);}var Jxt="6.5.0",_2=class{constructor(e={}){this.config={debug:false,version:Jxt,...e};}init(){this.config.debug;}getConfig(){return {...this.config}}updateConfig(e){this.config={...this.config,...e};}},l4t=t=>new _2(t);/*! Bundled license information:
|
|
1648
1648
|
|
|
1649
1649
|
forge-expr-evaluator/dist/forge-expr-evaluator.bundle.js:
|
|
1650
1650
|
(*! For license information please see forge-expr-evaluator.bundle.js.LICENSE.txt *)
|
|
@@ -298,7 +298,7 @@ A case document is JSON or YAML holding one case, an array of cases, or
|
|
|
298
298
|
Exit codes: 0 all passed, 1 some failed, 2 bad usage or unreadable input,
|
|
299
299
|
3 timed out.
|
|
300
300
|
|
|
301
|
-
Docs: https://sidprasad.github.io/spytial-core/#/testing-integrations`,Ut=class extends Error{},cD=300;function uD(e){let t={paths:[],readStdin:false,pretty:false,quiet:false,timeoutSeconds:cD};for(let s=0;s<e.length;s++){let o=e[s];switch(o){case "--pretty":t.pretty=true;break;case "--quiet":t.quiet=true;break;case "-":t.readStdin=true;break;case "--timeout":{let r=e[++s];if(r===void 0)throw new Ut("--timeout needs a value in seconds.");let n=Number(r);if(!Number.isFinite(n)||n<0)throw new Ut(`--timeout needs a non-negative number of seconds, got "${r}".`);t.timeoutSeconds=n;break}default:if(o.startsWith("-"))throw new Ut(`Unknown option "${o}".`);t.paths.push(o);}}if(t.paths.length===0&&!t.readStdin)throw new Ut("No case files given.");return t}function C0(){return "6.
|
|
301
|
+
Docs: https://sidprasad.github.io/spytial-core/#/testing-integrations`,Ut=class extends Error{},cD=300;function uD(e){let t={paths:[],readStdin:false,pretty:false,quiet:false,timeoutSeconds:cD};for(let s=0;s<e.length;s++){let o=e[s];switch(o){case "--pretty":t.pretty=true;break;case "--quiet":t.quiet=true;break;case "-":t.readStdin=true;break;case "--timeout":{let r=e[++s];if(r===void 0)throw new Ut("--timeout needs a value in seconds.");let n=Number(r);if(!Number.isFinite(n)||n<0)throw new Ut(`--timeout needs a non-negative number of seconds, got "${r}".`);t.timeoutSeconds=n;break}default:if(o.startsWith("-"))throw new Ut(`Unknown option "${o}".`);t.paths.push(o);}}if(t.paths.length===0&&!t.readStdin)throw new Ut("No case files given.");return t}function C0(){return "6.5.0"}function hD(e){let t;try{t=fs$1.statSync(e);}catch{throw new Ut(`Cannot read "${e}".`)}if(t.isFile())return [e];if(t.isDirectory()){let s=fs$1.readdirSync(e).filter(o=>lD.has(path.extname(o).toLowerCase())).map(o=>path.join(e,o)).filter(o=>fs$1.statSync(o).isFile()).sort();if(s.length===0)throw new Ut(`No .json/.yaml/.yml case files in "${e}".`);return s}throw new Ut(`"${e}" is neither a file nor a directory.`)}function pD(){try{return fs$1.readFileSync(0,"utf8")}catch{throw new Ut("Could not read stdin.")}}function A0(e,t){let s;try{s=_i.load(e);}catch(r){throw new Ut(`${t} is not valid JSON or YAML: ${r instanceof Error?r.message:String(r)}`)}let o=Oa(s);if(o.length===0)throw new Ut(`${t} holds no cases.`);return o}function dD(e){let t=[`${e.ok?"PASS":"FAIL"} ${e.name}`];for(let s of e.errors)t.push(` error [${s.code}] ${s.message}`),s.where&&t.push(` at ${s.where}`);for(let s of e.warnings)t.push(` warn [${s.code}] ${s.message}`),s.where&&t.push(` at ${s.where}`);for(let s of e.assertions.filter(o=>!o.ok))t.push(` failed ${s.query}`),t.push(` ${s.message}`),s.because&&t.push(` because: ${s.because}`);return t.join(`
|
|
302
302
|
`)}function fD(e,t){let o=(t?e.cases.filter(r=>!r.ok):e.cases).map(dD);return o.push(""),o.push(`${e.passed} passed, ${e.failed} failed (spytial-core ${e.spytialCoreVersion})`),o.join(`
|
|
303
303
|
`)}function gD(e){let t=process.stdout.write.bind(process.stdout);process.stdout.write=((s,...o)=>process.stderr.write(s,...o));try{return e()}finally{process.stdout.write=t;}}var R0="SPYTIAL_CHECK_SUPERVISED",mD=3;function yD(){return process.env[R0]!=="1"&&true&&typeof __filename=="string"&&fs$1.existsSync(__filename)}function xD(e,t,s){let o=child_process.spawnSync(process.execPath,[__filename,...e,"--timeout","0"],{input:s??"",encoding:"utf8",timeout:t*1e3,maxBuffer:268435456,env:{...process.env,[R0]:"1"}});return o.stdout&&process.stdout.write(o.stdout),o.stderr&&process.stderr.write(o.stderr),o.signal!==null||o.error?.code==="ETIMEDOUT"?(process.stderr.write(`spytial-check: gave up after ${t}s. A case is taking far longer than layout normally does \u2014 most likely a selector that does not terminate on this datum. Raise the limit with --timeout <seconds>, or disable it with --timeout 0.
|
|
304
304
|
`),mD):o.error?(process.stderr.write(`spytial-check: ${o.error.message}
|
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
.spytial-ed{font-family:var( --spytial-ed-font-family, "Avenir Next", "Avenir", "Seravek", "Segoe UI Variable", "Segoe UI", "Trebuchet MS", sans-serif );font-size:var(--spytial-ed-font-size, 14px);color:var(--spytial-ed-text, #221d14);--spytial-ed-gap: var(--spytial-ed-spacing, 8px);--spytial-ed-radius-sm: var(--spytial-ed-radius, 2px);--spytial-ed-chrome-font: var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace )}.spytial-ed *,.spytial-ed *:before,.spytial-ed *:after{box-sizing:border-box}.spytial-ed--compact{font-size:calc(var(--spytial-ed-font-size, 14px) - 1px);--spytial-ed-gap: calc(var(--spytial-ed-spacing, 8px) * .625)}@keyframes spytial-ed-pop{0%{opacity:0;transform:translateY(-3px) scale(.99)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes spytial-ed-unfold{0%{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:translateY(0)}}.spytial-ed-fields{display:flex;flex-direction:column;gap:var(--spytial-ed-gap, 8px);width:100%}.spytial-ed-field{display:grid;grid-template-columns:minmax(7rem,9rem) 1fr;align-items:start;gap:var(--spytial-ed-gap, 8px)}.spytial-ed--compact .spytial-ed-field{grid-template-columns:minmax(6rem,8rem) 1fr}.spytial-ed-field-label{font-family:var(--spytial-ed-chrome-font);font-size:.72em;font-weight:600;text-transform:uppercase;letter-spacing:.09em;color:var(--spytial-ed-text-muted, #6e6553);padding-top:.55em;line-height:1.3;cursor:default;user-select:none}.spytial-ed-field-required{color:var(--spytial-ed-danger, #a32014);font-weight:700}.spytial-ed-field-control{display:flex;flex-direction:column;gap:.25em;min-width:0}.spytial-ed-input{width:100%;font-family:inherit;font-size:inherit;color:var(--spytial-ed-text, #221d14);background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .55em;line-height:1.4;transition:border-color .15s ease,box-shadow .15s ease}.spytial-ed--compact .spytial-ed-input{padding:.3em .45em}.spytial-ed-input::placeholder{color:var(--spytial-ed-text-muted, #6e6553);opacity:.65}.spytial-ed-input:focus,.spytial-ed-input:focus-visible{outline:none;border-color:var(--spytial-ed-accent, #b5431a);box-shadow:0 0 0 2px color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 20%,transparent)}.spytial-ed-input:disabled{background:var(--spytial-ed-surface-raised, #f1ecdf);color:var(--spytial-ed-text-muted, #6e6553);cursor:not-allowed}.spytial-ed-input--number{width:8rem}.spytial-ed-input[aria-invalid=true]{border-color:var(--spytial-ed-danger, #a32014)}.spytial-ed-color{display:flex;align-items:center;gap:var(--spytial-ed-gap, 8px)}.spytial-ed-color-swatch{inline-size:2rem;block-size:2rem;padding:0;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);background:var(--spytial-ed-surface, #faf8f2);cursor:pointer}.spytial-ed-color-swatch:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:1px}.spytial-ed-color-text{width:9rem;font-family:var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace )}.spytial-ed-pills{display:flex;flex-wrap:wrap;gap:.3em}.spytial-ed-pill{font-family:var(--spytial-ed-chrome-font);font-size:.8em;color:var(--spytial-ed-text, #221d14);background:transparent;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.28em .65em;cursor:pointer;transition:background .15s ease,border-color .15s ease,color .15s ease,transform .1s ease}.spytial-ed-pill:hover:not(:disabled){border-color:var(--spytial-ed-accent, #b5431a);color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-pill:active:not(:disabled){transform:translateY(1px)}.spytial-ed-pill:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:1px}.spytial-ed-pill--active{background:var(--spytial-ed-accent, #b5431a);border-color:var(--spytial-ed-accent, #b5431a);color:var(--spytial-ed-accent-text, #fdf6ec);font-weight:600}.spytial-ed-pill--active:hover:not(:disabled){color:var(--spytial-ed-accent-text, #fdf6ec)}.spytial-ed-pill--negated{background:var(--spytial-ed-danger, #a32014);border-color:var(--spytial-ed-danger, #a32014)}.spytial-ed-pill--negated:hover:not(:disabled){border-color:var(--spytial-ed-danger, #a32014)}.spytial-ed-pill:disabled{opacity:.55;cursor:not-allowed}.spytial-ed-switch{position:relative;inline-size:2.4rem;block-size:1.35rem;padding:0;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:999px;background:var(--spytial-ed-surface-raised, #f1ecdf);cursor:pointer;transition:background .15s ease,border-color .15s ease}.spytial-ed-switch-thumb{position:absolute;top:50%;left:.18rem;transform:translateY(-50%);inline-size:.95rem;block-size:.95rem;border-radius:50%;background:var(--spytial-ed-surface, #faf8f2);box-shadow:0 1px 2px #00000040;transition:left .15s ease}.spytial-ed-switch--on{background:var(--spytial-ed-accent, #b5431a);border-color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-switch--on .spytial-ed-switch-thumb{left:calc(100% - 1.13rem)}.spytial-ed-switch:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:2px}.spytial-ed-switch:disabled{opacity:.55;cursor:not-allowed}.spytial-ed-selector{display:flex;flex-direction:column;gap:.25em;width:100%}.spytial-ed-selector-input-wrap{position:relative;width:100%;background:var(--spytial-ed-surface, #faf8f2);border-radius:var(--spytial-ed-radius-sm, 2px)}.spytial-ed-selector-textarea,.spytial-ed-selector-mirror{margin:0;font-family:var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace );font-size:.95em;line-height:1.5;letter-spacing:normal;word-spacing:normal;font-variant-ligatures:none;font-feature-settings:normal;font-kerning:none;hyphens:none;text-rendering:auto;tab-size:2;padding:.4em .55em;border:1px solid transparent;border-radius:var(--spytial-ed-radius-sm, 2px);white-space:pre-wrap;word-break:break-word;overflow-wrap:break-word}.spytial-ed--compact .spytial-ed-selector-textarea,.spytial-ed--compact .spytial-ed-selector-mirror{padding:.3em .45em}.spytial-ed-selector-input-wrap--with-synth .spytial-ed-selector-textarea,.spytial-ed-selector-input-wrap--with-synth .spytial-ed-selector-mirror{padding-right:2.3em}.spytial-ed-selector-mirror{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;color:var(--spytial-ed-text, #221d14);background:transparent}.spytial-ed-selector-textarea{position:relative;z-index:1;display:block;width:100%;min-height:2.2em;resize:none;overflow:hidden;background:transparent;border-color:var(--spytial-ed-border, #d9d2c0);color:transparent;caret-color:var(--spytial-ed-accent, #b5431a);transition:border-color .15s ease,box-shadow .15s ease}.spytial-ed-selector-textarea::placeholder{color:var(--spytial-ed-text-muted, #6e6553);opacity:.65}.spytial-ed-selector-textarea::selection{background:color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 26%,transparent)}.spytial-ed-selector-textarea:focus,.spytial-ed-selector-textarea:focus-visible{outline:none;border-color:var(--spytial-ed-accent, #b5431a);box-shadow:0 0 0 2px color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 20%,transparent)}.spytial-ed-selector-textarea:disabled{cursor:not-allowed}.spytial-ed-selector-input-wrap:has(.spytial-ed-selector-textarea:disabled){background:var(--spytial-ed-surface-raised, #f1ecdf)}.spytial-ed-selector-textarea--plain{color:var(--spytial-ed-text, #221d14)}.spytial-ed-selector--error .spytial-ed-selector-textarea{border-color:var(--spytial-ed-danger, #a32014);box-shadow:inset 0 -2px 0 var(--spytial-ed-danger, #a32014)}.spytial-ed-selector--warning .spytial-ed-selector-textarea{border-color:var(--spytial-ed-warning, #8a6200);box-shadow:inset 0 -2px 0 var(--spytial-ed-warning, #8a6200)}.spytial-ed-syn-keyword{color:var(--spytial-ed-syn-keyword, #6d28a8);font-weight:600}.spytial-ed-syn-type{color:var(--spytial-ed-syn-type, #0e6b6b)}.spytial-ed-syn-relation,.spytial-ed-syn-identifier{color:var(--spytial-ed-syn-relation, #1f4f9e)}.spytial-ed-syn-operator{color:var(--spytial-ed-syn-operator, #b5431a)}.spytial-ed-syn-string{color:var(--spytial-ed-syn-string, #7a5901)}.spytial-ed-syn-number{color:var(--spytial-ed-syn-type, #0e6b6b)}.spytial-ed-syn-comment{color:var(--spytial-ed-syn-comment, #8a8170);font-style:italic}.spytial-ed-selector-synth-btn{position:absolute;top:.25em;right:.25em;z-index:2;inline-size:1.7em;block-size:1.7em;display:inline-flex;align-items:center;justify-content:center;padding:0;font-size:.95em;line-height:1;background:var(--spytial-ed-surface-raised, #f1ecdf);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);cursor:pointer;transition:border-color .15s ease,background .15s ease,transform .12s ease}.spytial-ed-selector-synth-btn:hover:not(:disabled){border-color:var(--spytial-ed-accent, #b5431a);transform:rotate(-8deg)}.spytial-ed-selector-synth-btn:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:1px}.spytial-ed-selector-synth-btn:disabled{opacity:.5;cursor:not-allowed}.spytial-ed-autocomplete{position:fixed;z-index:1000;margin:0;padding:.2em;list-style:none;overflow-y:auto;background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px);box-shadow:0 1px color-mix(in srgb,var(--spytial-ed-text, #221d14) 8%,transparent),0 8px 24px color-mix(in srgb,var(--spytial-ed-text, #221d14) 18%,transparent);animation:spytial-ed-pop .12s ease-out}.spytial-ed-autocomplete-item{display:flex;align-items:center;gap:.5em;padding:.3em .5em;border-radius:var(--spytial-ed-radius-sm, 2px);cursor:pointer;font-size:.9em}.spytial-ed-autocomplete-item--active{background:color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 14%,transparent)}.spytial-ed-autocomplete-kind{inline-size:.6em;block-size:.6em;border-radius:1px;flex:0 0 auto;background:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-kind-type{background:var(--spytial-ed-syn-type, #0e6b6b)}.spytial-ed-kind-relation{background:var(--spytial-ed-syn-relation, #1f4f9e)}.spytial-ed-kind-atom{background:var(--spytial-ed-syn-string, #7a5901)}.spytial-ed-kind-keyword{background:var(--spytial-ed-syn-keyword, #6d28a8)}.spytial-ed-kind-snippet{background:var(--spytial-ed-success, #2f6c43)}.spytial-ed-autocomplete-label{font-family:var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace );color:var(--spytial-ed-text, #221d14)}.spytial-ed-autocomplete-detail{margin-left:auto;font-size:.85em;color:var(--spytial-ed-text-muted, #6e6553);white-space:nowrap}.spytial-ed-synth-popover{margin-top:.3em;padding:var(--spytial-ed-gap, 8px);background:var(--spytial-ed-surface-raised, #f1ecdf);border:1px solid var(--spytial-ed-border, #d9d2c0);border-left:3px solid var(--spytial-ed-accent, #b5431a);border-radius:var(--spytial-ed-radius, 2px);display:flex;flex-direction:column;gap:var(--spytial-ed-gap, 8px);animation:spytial-ed-unfold .14s ease-out}.spytial-ed-synth-row{display:flex;gap:.4em}.spytial-ed-synth-input{flex:1 1 auto;min-width:0;font-family:inherit;font-size:.9em;color:var(--spytial-ed-text, #221d14);background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .55em}.spytial-ed-synth-input:focus-visible{outline:none;border-color:var(--spytial-ed-accent, #b5431a);box-shadow:0 0 0 2px color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 20%,transparent)}.spytial-ed-synth-generate,.spytial-ed-synth-accept{font-family:var(--spytial-ed-chrome-font);font-size:.82em;font-weight:600;color:var(--spytial-ed-accent-text, #fdf6ec);background:var(--spytial-ed-accent, #b5431a);border:1px solid var(--spytial-ed-accent, #b5431a);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .8em;cursor:pointer;white-space:nowrap;transition:filter .15s ease,transform .1s ease}.spytial-ed-synth-generate:hover:not(:disabled),.spytial-ed-synth-accept:hover:not(:disabled){filter:brightness(1.08)}.spytial-ed-synth-generate:active:not(:disabled),.spytial-ed-synth-accept:active:not(:disabled){transform:translateY(1px)}.spytial-ed-synth-generate:disabled{opacity:.5;cursor:not-allowed}.spytial-ed-synth-dismiss{font-family:var(--spytial-ed-chrome-font);font-size:.82em;color:var(--spytial-ed-text, #221d14);background:transparent;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .8em;cursor:pointer}.spytial-ed-synth-generate:focus-visible,.spytial-ed-synth-accept:focus-visible,.spytial-ed-synth-dismiss:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:1px}.spytial-ed-synth-error{color:var(--spytial-ed-danger, #a32014);font-size:.85em}.spytial-ed-synth-result{display:flex;flex-direction:column;gap:.4em}.spytial-ed-synth-preview{margin:0;padding:.4em .55em;font-family:var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace );font-size:.9em;line-height:1.5;background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);white-space:pre-wrap;word-break:break-word;color:var(--spytial-ed-text, #221d14)}.spytial-ed-synth-explanation{margin:0;font-size:.85em;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-synth-actions{display:flex;gap:.4em}.spytial-ed-diagnostics{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.1em}.spytial-ed-diagnostic{display:flex;align-items:baseline;gap:.4em;font-size:.8em;line-height:1.35;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.spytial-ed-diagnostics--item{gap:.2em}.spytial-ed-diagnostics--item .spytial-ed-diagnostic{white-space:normal;overflow:visible}.spytial-ed-diagnostics--item .spytial-ed-diagnostic-msg{overflow:visible;text-overflow:clip}.spytial-ed-diagnostic-dot{flex:0 0 auto;inline-size:.5em;block-size:.5em;border-radius:50%;align-self:center}.spytial-ed-diagnostic-msg{min-width:0;overflow:hidden;text-overflow:ellipsis}.spytial-ed-diagnostic--error{color:var(--spytial-ed-danger, #a32014)}.spytial-ed-diagnostic--error .spytial-ed-diagnostic-dot{background:var(--spytial-ed-danger, #a32014)}.spytial-ed-diagnostic--warning{color:var(--spytial-ed-warning, #8a6200)}.spytial-ed-diagnostic--warning .spytial-ed-diagnostic-dot{background:var(--spytial-ed-warning, #8a6200)}.spytial-ed-diagnostic--info{color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-diagnostic--info .spytial-ed-diagnostic-dot{background:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-diagnostic-badge{display:inline-flex;align-items:center;justify-content:center;min-inline-size:.9em;block-size:.9em;padding:0 .2em;margin-inline-start:.4em;border-radius:999px;font-size:.7em;font-weight:700;line-height:1;color:#fff;background:var(--spytial-ed-danger, #a32014)}.spytial-ed-diagnostic-badge--warning{background:var(--spytial-ed-warning, #8a6200)}.spytial-ed-diagnostic-badge--info{background:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed{display:block;background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px)}.spytial-ed-toolbar{display:flex;align-items:center;justify-content:space-between;gap:var(--spytial-ed-gap, 8px);padding:calc(var(--spytial-ed-gap, 8px) * .75) var(--spytial-ed-gap, 8px);background:var(--spytial-ed-surface-raised, #f1ecdf);border-bottom:1px solid var(--spytial-ed-border, #d9d2c0)}.spytial-ed-viewtoggle{display:inline-flex;gap:var(--spytial-ed-gap, 8px)}.spytial-ed-viewtoggle-btn{position:relative;display:inline-flex;align-items:center;font-family:var(--spytial-ed-chrome-font);font-size:.78em;font-weight:600;text-transform:uppercase;letter-spacing:.09em;color:var(--spytial-ed-text-muted, #6e6553);background:transparent;border:none;padding:.3em .15em;cursor:pointer;transition:color .15s ease}.spytial-ed-viewtoggle-btn:after{content:"";position:absolute;left:0;right:100%;bottom:-2px;height:2px;background:var(--spytial-ed-accent, #b5431a);transition:right .18s ease}.spytial-ed-viewtoggle-btn:hover:not(:disabled){color:var(--spytial-ed-text, #221d14)}.spytial-ed-viewtoggle-btn--active{color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-viewtoggle-btn--active:after{right:0}.spytial-ed-viewtoggle-btn:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:2px}.spytial-ed-viewtoggle-btn:disabled{opacity:.55;cursor:not-allowed}.spytial-ed-toolbar-actions{display:inline-flex;align-items:center;gap:var(--spytial-ed-gap, 8px)}.spytial-ed-history{display:inline-flex;gap:4px}.spytial-ed-suggest-btn{display:inline-flex;align-items:center;gap:.35em;font-family:var(--spytial-ed-chrome-font);font-size:.78em;font-weight:600;text-transform:uppercase;letter-spacing:.09em;color:var(--spytial-ed-accent, #b5431a);background:transparent;border:1px solid var(--spytial-ed-accent, #b5431a);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.3em .7em;cursor:pointer;white-space:nowrap;transition:background .15s ease,color .15s ease}.spytial-ed-suggest-btn:hover:not(:disabled){color:var(--spytial-ed-accent-text, #fdf6ec);background:var(--spytial-ed-accent, #b5431a)}.spytial-ed-suggest-btn:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:2px}.spytial-ed-suggest-btn:disabled{opacity:.5;cursor:not-allowed}.spytial-ed-suggest-error{margin:0;padding:calc(var(--spytial-ed-gap, 8px) * .75) var(--spytial-ed-gap, 8px);font-size:.85em;color:var(--spytial-ed-danger, #a32014);background:color-mix(in srgb,var(--spytial-ed-danger, #a32014) 8%,transparent);border-bottom:1px solid var(--spytial-ed-border, #d9d2c0)}.spytial-ed-suggestions{padding:calc(var(--spytial-ed-gap, 8px) * .75) var(--spytial-ed-gap, 8px);background:var(--spytial-ed-surface-raised, #f1ecdf);border-bottom:1px solid var(--spytial-ed-border, #d9d2c0);border-left:3px solid var(--spytial-ed-accent, #b5431a);animation:spytial-ed-unfold .14s ease-out}.spytial-ed-suggestions-head{display:flex;align-items:center;justify-content:space-between;gap:var(--spytial-ed-gap, 8px)}.spytial-ed-suggestions-title{font-family:var(--spytial-ed-chrome-font);font-size:.74em;font-weight:600;text-transform:uppercase;letter-spacing:.09em;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-suggestions-dismiss{font:inherit;font-size:1.05em;line-height:1;color:var(--spytial-ed-text-muted, #6e6553);background:transparent;border:none;padding:0 .2em;cursor:pointer}.spytial-ed-suggestions-dismiss:hover{color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-suggestions-dismiss:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:1px}.spytial-ed-suggestions-list,.spytial-ed-suggestions-notes{list-style:none;margin:calc(var(--spytial-ed-gap, 8px) * .5) 0 0;padding:0;display:flex;flex-direction:column;gap:calc(var(--spytial-ed-gap, 8px) * .5)}.spytial-ed-suggestions-notes{font-size:.82em;color:var(--spytial-ed-text-muted, #6e6553);border-top:1px solid var(--spytial-ed-border, #d9d2c0);padding-top:calc(var(--spytial-ed-gap, 8px) * .5)}.spytial-ed-suggestion--omitted{opacity:.62}.spytial-ed-suggestion-head{display:flex;align-items:baseline;flex-wrap:wrap;gap:.4em}.spytial-ed-suggestion-text{flex:1 1 12em;font-size:.88em;color:var(--spytial-ed-text, #221d14)}.spytial-ed-suggestion-id{display:block;margin-top:.15em;font-family:var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace );font-size:.74em;color:var(--spytial-ed-text-muted, #6e6553);word-break:break-all}.spytial-ed-suggestion-chip{font-family:var(--spytial-ed-chrome-font);font-size:.66em;font-weight:600;text-transform:uppercase;letter-spacing:.07em;border:1px solid currentColor;border-radius:var(--spytial-ed-radius-sm, 2px);padding:.15em .4em;white-space:nowrap;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-suggestion-chip--high,.spytial-ed-suggestion-chip--applied{color:var(--spytial-ed-success, #2f6c43)}.spytial-ed-suggestion-chip--medium,.spytial-ed-suggestion-chip--weakened{color:var(--spytial-ed-warning, #8a6200)}.spytial-ed-suggestion-chip--omitted{color:var(--spytial-ed-danger, #a32014)}.spytial-ed-history-btn{font:inherit;font-size:1.05em;line-height:1;color:var(--spytial-ed-text, #221d14);background:transparent;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.2em .45em;cursor:pointer;transition:border-color .15s ease,color .15s ease}.spytial-ed-history-btn:hover:not(:disabled){border-color:var(--spytial-ed-accent, #b5431a);color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-history-btn:disabled{opacity:.4;cursor:not-allowed}.spytial-ed-body{padding:var(--spytial-ed-gap, 8px)}.spytial-ed-builder{display:flex;flex-direction:column;gap:calc(var(--spytial-ed-gap, 8px) * 1.25)}.spytial-ed-section-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:calc(var(--spytial-ed-gap, 8px) * .5)}.spytial-ed-section-title{margin:0;font-family:var(--spytial-ed-chrome-font);font-size:.72em;font-weight:700;text-transform:uppercase;letter-spacing:.14em;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-rows{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px}.spytial-ed-row{border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px);background:var(--spytial-ed-surface, #faf8f2);transition:border-color .15s ease}.spytial-ed-row:hover{border-color:color-mix(in srgb,var(--spytial-ed-text-muted, #6e6553) 55%,var(--spytial-ed-border, #d9d2c0))}.spytial-ed-row--expanded{border-color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-row--error{border-left:3px solid var(--spytial-ed-danger, #a32014)}.spytial-ed-row--warning{border-left:3px solid var(--spytial-ed-warning, #8a6200)}.spytial-ed-row-main{display:flex;align-items:center;gap:4px}.spytial-ed-row-toggle{flex:1 1 auto;display:flex;align-items:center;gap:.55em;min-width:0;font:inherit;text-align:left;color:inherit;background:transparent;border:none;cursor:pointer;padding:calc(var(--spytial-ed-gap, 8px) * .55) var(--spytial-ed-gap, 8px)}.spytial-ed--compact .spytial-ed-row-toggle{padding:calc(var(--spytial-ed-gap, 8px) * .4) calc(var(--spytial-ed-gap, 8px) * .75)}.spytial-ed-row-type{font-family:var(--spytial-ed-chrome-font);font-size:.88em;font-weight:600;flex:0 0 auto}.spytial-ed-row-negated{color:var(--spytial-ed-danger, #a32014);font-weight:700;flex:0 0 auto}.spytial-ed-row-summary{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.85em;color:var(--spytial-ed-text-muted, #6e6553);font-family:var(--spytial-ed-mono-font-family, ui-monospace, monospace)}.spytial-ed-row-summary--muted{font-style:italic;font-family:inherit}.spytial-ed-row-dot{flex:0 0 auto;inline-size:.55em;block-size:.55em;border-radius:50%;background:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-row-dot--error{background:var(--spytial-ed-danger, #a32014)}.spytial-ed-row-dot--warning{background:var(--spytial-ed-warning, #8a6200)}.spytial-ed-row-panel{padding:var(--spytial-ed-gap, 8px);border-top:1px solid var(--spytial-ed-border, #d9d2c0);background:var(--spytial-ed-surface-raised, #f1ecdf);display:flex;flex-direction:column;gap:var(--spytial-ed-gap, 8px);animation:spytial-ed-unfold .14s ease-out}.spytial-ed-row--unknown{background:var(--spytial-ed-surface-raised, #f1ecdf)}.spytial-ed-row--unknown .spytial-ed-row-main{padding:calc(var(--spytial-ed-gap, 8px) * .55) var(--spytial-ed-gap, 8px);gap:.55em}.spytial-ed-builder-empty{margin:0;font-size:.9em;color:var(--spytial-ed-text-muted, #6e6553);font-style:italic}.spytial-ed-overflow{position:relative;flex:0 0 auto;margin-inline-end:4px}.spytial-ed-overflow-btn{font:inherit;font-size:1.1em;line-height:1;color:var(--spytial-ed-text-muted, #6e6553);background:transparent;border:none;border-radius:var(--spytial-ed-radius-sm, 2px);padding:.1em .4em;cursor:pointer}.spytial-ed-overflow-btn:hover{background:var(--spytial-ed-border, #d9d2c0)}.spytial-ed-overflow-btn:disabled{opacity:.4;cursor:not-allowed}.spytial-ed-overflow-menu,.spytial-ed-add-menu{position:fixed;z-index:1000;min-inline-size:10rem;background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px);box-shadow:0 1px color-mix(in srgb,var(--spytial-ed-text, #221d14) 8%,transparent),0 8px 24px color-mix(in srgb,var(--spytial-ed-text, #221d14) 18%,transparent);padding:4px;animation:spytial-ed-pop .12s ease-out}.spytial-ed-overflow-menu{list-style:none;margin:0;overflow-y:auto}.spytial-ed-overflow-item,.spytial-ed-add-item{display:block;inline-size:100%;font:inherit;font-size:.88em;text-align:left;color:var(--spytial-ed-text, #221d14);background:transparent;border:none;border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .6em;cursor:pointer}.spytial-ed-overflow-item:hover:not(:disabled),.spytial-ed-add-item:hover{background:var(--spytial-ed-surface-raised, #f1ecdf)}.spytial-ed-overflow-item:disabled{opacity:.4;cursor:not-allowed}.spytial-ed-overflow-item--danger{color:var(--spytial-ed-danger, #a32014)}.spytial-ed-add{position:relative}.spytial-ed-add-btn{font-family:var(--spytial-ed-chrome-font);font-size:.78em;font-weight:600;color:var(--spytial-ed-accent, #b5431a);background:transparent;border:1px solid var(--spytial-ed-accent, #b5431a);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.28em .6em;cursor:pointer;transition:background .15s ease,color .15s ease,transform .1s ease}.spytial-ed-add-btn:hover:not(:disabled){background:var(--spytial-ed-accent, #b5431a);color:var(--spytial-ed-accent-text, #fdf6ec)}.spytial-ed-add-btn:active:not(:disabled){transform:translateY(1px)}.spytial-ed-add-btn:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:2px}.spytial-ed-add-btn:disabled{opacity:.5;cursor:not-allowed}.spytial-ed-add-menu{display:flex;flex-direction:column;min-inline-size:15rem}.spytial-ed-add-search{inline-size:100%;flex:0 0 auto;font:inherit;font-size:.85em;color:var(--spytial-ed-text, #221d14);background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.35em .5em;margin-bottom:4px}.spytial-ed-add-search:focus-visible{outline:none;border-color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-add-list{list-style:none;margin:0;padding:0;flex:1 1 auto;min-block-size:0;overflow-y:auto}.spytial-ed-add-item{display:flex;flex-direction:column;gap:1px}.spytial-ed-add-item-label{font-family:var(--spytial-ed-chrome-font);font-size:.95em;font-weight:600}.spytial-ed-add-item-desc{font-size:.78em;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-add-empty{font-size:.85em;color:var(--spytial-ed-text-muted, #6e6553);padding:.4em .6em}.spytial-ed-code{display:flex;flex-direction:column;gap:var(--spytial-ed-gap, 8px)}.spytial-ed-code-notice{font-size:.82em;color:var(--spytial-ed-warning, #8a6200);background:color-mix(in srgb,var(--spytial-ed-warning, #8a6200) 10%,transparent);border:1px solid var(--spytial-ed-warning, #8a6200);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .6em}.spytial-ed-code-cm{display:block}.spytial-ed-code-cm .cm-editor{max-height:32rem}.spytial-ed-code-cm--disabled{opacity:.65}.spytial-ed-code-editor{display:flex;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px);background:var(--spytial-ed-surface, #faf8f2);overflow:hidden}.spytial-ed-code-gutter{flex:0 0 auto;overflow:hidden;text-align:right;user-select:none;padding:.5em .4em;color:var(--spytial-ed-text-muted, #6e6553);background:var(--spytial-ed-surface-raised, #f1ecdf);border-inline-end:1px solid var(--spytial-ed-border, #d9d2c0);font-family:var(--spytial-ed-mono-font-family, ui-monospace, monospace);font-size:.85em;line-height:1.5}.spytial-ed-code-gutter-line{min-inline-size:1.6em}.spytial-ed-code-input-wrap{position:relative;flex:1 1 auto;min-width:0;display:flex}.spytial-ed-code-textarea,.spytial-ed-code-mirror{margin:0;font-family:var(--spytial-ed-mono-font-family, ui-monospace, monospace);font-size:.85em;line-height:1.5;letter-spacing:normal;word-spacing:normal;font-variant-ligatures:none;font-feature-settings:normal;font-kerning:none;hyphens:none;text-rendering:auto;padding:.5em .6em;border:none;white-space:pre;overflow-wrap:normal;tab-size:2}.spytial-ed-code-mirror{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;color:var(--spytial-ed-text, #221d14);background:transparent}.spytial-ed-code-textarea{position:relative;z-index:1;flex:1 1 auto;width:100%;resize:vertical;min-block-size:12rem;color:transparent;caret-color:var(--spytial-ed-accent, #b5431a);background:transparent;outline:none}.spytial-ed-code-textarea::selection{background:color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 26%,transparent)}.spytial-ed-code-textarea:disabled{opacity:.6}.spytial-ed-code-textarea--plain{color:var(--spytial-ed-text, #221d14)}.spytial-ed-code-textarea:disabled+.spytial-ed-code-mirror,.spytial-ed-code-input-wrap:has(.spytial-ed-code-textarea:disabled) .spytial-ed-code-mirror{opacity:.6}.spytial-ed-code-diagnostics{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}.spytial-ed-code-diagnostic-loc{font-family:var(--spytial-ed-mono-font-family, ui-monospace, monospace);font-size:.85em;color:var(--spytial-ed-text-muted, #6e6553);flex:0 0 auto}@media(prefers-reduced-motion:reduce){.spytial-ed *,.spytial-ed *:before,.spytial-ed *:after,.spytial-ed-autocomplete,.spytial-ed-overflow-menu,.spytial-ed-add-menu,.spytial-ed-synth-popover,.spytial-ed-row-panel{animation:none!important;transition:none!important}}.spytial-ed-group{border:1px solid var(--spytial-ed-border, #d0d7de);border-radius:6px;padding:.25rem .6rem .4rem;margin:.25rem 0;min-inline-size:0}.spytial-ed-group-legend{display:inline-flex;align-items:center;gap:.35rem;padding-inline:.3rem;font-size:.78rem;font-weight:600;color:var(--spytial-ed-muted, #656d76)}.spytial-ed-group-remove{border:none;background:transparent;cursor:pointer;font-size:1rem;line-height:1;padding:0 .15rem;color:var(--spytial-ed-muted, #656d76)}.spytial-ed-group-remove:hover{color:var(--spytial-ed-danger, #cf222e)}.spytial-ed-group-add{align-self:flex-start;border:1px dashed var(--spytial-ed-border, #d0d7de);border-radius:6px;background:transparent;cursor:pointer;padding:.3rem .6rem;margin:.15rem 0;font-size:.78rem;color:var(--spytial-ed-accent, #0969da)}.spytial-ed-group-add:hover{background:var(--spytial-ed-hover, #f6f8fa)}.spytial-ed-icon{position:relative;width:100%}.spytial-ed-icon-row{display:flex;align-items:center;gap:.35rem}.spytial-ed-icon-preview,.spytial-ed-icon-cell-glyph{display:inline-flex;flex:0 0 auto;color:var(--spytial-ed-text, #221d14)}.spytial-ed-icon-preview svg{inline-size:1.15rem;block-size:1.15rem}.spytial-ed-icon-cell-glyph svg{inline-size:1.35rem;block-size:1.35rem}.spytial-ed-icon-btn{flex:0 0 auto;cursor:pointer;padding:.3em .5em;line-height:1;color:var(--spytial-ed-text-muted, #6e6553);background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px)}.spytial-ed-icon-btn:hover:not(:disabled){color:var(--spytial-ed-text, #221d14);background:var(--spytial-ed-hover, #f6f8fa)}.spytial-ed-icon-btn:disabled{cursor:default;opacity:.5}.spytial-ed-icon-pop{position:fixed;z-index:1000;inline-size:20rem;max-inline-size:calc(100vw - 1rem);overflow-y:auto;padding:.5rem;background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px);box-shadow:0 1px color-mix(in srgb,var(--spytial-ed-text, #221d14) 8%,transparent),0 8px 24px color-mix(in srgb,var(--spytial-ed-text, #221d14) 18%,transparent);animation:spytial-ed-pop .12s ease-out}.spytial-ed-icon-search{margin-block-end:.4rem}.spytial-ed-icon-note,.spytial-ed-icon-empty{margin:0 0 .45rem;font-size:.75rem;line-height:1.45;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-icon-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(4.25rem,1fr));gap:.25rem}.spytial-ed-icon-cell{display:flex;flex-direction:column;align-items:center;gap:.2rem;cursor:pointer;padding:.4rem .2rem;background:transparent;border:1px solid transparent;border-radius:var(--spytial-ed-radius-sm, 2px);color:var(--spytial-ed-text, #221d14)}.spytial-ed-icon-cell:hover{background:var(--spytial-ed-hover, #f6f8fa);border-color:var(--spytial-ed-border, #d9d2c0)}.spytial-ed-icon-cell--active{border-color:var(--spytial-ed-accent, #0969da);background:color-mix(in srgb,var(--spytial-ed-accent, #0969da) 10%,transparent)}.spytial-ed-icon-cell-name{max-inline-size:100%;overflow:hidden;font-size:.65rem;line-height:1.2;text-overflow:ellipsis;white-space:nowrap;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-icon-packs{margin-block-start:.6rem;padding-block-start:.5rem;border-block-start:1px solid var(--spytial-ed-border, #d9d2c0)}.spytial-ed-icon-packs ul{margin:0;padding:0;list-style:none;font-size:.72rem;line-height:1.6;color:var(--spytial-ed-text, #221d14)}.spytial-ed-icon-pack-eg{color:var(--spytial-ed-text-muted, #6e6553)}.error-card{min-width:320px;max-width:100%}#error-message-modal{border-radius:.5rem;border:2px var(--bs-danger) solid}.constraint-item.highlight-source{background-color:#ffc10759;border-radius:4px}.constraint-item.highlight-diagram{background-color:#ffc107b3;border-radius:4px}.constraint-relationship-table{width:100%;margin-bottom:1rem}.constraint-columns{display:flex;gap:0;max-height:45vh;min-height:5rem;overflow:hidden;resize:vertical}.constraint-column{flex:1 1 0;min-width:0;min-height:0;display:flex;flex-direction:column;border:1px solid #dee2e6}.constraint-column+.constraint-column{border-left:none}.constraint-column-header{flex:0 0 auto;font-weight:600;padding:.5rem;background:#f8f9fa;border-bottom:1px solid #dee2e6}.constraint-column-body{flex:1 1 auto;min-height:0;overflow:auto}.constraint-relationship-table .constraint-item{padding:.5rem;border-bottom:1px solid #eee}.constraint-relationship-table .constraint-item:last-child{border-bottom:none}code>code,code>pre{border:1px solid var(--bs-code-color);padding:.2em .4em;border-radius:4px}.error-modal-header{gap:.5rem}.error-modal-toggle{background:transparent;border:none;color:var(--bs-danger);font-size:1.1rem;line-height:1;padding:0 .25rem;cursor:pointer}.error-modal-toggle:hover,.error-modal-toggle:focus{opacity:.75}.code-input{font-family:monospace}#repl-output{font-family:monospace;white-space:pre-wrap;max-height:80vh;overflow-y:auto}#evaluator-input{margin:10px 0}.repl-output-line{margin:2px 0;padding:2px 0}.relation-highlighter{border:1px solid #ddd;border-radius:6px;background:#fff;font-family:system-ui,-apple-system,sans-serif;max-width:320px;box-shadow:0 2px 4px #0000001a;overflow:hidden}.relation-highlighter-header{display:flex;justify-content:space-between;align-items:center;padding:14px 18px;background:linear-gradient(135deg,#f8f9fa,#e9ecef);border-bottom:1px solid #dee2e6;cursor:pointer;user-select:none;transition:background-color .2s ease;position:relative}.relation-highlighter-header:hover{background:linear-gradient(135deg,#e9ecef,#dee2e6)}.relation-highlighter-header:active{background:linear-gradient(135deg,#dee2e6,#ced4da)}.relation-highlighter-title{margin:0;font-size:15px;font-weight:600;color:#495057;letter-spacing:.025em}.collapse-toggle{background:none;border:none;font-size:16px;color:#6c757d;cursor:pointer;padding:6px;border-radius:4px;transition:all .25s ease;line-height:1;min-width:28px;min-height:28px;display:flex;align-items:center;justify-content:center}.collapse-toggle:hover{background:#6c757d1a;color:#495057}.collapse-toggle.collapsed{transform:rotate(-90deg);color:#868e96}.relation-highlighter-content{max-height:350px;overflow:hidden;transition:max-height .35s cubic-bezier(.4,0,.2,1);background:#fff}.relation-highlighter-content.collapsed{max-height:0;border-top:none}.no-relations{padding:20px 18px;text-align:center;color:#6c757d;font-style:italic;margin:0;font-size:14px}.relation-list{list-style:none;margin:0;padding:0;max-height:320px;overflow-y:auto;overflow-x:auto}.relation-item{padding:12px 18px;cursor:pointer;border-bottom:1px solid #f1f3f4;color:#495057;font-size:14px;font-weight:500;transition:all .2s ease;user-select:none;position:relative;background:#fff;overflow:hidden;white-space:nowrap;min-width:100px}.relation-item:last-child{border-bottom:none}.relation-item:hover{background:linear-gradient(90deg,#e3f2fd,#f3e5f5);color:#1565c0;font-weight:600;padding-left:28px;padding-right:18px}.relation-item:active{background:linear-gradient(90deg,#bbdefb,#e1bee7)}.relation-list::-webkit-scrollbar{width:8px}.relation-list::-webkit-scrollbar-track{background:#f8f9fa;border-radius:4px}.relation-list::-webkit-scrollbar-thumb{background:linear-gradient(180deg,#ced4da,#adb5bd);border-radius:4px;border:1px solid #dee2e6}.relation-list::-webkit-scrollbar-thumb:hover{background:linear-gradient(180deg,#adb5bd,#868e96)}@keyframes accordionExpand{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.relation-highlighter-content:not(.collapsed) .relation-list{animation:accordionExpand .3s ease-out}@media(max-width:480px){.relation-highlighter{max-width:100%;border-radius:4px}.relation-highlighter-title{font-size:14px}.relation-item{padding:14px 32px 14px 18px;font-size:15px}.relation-item:hover{padding-left:32px;padding-right:18px}}.relation-highlighter-header:focus{outline:2px solid #0d6efd;outline-offset:-2px}.collapse-toggle:focus{outline:2px solid #0d6efd;outline-offset:2px;border-radius:4px}.relation-item:focus{outline:2px solid #0d6efd;outline-offset:-2px;background:#e3f2fd}
|
|
1
|
+
.spytial-ed{font-family:var( --spytial-ed-font-family, "Avenir Next", "Avenir", "Seravek", "Segoe UI Variable", "Segoe UI", "Trebuchet MS", sans-serif );font-size:var(--spytial-ed-font-size, 14px);color:var(--spytial-ed-text, #221d14);--spytial-ed-gap: var(--spytial-ed-spacing, 8px);--spytial-ed-radius-sm: var(--spytial-ed-radius, 2px);--spytial-ed-chrome-font: var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace )}.spytial-ed *,.spytial-ed *:before,.spytial-ed *:after{box-sizing:border-box}.spytial-ed--compact{font-size:calc(var(--spytial-ed-font-size, 14px) - 1px);--spytial-ed-gap: calc(var(--spytial-ed-spacing, 8px) * .625)}@keyframes spytial-ed-pop{0%{opacity:0;transform:translateY(-3px) scale(.99)}to{opacity:1;transform:translateY(0) scale(1)}}@keyframes spytial-ed-unfold{0%{opacity:0;transform:translateY(-2px)}to{opacity:1;transform:translateY(0)}}.spytial-ed-fields{display:flex;flex-direction:column;gap:var(--spytial-ed-gap, 8px);width:100%}.spytial-ed-field{display:grid;grid-template-columns:minmax(7rem,9rem) 1fr;align-items:start;gap:var(--spytial-ed-gap, 8px)}.spytial-ed--compact .spytial-ed-field{grid-template-columns:minmax(6rem,8rem) 1fr}.spytial-ed-field-label{font-family:var(--spytial-ed-chrome-font);font-size:.72em;font-weight:600;text-transform:uppercase;letter-spacing:.09em;color:var(--spytial-ed-text-muted, #6e6553);padding-top:.55em;line-height:1.3;cursor:default;user-select:none}.spytial-ed-field-required{color:var(--spytial-ed-danger, #a32014);font-weight:700}.spytial-ed-field-control{display:flex;flex-direction:column;gap:.25em;min-width:0}.spytial-ed-input{width:100%;font-family:inherit;font-size:inherit;color:var(--spytial-ed-text, #221d14);background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .55em;line-height:1.4;transition:border-color .15s ease,box-shadow .15s ease}.spytial-ed--compact .spytial-ed-input{padding:.3em .45em}.spytial-ed-input::placeholder{color:var(--spytial-ed-text-muted, #6e6553);opacity:.65}.spytial-ed-input:focus,.spytial-ed-input:focus-visible{outline:none;border-color:var(--spytial-ed-accent, #b5431a);box-shadow:0 0 0 2px color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 20%,transparent)}.spytial-ed-input:disabled{background:var(--spytial-ed-surface-raised, #f1ecdf);color:var(--spytial-ed-text-muted, #6e6553);cursor:not-allowed}.spytial-ed-input--number{width:8rem}.spytial-ed-input[aria-invalid=true]{border-color:var(--spytial-ed-danger, #a32014)}.spytial-ed-color{display:flex;align-items:center;gap:var(--spytial-ed-gap, 8px)}.spytial-ed-color-swatch{inline-size:2rem;block-size:2rem;padding:0;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);background:var(--spytial-ed-surface, #faf8f2);cursor:pointer}.spytial-ed-color-swatch:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:1px}.spytial-ed-color-text{width:9rem;font-family:var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace )}.spytial-ed-pills{display:flex;flex-wrap:wrap;gap:.3em}.spytial-ed-pill{font-family:var(--spytial-ed-chrome-font);font-size:.8em;color:var(--spytial-ed-text, #221d14);background:transparent;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.28em .65em;cursor:pointer;transition:background .15s ease,border-color .15s ease,color .15s ease,transform .1s ease}.spytial-ed-pill:hover:not(:disabled){border-color:var(--spytial-ed-accent, #b5431a);color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-pill:active:not(:disabled){transform:translateY(1px)}.spytial-ed-pill:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:1px}.spytial-ed-pill--active{background:var(--spytial-ed-accent, #b5431a);border-color:var(--spytial-ed-accent, #b5431a);color:var(--spytial-ed-accent-text, #fdf6ec);font-weight:600}.spytial-ed-pill--active:hover:not(:disabled){color:var(--spytial-ed-accent-text, #fdf6ec)}.spytial-ed-pill--negated{background:var(--spytial-ed-danger, #a32014);border-color:var(--spytial-ed-danger, #a32014)}.spytial-ed-pill--negated:hover:not(:disabled){border-color:var(--spytial-ed-danger, #a32014)}.spytial-ed-pill:disabled{opacity:.55;cursor:not-allowed}.spytial-ed-switch{position:relative;inline-size:2.4rem;block-size:1.35rem;padding:0;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:999px;background:var(--spytial-ed-surface-raised, #f1ecdf);cursor:pointer;transition:background .15s ease,border-color .15s ease}.spytial-ed-switch-thumb{position:absolute;top:50%;left:.18rem;transform:translateY(-50%);inline-size:.95rem;block-size:.95rem;border-radius:50%;background:var(--spytial-ed-surface, #faf8f2);box-shadow:0 1px 2px #00000040;transition:left .15s ease}.spytial-ed-switch--on{background:var(--spytial-ed-accent, #b5431a);border-color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-switch--on .spytial-ed-switch-thumb{left:calc(100% - 1.13rem)}.spytial-ed-switch:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:2px}.spytial-ed-switch:disabled{opacity:.55;cursor:not-allowed}.spytial-ed-selector{display:flex;flex-direction:column;gap:.25em;width:100%}.spytial-ed-selector-input-wrap{position:relative;width:100%;background:var(--spytial-ed-surface, #faf8f2);border-radius:var(--spytial-ed-radius-sm, 2px)}.spytial-ed-selector-textarea,.spytial-ed-selector-mirror{margin:0;font-family:var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace );font-size:.95em;line-height:1.5;letter-spacing:normal;word-spacing:normal;font-variant-ligatures:none;font-feature-settings:normal;font-kerning:none;hyphens:none;text-rendering:auto;tab-size:2;padding:.4em .55em;border:1px solid transparent;border-radius:var(--spytial-ed-radius-sm, 2px);white-space:pre-wrap;word-break:break-word;overflow-wrap:break-word}.spytial-ed--compact .spytial-ed-selector-textarea,.spytial-ed--compact .spytial-ed-selector-mirror{padding:.3em .45em}.spytial-ed-selector-input-wrap--with-synth .spytial-ed-selector-textarea,.spytial-ed-selector-input-wrap--with-synth .spytial-ed-selector-mirror{padding-right:2.3em}.spytial-ed-selector-mirror{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;color:var(--spytial-ed-text, #221d14);background:transparent}.spytial-ed-selector-textarea{position:relative;z-index:1;display:block;width:100%;min-height:2.2em;resize:none;overflow:hidden;background:transparent;border-color:var(--spytial-ed-border, #d9d2c0);color:transparent;caret-color:var(--spytial-ed-accent, #b5431a);transition:border-color .15s ease,box-shadow .15s ease}.spytial-ed-selector-textarea::placeholder{color:var(--spytial-ed-text-muted, #6e6553);opacity:.65}.spytial-ed-selector-textarea::selection{background:color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 26%,transparent)}.spytial-ed-selector-textarea:focus,.spytial-ed-selector-textarea:focus-visible{outline:none;border-color:var(--spytial-ed-accent, #b5431a);box-shadow:0 0 0 2px color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 20%,transparent)}.spytial-ed-selector-textarea:disabled{cursor:not-allowed}.spytial-ed-selector-input-wrap:has(.spytial-ed-selector-textarea:disabled){background:var(--spytial-ed-surface-raised, #f1ecdf)}.spytial-ed-selector-textarea--plain{color:var(--spytial-ed-text, #221d14)}.spytial-ed-selector--error .spytial-ed-selector-textarea{border-color:var(--spytial-ed-danger, #a32014);box-shadow:inset 0 -2px 0 var(--spytial-ed-danger, #a32014)}.spytial-ed-selector--warning .spytial-ed-selector-textarea{border-color:var(--spytial-ed-warning, #8a6200);box-shadow:inset 0 -2px 0 var(--spytial-ed-warning, #8a6200)}.spytial-ed-syn-keyword{color:var(--spytial-ed-syn-keyword, #6d28a8);font-weight:600}.spytial-ed-syn-type{color:var(--spytial-ed-syn-type, #0e6b6b)}.spytial-ed-syn-relation,.spytial-ed-syn-identifier{color:var(--spytial-ed-syn-relation, #1f4f9e)}.spytial-ed-syn-operator{color:var(--spytial-ed-syn-operator, #b5431a)}.spytial-ed-syn-string{color:var(--spytial-ed-syn-string, #7a5901)}.spytial-ed-syn-number{color:var(--spytial-ed-syn-type, #0e6b6b)}.spytial-ed-syn-comment{color:var(--spytial-ed-syn-comment, #8a8170);font-style:italic}.spytial-ed-selector-synth-btn{position:absolute;top:.25em;right:.25em;z-index:2;inline-size:1.7em;block-size:1.7em;display:inline-flex;align-items:center;justify-content:center;padding:0;font-size:.95em;line-height:1;background:var(--spytial-ed-surface-raised, #f1ecdf);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);cursor:pointer;transition:border-color .15s ease,background .15s ease,transform .12s ease}.spytial-ed-selector-synth-btn:hover:not(:disabled){border-color:var(--spytial-ed-accent, #b5431a);transform:rotate(-8deg)}.spytial-ed-selector-synth-btn:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:1px}.spytial-ed-selector-synth-btn:disabled{opacity:.5;cursor:not-allowed}.spytial-ed-autocomplete{position:fixed;z-index:1000;margin:0;padding:.2em;list-style:none;overflow-y:auto;background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px);box-shadow:0 1px color-mix(in srgb,var(--spytial-ed-text, #221d14) 8%,transparent),0 8px 24px color-mix(in srgb,var(--spytial-ed-text, #221d14) 18%,transparent);animation:spytial-ed-pop .12s ease-out}.spytial-ed-autocomplete-item{display:flex;align-items:center;gap:.5em;padding:.3em .5em;border-radius:var(--spytial-ed-radius-sm, 2px);cursor:pointer;font-size:.9em}.spytial-ed-autocomplete-item--active{background:color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 14%,transparent)}.spytial-ed-autocomplete-kind{inline-size:.6em;block-size:.6em;border-radius:1px;flex:0 0 auto;background:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-kind-type{background:var(--spytial-ed-syn-type, #0e6b6b)}.spytial-ed-kind-relation{background:var(--spytial-ed-syn-relation, #1f4f9e)}.spytial-ed-kind-atom{background:var(--spytial-ed-syn-string, #7a5901)}.spytial-ed-kind-keyword{background:var(--spytial-ed-syn-keyword, #6d28a8)}.spytial-ed-kind-snippet{background:var(--spytial-ed-success, #2f6c43)}.spytial-ed-autocomplete-label{font-family:var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace );color:var(--spytial-ed-text, #221d14)}.spytial-ed-autocomplete-detail{margin-left:auto;font-size:.85em;color:var(--spytial-ed-text-muted, #6e6553);white-space:nowrap}.spytial-ed-synth-popover{margin-top:.3em;padding:var(--spytial-ed-gap, 8px);background:var(--spytial-ed-surface-raised, #f1ecdf);border:1px solid var(--spytial-ed-border, #d9d2c0);border-left:3px solid var(--spytial-ed-accent, #b5431a);border-radius:var(--spytial-ed-radius, 2px);display:flex;flex-direction:column;gap:var(--spytial-ed-gap, 8px);animation:spytial-ed-unfold .14s ease-out}.spytial-ed-synth-row{display:flex;gap:.4em}.spytial-ed-synth-input{flex:1 1 auto;min-width:0;font-family:inherit;font-size:.9em;color:var(--spytial-ed-text, #221d14);background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .55em}.spytial-ed-synth-input:focus-visible{outline:none;border-color:var(--spytial-ed-accent, #b5431a);box-shadow:0 0 0 2px color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 20%,transparent)}.spytial-ed-synth-generate,.spytial-ed-synth-accept{font-family:var(--spytial-ed-chrome-font);font-size:.82em;font-weight:600;color:var(--spytial-ed-accent-text, #fdf6ec);background:var(--spytial-ed-accent, #b5431a);border:1px solid var(--spytial-ed-accent, #b5431a);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .8em;cursor:pointer;white-space:nowrap;transition:filter .15s ease,transform .1s ease}.spytial-ed-synth-generate:hover:not(:disabled),.spytial-ed-synth-accept:hover:not(:disabled){filter:brightness(1.08)}.spytial-ed-synth-generate:active:not(:disabled),.spytial-ed-synth-accept:active:not(:disabled){transform:translateY(1px)}.spytial-ed-synth-generate:disabled{opacity:.5;cursor:not-allowed}.spytial-ed-synth-dismiss{font-family:var(--spytial-ed-chrome-font);font-size:.82em;color:var(--spytial-ed-text, #221d14);background:transparent;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .8em;cursor:pointer}.spytial-ed-synth-generate:focus-visible,.spytial-ed-synth-accept:focus-visible,.spytial-ed-synth-dismiss:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:1px}.spytial-ed-synth-error{color:var(--spytial-ed-danger, #a32014);font-size:.85em}.spytial-ed-synth-result{display:flex;flex-direction:column;gap:.4em}.spytial-ed-synth-preview{margin:0;padding:.4em .55em;font-family:var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace );font-size:.9em;line-height:1.5;background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);white-space:pre-wrap;word-break:break-word;color:var(--spytial-ed-text, #221d14)}.spytial-ed-synth-explanation{margin:0;font-size:.85em;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-synth-actions{display:flex;gap:.4em}.spytial-ed-diagnostics{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.1em}.spytial-ed-diagnostic{display:flex;align-items:baseline;gap:.4em;font-size:.8em;line-height:1.35;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.spytial-ed-diagnostics--item{gap:.2em}.spytial-ed-diagnostics--item .spytial-ed-diagnostic{white-space:normal;overflow:visible}.spytial-ed-diagnostics--item .spytial-ed-diagnostic-msg{overflow:visible;text-overflow:clip}.spytial-ed-diagnostic-dot{flex:0 0 auto;inline-size:.5em;block-size:.5em;border-radius:50%;align-self:center}.spytial-ed-diagnostic-msg{min-width:0;overflow:hidden;text-overflow:ellipsis}.spytial-ed-diagnostic--error{color:var(--spytial-ed-danger, #a32014)}.spytial-ed-diagnostic--error .spytial-ed-diagnostic-dot{background:var(--spytial-ed-danger, #a32014)}.spytial-ed-diagnostic--warning{color:var(--spytial-ed-warning, #8a6200)}.spytial-ed-diagnostic--warning .spytial-ed-diagnostic-dot{background:var(--spytial-ed-warning, #8a6200)}.spytial-ed-diagnostic--info{color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-diagnostic--info .spytial-ed-diagnostic-dot{background:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-diagnostic-badge{display:inline-flex;align-items:center;justify-content:center;min-inline-size:.9em;block-size:.9em;padding:0 .2em;margin-inline-start:.4em;border-radius:999px;font-size:.7em;font-weight:700;line-height:1;color:#fff;background:var(--spytial-ed-danger, #a32014)}.spytial-ed-diagnostic-badge--warning{background:var(--spytial-ed-warning, #8a6200)}.spytial-ed-diagnostic-badge--info{background:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed{display:block;background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px)}.spytial-ed-toolbar{display:flex;align-items:center;justify-content:space-between;gap:var(--spytial-ed-gap, 8px);padding:calc(var(--spytial-ed-gap, 8px) * .75) var(--spytial-ed-gap, 8px);background:var(--spytial-ed-surface-raised, #f1ecdf);border-bottom:1px solid var(--spytial-ed-border, #d9d2c0)}.spytial-ed-viewtoggle{display:inline-flex;gap:var(--spytial-ed-gap, 8px)}.spytial-ed-viewtoggle-btn{position:relative;display:inline-flex;align-items:center;font-family:var(--spytial-ed-chrome-font);font-size:.78em;font-weight:600;text-transform:uppercase;letter-spacing:.09em;color:var(--spytial-ed-text-muted, #6e6553);background:transparent;border:none;padding:.3em .15em;cursor:pointer;transition:color .15s ease}.spytial-ed-viewtoggle-btn:after{content:"";position:absolute;left:0;right:100%;bottom:-2px;height:2px;background:var(--spytial-ed-accent, #b5431a);transition:right .18s ease}.spytial-ed-viewtoggle-btn:hover:not(:disabled){color:var(--spytial-ed-text, #221d14)}.spytial-ed-viewtoggle-btn--active{color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-viewtoggle-btn--active:after{right:0}.spytial-ed-viewtoggle-btn:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:2px}.spytial-ed-viewtoggle-btn:disabled{opacity:.55;cursor:not-allowed}.spytial-ed-toolbar-actions{display:inline-flex;align-items:center;gap:var(--spytial-ed-gap, 8px)}.spytial-ed-history{display:inline-flex;gap:4px}.spytial-ed-suggest-btn{display:inline-flex;align-items:center;gap:.35em;font-family:var(--spytial-ed-chrome-font);font-size:.78em;font-weight:600;text-transform:uppercase;letter-spacing:.09em;color:var(--spytial-ed-accent, #b5431a);background:transparent;border:1px solid var(--spytial-ed-accent, #b5431a);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.3em .7em;cursor:pointer;white-space:nowrap;transition:background .15s ease,color .15s ease}.spytial-ed-suggest-btn:hover:not(:disabled){color:var(--spytial-ed-accent-text, #fdf6ec);background:var(--spytial-ed-accent, #b5431a)}.spytial-ed-suggest-btn:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:2px}.spytial-ed-suggest-btn:disabled{opacity:.5;cursor:not-allowed}.spytial-ed-suggest-error{margin:0;padding:calc(var(--spytial-ed-gap, 8px) * .75) var(--spytial-ed-gap, 8px);font-size:.85em;color:var(--spytial-ed-danger, #a32014);background:color-mix(in srgb,var(--spytial-ed-danger, #a32014) 8%,transparent);border-bottom:1px solid var(--spytial-ed-border, #d9d2c0)}.spytial-ed-suggestions{padding:calc(var(--spytial-ed-gap, 8px) * .75) var(--spytial-ed-gap, 8px);background:var(--spytial-ed-surface-raised, #f1ecdf);border-bottom:1px solid var(--spytial-ed-border, #d9d2c0);border-left:3px solid var(--spytial-ed-accent, #b5431a);animation:spytial-ed-unfold .14s ease-out}.spytial-ed-suggestions-head{display:flex;align-items:center;justify-content:space-between;gap:var(--spytial-ed-gap, 8px)}.spytial-ed-suggestions-title{font-family:var(--spytial-ed-chrome-font);font-size:.74em;font-weight:600;text-transform:uppercase;letter-spacing:.09em;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-suggestions-dismiss{font:inherit;font-size:1.05em;line-height:1;color:var(--spytial-ed-text-muted, #6e6553);background:transparent;border:none;padding:0 .2em;cursor:pointer}.spytial-ed-suggestions-dismiss:hover{color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-suggestions-dismiss:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:1px}.spytial-ed-suggestions-list,.spytial-ed-suggestions-notes{list-style:none;margin:calc(var(--spytial-ed-gap, 8px) * .5) 0 0;padding:0;display:flex;flex-direction:column;gap:calc(var(--spytial-ed-gap, 8px) * .5)}.spytial-ed-suggestions-notes{font-size:.82em;color:var(--spytial-ed-text-muted, #6e6553);border-top:1px solid var(--spytial-ed-border, #d9d2c0);padding-top:calc(var(--spytial-ed-gap, 8px) * .5)}.spytial-ed-suggestion--omitted{opacity:.62}.spytial-ed-suggestion-head{display:flex;align-items:baseline;flex-wrap:wrap;gap:.4em}.spytial-ed-suggestion-text{flex:1 1 12em;font-size:.88em;color:var(--spytial-ed-text, #221d14)}.spytial-ed-suggestion-id{display:block;margin-top:.15em;font-family:var( --spytial-ed-mono-font-family, ui-monospace, "Cascadia Code", "JetBrains Mono", "SF Mono", Menlo, Consolas, "Liberation Mono", monospace );font-size:.74em;color:var(--spytial-ed-text-muted, #6e6553);word-break:break-all}.spytial-ed-suggestion-chip{font-family:var(--spytial-ed-chrome-font);font-size:.66em;font-weight:600;text-transform:uppercase;letter-spacing:.07em;border:1px solid currentColor;border-radius:var(--spytial-ed-radius-sm, 2px);padding:.15em .4em;white-space:nowrap;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-suggestion-chip--high,.spytial-ed-suggestion-chip--applied{color:var(--spytial-ed-success, #2f6c43)}.spytial-ed-suggestion-chip--medium,.spytial-ed-suggestion-chip--weakened{color:var(--spytial-ed-warning, #8a6200)}.spytial-ed-suggestion-chip--omitted{color:var(--spytial-ed-danger, #a32014)}.spytial-ed-history-btn{font:inherit;font-size:1.05em;line-height:1;color:var(--spytial-ed-text, #221d14);background:transparent;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.2em .45em;cursor:pointer;transition:border-color .15s ease,color .15s ease}.spytial-ed-history-btn:hover:not(:disabled){border-color:var(--spytial-ed-accent, #b5431a);color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-history-btn:disabled{opacity:.4;cursor:not-allowed}.spytial-ed-body{padding:var(--spytial-ed-gap, 8px)}.spytial-ed-builder{display:flex;flex-direction:column;gap:calc(var(--spytial-ed-gap, 8px) * 1.25)}.spytial-ed-section-head{display:flex;align-items:center;justify-content:space-between;margin-bottom:calc(var(--spytial-ed-gap, 8px) * .5)}.spytial-ed-section-title{margin:0;font-family:var(--spytial-ed-chrome-font);font-size:.72em;font-weight:700;text-transform:uppercase;letter-spacing:.14em;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-rows{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:4px}.spytial-ed-row{border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px);background:var(--spytial-ed-surface, #faf8f2);transition:border-color .15s ease}.spytial-ed-row:hover{border-color:color-mix(in srgb,var(--spytial-ed-text-muted, #6e6553) 55%,var(--spytial-ed-border, #d9d2c0))}.spytial-ed-row--expanded{border-color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-row--error{border-left:3px solid var(--spytial-ed-danger, #a32014)}.spytial-ed-row--warning{border-left:3px solid var(--spytial-ed-warning, #8a6200)}.spytial-ed-row-main{display:flex;align-items:center;gap:4px}.spytial-ed-row-toggle{flex:1 1 auto;display:flex;align-items:center;gap:.55em;min-width:0;font:inherit;text-align:left;color:inherit;background:transparent;border:none;cursor:pointer;padding:calc(var(--spytial-ed-gap, 8px) * .55) var(--spytial-ed-gap, 8px)}.spytial-ed--compact .spytial-ed-row-toggle{padding:calc(var(--spytial-ed-gap, 8px) * .4) calc(var(--spytial-ed-gap, 8px) * .75)}.spytial-ed-row-type{font-family:var(--spytial-ed-chrome-font);font-size:.88em;font-weight:600;flex:0 0 auto}.spytial-ed-row-negated{color:var(--spytial-ed-danger, #a32014);font-weight:700;flex:0 0 auto}.spytial-ed-row-summary{flex:1 1 auto;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;font-size:.85em;color:var(--spytial-ed-text-muted, #6e6553);font-family:var(--spytial-ed-mono-font-family, ui-monospace, monospace)}.spytial-ed-row-summary--muted{font-style:italic;font-family:inherit}.spytial-ed-row-dot{flex:0 0 auto;inline-size:.55em;block-size:.55em;border-radius:50%;background:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-row-dot--error{background:var(--spytial-ed-danger, #a32014)}.spytial-ed-row-dot--warning{background:var(--spytial-ed-warning, #8a6200)}.spytial-ed-row-panel{padding:var(--spytial-ed-gap, 8px);border-top:1px solid var(--spytial-ed-border, #d9d2c0);background:var(--spytial-ed-surface-raised, #f1ecdf);display:flex;flex-direction:column;gap:var(--spytial-ed-gap, 8px);animation:spytial-ed-unfold .14s ease-out}.spytial-ed-row--unknown{background:var(--spytial-ed-surface-raised, #f1ecdf)}.spytial-ed-row--unknown .spytial-ed-row-main{padding:calc(var(--spytial-ed-gap, 8px) * .55) var(--spytial-ed-gap, 8px);gap:.55em}.spytial-ed-builder-empty{margin:0;font-size:.9em;color:var(--spytial-ed-text-muted, #6e6553);font-style:italic}.spytial-ed-overflow{position:relative;flex:0 0 auto;margin-inline-end:4px}.spytial-ed-overflow-btn{font:inherit;font-size:1.1em;line-height:1;color:var(--spytial-ed-text-muted, #6e6553);background:transparent;border:none;border-radius:var(--spytial-ed-radius-sm, 2px);padding:.1em .4em;cursor:pointer}.spytial-ed-overflow-btn:hover{background:var(--spytial-ed-border, #d9d2c0)}.spytial-ed-overflow-btn:disabled{opacity:.4;cursor:not-allowed}.spytial-ed-overflow-menu,.spytial-ed-add-menu{position:fixed;z-index:1000;min-inline-size:10rem;background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px);box-shadow:0 1px color-mix(in srgb,var(--spytial-ed-text, #221d14) 8%,transparent),0 8px 24px color-mix(in srgb,var(--spytial-ed-text, #221d14) 18%,transparent);padding:4px;animation:spytial-ed-pop .12s ease-out}.spytial-ed-overflow-menu{list-style:none;margin:0;overflow-y:auto}.spytial-ed-overflow-item,.spytial-ed-add-item{display:block;inline-size:100%;font:inherit;font-size:.88em;text-align:left;color:var(--spytial-ed-text, #221d14);background:transparent;border:none;border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .6em;cursor:pointer}.spytial-ed-overflow-item:hover:not(:disabled),.spytial-ed-add-item:hover{background:var(--spytial-ed-surface-raised, #f1ecdf)}.spytial-ed-overflow-item:disabled{opacity:.4;cursor:not-allowed}.spytial-ed-overflow-item--danger{color:var(--spytial-ed-danger, #a32014)}.spytial-ed-add{position:relative}.spytial-ed-add-btn{font-family:var(--spytial-ed-chrome-font);font-size:.78em;font-weight:600;color:var(--spytial-ed-accent, #b5431a);background:transparent;border:1px solid var(--spytial-ed-accent, #b5431a);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.28em .6em;cursor:pointer;transition:background .15s ease,color .15s ease,transform .1s ease}.spytial-ed-add-btn:hover:not(:disabled){background:var(--spytial-ed-accent, #b5431a);color:var(--spytial-ed-accent-text, #fdf6ec)}.spytial-ed-add-btn:active:not(:disabled){transform:translateY(1px)}.spytial-ed-add-btn:focus-visible{outline:2px solid var(--spytial-ed-accent, #b5431a);outline-offset:2px}.spytial-ed-add-btn:disabled{opacity:.5;cursor:not-allowed}.spytial-ed-add-menu{display:flex;flex-direction:column;min-inline-size:15rem}.spytial-ed-add-search{inline-size:100%;flex:0 0 auto;font:inherit;font-size:.85em;color:var(--spytial-ed-text, #221d14);background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.35em .5em;margin-bottom:4px}.spytial-ed-add-search:focus-visible{outline:none;border-color:var(--spytial-ed-accent, #b5431a)}.spytial-ed-add-list{list-style:none;margin:0;padding:0;flex:1 1 auto;min-block-size:0;overflow-y:auto}.spytial-ed-add-item{display:flex;flex-direction:column;gap:1px}.spytial-ed-add-item-label{font-family:var(--spytial-ed-chrome-font);font-size:.95em;font-weight:600}.spytial-ed-add-item-desc{font-size:.78em;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-add-empty{font-size:.85em;color:var(--spytial-ed-text-muted, #6e6553);padding:.4em .6em}.spytial-ed-code{display:flex;flex-direction:column;gap:var(--spytial-ed-gap, 8px)}.spytial-ed-code-notice{font-size:.82em;color:var(--spytial-ed-warning, #8a6200);background:color-mix(in srgb,var(--spytial-ed-warning, #8a6200) 10%,transparent);border:1px solid var(--spytial-ed-warning, #8a6200);border-radius:var(--spytial-ed-radius-sm, 2px);padding:.4em .6em}.spytial-ed-code-cm{display:block}.spytial-ed-code-cm .cm-editor{max-height:32rem}.spytial-ed-code-cm--disabled{opacity:.65}.spytial-ed-code-editor{display:flex;border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px);background:var(--spytial-ed-surface, #faf8f2);overflow:hidden}.spytial-ed-code-gutter{flex:0 0 auto;overflow:hidden;text-align:right;user-select:none;padding:.5em .4em;color:var(--spytial-ed-text-muted, #6e6553);background:var(--spytial-ed-surface-raised, #f1ecdf);border-inline-end:1px solid var(--spytial-ed-border, #d9d2c0);font-family:var(--spytial-ed-mono-font-family, ui-monospace, monospace);font-size:.85em;line-height:1.5}.spytial-ed-code-gutter-line{min-inline-size:1.6em}.spytial-ed-code-input-wrap{position:relative;flex:1 1 auto;min-width:0;display:flex}.spytial-ed-code-textarea,.spytial-ed-code-mirror{margin:0;font-family:var(--spytial-ed-mono-font-family, ui-monospace, monospace);font-size:.85em;line-height:1.5;letter-spacing:normal;word-spacing:normal;font-variant-ligatures:none;font-feature-settings:normal;font-kerning:none;hyphens:none;text-rendering:auto;padding:.5em .6em;border:none;white-space:pre;overflow-wrap:normal;tab-size:2}.spytial-ed-code-mirror{position:absolute;inset:0;z-index:0;pointer-events:none;overflow:hidden;color:var(--spytial-ed-text, #221d14);background:transparent}.spytial-ed-code-textarea{position:relative;z-index:1;flex:1 1 auto;width:100%;resize:vertical;min-block-size:12rem;color:transparent;caret-color:var(--spytial-ed-accent, #b5431a);background:transparent;outline:none}.spytial-ed-code-textarea::selection{background:color-mix(in srgb,var(--spytial-ed-accent, #b5431a) 26%,transparent)}.spytial-ed-code-textarea:disabled{opacity:.6}.spytial-ed-code-textarea--plain{color:var(--spytial-ed-text, #221d14)}.spytial-ed-code-textarea:disabled+.spytial-ed-code-mirror,.spytial-ed-code-input-wrap:has(.spytial-ed-code-textarea:disabled) .spytial-ed-code-mirror{opacity:.6}.spytial-ed-code-diagnostics{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:2px}.spytial-ed-code-diagnostic-loc{font-family:var(--spytial-ed-mono-font-family, ui-monospace, monospace);font-size:.85em;color:var(--spytial-ed-text-muted, #6e6553);flex:0 0 auto}@media(prefers-reduced-motion:reduce){.spytial-ed *,.spytial-ed *:before,.spytial-ed *:after,.spytial-ed-autocomplete,.spytial-ed-overflow-menu,.spytial-ed-add-menu,.spytial-ed-synth-popover,.spytial-ed-row-panel{animation:none!important;transition:none!important}}.spytial-ed-group{border:1px solid var(--spytial-ed-border, #d0d7de);border-radius:6px;padding:.25rem .6rem .4rem;margin:.25rem 0;min-inline-size:0}.spytial-ed-group-legend{display:inline-flex;align-items:center;gap:.35rem;padding-inline:.3rem;font-size:.78rem;font-weight:600;color:var(--spytial-ed-muted, #656d76)}.spytial-ed-group-remove{border:none;background:transparent;cursor:pointer;font-size:1rem;line-height:1;padding:0 .15rem;color:var(--spytial-ed-muted, #656d76)}.spytial-ed-group-remove:hover{color:var(--spytial-ed-danger, #cf222e)}.spytial-ed-group-add{align-self:flex-start;border:1px dashed var(--spytial-ed-border, #d0d7de);border-radius:6px;background:transparent;cursor:pointer;padding:.3rem .6rem;margin:.15rem 0;font-size:.78rem;color:var(--spytial-ed-accent, #0969da)}.spytial-ed-group-add:hover{background:var(--spytial-ed-hover, #f6f8fa)}.spytial-ed-icon{position:relative;width:100%}.spytial-ed-icon-row{display:flex;align-items:center;gap:.35rem}.spytial-ed-icon-preview,.spytial-ed-icon-cell-glyph{display:inline-flex;flex:0 0 auto;color:var(--spytial-ed-text, #221d14)}.spytial-ed-icon-preview svg{inline-size:1.15rem;block-size:1.15rem}.spytial-ed-icon-cell-glyph svg{inline-size:1.35rem;block-size:1.35rem}.spytial-ed-icon-btn{flex:0 0 auto;cursor:pointer;padding:.3em .5em;line-height:1;color:var(--spytial-ed-text-muted, #6e6553);background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius-sm, 2px)}.spytial-ed-icon-btn:hover:not(:disabled){color:var(--spytial-ed-text, #221d14);background:var(--spytial-ed-hover, #f6f8fa)}.spytial-ed-icon-btn:disabled{cursor:default;opacity:.5}.spytial-ed-icon-pop{position:fixed;z-index:1000;inline-size:20rem;max-inline-size:calc(100vw - 1rem);overflow-y:auto;padding:.5rem;background:var(--spytial-ed-surface, #faf8f2);border:1px solid var(--spytial-ed-border, #d9d2c0);border-radius:var(--spytial-ed-radius, 2px);box-shadow:0 1px color-mix(in srgb,var(--spytial-ed-text, #221d14) 8%,transparent),0 8px 24px color-mix(in srgb,var(--spytial-ed-text, #221d14) 18%,transparent);animation:spytial-ed-pop .12s ease-out}.spytial-ed-icon-search{margin-block-end:.4rem}.spytial-ed-icon-note,.spytial-ed-icon-empty{margin:0 0 .45rem;font-size:.75rem;line-height:1.45;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-icon-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(4.25rem,1fr));gap:.25rem}.spytial-ed-icon-cell{display:flex;flex-direction:column;align-items:center;gap:.2rem;cursor:pointer;padding:.4rem .2rem;background:transparent;border:1px solid transparent;border-radius:var(--spytial-ed-radius-sm, 2px);color:var(--spytial-ed-text, #221d14)}.spytial-ed-icon-cell:hover{background:var(--spytial-ed-hover, #f6f8fa);border-color:var(--spytial-ed-border, #d9d2c0)}.spytial-ed-icon-cell--active{border-color:var(--spytial-ed-accent, #0969da);background:color-mix(in srgb,var(--spytial-ed-accent, #0969da) 10%,transparent)}.spytial-ed-icon-cell-name{max-inline-size:100%;overflow:hidden;font-size:.65rem;line-height:1.2;text-overflow:ellipsis;white-space:nowrap;color:var(--spytial-ed-text-muted, #6e6553)}.spytial-ed-icon-packs{margin-block-start:.6rem;padding-block-start:.5rem;border-block-start:1px solid var(--spytial-ed-border, #d9d2c0)}.spytial-ed-icon-packs ul{margin:0;padding:0;list-style:none;font-size:.72rem;line-height:1.6;color:var(--spytial-ed-text, #221d14)}.spytial-ed-icon-pack-eg{color:var(--spytial-ed-text-muted, #6e6553)}.error-card{min-width:320px;max-width:100%}#error-message-modal{border-radius:.5rem;border:2px var(--bs-danger) solid}.constraint-item.highlight-source{background-color:#ffc10759;border-radius:4px}.constraint-item.highlight-diagram{background-color:#ffc107b3;border-radius:4px}.constraint-relationship-table{width:100%;margin-bottom:1rem}.constraint-columns{display:flex;gap:0;max-height:45vh;min-height:5rem;overflow:hidden;resize:vertical}.constraint-column{flex:1 1 0;min-width:0;min-height:0;display:flex;flex-direction:column;border:1px solid #dee2e6}.constraint-column+.constraint-column{border-left:none}.constraint-column-header{flex:0 0 auto;font-weight:600;padding:.5rem;background:#f8f9fa;border-bottom:1px solid #dee2e6}.constraint-column-body{flex:1 1 auto;min-height:0;overflow:auto}.constraint-relationship-table .constraint-item{padding:.5rem;border-bottom:1px solid #eee}.constraint-relationship-table .constraint-item:last-child{border-bottom:none}code>code,code>pre{border:1px solid var(--bs-code-color);padding:.2em .4em;border-radius:4px}.error-modal-header{gap:.5rem}.error-modal-toggle{display:inline-flex;align-items:center;gap:.35rem;min-height:2rem;background:transparent;border:1px solid currentColor;border-radius:.375rem;color:var(--bs-danger);font:inherit;font-size:.875rem;font-weight:600;line-height:1.2;padding:.25rem .5rem;cursor:pointer}.error-modal-toggle:hover{background:color-mix(in srgb,var(--bs-danger) 10%,transparent)}.error-modal-toggle:focus-visible{outline:2px solid currentColor;outline-offset:2px}.error-modal-chevron{flex:none;transition:transform .15s ease}.error-modal-toggle[aria-expanded=false] .error-modal-chevron{transform:rotate(-90deg)}.code-input{font-family:monospace}#repl-output{font-family:monospace;white-space:pre-wrap;max-height:80vh;overflow-y:auto}#evaluator-input{margin:10px 0}.repl-output-line{margin:2px 0;padding:2px 0}.relation-highlighter{border:1px solid #ddd;border-radius:6px;background:#fff;font-family:system-ui,-apple-system,sans-serif;max-width:320px;box-shadow:0 2px 4px #0000001a;overflow:hidden}.relation-highlighter-header{display:flex;justify-content:space-between;align-items:center;padding:14px 18px;background:linear-gradient(135deg,#f8f9fa,#e9ecef);border-bottom:1px solid #dee2e6;cursor:pointer;user-select:none;transition:background-color .2s ease;position:relative}.relation-highlighter-header:hover{background:linear-gradient(135deg,#e9ecef,#dee2e6)}.relation-highlighter-header:active{background:linear-gradient(135deg,#dee2e6,#ced4da)}.relation-highlighter-title{margin:0;font-size:15px;font-weight:600;color:#495057;letter-spacing:.025em}.collapse-toggle{background:none;border:none;font-size:16px;color:#6c757d;cursor:pointer;padding:6px;border-radius:4px;transition:all .25s ease;line-height:1;min-width:28px;min-height:28px;display:flex;align-items:center;justify-content:center}.collapse-toggle:hover{background:#6c757d1a;color:#495057}.collapse-toggle.collapsed{transform:rotate(-90deg);color:#868e96}.relation-highlighter-content{max-height:350px;overflow:hidden;transition:max-height .35s cubic-bezier(.4,0,.2,1);background:#fff}.relation-highlighter-content.collapsed{max-height:0;border-top:none}.no-relations{padding:20px 18px;text-align:center;color:#6c757d;font-style:italic;margin:0;font-size:14px}.relation-list{list-style:none;margin:0;padding:0;max-height:320px;overflow-y:auto;overflow-x:auto}.relation-item{padding:12px 18px;cursor:pointer;border-bottom:1px solid #f1f3f4;color:#495057;font-size:14px;font-weight:500;transition:all .2s ease;user-select:none;position:relative;background:#fff;overflow:hidden;white-space:nowrap;min-width:100px}.relation-item:last-child{border-bottom:none}.relation-item:hover{background:linear-gradient(90deg,#e3f2fd,#f3e5f5);color:#1565c0;font-weight:600;padding-left:28px;padding-right:18px}.relation-item:active{background:linear-gradient(90deg,#bbdefb,#e1bee7)}.relation-list::-webkit-scrollbar{width:8px}.relation-list::-webkit-scrollbar-track{background:#f8f9fa;border-radius:4px}.relation-list::-webkit-scrollbar-thumb{background:linear-gradient(180deg,#ced4da,#adb5bd);border-radius:4px;border:1px solid #dee2e6}.relation-list::-webkit-scrollbar-thumb:hover{background:linear-gradient(180deg,#adb5bd,#868e96)}@keyframes accordionExpand{0%{opacity:0;transform:translateY(-10px)}to{opacity:1;transform:translateY(0)}}.relation-highlighter-content:not(.collapsed) .relation-list{animation:accordionExpand .3s ease-out}@media(max-width:480px){.relation-highlighter{max-width:100%;border-radius:4px}.relation-highlighter-title{font-size:14px}.relation-item{padding:14px 32px 14px 18px;font-size:15px}.relation-item:hover{padding-left:32px;padding-right:18px}}.relation-highlighter-header:focus{outline:2px solid #0d6efd;outline-offset:-2px}.collapse-toggle:focus{outline:2px solid #0d6efd;outline-offset:2px;border-radius:4px}.relation-item:focus{outline:2px solid #0d6efd;outline-offset:-2px;background:#e3f2fd}
|
|
2
2
|
/*# sourceMappingURL=react-component-integration.css.map */
|