pict-docuserve 1.4.0 → 1.4.2

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.
@@ -5923,8 +5923,26 @@ if(this.options.CodeDataAddress){const tmpAddressSpace={Fable:this.fable,Pict:th
5923
5923
  */getCode(){if(!this.codeJar){this.log.warn('PICT-Code getCode called before editor initialized.');return'';}return this.codeJar.toString();}/**
5924
5924
  * Set the code content.
5925
5925
  *
5926
+ * Safe to call whether or not the editor's host element is currently
5927
+ * visible. CodeJar's `updateCode()` internally touches the
5928
+ * selection APIs (to preserve cursor position across the swap), and
5929
+ * those APIs return null / empty Range when the contenteditable is
5930
+ * inside a `display:none` ancestor. In that case CodeJar's internal
5931
+ * bookkeeping throws — but the actual content swap is the easy
5932
+ * part: just set the editor element's textContent and re-run the
5933
+ * highlighter directly. When the user makes the tab visible later,
5934
+ * CodeJar picks up the new textContent and cursor handling resumes.
5935
+ *
5926
5936
  * @param {string} pCode - The code to set
5927
- */setCode(pCode){if(!this.codeJar){this.log.warn('PICT-Code setCode called before editor initialized.');return;}this.codeJar.updateCode(pCode);this._updateLineNumbers();}/**
5937
+ */setCode(pCode){if(!this.codeJar){this.log.warn('PICT-Code setCode called before editor initialized.');return;}let tmpUsedFallback=false;try{this.codeJar.updateCode(pCode);}catch(pError){// Fall back to a direct textContent swap + re-highlight.
5938
+ // This branch typically fires when setCode is called on a
5939
+ // tab that's not currently active (display:none), or on an
5940
+ // editor whose host has been detached from the DOM.
5941
+ tmpUsedFallback=true;try{if(this._editorElement){this._editorElement.textContent=typeof pCode==='string'?pCode:'';if(typeof this._highlightFunction==='function'){this._highlightFunction(this._editorElement);}}}catch(pFallbackError){this.log.warn('PICT-Code setCode failed: '+pError+' (textContent fallback also failed: '+pFallbackError+')');return;}}// Line-number gutter sync is best-effort either way; if it
5942
+ // throws (e.g. gutter wasn't built because the editor never
5943
+ // became visible), keep going — line numbers redraw on the
5944
+ // next visible render.
5945
+ try{this._updateLineNumbers();}catch(pLineNumberError){/* gutter sync is non-fatal */}}/**
5928
5946
  * Change the editor language and re-highlight.
5929
5947
  *
5930
5948
  * @param {string} pLanguage - The language identifier
@@ -6039,7 +6057,15 @@ if(tmpInList){tmpHTML.push(tmpListType==='ul'?'</ul>':'</ol>');tmpInList=false;}
6039
6057
  let tmpFenceMatch=tmpLine.match(/^(`{3,})/);if(tmpFenceMatch){let tmpFenceLen=tmpFenceMatch[1].length;if(tmpInCodeBlock){// Only close if the closing fence is at least as long as the opening
6040
6058
  if(tmpFenceLen>=tmpCodeFenceLength&&tmpLine.trim()===tmpFenceMatch[1]){// End code block
6041
6059
  if(tmpCodeLang==='mermaid'){// Mermaid diagrams: output raw content for client-side rendering
6042
- tmpHTML.push('<pre class="mermaid">'+tmpCodeLines.join('\n')+'</pre>');}else{let tmpCodeText=tmpCodeLines.join('\n');let tmpHighlightedCode=this.highlightCode(tmpCodeText,tmpCodeLang);let tmpLineNumbersHTML=this.generateLineNumbers(tmpCodeText);tmpHTML.push('<div class="pict-content-code-wrap"><div class="pict-content-code-line-numbers">'+tmpLineNumbersHTML+'</div><pre><code class="language-'+this.escapeHTML(tmpCodeLang)+'">'+tmpHighlightedCode+'</code></pre></div>');}tmpInCodeBlock=false;tmpCodeFenceLength=0;tmpCodeLang='';tmpCodeLines=[];continue;}else{// Inner fence with fewer backticks treat as content
6060
+ tmpHTML.push('<pre class="mermaid">'+tmpCodeLines.join('\n')+'</pre>');}else if(tmpCodeLang==='excalidraw'){// Excalidraw scenes: emit a placeholder div with the
6061
+ // scene JSON URI-component encoded into a data
6062
+ // attribute. Pict-View-Content's
6063
+ // renderExcalidrawDiagrams() swaps these for rendered
6064
+ // SVGs once the wrapper bundle is ready. We don't
6065
+ // validate the JSON here — invalid fences just stay
6066
+ // as the loading placeholder until the runtime
6067
+ // reports the error.
6068
+ let tmpRawScene=tmpCodeLines.join('\n');let tmpEncoded;try{tmpEncoded=encodeURIComponent(tmpRawScene);}catch(pErr){tmpEncoded='';}tmpHTML.push('<div class="pict-excalidraw-fence" data-scene="'+tmpEncoded+'">'+'<div class="pict-excalidraw-fence-loading">Rendering Excalidraw diagram…</div>'+'</div>');}else{let tmpCodeText=tmpCodeLines.join('\n');let tmpHighlightedCode=this.highlightCode(tmpCodeText,tmpCodeLang);let tmpLineNumbersHTML=this.generateLineNumbers(tmpCodeText);tmpHTML.push('<div class="pict-content-code-wrap"><div class="pict-content-code-line-numbers">'+tmpLineNumbersHTML+'</div><pre><code class="language-'+this.escapeHTML(tmpCodeLang)+'">'+tmpHighlightedCode+'</code></pre></div>');}tmpInCodeBlock=false;tmpCodeFenceLength=0;tmpCodeLang='';tmpCodeLines=[];continue;}else{// Inner fence with fewer backticks — treat as content
6043
6069
  tmpCodeLines.push(tmpLine);continue;}}else{// Flush any pending paragraph
6044
6070
  fFlushParagraph();// Close any open list or blockquote
6045
6071
  if(tmpInList){tmpHTML.push(tmpListType==='ul'?'</ul>':'</ol>');tmpInList=false;}if(tmpInBlockquote){tmpHTML.push('<blockquote>'+this.parseMarkdown(tmpBlockquoteLines.join('\n'),pLinkResolver,pImageResolver,pVocabularyResolver)+'</blockquote>');tmpInBlockquote=false;tmpBlockquoteLines=[];}// Start code block — record fence length
@@ -6121,7 +6147,7 @@ let tmpResult=pResolver(tmpLower);if(!tmpResult)return pMatch;tmpLinked[tmpLower
6121
6147
  *
6122
6148
  * @param {string} pText - The text to escape
6123
6149
  * @returns {string} The escaped text
6124
- */escapeHTML(pText){if(!pText){return'';}return pText.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;').replace(/'/g,'&#39;');}}module.exports=PictContentProvider;module.exports.default_configuration={ProviderIdentifier:"Pict-Content",AutoInitialize:true,AutoInitializeOrdinal:0};},{"pict-provider":148,"pict-section-code":151}],155:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"Pict-Content",DefaultRenderable:"Pict-Content-Display",DefaultDestinationAddress:"#Pict-Content-Container",AutoRender:false,CSS:/*css*/"\n\t\t.pict-content {\n\t\t\tpadding: 2em 3em;\n\t\t\tmax-width: 900px;\n\t\t\tmargin: 0 auto;\n\t\t}\n\t\t.pict-content-loading {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tmin-height: 200px;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tfont-size: 1em;\n\t\t}\n\t\t.pict-content h1 {\n\t\t\tfont-size: 2em;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tborder-bottom: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tpadding-bottom: 0.3em;\n\t\t\tmargin-top: 0;\n\t\t}\n\t\t.pict-content h2 {\n\t\t\tfont-size: 1.5em;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tborder-bottom: 1px solid var(--theme-color-border-light, #EAE3D8);\n\t\t\tpadding-bottom: 0.25em;\n\t\t\tmargin-top: 1.5em;\n\t\t}\n\t\t.pict-content h3 {\n\t\t\tfont-size: 1.25em;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tmargin-top: 1.25em;\n\t\t}\n\t\t.pict-content h4, .pict-content h5, .pict-content h6 {\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tmargin-top: 1em;\n\t\t}\n\t\t.pict-content p {\n\t\t\tline-height: 1.7;\n\t\t\tcolor: var(--theme-color-text-primary, #423D37);\n\t\t\tmargin: 0.75em 0;\n\t\t}\n\t\t.pict-content a {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\ttext-decoration: none;\n\t\t}\n\t\t.pict-content a:hover {\n\t\t\ttext-decoration: underline;\n\t\t}\n\t\t/* \u2500\u2500\u2500 Code blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\t\t Background, text color, line-number gutter, and every\n\t\t syntax token route through pict-provider-theme tokens \u2014\n\t\t the same set pict-section-code (the live editor) uses.\n\t\t This way the rendered-preview code blocks look identical\n\t\t to the live editor and re-skin together when the theme\n\t\t switches. Previous version used the text-primary token\n\t\t as the code background (a TEXT token used as BACKGROUND),\n\t\t which broke in dark mode and any palette where text and\n\t\t background-tertiary diverge.\n\t\t*/\n\t\t.pict-content pre {\n\t\t\tbackground: var(--theme-color-background-tertiary, #F0ECE4);\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tpadding: 1.25em;\n\t\t\tborder-radius: 6px;\n\t\t\toverflow-x: auto;\n\t\t\tline-height: 1.5;\n\t\t\tfont-size: 0.9em;\n\t\t\tfont-family: var(--theme-typography-family-mono, 'SFMono-Regular', 'SF Mono', 'Menlo', 'Consolas', 'Liberation Mono', 'Courier New', monospace);\n\t\t}\n\t\t/* Inline code (single backtick) \u2014 slightly differentiated\n\t\t from block code so it doesn't disappear into prose. */\n\t\t.pict-content code {\n\t\t\tbackground: var(--theme-color-background-secondary, #FAF8F4);\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tpadding: 0.15em 0.4em;\n\t\t\tborder-radius: 3px;\n\t\t\tfont-size: 0.9em;\n\t\t\tfont-family: var(--theme-typography-family-mono, 'SFMono-Regular', 'SF Mono', 'Menlo', monospace);\n\t\t}\n\t\t.pict-content-code-wrap {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: row;\n\t\t\tfont-family: var(--theme-typography-family-mono, 'SFMono-Regular', 'SF Mono', 'Menlo', 'Consolas', 'Liberation Mono', 'Courier New', monospace);\n\t\t\tfont-size: 14px;\n\t\t\tline-height: 1.5;\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tborder-radius: 6px;\n\t\t\toverflow: hidden;\n\t\t\tmargin: 1em 0;\n\t\t\tbackground: var(--theme-color-background-tertiary, #F0ECE4);\n\t\t}\n\t\t.pict-content-code-wrap .pict-content-code-line-numbers {\n\t\t\twidth: 40px;\n\t\t\tmin-width: 40px;\n\t\t\tpadding: 1.25em 0;\n\t\t\ttext-align: right;\n\t\t\tbackground: var(--theme-color-background-secondary, #FAF8F4);\n\t\t\tborder-right: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tfont-family: inherit;\n\t\t\tfont-size: inherit;\n\t\t\tline-height: inherit;\n\t\t\tuser-select: none;\n\t\t\tpointer-events: none;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\t\t.pict-content-code-wrap .pict-content-code-line-numbers span {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0 8px 0 0;\n\t\t}\n\t\t.pict-content-code-wrap pre {\n\t\t\tmargin: 0;\n\t\t\tbackground: var(--theme-color-background-tertiary, #F0ECE4);\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tborder: none;\n\t\t\tpadding: 1.25em 1.25em 1.25em 8px;\n\t\t\tborder-radius: 0 6px 6px 0;\n\t\t\toverflow-x: auto;\n\t\t\tline-height: 1.5;\n\t\t\tfont-size: inherit;\n\t\t\tflex: 1;\n\t\t\tmin-width: 0;\n\t\t}\n\t\t.pict-content-code-wrap pre code {\n\t\t\tbackground: none;\n\t\t\tpadding: 0;\n\t\t\tcolor: inherit;\n\t\t\tfont-size: inherit;\n\t\t\tfont-family: inherit;\n\t\t}\n\t\t/* Syntax token colors \u2014 every class binds to a --theme-color-syntax-*\n\t\t variable, the same tokens pict-section-code (the live editor) uses.\n\t\t Each var() carries an Atom One Light hex as fallback for hosts\n\t\t without a theme provider; themes that DO ship syntax tokens\n\t\t (pict-default, retold-content-system, etc.) drive everything\n\t\t coherently. */\n\t\t.pict-content-code-wrap .keyword { color: var(--theme-color-syntax-keyword, #A626A4); }\n\t\t.pict-content-code-wrap .string { color: var(--theme-color-syntax-string, #50A14F); }\n\t\t.pict-content-code-wrap .number { color: var(--theme-color-syntax-number, #986801); }\n\t\t.pict-content-code-wrap .comment { color: var(--theme-color-syntax-comment, #A0A1A7); font-style: italic; }\n\t\t.pict-content-code-wrap .operator { color: var(--theme-color-syntax-operator, #0184BC); }\n\t\t.pict-content-code-wrap .punctuation { color: var(--theme-color-syntax-punctuation, #383A42); }\n\t\t.pict-content-code-wrap .function-name { color: var(--theme-color-syntax-function, #4078F2); }\n\t\t.pict-content-code-wrap .property { color: var(--theme-color-syntax-property, #E45649); }\n\t\t.pict-content-code-wrap .tag { color: var(--theme-color-syntax-tag, #E45649); }\n\t\t.pict-content-code-wrap .attr-name { color: var(--theme-color-syntax-attrname, #986801); }\n\t\t.pict-content-code-wrap .attr-value { color: var(--theme-color-syntax-attrvalue, #50A14F); }\n\t\t.pict-content-code-wrap .builtin { color: var(--theme-color-syntax-builtin, #986801); }\n\t\t.pict-content-code-wrap .type { color: var(--theme-color-syntax-type, #C18401); }\n\t\t.pict-content-code-wrap .variable { color: var(--theme-color-syntax-variable, #383A42); }\n\t\t.pict-content pre code {\n\t\t\tbackground: none;\n\t\t\tpadding: 0;\n\t\t\tcolor: inherit;\n\t\t\tfont-size: inherit;\n\t\t}\n\t\t.pict-content blockquote {\n\t\t\tborder-left: 4px solid var(--theme-color-brand-primary, #2E7D74);\n\t\t\tmargin: 1em 0;\n\t\t\tpadding: 0.5em 1em;\n\t\t\tbackground: var(--theme-color-background-secondary, #F7F5F0);\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t}\n\t\t.pict-content blockquote p {\n\t\t\tmargin: 0.25em 0;\n\t\t}\n\t\t.pict-content ul, .pict-content ol {\n\t\t\tpadding-left: 2em;\n\t\t\tline-height: 1.8;\n\t\t}\n\t\t.pict-content li {\n\t\t\tmargin: 0.25em 0;\n\t\t\tcolor: var(--theme-color-text-primary, #423D37);\n\t\t}\n\t\t.pict-content hr {\n\t\t\tborder: none;\n\t\t\tborder-top: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tmargin: 2em 0;\n\t\t}\n\t\t.pict-content table {\n\t\t\twidth: 100%;\n\t\t\tborder-collapse: collapse;\n\t\t\tmargin: 1em 0;\n\t\t}\n\t\t.pict-content table th {\n\t\t\tbackground: var(--theme-color-background-secondary, #F5F0E8);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tpadding: 0.6em 0.8em;\n\t\t\ttext-align: left;\n\t\t\tfont-weight: 600;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t}\n\t\t.pict-content table td {\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tpadding: 0.5em 0.8em;\n\t\t\tcolor: var(--theme-color-text-primary, #423D37);\n\t\t}\n\t\t.pict-content table tr:nth-child(even) {\n\t\t\tbackground: var(--theme-color-background-secondary, #F7F5F0);\n\t\t}\n\t\t.pict-content img {\n\t\t\tmax-width: 100%;\n\t\t\theight: auto;\n\t\t}\n\t\t.pict-content pre.mermaid {\n\t\t\tbackground: var(--theme-color-background-panel, #fff);\n\t\t\tcolor: var(--theme-color-text-primary, #2A241E);\n\t\t\ttext-align: center;\n\t\t\tpadding: 1em;\n\t\t}\n\t\t.pict-content pre.mermaid text,\n\t\t.pict-content pre.mermaid .nodeLabel,\n\t\t.pict-content pre.mermaid .edgeLabel,\n\t\t.pict-content pre.mermaid .label,\n\t\t.pict-content pre.mermaid .cluster-label,\n\t\t.pict-content pre.mermaid span,\n\t\t.pict-content pre.mermaid foreignObject p,\n\t\t.pict-content pre.mermaid foreignObject div,\n\t\t.pict-content pre.mermaid foreignObject span {\n\t\t\tcolor: var(--theme-color-text-primary, #2A241E) !important;\n\t\t\tfill: var(--theme-color-text-primary, #2A241E) !important;\n\t\t}\n\t\t.pict-content pre.mermaid .edgePath .path {\n\t\t\tstroke: var(--theme-color-text-secondary, #5E5549) !important;\n\t\t}\n\t\t.pict-content pre.mermaid .arrowheadPath {\n\t\t\tfill: var(--theme-color-text-secondary, #5E5549) !important;\n\t\t}\n\t\t.pict-content .pict-content-katex-display {\n\t\t\ttext-align: center;\n\t\t\tmargin: 1em 0;\n\t\t\tpadding: 0.5em;\n\t\t\toverflow-x: auto;\n\t\t}\n\t\t.pict-content .pict-content-katex-inline {\n\t\t\tdisplay: inline;\n\t\t}\n\n\t\t/* Fullscreen viewer for images and mermaid diagrams (click-to-zoom) */\n\t\t.pict-content [data-fullscreen-source] {\n\t\t\tcursor: zoom-in;\n\t\t\toutline: 1px solid transparent;\n\t\t\toutline-offset: 3px;\n\t\t\tborder-radius: 4px;\n\t\t\ttransition: outline-color 0.15s ease;\n\t\t}\n\t\t.pict-content [data-fullscreen-source]:hover {\n\t\t\toutline-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t/* Code block container with hover-revealed action buttons */\n\t\t.pict-content-code-container {\n\t\t\tposition: relative;\n\t\t\tdisplay: flex;\n\t\t\talign-items: flex-start;\n\t\t\tgap: 8px;\n\t\t\tmargin: 1em 0;\n\t\t}\n\t\t.pict-content-code-container > .pict-content-code-wrap {\n\t\t\tmargin: 0;\n\t\t\tflex: 1 1 auto;\n\t\t\tmin-width: 0;\n\t\t}\n\t\t.pict-content-code-actions {\n\t\t\tposition: sticky;\n\t\t\ttop: 64px;\n\t\t\talign-self: flex-start;\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tgap: 6px;\n\t\t\tflex: 0 0 auto;\n\t\t\tpadding-top: 6px;\n\t\t\topacity: 0;\n\t\t\ttransform: translateX(-4px);\n\t\t\ttransition: opacity 0.15s ease, transform 0.15s ease;\n\t\t\tpointer-events: none;\n\t\t}\n\t\t.pict-content-code-container:hover .pict-content-code-actions,\n\t\t.pict-content-code-container:focus-within .pict-content-code-actions {\n\t\t\topacity: 1;\n\t\t\ttransform: translateX(0);\n\t\t\tpointer-events: auto;\n\t\t}\n\t\t.pict-content-code-action-btn {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\twidth: 28px;\n\t\t\theight: 28px;\n\t\t\tpadding: 0;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tcolor: var(--theme-color-text-muted, #5E5549);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tborder-radius: 6px;\n\t\t\tcursor: pointer;\n\t\t\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n\t\t\ttransition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;\n\t\t}\n\t\t.pict-content-code-action-btn svg {\n\t\t\tdisplay: block;\n\t\t\twidth: 14px;\n\t\t\theight: 14px;\n\t\t\tstroke: currentColor;\n\t\t\tfill: none;\n\t\t\tstroke-width: 1.6;\n\t\t\tstroke-linecap: round;\n\t\t\tstroke-linejoin: round;\n\t\t}\n\t\t.pict-content-code-action-btn:hover {\n\t\t\tbackground: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tcolor: var(--theme-color-text-on-brand, #FFFFFF);\n\t\t\tborder-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tbox-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);\n\t\t}\n\t\t.pict-content-code-action-btn:focus-visible {\n\t\t\toutline: 2px solid var(--theme-color-brand-primary, #2E7D74);\n\t\t\toutline-offset: 2px;\n\t\t}\n\t\t.pict-content-code-action-btn.is-copied {\n\t\t\tbackground: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tcolor: var(--theme-color-text-on-brand, #FFFFFF);\n\t\t\tborder-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.pict-content-code-action-btn.is-copy-failed {\n\t\t\tbackground: var(--theme-color-status-error, #B23A3A);\n\t\t\tcolor: var(--theme-color-text-on-brand, #FFFFFF);\n\t\t\tborder-color: var(--theme-color-status-error, #B23A3A);\n\t\t}\n\t\t.pict-fullscreen-overlay {\n\t\t\tposition: fixed;\n\t\t\tinset: 0;\n\t\t\tz-index: 9999;\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tbackground: rgba(0, 0, 0, 0.62);\n\t\t\tbackdrop-filter: blur(6px);\n\t\t\t-webkit-backdrop-filter: blur(6px);\n\t\t\tcolor: var(--theme-color-text-primary, #2A241E);\n\t\t}\n\t\t.pict-fullscreen-overlay[hidden] {\n\t\t\tdisplay: none;\n\t\t}\n\t\t.pict-fullscreen-titlebar {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: space-between;\n\t\t\tgap: 1em;\n\t\t\theight: 48px;\n\t\t\tpadding: 0 1em;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tcolor: var(--theme-color-text-primary, #1A1612);\n\t\t\tborder-bottom: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tbox-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);\n\t\t\tflex: 0 0 auto;\n\t\t}\n\t\t.pict-fullscreen-title {\n\t\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n\t\t\tfont-size: 0.95em;\n\t\t\tfont-weight: 600;\n\t\t\tletter-spacing: 0.01em;\n\t\t\twhite-space: nowrap;\n\t\t\toverflow: hidden;\n\t\t\ttext-overflow: ellipsis;\n\t\t\tcolor: var(--theme-color-text-primary, #1A1612);\n\t\t}\n\t\t.pict-fullscreen-controls {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tgap: 4px;\n\t\t}\n\t\t.pict-fullscreen-btn {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\twidth: 32px;\n\t\t\theight: 32px;\n\t\t\tpadding: 0;\n\t\t\tbackground: transparent;\n\t\t\tborder: 1px solid transparent;\n\t\t\tborder-radius: 6px;\n\t\t\tcolor: var(--theme-color-text-muted, #5E5549);\n\t\t\tcursor: pointer;\n\t\t\ttransition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;\n\t\t}\n\t\t.pict-fullscreen-btn svg {\n\t\t\tdisplay: block;\n\t\t\twidth: 16px;\n\t\t\theight: 16px;\n\t\t\tstroke: currentColor;\n\t\t\tfill: none;\n\t\t\tstroke-width: 1.75;\n\t\t\tstroke-linecap: round;\n\t\t\tstroke-linejoin: round;\n\t\t}\n\t\t.pict-fullscreen-btn:hover {\n\t\t\tbackground: var(--theme-color-border-light, #EAE3D8);\n\t\t\tcolor: var(--theme-color-text-primary, #1A1612);\n\t\t}\n\t\t.pict-fullscreen-btn:focus-visible {\n\t\t\toutline: 2px solid var(--theme-color-brand-primary, #2E7D74);\n\t\t\toutline-offset: 2px;\n\t\t}\n\t\t.pict-fullscreen-close:hover {\n\t\t\tbackground: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tcolor: var(--theme-color-text-on-brand, #FFFFFF);\n\t\t}\n\t\t.pict-fullscreen-stage {\n\t\t\tflex: 1 1 auto;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\toverflow: hidden;\n\t\t\tpadding: 1.5em;\n\t\t\tcursor: zoom-in;\n\t\t\ttouch-action: none;\n\t\t}\n\t\t.pict-fullscreen-stage.is-zoomed {\n\t\t\tcursor: grab;\n\t\t}\n\t\t.pict-fullscreen-stage.is-panning {\n\t\t\tcursor: grabbing;\n\t\t}\n\t\t.pict-fullscreen-content {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tmax-width: 100%;\n\t\t\tmax-height: 100%;\n\t\t\ttransform-origin: center center;\n\t\t\ttransition: transform 0.05s linear;\n\t\t\twill-change: transform;\n\t\t}\n\t\t.pict-fullscreen-content > * {\n\t\t\tbox-shadow: 0 12px 48px rgba(0, 0, 0, 0.45);\n\t\t}\n\t\t.pict-fullscreen-content .pict-fullscreen-img {\n\t\t\tmax-width: 90vw;\n\t\t\tmax-height: calc(100vh - 96px);\n\t\t\twidth: auto;\n\t\t\theight: auto;\n\t\t\tobject-fit: contain;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tpadding: 12px;\n\t\t\tborder-radius: 6px;\n\t\t}\n\t\t.pict-fullscreen-content .pict-fullscreen-mermaid-svg {\n\t\t\twidth: min(90vw, 1400px);\n\t\t\theight: auto;\n\t\t\tmax-height: calc(100vh - 96px);\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tpadding: 16px;\n\t\t\tborder-radius: 6px;\n\t\t}\n\t\t.pict-fullscreen-content .pict-fullscreen-codewrap {\n\t\t\tmax-width: 90vw;\n\t\t\tmax-height: calc(100vh - 96px);\n\t\t\tmargin: 0;\n\t\t\toverflow: auto;\n\t\t\tbox-shadow: 0 12px 48px rgba(0, 0, 0, 0.45);\n\t\t}\n\t",Templates:[{Hash:"Pict-Content-Template",Template:/*html*/"\n<div class=\"pict-content\" id=\"Pict-Content-Body\">\n\t<div class=\"pict-content-loading\">Loading content...</div>\n</div>\n"}],Renderables:[{RenderableHash:"Pict-Content-Display",TemplateHash:"Pict-Content-Template",DestinationAddress:"#Pict-Content-Container",RenderMethod:"replace"}]};class PictContentView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);}/**
6150
+ */escapeHTML(pText){if(!pText){return'';}return pText.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;').replace(/'/g,'&#39;');}}module.exports=PictContentProvider;module.exports.default_configuration={ProviderIdentifier:"Pict-Content",AutoInitialize:true,AutoInitializeOrdinal:0};},{"pict-provider":148,"pict-section-code":151}],155:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"Pict-Content",DefaultRenderable:"Pict-Content-Display",DefaultDestinationAddress:"#Pict-Content-Container",AutoRender:false,CSS:/*css*/"\n\t\t.pict-content {\n\t\t\tpadding: 2em 3em;\n\t\t\tmax-width: 900px;\n\t\t\tmargin: 0 auto;\n\t\t}\n\t\t.pict-content-loading {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tmin-height: 200px;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tfont-size: 1em;\n\t\t}\n\t\t.pict-content h1 {\n\t\t\tfont-size: 2em;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tborder-bottom: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tpadding-bottom: 0.3em;\n\t\t\tmargin-top: 0;\n\t\t}\n\t\t.pict-content h2 {\n\t\t\tfont-size: 1.5em;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tborder-bottom: 1px solid var(--theme-color-border-light, #EAE3D8);\n\t\t\tpadding-bottom: 0.25em;\n\t\t\tmargin-top: 1.5em;\n\t\t}\n\t\t.pict-content h3 {\n\t\t\tfont-size: 1.25em;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tmargin-top: 1.25em;\n\t\t}\n\t\t.pict-content h4, .pict-content h5, .pict-content h6 {\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tmargin-top: 1em;\n\t\t}\n\t\t.pict-content p {\n\t\t\tline-height: 1.7;\n\t\t\tcolor: var(--theme-color-text-primary, #423D37);\n\t\t\tmargin: 0.75em 0;\n\t\t}\n\t\t.pict-content a {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\ttext-decoration: none;\n\t\t}\n\t\t.pict-content a:hover {\n\t\t\ttext-decoration: underline;\n\t\t}\n\t\t/* \u2500\u2500\u2500 Code blocks \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n\t\t Background, text color, line-number gutter, and every\n\t\t syntax token route through pict-provider-theme tokens \u2014\n\t\t the same set pict-section-code (the live editor) uses.\n\t\t This way the rendered-preview code blocks look identical\n\t\t to the live editor and re-skin together when the theme\n\t\t switches. Previous version used the text-primary token\n\t\t as the code background (a TEXT token used as BACKGROUND),\n\t\t which broke in dark mode and any palette where text and\n\t\t background-tertiary diverge.\n\t\t*/\n\t\t.pict-content pre {\n\t\t\tbackground: var(--theme-color-background-tertiary, #F0ECE4);\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tpadding: 1.25em;\n\t\t\tborder-radius: 6px;\n\t\t\toverflow-x: auto;\n\t\t\tline-height: 1.5;\n\t\t\tfont-size: 0.9em;\n\t\t\tfont-family: var(--theme-typography-family-mono, 'SFMono-Regular', 'SF Mono', 'Menlo', 'Consolas', 'Liberation Mono', 'Courier New', monospace);\n\t\t}\n\t\t/* Inline code (single backtick) \u2014 slightly differentiated\n\t\t from block code so it doesn't disappear into prose. */\n\t\t.pict-content code {\n\t\t\tbackground: var(--theme-color-background-secondary, #FAF8F4);\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tpadding: 0.15em 0.4em;\n\t\t\tborder-radius: 3px;\n\t\t\tfont-size: 0.9em;\n\t\t\tfont-family: var(--theme-typography-family-mono, 'SFMono-Regular', 'SF Mono', 'Menlo', monospace);\n\t\t}\n\t\t.pict-content-code-wrap {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: row;\n\t\t\tfont-family: var(--theme-typography-family-mono, 'SFMono-Regular', 'SF Mono', 'Menlo', 'Consolas', 'Liberation Mono', 'Courier New', monospace);\n\t\t\tfont-size: 14px;\n\t\t\tline-height: 1.5;\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tborder-radius: 6px;\n\t\t\toverflow: hidden;\n\t\t\tmargin: 1em 0;\n\t\t\tbackground: var(--theme-color-background-tertiary, #F0ECE4);\n\t\t}\n\t\t.pict-content-code-wrap .pict-content-code-line-numbers {\n\t\t\twidth: 40px;\n\t\t\tmin-width: 40px;\n\t\t\tpadding: 1.25em 0;\n\t\t\ttext-align: right;\n\t\t\tbackground: var(--theme-color-background-secondary, #FAF8F4);\n\t\t\tborder-right: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tfont-family: inherit;\n\t\t\tfont-size: inherit;\n\t\t\tline-height: inherit;\n\t\t\tuser-select: none;\n\t\t\tpointer-events: none;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\t\t.pict-content-code-wrap .pict-content-code-line-numbers span {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0 8px 0 0;\n\t\t}\n\t\t.pict-content-code-wrap pre {\n\t\t\tmargin: 0;\n\t\t\tbackground: var(--theme-color-background-tertiary, #F0ECE4);\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tborder: none;\n\t\t\tpadding: 1.25em 1.25em 1.25em 8px;\n\t\t\tborder-radius: 0 6px 6px 0;\n\t\t\toverflow-x: auto;\n\t\t\tline-height: 1.5;\n\t\t\tfont-size: inherit;\n\t\t\tflex: 1;\n\t\t\tmin-width: 0;\n\t\t}\n\t\t.pict-content-code-wrap pre code {\n\t\t\tbackground: none;\n\t\t\tpadding: 0;\n\t\t\tcolor: inherit;\n\t\t\tfont-size: inherit;\n\t\t\tfont-family: inherit;\n\t\t}\n\t\t/* Syntax token colors \u2014 every class binds to a --theme-color-syntax-*\n\t\t variable, the same tokens pict-section-code (the live editor) uses.\n\t\t Each var() carries an Atom One Light hex as fallback for hosts\n\t\t without a theme provider; themes that DO ship syntax tokens\n\t\t (pict-default, retold-content-system, etc.) drive everything\n\t\t coherently. */\n\t\t.pict-content-code-wrap .keyword { color: var(--theme-color-syntax-keyword, #A626A4); }\n\t\t.pict-content-code-wrap .string { color: var(--theme-color-syntax-string, #50A14F); }\n\t\t.pict-content-code-wrap .number { color: var(--theme-color-syntax-number, #986801); }\n\t\t.pict-content-code-wrap .comment { color: var(--theme-color-syntax-comment, #A0A1A7); font-style: italic; }\n\t\t.pict-content-code-wrap .operator { color: var(--theme-color-syntax-operator, #0184BC); }\n\t\t.pict-content-code-wrap .punctuation { color: var(--theme-color-syntax-punctuation, #383A42); }\n\t\t.pict-content-code-wrap .function-name { color: var(--theme-color-syntax-function, #4078F2); }\n\t\t.pict-content-code-wrap .property { color: var(--theme-color-syntax-property, #E45649); }\n\t\t.pict-content-code-wrap .tag { color: var(--theme-color-syntax-tag, #E45649); }\n\t\t.pict-content-code-wrap .attr-name { color: var(--theme-color-syntax-attrname, #986801); }\n\t\t.pict-content-code-wrap .attr-value { color: var(--theme-color-syntax-attrvalue, #50A14F); }\n\t\t.pict-content-code-wrap .builtin { color: var(--theme-color-syntax-builtin, #986801); }\n\t\t.pict-content-code-wrap .type { color: var(--theme-color-syntax-type, #C18401); }\n\t\t.pict-content-code-wrap .variable { color: var(--theme-color-syntax-variable, #383A42); }\n\t\t.pict-content pre code {\n\t\t\tbackground: none;\n\t\t\tpadding: 0;\n\t\t\tcolor: inherit;\n\t\t\tfont-size: inherit;\n\t\t}\n\t\t.pict-content blockquote {\n\t\t\tborder-left: 4px solid var(--theme-color-brand-primary, #2E7D74);\n\t\t\tmargin: 1em 0;\n\t\t\tpadding: 0.5em 1em;\n\t\t\tbackground: var(--theme-color-background-secondary, #F7F5F0);\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t}\n\t\t.pict-content blockquote p {\n\t\t\tmargin: 0.25em 0;\n\t\t}\n\t\t.pict-content ul, .pict-content ol {\n\t\t\tpadding-left: 2em;\n\t\t\tline-height: 1.8;\n\t\t}\n\t\t.pict-content li {\n\t\t\tmargin: 0.25em 0;\n\t\t\tcolor: var(--theme-color-text-primary, #423D37);\n\t\t}\n\t\t.pict-content hr {\n\t\t\tborder: none;\n\t\t\tborder-top: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tmargin: 2em 0;\n\t\t}\n\t\t.pict-content table {\n\t\t\twidth: 100%;\n\t\t\tborder-collapse: collapse;\n\t\t\tmargin: 1em 0;\n\t\t}\n\t\t.pict-content table th {\n\t\t\tbackground: var(--theme-color-background-secondary, #F5F0E8);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tpadding: 0.6em 0.8em;\n\t\t\ttext-align: left;\n\t\t\tfont-weight: 600;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t}\n\t\t.pict-content table td {\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tpadding: 0.5em 0.8em;\n\t\t\tcolor: var(--theme-color-text-primary, #423D37);\n\t\t}\n\t\t.pict-content table tr:nth-child(even) {\n\t\t\tbackground: var(--theme-color-background-secondary, #F7F5F0);\n\t\t}\n\t\t.pict-content img {\n\t\t\tmax-width: 100%;\n\t\t\theight: auto;\n\t\t}\n\t\t.pict-content pre.mermaid {\n\t\t\tbackground: var(--theme-color-background-panel, #fff);\n\t\t\tcolor: var(--theme-color-text-primary, #2A241E);\n\t\t\ttext-align: center;\n\t\t\tpadding: 1em;\n\t\t}\n\t\t.pict-content pre.mermaid text,\n\t\t.pict-content pre.mermaid .nodeLabel,\n\t\t.pict-content pre.mermaid .edgeLabel,\n\t\t.pict-content pre.mermaid .label,\n\t\t.pict-content pre.mermaid .cluster-label,\n\t\t.pict-content pre.mermaid span,\n\t\t.pict-content pre.mermaid foreignObject p,\n\t\t.pict-content pre.mermaid foreignObject div,\n\t\t.pict-content pre.mermaid foreignObject span {\n\t\t\tcolor: var(--theme-color-text-primary, #2A241E) !important;\n\t\t\tfill: var(--theme-color-text-primary, #2A241E) !important;\n\t\t}\n\t\t.pict-content pre.mermaid .edgePath .path {\n\t\t\tstroke: var(--theme-color-text-secondary, #5E5549) !important;\n\t\t}\n\t\t.pict-content pre.mermaid .arrowheadPath {\n\t\t\tfill: var(--theme-color-text-secondary, #5E5549) !important;\n\t\t}\n\t\t/* Excalidraw fence placeholders + rendered SVGs */\n\t\t.pict-content .pict-excalidraw-fence {\n\t\t\tdisplay: block;\n\t\t\tbackground: var(--theme-color-background-panel, #fff);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tborder-radius: 4px;\n\t\t\tpadding: 1em;\n\t\t\tmargin: 1em 0;\n\t\t\ttext-align: center;\n\t\t}\n\t\t.pict-content .pict-excalidraw-fence svg {\n\t\t\tmax-width: 100%;\n\t\t\theight: auto;\n\t\t}\n\t\t.pict-content .pict-excalidraw-fence-loading {\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tfont-style: italic;\n\t\t\tfont-size: 0.9em;\n\t\t\tpadding: 1em;\n\t\t}\n\t\t.pict-content .pict-excalidraw-fence-error {\n\t\t\tborder-color: var(--theme-color-status-error, #D9534F);\n\t\t\tbackground: var(--theme-color-background-secondary, #FFF5F5);\n\t\t}\n\t\t.pict-content .pict-excalidraw-fence-error-message {\n\t\t\tcolor: var(--theme-color-status-error, #D9534F);\n\t\t\tfont-family: var(--theme-typography-family-mono, monospace);\n\t\t\tfont-size: 0.85em;\n\t\t\ttext-align: left;\n\t\t}\n\t\t.pict-content .pict-content-katex-display {\n\t\t\ttext-align: center;\n\t\t\tmargin: 1em 0;\n\t\t\tpadding: 0.5em;\n\t\t\toverflow-x: auto;\n\t\t}\n\t\t.pict-content .pict-content-katex-inline {\n\t\t\tdisplay: inline;\n\t\t}\n\n\t\t/* Fullscreen viewer for images and mermaid diagrams (click-to-zoom) */\n\t\t.pict-content [data-fullscreen-source] {\n\t\t\tcursor: zoom-in;\n\t\t\toutline: 1px solid transparent;\n\t\t\toutline-offset: 3px;\n\t\t\tborder-radius: 4px;\n\t\t\ttransition: outline-color 0.15s ease;\n\t\t}\n\t\t.pict-content [data-fullscreen-source]:hover {\n\t\t\toutline-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t/* Code block container with hover-revealed action buttons */\n\t\t.pict-content-code-container {\n\t\t\tposition: relative;\n\t\t\tdisplay: flex;\n\t\t\talign-items: flex-start;\n\t\t\tgap: 8px;\n\t\t\tmargin: 1em 0;\n\t\t}\n\t\t.pict-content-code-container > .pict-content-code-wrap {\n\t\t\tmargin: 0;\n\t\t\tflex: 1 1 auto;\n\t\t\tmin-width: 0;\n\t\t}\n\t\t.pict-content-code-actions {\n\t\t\tposition: sticky;\n\t\t\ttop: 64px;\n\t\t\talign-self: flex-start;\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tgap: 6px;\n\t\t\tflex: 0 0 auto;\n\t\t\tpadding-top: 6px;\n\t\t\topacity: 0;\n\t\t\ttransform: translateX(-4px);\n\t\t\ttransition: opacity 0.15s ease, transform 0.15s ease;\n\t\t\tpointer-events: none;\n\t\t}\n\t\t.pict-content-code-container:hover .pict-content-code-actions,\n\t\t.pict-content-code-container:focus-within .pict-content-code-actions {\n\t\t\topacity: 1;\n\t\t\ttransform: translateX(0);\n\t\t\tpointer-events: auto;\n\t\t}\n\t\t.pict-content-code-action-btn {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\twidth: 28px;\n\t\t\theight: 28px;\n\t\t\tpadding: 0;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tcolor: var(--theme-color-text-muted, #5E5549);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tborder-radius: 6px;\n\t\t\tcursor: pointer;\n\t\t\tbox-shadow: 0 1px 3px rgba(0, 0, 0, 0.08);\n\t\t\ttransition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease, box-shadow 0.15s ease;\n\t\t}\n\t\t.pict-content-code-action-btn svg {\n\t\t\tdisplay: block;\n\t\t\twidth: 14px;\n\t\t\theight: 14px;\n\t\t\tstroke: currentColor;\n\t\t\tfill: none;\n\t\t\tstroke-width: 1.6;\n\t\t\tstroke-linecap: round;\n\t\t\tstroke-linejoin: round;\n\t\t}\n\t\t.pict-content-code-action-btn:hover {\n\t\t\tbackground: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tcolor: var(--theme-color-text-on-brand, #FFFFFF);\n\t\t\tborder-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tbox-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);\n\t\t}\n\t\t.pict-content-code-action-btn:focus-visible {\n\t\t\toutline: 2px solid var(--theme-color-brand-primary, #2E7D74);\n\t\t\toutline-offset: 2px;\n\t\t}\n\t\t.pict-content-code-action-btn.is-copied {\n\t\t\tbackground: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tcolor: var(--theme-color-text-on-brand, #FFFFFF);\n\t\t\tborder-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.pict-content-code-action-btn.is-copy-failed {\n\t\t\tbackground: var(--theme-color-status-error, #B23A3A);\n\t\t\tcolor: var(--theme-color-text-on-brand, #FFFFFF);\n\t\t\tborder-color: var(--theme-color-status-error, #B23A3A);\n\t\t}\n\t\t.pict-fullscreen-overlay {\n\t\t\tposition: fixed;\n\t\t\tinset: 0;\n\t\t\tz-index: 9999;\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tbackground: rgba(0, 0, 0, 0.62);\n\t\t\tbackdrop-filter: blur(6px);\n\t\t\t-webkit-backdrop-filter: blur(6px);\n\t\t\tcolor: var(--theme-color-text-primary, #2A241E);\n\t\t}\n\t\t.pict-fullscreen-overlay[hidden] {\n\t\t\tdisplay: none;\n\t\t}\n\t\t.pict-fullscreen-titlebar {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: space-between;\n\t\t\tgap: 1em;\n\t\t\theight: 48px;\n\t\t\tpadding: 0 1em;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tcolor: var(--theme-color-text-primary, #1A1612);\n\t\t\tborder-bottom: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tbox-shadow: 0 2px 8px rgba(0, 0, 0, 0.18);\n\t\t\tflex: 0 0 auto;\n\t\t}\n\t\t.pict-fullscreen-title {\n\t\t\tfont-family: -apple-system, BlinkMacSystemFont, \"Segoe UI\", Roboto, sans-serif;\n\t\t\tfont-size: 0.95em;\n\t\t\tfont-weight: 600;\n\t\t\tletter-spacing: 0.01em;\n\t\t\twhite-space: nowrap;\n\t\t\toverflow: hidden;\n\t\t\ttext-overflow: ellipsis;\n\t\t\tcolor: var(--theme-color-text-primary, #1A1612);\n\t\t}\n\t\t.pict-fullscreen-controls {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tgap: 4px;\n\t\t}\n\t\t.pict-fullscreen-btn {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\twidth: 32px;\n\t\t\theight: 32px;\n\t\t\tpadding: 0;\n\t\t\tbackground: transparent;\n\t\t\tborder: 1px solid transparent;\n\t\t\tborder-radius: 6px;\n\t\t\tcolor: var(--theme-color-text-muted, #5E5549);\n\t\t\tcursor: pointer;\n\t\t\ttransition: background-color 0.15s ease, color 0.15s ease, border-color 0.15s ease;\n\t\t}\n\t\t.pict-fullscreen-btn svg {\n\t\t\tdisplay: block;\n\t\t\twidth: 16px;\n\t\t\theight: 16px;\n\t\t\tstroke: currentColor;\n\t\t\tfill: none;\n\t\t\tstroke-width: 1.75;\n\t\t\tstroke-linecap: round;\n\t\t\tstroke-linejoin: round;\n\t\t}\n\t\t.pict-fullscreen-btn:hover {\n\t\t\tbackground: var(--theme-color-border-light, #EAE3D8);\n\t\t\tcolor: var(--theme-color-text-primary, #1A1612);\n\t\t}\n\t\t.pict-fullscreen-btn:focus-visible {\n\t\t\toutline: 2px solid var(--theme-color-brand-primary, #2E7D74);\n\t\t\toutline-offset: 2px;\n\t\t}\n\t\t.pict-fullscreen-close:hover {\n\t\t\tbackground: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tcolor: var(--theme-color-text-on-brand, #FFFFFF);\n\t\t}\n\t\t.pict-fullscreen-stage {\n\t\t\tflex: 1 1 auto;\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\toverflow: hidden;\n\t\t\tpadding: 1.5em;\n\t\t\tcursor: zoom-in;\n\t\t\ttouch-action: none;\n\t\t}\n\t\t.pict-fullscreen-stage.is-zoomed {\n\t\t\tcursor: grab;\n\t\t}\n\t\t.pict-fullscreen-stage.is-panning {\n\t\t\tcursor: grabbing;\n\t\t}\n\t\t.pict-fullscreen-content {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tmax-width: 100%;\n\t\t\tmax-height: 100%;\n\t\t\ttransform-origin: center center;\n\t\t\ttransition: transform 0.05s linear;\n\t\t\twill-change: transform;\n\t\t}\n\t\t.pict-fullscreen-content > * {\n\t\t\tbox-shadow: 0 12px 48px rgba(0, 0, 0, 0.45);\n\t\t}\n\t\t.pict-fullscreen-content .pict-fullscreen-img {\n\t\t\tmax-width: 90vw;\n\t\t\tmax-height: calc(100vh - 96px);\n\t\t\twidth: auto;\n\t\t\theight: auto;\n\t\t\tobject-fit: contain;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tpadding: 12px;\n\t\t\tborder-radius: 6px;\n\t\t}\n\t\t.pict-fullscreen-content .pict-fullscreen-mermaid-svg {\n\t\t\twidth: min(90vw, 1400px);\n\t\t\theight: auto;\n\t\t\tmax-height: calc(100vh - 96px);\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tpadding: 16px;\n\t\t\tborder-radius: 6px;\n\t\t}\n\t\t.pict-fullscreen-content .pict-fullscreen-codewrap {\n\t\t\tmax-width: 90vw;\n\t\t\tmax-height: calc(100vh - 96px);\n\t\t\tmargin: 0;\n\t\t\toverflow: auto;\n\t\t\tbox-shadow: 0 12px 48px rgba(0, 0, 0, 0.45);\n\t\t}\n\t",Templates:[{Hash:"Pict-Content-Template",Template:/*html*/"\n<div class=\"pict-content\" id=\"Pict-Content-Body\">\n\t<div class=\"pict-content-loading\">Loading content...</div>\n</div>\n"}],Renderables:[{RenderableHash:"Pict-Content-Display",TemplateHash:"Pict-Content-Template",DestinationAddress:"#Pict-Content-Container",RenderMethod:"replace"}]};class PictContentView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);}/**
6125
6151
  * Display parsed HTML content in the content area.
6126
6152
  *
6127
6153
  * @param {string} pHTMLContent - The HTML to display
@@ -6136,8 +6162,31 @@ if(tmpContentContainer&&!tmpContentContainer.classList.contains('pict-content'))
6136
6162
  // Mermaid blocks are tagged after mermaid.run() resolves (see below).
6137
6163
  this.enableFullscreenViewers(tmpContainerID,{skipMermaid:true});// Post-render: initialize Mermaid diagrams if mermaid is available.
6138
6164
  // Once mermaid finishes, retag so the rendered SVGs are also clickable.
6139
- this.renderMermaidDiagrams(tmpContainerID);// Post-render: render KaTeX equations if katex is available
6165
+ this.renderMermaidDiagrams(tmpContainerID);// Post-render: render ```excalidraw fenced scenes if the
6166
+ // pict-section-excalidraw wrapper bundle is loaded. Each fence
6167
+ // becomes a static SVG (with the scene embedded for re-edit by
6168
+ // retold-content-system).
6169
+ this.renderExcalidrawDiagrams(tmpContainerID);// Post-render: render KaTeX equations if katex is available
6140
6170
  this.renderKaTeXEquations(tmpContainerID);}/**
6171
+ * Render any `.pict-excalidraw-fence` placeholders inside the container
6172
+ * as static SVGs using the pict-section-excalidraw wrapper bundle's
6173
+ * exportToSvg helper. Each fence's scene JSON travels through a
6174
+ * URI-component-encoded data-scene attribute (placed there by the
6175
+ * markdown parser in Pict-Provider-Content).
6176
+ *
6177
+ * Gracefully degrades when the wrapper bundle isn't on the page:
6178
+ * leaves the loading placeholder visible with a one-time console hint.
6179
+ * Idempotent — placeholders carry `data-rendered="true"` after the
6180
+ * first pass so re-renders don't double-emit.
6181
+ *
6182
+ * @param {string} [pContainerID]
6183
+ */renderExcalidrawDiagrams(pContainerID){if(typeof document==='undefined')return;let tmpContainerID=pContainerID||'Pict-Content-Body';let tmpContentBody=document.getElementById(tmpContainerID);if(!tmpContentBody)return;let tmpFences=tmpContentBody.querySelectorAll('.pict-excalidraw-fence:not([data-rendered])');if(tmpFences.length<1)return;let tmpVendor=typeof window!=='undefined'?window.PictSectionExcalidrawVendor:null;if(!tmpVendor||typeof tmpVendor.exportToSvg!=='function'){// Bundle not loaded — leave the placeholder visible. The host
6184
+ // can load the wrapper bundle and call renderExcalidrawDiagrams
6185
+ // again, or include the script tag in its HTML shell.
6186
+ if(this.log&&this.log.warn&&!this._excalidrawBundleWarnLogged){this.log.warn('pict-excalidraw fence(s) found but pict-section-excalidraw wrapper bundle is not loaded — leaving as placeholders.');this._excalidrawBundleWarnLogged=true;}return;}for(let i=0;i<tmpFences.length;i++){let tmpFence=tmpFences[i];let tmpEncoded=tmpFence.getAttribute('data-scene')||'';let tmpJson='';try{tmpJson=decodeURIComponent(tmpEncoded);}catch(pErr){tmpJson='';}let tmpScene;try{tmpScene=JSON.parse(tmpJson);}catch(pErr){this._renderExcalidrawFenceError(tmpFence,'Invalid scene JSON: '+pErr.message);continue;}let tmpExportArgs={elements:tmpScene.elements||[],appState:Object.assign({exportEmbedScene:true},tmpScene.appState||{}),files:tmpScene.files||{}};tmpVendor.exportToSvg(tmpExportArgs).then(pSvgEl=>{if(!pSvgEl)return;// Style the SVG to fit the fence's content width while preserving aspect.
6187
+ pSvgEl.removeAttribute('width');pSvgEl.removeAttribute('height');pSvgEl.setAttribute('style','max-width: 100%; height: auto;');tmpFence.innerHTML='';tmpFence.appendChild(pSvgEl);tmpFence.setAttribute('data-rendered','true');}).catch(pErr=>{this._renderExcalidrawFenceError(tmpFence,'Excalidraw render failed: '+(pErr&&pErr.message?pErr.message:pErr));});}}_renderExcalidrawFenceError(pFence,pMessage){pFence.setAttribute('data-rendered','true');pFence.classList.add('pict-excalidraw-fence-error');pFence.innerHTML='<div class="pict-excalidraw-fence-error-message"></div>';// Use textContent on the inner div so any user-supplied error
6188
+ // substrings (e.g. parser error positions) can't introduce HTML.
6189
+ let tmpMsg=pFence.querySelector('.pict-excalidraw-fence-error-message');if(tmpMsg)tmpMsg.textContent=pMessage;if(this.log&&this.log.warn)this.log.warn('pict-excalidraw fence: '+pMessage);}/**
6141
6190
  * Initialize Mermaid with theme variables read from the active
6142
6191
  * pict-provider-theme palette. Mermaid's `base` theme honors
6143
6192
  * `themeVariables`, so the diagram colors (node fills, cluster
@@ -7198,7 +7247,7 @@ if(typeof pOptions.onOpen==='function'){pOptions.onOpen(pDialog);}}/**
7198
7247
  *
7199
7248
  * @param {string} pText
7200
7249
  * @returns {string}
7201
- */_escapeHTML(pText){if(typeof pText!=='string'){return'';}return pText.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}}module.exports=PictModalWindow;},{}],169:[function(require,module,exports){module.exports={"AutoInitialize":true,"AutoRender":false,"AutoSolveWithApp":false,"ViewIdentifier":"Pict-Section-Modal","OverlayClickDismisses":true,"DefaultConfirmOptions":{"title":"Confirm","confirmLabel":"OK","cancelLabel":"Cancel","dangerous":false,"unbounded":false},"DefaultDoubleConfirmOptions":{"title":"Are you sure?","confirmLabel":"Confirm","cancelLabel":"Cancel","phrasePrompt":"Type \"{phrase}\" to confirm:","confirmPhrase":"","unbounded":false},"DefaultModalOptions":{"title":"","content":"","buttons":[],"closeable":true,"width":"480px","unbounded":false},"DefaultTooltipOptions":{"position":"top","delay":200,"maxWidth":"300px","interactive":false},"DefaultToastOptions":{"type":"info","duration":3000,"position":"top-right","dismissible":true},"DefaultPanelOptions":{"position":"right","width":340,"minWidth":200,"maxWidth":600,"collapsible":true,"collapsed":false,"persist":false,"persistKey":""},"Templates":[],"Renderables":[],"CSS":/*css*/"\n/* pict-section-modal */\n.pict-modal-root\n{\n\t/* Defaults are routed through pict-provider-theme tokens so apps\n\t using the theme provider get themed modals automatically. Each\n\t var() carries its original hex as the fallback so apps that don't\n\t install pict-provider-theme look exactly as before. Apps may\n\t still override any --pict-modal-* var directly to layer over the\n\t theme-driven defaults. */\n\n\t/* Overlay */\n\t--pict-modal-overlay-bg: rgba(0, 0, 0, 0.5);\n\n\t/* Dialog */\n\t--pict-modal-bg: var(--theme-color-background-panel, #ffffff);\n\t--pict-modal-fg: var(--theme-color-text-primary, #1a1a1a);\n\t--pict-modal-border: var(--theme-color-border-default, #e0e0e0);\n\t--pict-modal-border-radius: 8px;\n\t--pict-modal-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);\n\t--pict-modal-header-bg: var(--theme-color-background-secondary, #f5f5f5);\n\t--pict-modal-header-fg: var(--theme-color-text-primary, #1a1a1a);\n\t--pict-modal-header-border: var(--theme-color-border-default, #e0e0e0);\n\n\t/* Buttons */\n\t--pict-modal-btn-bg: var(--theme-color-background-secondary, #e0e0e0);\n\t--pict-modal-btn-fg: var(--theme-color-text-primary, #1a1a1a);\n\t--pict-modal-btn-hover-bg: var(--theme-color-background-hover, #d0d0d0);\n\t--pict-modal-btn-primary-bg: var(--theme-color-brand-primary, #2563eb);\n\t--pict-modal-btn-primary-fg: var(--theme-color-text-on-brand, #ffffff);\n\t--pict-modal-btn-primary-hover-bg:var(--theme-color-brand-primary-hover,#1d4ed8);\n\t--pict-modal-btn-danger-bg: var(--theme-color-status-error, #dc2626);\n\t--pict-modal-btn-danger-fg: var(--theme-color-text-on-brand, #ffffff);\n\t--pict-modal-btn-danger-hover-bg: var(--theme-color-status-error, #b91c1c);\n\t--pict-modal-btn-border-radius: 4px;\n\n\t/* Toast */\n\t--pict-modal-toast-bg: var(--theme-color-background-panel, #333333);\n\t--pict-modal-toast-fg: var(--theme-color-text-primary, #ffffff);\n\t--pict-modal-toast-success-bg: var(--theme-color-status-success, #16a34a);\n\t--pict-modal-toast-warning-bg: var(--theme-color-status-warning, #d97706);\n\t--pict-modal-toast-error-bg: var(--theme-color-status-error, #dc2626);\n\t--pict-modal-toast-info-bg: var(--theme-color-status-info, #2563eb);\n\t--pict-modal-toast-border-radius: 6px;\n\t--pict-modal-toast-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);\n\n\t/* Tooltip */\n\t--pict-modal-tooltip-bg: var(--theme-color-background-tertiary,#1a1a1a);\n\t--pict-modal-tooltip-fg: var(--theme-color-text-primary, #ffffff);\n\t--pict-modal-tooltip-border-radius:4px;\n\t--pict-modal-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n\n\t/* Dropdown */\n\t--pict-modal-dropdown-bg: var(--theme-color-background-panel, #ffffff);\n\t--pict-modal-dropdown-fg: var(--theme-color-text-primary, #1a1a1a);\n\t--pict-modal-dropdown-border: var(--theme-color-border-default, #e0e0e0);\n\t--pict-modal-dropdown-border-radius: 6px;\n\t--pict-modal-dropdown-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);\n\t--pict-modal-dropdown-item-hover-bg: var(--theme-color-background-hover, rgba(37, 99, 235, 0.10));\n\t--pict-modal-dropdown-item-hover-fg: var(--theme-color-text-primary, #1a1a1a);\n\t--pict-modal-dropdown-item-disabled-fg: var(--theme-color-text-muted, #9aa0a6);\n\t--pict-modal-dropdown-separator: var(--theme-color-border-light, #e8e8e8);\n\t--pict-modal-dropdown-header-fg: var(--theme-color-text-secondary, #6b7280);\n\t--pict-modal-dropdown-danger-fg: var(--theme-color-status-error, #dc2626);\n\t--pict-modal-dropdown-primary-fg: var(--theme-color-brand-primary, #2563eb);\n\n\t/* Typography */\n\t--pict-modal-font-family: var(--theme-typography-family-sans, system-ui, -apple-system, sans-serif);\n\t--pict-modal-font-size: 14px;\n\t--pict-modal-title-font-size: 16px;\n\n\t/* Animation */\n\t--pict-modal-transition-duration: 200ms;\n}\n\n/* Overlay */\n.pict-modal-overlay\n{\n\tposition: fixed;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tz-index: 1000;\n\tbackground: var(--pict-modal-overlay-bg);\n\topacity: 0;\n\ttransition: opacity var(--pict-modal-transition-duration) ease;\n}\n\n.pict-modal-overlay.pict-modal-visible\n{\n\topacity: 1;\n}\n\n/* Dialog */\n.pict-modal-dialog\n{\n\tposition: fixed;\n\tz-index: 1010;\n\ttop: 50%;\n\tleft: 50%;\n\ttransform: translate(-50%, -50%) translateY(-20px);\n\topacity: 0;\n\ttransition: opacity var(--pict-modal-transition-duration) ease,\n\t transform var(--pict-modal-transition-duration) ease;\n\n\tmax-width: 90vw;\n\tmax-height: 90vh;\n\tdisplay: flex;\n\tflex-direction: column;\n\n\tbackground: var(--pict-modal-bg);\n\tcolor: var(--pict-modal-fg);\n\tborder: 1px solid var(--pict-modal-border);\n\tborder-radius: var(--pict-modal-border-radius);\n\tbox-shadow: var(--pict-modal-shadow);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: var(--pict-modal-font-size);\n}\n\n.pict-modal-dialog.pict-modal-visible\n{\n\topacity: 1;\n\ttransform: translate(-50%, -50%) translateY(0);\n}\n\n/* Unbounded modifier \u2014 lets callers opt out of the 90vh/90vw viewport cap.\n Use with caution: content taller than the viewport will push buttons\n below the fold. */\n.pict-modal-dialog.pict-modal-dialog--unbounded\n{\n\tmax-height: none;\n\tmax-width: none;\n}\n\n.pict-modal-dialog-header\n{\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 12px 16px;\n\tbackground: var(--pict-modal-header-bg);\n\tcolor: var(--pict-modal-header-fg);\n\tborder-bottom: 1px solid var(--pict-modal-header-border);\n\tborder-radius: var(--pict-modal-border-radius) var(--pict-modal-border-radius) 0 0;\n}\n\n.pict-modal-dialog-title\n{\n\tfont-size: var(--pict-modal-title-font-size);\n\tfont-weight: 600;\n}\n\n.pict-modal-dialog-close\n{\n\tbackground: none;\n\tborder: none;\n\tfont-size: 20px;\n\tcursor: pointer;\n\tcolor: var(--pict-modal-fg);\n\tpadding: 0 4px;\n\tline-height: 1;\n\topacity: 0.6;\n}\n\n.pict-modal-dialog-close:hover\n{\n\topacity: 1;\n}\n\n.pict-modal-dialog-body\n{\n\tpadding: 16px;\n\toverflow-y: auto;\n\tflex: 1;\n}\n\n.pict-modal-dialog-footer\n{\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tgap: 8px;\n\tpadding: 12px 16px;\n\tborder-top: 1px solid var(--pict-modal-border);\n}\n\n/* Buttons */\n.pict-modal-btn\n{\n\tpadding: 8px 16px;\n\tborder: none;\n\tborder-radius: var(--pict-modal-btn-border-radius);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: var(--pict-modal-font-size);\n\tcursor: pointer;\n\tbackground: var(--pict-modal-btn-bg);\n\tcolor: var(--pict-modal-btn-fg);\n\ttransition: background var(--pict-modal-transition-duration) ease;\n}\n\n.pict-modal-btn:hover\n{\n\tbackground: var(--pict-modal-btn-hover-bg);\n}\n\n.pict-modal-btn:disabled\n{\n\topacity: 0.5;\n\tcursor: not-allowed;\n}\n\n.pict-modal-btn--primary\n{\n\tbackground: var(--pict-modal-btn-primary-bg);\n\tcolor: var(--pict-modal-btn-primary-fg);\n}\n\n.pict-modal-btn--primary:hover\n{\n\tbackground: var(--pict-modal-btn-primary-hover-bg);\n}\n\n.pict-modal-btn--danger\n{\n\tbackground: var(--pict-modal-btn-danger-bg);\n\tcolor: var(--pict-modal-btn-danger-fg);\n}\n\n.pict-modal-btn--danger:hover\n{\n\tbackground: var(--pict-modal-btn-danger-hover-bg);\n}\n\n/* Double confirm input */\n.pict-modal-confirm-input\n{\n\twidth: 100%;\n\tpadding: 8px 12px;\n\tmargin-top: 12px;\n\tborder: 1px solid var(--pict-modal-border);\n\tborder-radius: var(--pict-modal-btn-border-radius);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: var(--pict-modal-font-size);\n\tbox-sizing: border-box;\n}\n\n.pict-modal-confirm-input:focus\n{\n\toutline: 2px solid var(--pict-modal-btn-primary-bg);\n\toutline-offset: -1px;\n}\n\n.pict-modal-confirm-prompt\n{\n\tmargin-top: 12px;\n\tfont-size: 13px;\n\tcolor: var(--pict-modal-fg);\n\topacity: 0.7;\n}\n\n/* Toast container */\n.pict-modal-toast-container\n{\n\tposition: fixed;\n\tz-index: 1030;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tpointer-events: none;\n\tmax-width: 400px;\n}\n\n.pict-modal-toast-container--top-right\n{\n\ttop: 16px;\n\tright: 16px;\n}\n\n.pict-modal-toast-container--top-left\n{\n\ttop: 16px;\n\tleft: 16px;\n}\n\n.pict-modal-toast-container--bottom-right\n{\n\tbottom: 16px;\n\tright: 16px;\n}\n\n.pict-modal-toast-container--bottom-left\n{\n\tbottom: 16px;\n\tleft: 16px;\n}\n\n.pict-modal-toast-container--top-center\n{\n\ttop: 16px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n}\n\n.pict-modal-toast-container--bottom-center\n{\n\tbottom: 16px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n}\n\n/* Toast */\n.pict-modal-toast\n{\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n\tpadding: 12px 16px;\n\tborder-radius: var(--pict-modal-toast-border-radius);\n\tbox-shadow: var(--pict-modal-toast-shadow);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: var(--pict-modal-font-size);\n\tbackground: var(--pict-modal-toast-bg);\n\tcolor: var(--pict-modal-toast-fg);\n\tpointer-events: auto;\n\topacity: 0;\n\ttransform: translateX(100%);\n\ttransition: opacity var(--pict-modal-transition-duration) ease,\n\t transform var(--pict-modal-transition-duration) ease;\n}\n\n.pict-modal-toast.pict-modal-visible\n{\n\topacity: 1;\n\ttransform: translateX(0);\n}\n\n.pict-modal-toast.pict-modal-toast-exit\n{\n\topacity: 0;\n\ttransform: translateX(100%);\n}\n\n.pict-modal-toast--info\n{\n\tbackground: var(--pict-modal-toast-info-bg);\n}\n\n.pict-modal-toast--success\n{\n\tbackground: var(--pict-modal-toast-success-bg);\n}\n\n.pict-modal-toast--warning\n{\n\tbackground: var(--pict-modal-toast-warning-bg);\n}\n\n.pict-modal-toast--error\n{\n\tbackground: var(--pict-modal-toast-error-bg);\n}\n\n.pict-modal-toast-message\n{\n\tflex: 1;\n}\n\n.pict-modal-toast-dismiss\n{\n\tbackground: none;\n\tborder: none;\n\tcolor: inherit;\n\tfont-size: 18px;\n\tcursor: pointer;\n\tpadding: 0 2px;\n\tline-height: 1;\n\topacity: 0.7;\n}\n\n.pict-modal-toast-dismiss:hover\n{\n\topacity: 1;\n}\n\n/* Tooltip */\n.pict-modal-tooltip\n{\n\tposition: fixed;\n\tz-index: 1020;\n\tpadding: 6px 10px;\n\tborder-radius: var(--pict-modal-tooltip-border-radius);\n\tbox-shadow: var(--pict-modal-tooltip-shadow);\n\tbackground: var(--pict-modal-tooltip-bg);\n\tcolor: var(--pict-modal-tooltip-fg);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: 13px;\n\tpointer-events: none;\n\topacity: 0;\n\ttransition: opacity var(--pict-modal-transition-duration) ease;\n\twhite-space: normal;\n\tword-wrap: break-word;\n}\n\n.pict-modal-tooltip.pict-modal-tooltip-interactive\n{\n\tpointer-events: auto;\n}\n\n.pict-modal-tooltip.pict-modal-visible\n{\n\topacity: 1;\n}\n\n.pict-modal-tooltip-arrow\n{\n\tposition: absolute;\n\twidth: 8px;\n\theight: 8px;\n\tbackground: var(--pict-modal-tooltip-bg);\n\ttransform: rotate(45deg);\n}\n\n.pict-modal-tooltip--top .pict-modal-tooltip-arrow\n{\n\tbottom: -4px;\n\tleft: 50%;\n\tmargin-left: -4px;\n}\n\n.pict-modal-tooltip--bottom .pict-modal-tooltip-arrow\n{\n\ttop: -4px;\n\tleft: 50%;\n\tmargin-left: -4px;\n}\n\n.pict-modal-tooltip--left .pict-modal-tooltip-arrow\n{\n\tright: -4px;\n\ttop: 50%;\n\tmargin-top: -4px;\n}\n\n.pict-modal-tooltip--right .pict-modal-tooltip-arrow\n{\n\tleft: -4px;\n\ttop: 50%;\n\tmargin-top: -4px;\n}\n\n/* \u2500\u2500 Dropdown \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Anchor-positioned menu (no overlay). Used for nav menus and\n \"split button\" addenda \u2014 see Pict-Modal-Dropdown.js.\n*/\n.pict-modal-dropdown\n{\n\tposition: fixed;\n\tz-index: 1025;\n\tmin-width: 160px;\n\tmax-width: 360px;\n\tmax-height: 60vh;\n\toverflow-y: auto;\n\tbackground: var(--pict-modal-dropdown-bg);\n\tcolor: var(--pict-modal-dropdown-fg);\n\tborder: 1px solid var(--pict-modal-dropdown-border);\n\tborder-radius: var(--pict-modal-dropdown-border-radius);\n\tbox-shadow: var(--pict-modal-dropdown-shadow);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: var(--pict-modal-font-size);\n\tpadding: 4px 0;\n\topacity: 0;\n\ttransform: translateY(-4px);\n\ttransition: opacity var(--pict-modal-transition-duration) ease,\n\t transform var(--pict-modal-transition-duration) ease;\n}\n\n.pict-modal-dropdown.pict-modal-dropdown--above { transform: translateY(4px); }\n\n.pict-modal-dropdown.pict-modal-visible\n{\n\topacity: 1;\n\ttransform: translateY(0);\n}\n\n.pict-modal-dropdown-item\n{\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 7px 14px;\n\tcursor: pointer;\n\tuser-select: none;\n\tcolor: inherit;\n\toutline: none;\n}\n\n.pict-modal-dropdown-item:hover,\n.pict-modal-dropdown-item:focus\n{\n\tbackground: var(--pict-modal-dropdown-item-hover-bg);\n\tcolor: var(--pict-modal-dropdown-item-hover-fg);\n}\n\n.pict-modal-dropdown-item--disabled\n{\n\tcursor: not-allowed;\n\tcolor: var(--pict-modal-dropdown-item-disabled-fg);\n}\n\n.pict-modal-dropdown-item--disabled:hover,\n.pict-modal-dropdown-item--disabled:focus\n{\n\tbackground: transparent;\n\tcolor: var(--pict-modal-dropdown-item-disabled-fg);\n}\n\n.pict-modal-dropdown-item--primary { color: var(--pict-modal-dropdown-primary-fg); }\n.pict-modal-dropdown-item--danger { color: var(--pict-modal-dropdown-danger-fg); }\n\n.pict-modal-dropdown-item-icon\n{\n\tflex: 0 0 auto;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n}\n\n.pict-modal-dropdown-item-icon svg { width: 100%; height: 100%; display: block; }\n\n.pict-modal-dropdown-item-label { flex: 1 1 auto; min-width: 0; }\n\n.pict-modal-dropdown-item-hint\n{\n\tflex: 0 0 auto;\n\tfont-size: 11px;\n\topacity: 0.6;\n\tmargin-left: 12px;\n}\n\n.pict-modal-dropdown-separator\n{\n\theight: 1px;\n\tbackground: var(--pict-modal-dropdown-separator);\n\tmargin: 4px 0;\n}\n\n.pict-modal-dropdown-header\n{\n\tpadding: 6px 14px 2px;\n\tfont-size: 11px;\n\tfont-weight: 600;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tcolor: var(--pict-modal-dropdown-header-fg);\n}\n\n/* \u2500\u2500 Resizable / Collapsible Panels \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pict-panel\n{\n\tposition: relative;\n\ttransition: width 0.2s ease;\n\tflex-shrink: 0;\n\toverflow: visible;\n}\n.pict-panel-collapsed\n{\n\twidth: 0 !important;\n\tmin-width: 0 !important;\n\toverflow: visible;\n}\n.pict-panel-collapsed > *:not(.pict-panel-edge)\n{\n\tdisplay: none;\n}\n\n/* Edge container \u2014 zero-width flex sibling of the panel.\n Sits next to the panel in the flex layout; children\n use absolute positioning to overlap the panel boundary. */\n.pict-panel-edge\n{\n\tposition: relative;\n\twidth: 0;\n\tflex-shrink: 0;\n\tz-index: 50;\n\toverflow: visible;\n}\n\n/* Resize handle \u2014 thin strip on the panel boundary */\n.pict-panel-resize\n{\n\tposition: absolute;\n\ttop: 0;\n\tbottom: 0;\n\twidth: 4px;\n\tcursor: col-resize;\n\tbackground: transparent;\n\ttransition: background 0.15s, width 0.15s;\n}\n.pict-panel-edge-right .pict-panel-resize\n{\n\tright: 0;\n\tborder-right: 1px solid var(--pict-panel-border, #DDD6CA);\n}\n.pict-panel-edge-left .pict-panel-resize\n{\n\tleft: 0;\n\tborder-left: 1px solid var(--pict-panel-border, #DDD6CA);\n}\n.pict-panel-resize:hover,\n.pict-panel-edge:hover .pict-panel-resize\n{\n\twidth: 5px;\n\tbackground: var(--pict-panel-accent, #2E7D74);\n\topacity: 0.5;\n}\n.pict-panel-resize.dragging\n{\n\twidth: 5px;\n\tbackground: var(--pict-panel-accent, #2E7D74);\n\topacity: 1;\n\ttransition: none;\n}\n.pict-panel-edge-collapsed .pict-panel-resize\n{\n\tdisplay: none;\n}\n\n/* Collapse tab \u2014 tucked sliver at rest, slides out on hover */\n.pict-panel-tab\n{\n\tposition: absolute;\n\ttop: 8px;\n\twidth: 8px;\n\theight: 24px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\toverflow: hidden;\n\tbackground: var(--pict-panel-border, #DDD6CA);\n\tborder: 1px solid var(--pict-panel-border, #DDD6CA);\n\tcursor: pointer;\n\tcolor: var(--pict-panel-fg, #8A7F72);\n\tfont-size: 10px;\n\tline-height: 1;\n\topacity: 0.5;\n\ttransition: opacity 0.25s, width 0.2s ease, height 0.2s ease, left 0.2s ease, right 0.2s ease, background 0.2s;\n\tz-index: 51;\n}\n.pict-panel-edge:hover .pict-panel-tab,\n.pict-panel-tab:hover\n{\n\twidth: 20px;\n\theight: 32px;\n\topacity: 1;\n\toverflow: visible;\n\tbackground: var(--pict-panel-bg, #FAF8F4);\n}\n/* Right panel: tab to the left of the edge */\n.pict-panel-edge-right .pict-panel-tab\n{\n\tright: 0;\n\tborder-right: none;\n\tborder-radius: 4px 0 0 4px;\n}\n.pict-panel-edge-right:hover .pict-panel-tab,\n.pict-panel-edge-right .pict-panel-tab:hover\n{\n\tright: 0;\n}\n/* Left panel: tab to the right of the edge */\n.pict-panel-edge-left .pict-panel-tab\n{\n\tleft: 0;\n\tborder-left: none;\n\tborder-radius: 0 4px 4px 0;\n}\n.pict-panel-edge-left:hover .pict-panel-tab,\n.pict-panel-edge-left .pict-panel-tab:hover\n{\n\tleft: 0;\n}\n/* When collapsed \u2014 more visible */\n.pict-panel-edge-collapsed .pict-panel-tab\n{\n\twidth: 10px;\n\theight: 28px;\n\topacity: 0.6;\n}\n.pict-panel-edge-collapsed .pict-panel-tab:hover,\n.pict-panel-edge-collapsed:hover .pict-panel-tab\n{\n\twidth: 20px;\n\theight: 32px;\n\topacity: 1;\n\toverflow: visible;\n\tbackground: var(--pict-panel-bg, #FAF8F4);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Pict-Modal-Shell \u2014 viewport-managing layout for top / right /\n * bottom / left panels around a center.\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.pict-modal-shell-host { display: block; height: 100%; min-height: 0; }\n.pict-modal-shell\n{\n\tdisplay: flex;\n\tflex-direction: column;\n\twidth: 100%;\n\theight: 100%;\n\tmin-height: 0;\n\tposition: relative;\n\tcolor: var(--pict-modal-fg, var(--theme-color-text-primary, #1a1a1a));\n\tbackground: var(--theme-color-background-primary, transparent);\n}\n.pict-modal-shell-row { display: flex; min-width: 0; min-height: 0; }\n/* \"First added = at the edge\" convention is held by reversing the\n flex-direction on the bottom row + right side. That way, for ALL\n four sides, calling addPanel() N times stacks panel #1 against\n the viewport edge, panel #2 just inside it, panel #3 further in,\n and so on. Without these reverses, top + left worked that way but\n bottom + right inverted (first-added at content side, last-added\n at edge), which surprised callers. */\n.pict-modal-shell-row-top { flex: 0 0 auto; flex-direction: column; }\n.pict-modal-shell-row-bottom { flex: 0 0 auto; flex-direction: column-reverse; }\n.pict-modal-shell-row-middle\n{\n\tflex: 1 1 0;\n\tflex-direction: row;\n\tmin-height: 0;\n\tposition: relative;\n}\n.pict-modal-shell-side\n{\n\tdisplay: flex;\n\tflex: 0 0 auto;\n\tmin-height: 0;\n}\n.pict-modal-shell-side-left { flex-direction: row; }\n.pict-modal-shell-side-right { flex-direction: row-reverse; }\n.pict-modal-shell-center\n{\n\tflex: 1 1 0;\n\tmin-width: 0;\n\tmin-height: 0;\n\toverflow: auto;\n\tposition: relative;\n}\n.pict-modal-shell-center-content\n{\n\tmin-height: 100%;\n}\n/* Center column gains this class when at least one Scope:'center'\n panel is added. The center stops scrolling internally \u2014 that job\n moves to the content destination \u2014 and switches to a vertical flex\n so the destination and any inner panels stack cleanly. */\n.pict-modal-shell-center.pict-modal-shell-center-with-inner-panel\n{\n\tdisplay: flex;\n\tflex-direction: column;\n\toverflow: hidden;\n}\n.pict-modal-shell-center.pict-modal-shell-center-with-inner-panel > .pict-modal-shell-center-content\n{\n\tflex: 1 1 0;\n\tmin-height: 0;\n\toverflow: auto;\n}\n.pict-modal-shell-center.pict-modal-shell-center-with-inner-panel > .pict-modal-shell-panel\n{\n\tflex: 0 0 auto;\n\twidth: 100%;\n}\n\n/* Panels \u2014 base */\n.pict-modal-shell-panel\n{\n\t/* How far the collapse-tab's panel-bg \"merge bar\" extends INTO\n\t the panel past the tab's geometric edge. Painted via box-shadow\n\t on the tab (no DOM impact), it masks any 1px theme border on an\n\t inner element, content padding offset, or resize-handle hover\n\t bleed in the strip between the tab's panel-facing edge and the\n\t first real pixel of panel content. Consumers can bump this for\n\t themes with thicker (2+px) inner borders. */\n\t--pict-modal-collapse-tab-merge: 2px;\n\tposition: relative;\n\tdisplay: flex;\n\tflex-direction: column;\n\tbox-sizing: border-box;\n\tbackground: var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff));\n\tcolor: inherit;\n\tmin-width: 0;\n\tmin-height: 0;\n\ttransition: width 140ms ease, height 140ms ease;\n}\n.pict-modal-shell-panel-content\n{\n\tflex: 1 1 auto;\n\tmin-width: 0;\n\tmin-height: 0;\n\toverflow: auto;\n}\n/* Fixed-mode panels are pure chrome (topbars, status rows). Their\n content should fit the configured Size exactly \u2014 never scroll. The\n 1px border that .pict-modal-shell-panel-mode-fixed adds on the\n inner edge shaves 1px off the content's available height, which\n then triggers a sliver-scrollbar on any inner widget with\n min-height matching the panel Size. overflow:hidden here suppresses\n that without affecting resizable/collapsible panels (sidebars,\n drawers) where scrollable content is the whole point. */\n.pict-modal-shell-panel-mode-fixed > .pict-modal-shell-panel-content\n{\n\toverflow: hidden;\n}\n.pict-modal-shell-panel-content-inner\n{\n\tmin-height: 100%;\n}\n/* Panel boundary \u2014 fixed-mode panels get a hairline border for explicit\n demarcation. Collapsible / resizable panels DROP the boundary border\n (background contrast separates them from the center anyway) so the\n collapse tab can pull out cleanly without a hairline cutting across\n it. The host stylesheet still gets full control via the panel's own\n background. */\n.pict-modal-shell-panel-mode-fixed.pict-modal-shell-panel-top { border-bottom: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #e0e0e0)); }\n.pict-modal-shell-panel-mode-fixed.pict-modal-shell-panel-bottom { border-top: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #e0e0e0)); }\n.pict-modal-shell-panel-mode-fixed.pict-modal-shell-panel-left { border-right: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #e0e0e0)); }\n.pict-modal-shell-panel-mode-fixed.pict-modal-shell-panel-right { border-left: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #e0e0e0)); }\n\n/* Resize handle \u2014 absolute on the inner edge of each panel. */\n.pict-modal-shell-panel-resize-handle\n{\n\tposition: absolute;\n\tbackground: transparent;\n\tz-index: 5;\n\ttransition: background-color 120ms ease;\n}\n/* Resize handle hover \u2014 use the active brand's mode-aware primary\n color (set by pict-section-theme's Brand provider as\n --brand-color-primary-mode) so the resize affordance picks up the\n app's wordmark color. Falls back to the theme's brand-primary\n token if no brand is registered. */\n.pict-modal-shell-panel-resize-handle:hover\n{\n\tbackground: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\topacity: 0.4;\n}\n.pict-modal-shell-panel-left .pict-modal-shell-panel-resize-handle { right: -3px; top: 0; bottom: 0; width: 6px; cursor: col-resize; }\n.pict-modal-shell-panel-right .pict-modal-shell-panel-resize-handle { left: -3px; top: 0; bottom: 0; width: 6px; cursor: col-resize; }\n.pict-modal-shell-panel-top .pict-modal-shell-panel-resize-handle { bottom:-3px; left: 0; right: 0; height: 6px; cursor: row-resize; }\n.pict-modal-shell-panel-bottom .pict-modal-shell-panel-resize-handle { top: -3px; left: 0; right: 0; height: 6px; cursor: row-resize; }\n\n/* Collapse tab \u2014 slim sliver flush on the panel's OUTER boundary\n (where the resize handle sits), modelled on retold-content-system's\n sidebar tab. At rest it's a 6\xD728 px sliver; hover expands to\n 18\xD736 px without overlapping the panel's own content. The tab is\n positioned with its center on the boundary so half pokes into the\n adjacent area \u2014 the only place we can safely take over without\n stepping on app UI inside the panel. Title text only renders in the\n collapsed state where there's room for it. */\n.pict-modal-shell-panel-collapse-tab\n{\n\tposition: absolute;\n\tdisplay: flex; /* not inline-flex \u2014 avoids baseline alignment quirks */\n\talign-items: center;\n\tjustify-content: center;\n\toverflow: hidden;\n\tborder: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #d0d7de));\n\tbackground: var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff));\n\tcolor: var(--theme-color-text-muted, #6b7280);\n\tfont: inherit;\n\tfont-size: 10px;\n\tletter-spacing: 0.4px;\n\ttext-transform: uppercase;\n\tcursor: pointer;\n\tz-index: 50;\n\topacity: 0.55;\n\tpadding: 0;\n\tbox-sizing: border-box;\n\tline-height: 0; /* keep child boxes from inflating around the rotated chevron */\n\t/* Geometry (width/height/right/left) is intentionally NOT animated.\n\t Sliding the tab's outer edge inward on hover-out makes it look like\n\t the tab is \"sliding into\" the panel content \u2014 weird visual.\n\t Snapping the size change instead, and animating only the appearance\n\t (opacity/color/shadow), gives a clean fade-in/out with no boundary\n\t weirdness. */\n\ttransition: opacity 160ms ease,\n\t background-color 160ms ease, color 160ms ease,\n\t border-color 160ms ease, box-shadow 160ms ease;\n}\n/* Hover state pulls accent color from the active brand (mode-aware,\n so it's legible in both light + dark) with theme brand-primary as\n fallback. The whole point of brand colors is that they show up\n across the app's chrome. */\n.pict-modal-shell-panel-collapse-tab:hover,\n.pict-modal-shell-panel:hover > .pict-modal-shell-panel-collapse-tab\n{\n\topacity: 1;\n\tcolor: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\tborder-color: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n}\n/* Drop shadow casts AWAY from the panel so the tab feels pulled out\n (extension of the panel) rather than floating across the boundary.\n The first shadow value is the merge-bar (panel-bg colored, offset\n INTO the panel) which has to be repeated here so the hover override\n doesn't drop it. */\n.pict-modal-shell-panel-left:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-left > .pict-modal-shell-panel-collapse-tab:hover\n{\n\tbox-shadow:\n\t\tcalc(-1 * var(--pict-modal-collapse-tab-merge)) 0 0 0 var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff)),\n\t\t3px 0 6px -2px rgba(0, 0, 0, 0.18);\n}\n.pict-modal-shell-panel-right:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-right > .pict-modal-shell-panel-collapse-tab:hover\n{\n\tbox-shadow:\n\t\tvar(--pict-modal-collapse-tab-merge) 0 0 0 var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff)),\n\t\t-3px 0 6px -2px rgba(0, 0, 0, 0.18);\n}\n.pict-modal-shell-panel-top:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-top > .pict-modal-shell-panel-collapse-tab:hover\n{\n\tbox-shadow:\n\t\t0 calc(-1 * var(--pict-modal-collapse-tab-merge)) 0 0 var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff)),\n\t\t0 3px 6px -2px rgba(0, 0, 0, 0.18);\n}\n.pict-modal-shell-panel-bottom:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab:hover\n{\n\tbox-shadow:\n\t\t0 var(--pict-modal-collapse-tab-merge) 0 0 var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff)),\n\t\t0 -3px 6px -2px rgba(0, 0, 0, 0.18);\n}\n\n/* Side panels: slim VERTICAL sliver pulled OUT of the panel's outer\n boundary like a drawer tab. The geometric inner edge sits 1px\n INSIDE the panel boundary, and the merge-bar box-shadow paints\n another --pict-modal-collapse-tab-merge px of panel-bg color past\n it INTO the panel \u2014 together they mask any 1px theme border on an\n inner element, content padding offset, or resize-handle hover bleed\n that would otherwise leak between the tab and the panel content.\n The tab grows OUTWARD only on hover; the inner edge stays put so\n the tab always looks like an extension of the panel rather than a\n floating button. Border-left is removed for left panels (and\n border-right for right panels) so the panel-facing edge is open. */\n.pict-modal-shell-panel-left > .pict-modal-shell-panel-collapse-tab\n{\n\tright: -5px; top: 14px; width: 6px; height: 28px;\n\tborder-radius: 0 4px 4px 0;\n\tborder-left: 0;\n\tbox-shadow: calc(-1 * var(--pict-modal-collapse-tab-merge)) 0 0 0 var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff));\n}\n.pict-modal-shell-panel-right > .pict-modal-shell-panel-collapse-tab\n{\n\tleft: -5px; top: 14px; width: 6px; height: 28px;\n\tborder-radius: 4px 0 0 4px;\n\tborder-right: 0;\n\tbox-shadow: var(--pict-modal-collapse-tab-merge) 0 0 0 var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff));\n}\n/* Hover: same inner anchor (panelRight - 1), tab grows outward to\n width 18 \u2192 right: -17px. Top + height grow downward only (top\n stays, height extends so the tab visually 'drops' the chevron\n into view). */\n.pict-modal-shell-panel-left:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-left > .pict-modal-shell-panel-collapse-tab:hover\n{\n\twidth: 18px; height: 36px; right: -17px;\n}\n.pict-modal-shell-panel-right:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-right > .pict-modal-shell-panel-collapse-tab:hover\n{\n\twidth: 18px; height: 36px; left: -17px;\n}\n\n/* Top / bottom panels: slim HORIZONTAL sliver pulled OUT of the\n horizontal boundary, anchored 14 px in from the right. Same\n inner-edge-anchored + merge-bar pattern as the side panels \u2014 the\n merge-bar offsets vertically instead of horizontally. */\n.pict-modal-shell-panel-top > .pict-modal-shell-panel-collapse-tab\n{\n\tbottom: -5px; right: 14px; width: 28px; height: 6px;\n\tborder-radius: 0 0 4px 4px;\n\tborder-top: 0;\n\tbox-shadow: 0 calc(-1 * var(--pict-modal-collapse-tab-merge)) 0 0 var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff));\n}\n.pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab\n{\n\ttop: -5px; right: 14px; width: 28px; height: 6px;\n\tborder-radius: 4px 4px 0 0;\n\tborder-bottom: 0;\n\tbox-shadow: 0 var(--pict-modal-collapse-tab-merge) 0 0 var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff));\n}\n.pict-modal-shell-panel-top:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-top > .pict-modal-shell-panel-collapse-tab:hover\n{\n\twidth: 36px; height: 18px; bottom: -17px;\n}\n.pict-modal-shell-panel-bottom:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab:hover\n{\n\twidth: 36px; height: 18px; top: -17px;\n}\n\n.pict-modal-shell-panel-collapse-tab-title { display: none; white-space: nowrap; }\n\n/* Auto-generated chevron glyph inside the tab \u2014 only visible once the\n tab is wide / tall enough to show it (i.e. hover state, or when the\n panel is collapsed). Direction follows side + state.\n Sized 5\xD75 (down from 6) so even with rotation the visual stays\n well clear of the tab's overflow:hidden bounds at 18\xD736 hover and\n the 24px collapsed tab strip width. flex-shrink:0 ensures the\n pseudo never collapses to zero in tight tab dimensions. */\n.pict-modal-shell-panel-collapse-tab::before\n{\n\tcontent: '';\n\tdisplay: block;\n\twidth: 5px; height: 5px;\n\tflex-shrink: 0;\n\topacity: 0;\n\tborder-right: 1.5px solid currentColor;\n\tborder-bottom: 1.5px solid currentColor;\n\ttransform: rotate(135deg);\n\ttransform-origin: center center;\n\ttransition: opacity 160ms ease, transform 160ms ease;\n}\n.pict-modal-shell-panel:hover > .pict-modal-shell-panel-collapse-tab::before,\n.pict-modal-shell-panel-collapse-tab:hover::before,\n.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before\n{\n\topacity: 1;\n}\n.pict-modal-shell-panel-right > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(-45deg); }\n.pict-modal-shell-panel-top > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(-135deg); }\n.pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(45deg); }\n.pict-modal-shell-panel-left.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(-45deg); }\n.pict-modal-shell-panel-right.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(135deg); }\n.pict-modal-shell-panel-top.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(45deg); }\n.pict-modal-shell-panel-bottom.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(-135deg); }\n\n/* Collapsed state \u2014 content disappears, only the collapse tab remains. */\n.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-content\n{\n\tdisplay: none;\n}\n.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-resize-handle\n{\n\tdisplay: none;\n}\n.pict-modal-shell-panel-left.pict-modal-shell-panel-collapsed,\n.pict-modal-shell-panel-right.pict-modal-shell-panel-collapsed\n{\n\t/* When collapsed, side panels rotate the title for vertical reading. */\n\toverflow: hidden;\n}\n/* When collapsed: the entire panel becomes the tab strip \u2014 full width\n for sides, full height for top/bottom \u2014 with the title visible\n vertically (sides) or horizontally (top/bottom). The little sliver\n tab on the boundary disappears (we don't need it anymore \u2014 clicking\n anywhere on the panel toggles it back open). */\n.pict-modal-shell-panel-left.pict-modal-shell-panel-collapsed,\n.pict-modal-shell-panel-right.pict-modal-shell-panel-collapsed,\n.pict-modal-shell-panel-top.pict-modal-shell-panel-collapsed,\n.pict-modal-shell-panel-bottom.pict-modal-shell-panel-collapsed\n{\n\toverflow: hidden;\n}\n.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab\n{\n\t/* Promote the tab to FILL the collapsed panel (not just hug its\n\t content) so the centered chevron + title group sits in the middle\n\t of the panel. Without explicit width/height: 100%, the position:\n\t absolute element shrinks to its natural content size and the\n\t group ends up flush at the top of the panel \u2014 where the chevron\n\t gets clipped by the topbar. */\n\tposition: absolute !important;\n\ttop: 0 !important; right: 0 !important; bottom: 0 !important; left: 0 !important;\n\twidth: 100% !important;\n\theight: 100% !important;\n\tborder: 0;\n\tborder-radius: 0;\n\tbackground: transparent;\n\topacity: 0.85;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 8px;\n\tpadding: 12px 4px; /* keeps chevron + title clear of edges */\n\tbox-shadow: none;\n\tcolor: var(--theme-color-text-muted, #6b7280);\n\tbox-sizing: border-box;\n\toverflow: hidden;\n}\n.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab:hover\n{\n\tbackground: var(--theme-color-background-hover, var(--pict-modal-bg, #fff));\n\tcolor: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\tbox-shadow: none;\n}\n/* Side panels (collapsed): rotate the title for vertical reading. */\n.pict-modal-shell-panel-left.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-right.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab\n{\n\twriting-mode: vertical-rl;\n\ttext-orientation: mixed;\n}\n.pict-modal-shell-panel-collapsed .pict-modal-shell-panel-collapse-tab-title\n{\n\tdisplay: inline;\n}\n\n/* Hidden panels \u2014 when Hidden:true is passed to addPanel, the collapsed\n state has zero footprint: no collapse tab (the tab is never built),\n the panel root is display:none, and the resize handle vanishes. The\n only path to the open state is a programmatic expand()/toggle() from\n somewhere else in the app (e.g. a topbar gear button). When expanded,\n the panel renders normally \u2014 so resize/drag handles continue to work\n while the panel is open. */\n.pict-modal-shell-panel-hidden.pict-modal-shell-panel-collapsed\n{\n\tdisplay: none !important;\n}\n\n/* Overlay panels \u2014 float over the middle row instead of taking layout\n space. The overlay layer is positioned absolutely inside the middle\n row; individual overlay panels stack with positive z-index. */\n.pict-modal-shell-overlay-layer\n{\n\tposition: absolute;\n\tinset: 0;\n\tpointer-events: none;\n\tz-index: 10;\n}\n.pict-modal-shell-overlay-layer .pict-modal-shell-panel\n{\n\tpointer-events: auto;\n\tposition: absolute;\n\tbox-shadow: 0 4px 24px rgba(0, 0, 0, 0.18);\n}\n.pict-modal-shell-overlay-layer .pict-modal-shell-panel-left { left: 0; top: 0; bottom: 0; }\n.pict-modal-shell-overlay-layer .pict-modal-shell-panel-right { right: 0; top: 0; bottom: 0; }\n.pict-modal-shell-overlay-layer .pict-modal-shell-panel-top { top: 0; left: 0; right: 0; }\n.pict-modal-shell-overlay-layer .pict-modal-shell-panel-bottom { bottom: 0; left: 0; right: 0; }\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Responsive drawer mode \u2014 .pict-modal-shell-drawer-active toggles\n onto the middle row when any panel with ResponsiveDrawer crosses\n below its breakpoint. Flips the row's flex-direction from row to\n column, stacking side panels above the center and stretching them\n to full width. Each opted-in panel itself gets the\n .pict-modal-shell-panel-drawer class so per-panel rules below\n target only the drawer-mode panels (right + non-drawer panels in\n the same row are unaffected). The drawer height is read from a\n per-panel --pict-modal-drawer-height CSS variable (default\n 33vh, set in JS from the DrawerHeight option).\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pict-modal-shell-row-middle.pict-modal-shell-drawer-active\n{\n\tflex-direction: column;\n\t/* The drawer tab lives outside the drawer's bottom edge \u2014 ancestor\n\t chain MUST allow it to escape clip. */\n\toverflow: visible;\n}\n.pict-modal-shell-row-middle.pict-modal-shell-drawer-active .pict-modal-shell-side\n{\n\t/* Side stacks stretch full-width and lay out their panels as a\n\t horizontal row of stacked drawers (so two drawers from the same\n\t side don't end up overlapping). overflow: visible so the\n\t per-panel tab can extend below the side stack into the workspace. */\n\twidth: 100% !important;\n\tflex-direction: column;\n\toverflow: visible;\n}\n/* The drawer-tagged panel itself: kill the inline width set by\n _applySize (we override with !important since the inline style has\n higher specificity than a class selector), then size by height\n from the CSS variable. Resize handle is hidden in drawer mode\n because horizontal dragging doesn't translate to vertical sizing\n and the user already has the collapse tab to dismiss / restore.\n\n padding-bottom reserves an 18px strip at the bottom of the panel\n for the tab. The tab sits INSIDE the drawer's footprint \u2014 never\n below it \u2014 so the workspace header below the drawer is never in\n the same vertical band as the tab. (Previously the tab hung\n below the drawer's bottom edge into the workspace's top padding;\n that made the tab visually compete with the workspace header,\n even when the tab box-model bounds technically cleared the\n header.) box-sizing: border-box so the padding eats from the\n 33vh, not adding to it. */\n.pict-modal-shell-panel-drawer\n{\n\twidth: 100% !important;\n\tmax-width: 100% !important;\n\theight: var(--pict-modal-drawer-height, 33vh);\n\ttransition: height 140ms ease;\n\tpadding-bottom: 18px;\n\tbox-sizing: border-box;\n\toverflow: visible !important;\n\t/* Clip the panel bg to its CONTENT area only \u2014 the 18px\n\t padding-bottom reserve (where the tab lives) becomes\n\t transparent, so the middle row's primary background shows\n\t through. Without this the reserve would render with the\n\t panel's chrome bg, creating a visible \"strip\" between the\n\t drawer content above and the workspace below \u2014 the tab would\n\t look like it's sitting on its own miscoloured band rather\n\t than at the seam between drawer and workspace. */\n\tbackground-clip: content-box;\n}\n.pict-modal-shell-panel-drawer.pict-modal-shell-panel-collapsed\n{\n\t/* Collapsed = \"just the tab strip is visible\". 18px matches the\n\t panel's tab reserve so the height is consistent across states.\n\t When this is 0 the tab would have nowhere to render and the\n\t user couldn't reopen the drawer. */\n\theight: 18px !important;\n\tpadding-bottom: 0 !important;\n\t/* Drop the panel's bg in collapsed state \u2014 without this the 18px\n\t strip shows the --pict-modal-bg (panel chrome) which doesn't\n\t match the workspace --theme-color-background-primary below it,\n\t creating a visible \"drawer band\" around the tab that breaks the\n\t illusion of the tab belonging to the workspace area. With\n\t transparent bg the middle row's primary background shows\n\t through, the strip blends with the workspace, and the tab pill\n\t reads as a free-floating handle. */\n\tbackground: transparent !important;\n}\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-resize-handle\n{\n\tdisplay: none;\n}\n/* The drawer's collapse tab is a horizontal pill protruding from the\n bottom of the drawer (rather than the inner edge of a side panel).\n Override the side-panel positioning rules from above so the tab\n always sits at the drawer's bottom-center seam, in both expanded\n and collapsed states. The expand-from-zero affordance: when\n collapsed (height: 0), the tab still hangs below \"where the\n drawer would be\" \u2014 a small handle the user can click to pull\n the drawer back down. */\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-drawer.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab\n{\n\tposition: absolute !important;\n\t/* Anchored to the panel's BOTTOM edge \u2014 the tab lives INSIDE the\n\t drawer's footprint (in the 18px reserve at the bottom), never\n\t below it into the workspace. This means the workspace below\n\t the drawer is never sharing a vertical band with the tab, so\n\t the workspace header doesn't optically compete with it.\n\t bottom: 4px aligns the tab's top edge exactly with the panel's\n\t CONTENT-AREA bottom (panel.height \u2212 padding-bottom 18px). With\n\t border-top: 0 on the tab, the seam between the drawer content\n\t above and the tab body is invisible \u2014 they share --pict-modal-bg\n\t and merge into one shape, the tab reading as a labelled\n\t extension of the drawer hanging downward. Collapsed state\n\t keeps the smaller offset (overridden below) because its panel\n\t has no padding-bottom, so the math doesn't apply. */\n\ttop: auto !important;\n\tbottom: 4px !important;\n\tleft: 50% !important;\n\tright: auto !important;\n\ttransform: translate(-50%, 0) !important;\n\twidth: 64px !important;\n\theight: 14px !important;\n\t/* CRITICAL: border-box + padding: 0 \u2014 the collapsed-state base\n\t rule inherits \"padding: 12px 4px\" (so the chevron clears the\n\t edges of a tab that fills a 24px-wide side strip). In drawer\n\t mode the tab is a 14px tall pill, NOT a strip-fill, so that\n\t 12px vertical padding would balloon the tab's outer height to\n\t ~38px and crash into the workspace header text. The chevron\n\t is centered via flex anyway. */\n\tbox-sizing: border-box !important;\n\tpadding: 0 !important;\n\t/* Rounded BOTTOM corners + no top border \u2014 the tab looks like a\n\t traditional drawer-handle/tab hanging from above. Its rounded\n\t bottom curves face the workspace (the \"open downward\" affordance\n\t for a top drawer). border-top: 0 lets the tab visually merge\n\t with whatever's directly above it inside the panel (sidebar\n\t content when expanded, the panel background when collapsed). */\n\tborder-radius: 0 0 8px 8px;\n\tborder: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #cfd5dd));\n\tborder-top: 0;\n\tbackground: var(--pict-modal-bg, var(--theme-color-background-panel, #fff));\n\topacity: 0.95;\n\tz-index: 20;\n\t/* The default side-panel hover-grow values would yank the tab off\n\t to the wrong spot in drawer mode \u2014 neutralise. */\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-collapse-tab:hover,\n.pict-modal-shell-panel-drawer.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab:hover\n{\n\topacity: 1;\n\twidth: 96px !important;\n\t/* height stays at 14px \u2014 the tab is anchored with bottom, so any\n\t height growth would push the tab's TOP edge UPWARD past the\n\t space available above it. In EXPANDED state that crashes into\n\t the drawer content above; in COLLAPSED state it crashes into\n\t the topbar's brand stripes. Width-only growth (64 to 96, +50%)\n\t still gives the \"tab is reaching toward me\" affordance without\n\t the encroachment. */\n\tcolor: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\tborder-color: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\tbox-shadow: 0 3px 6px -2px rgba(0, 0, 0, 0.18);\n}\n/* Collapsed-state bottom-offset override. Expanded panels have an\n 18px padding-bottom reserve, and \"bottom: 4px\" anchors the tab's\n top edge exactly at the content-area boundary (so it merges\n visually with the drawer above). Collapsed panels have\n padding-bottom: 0 and a total height of 18px \u2014 \"bottom: 4px\"\n there would put the tab's top at the panel's actual top edge,\n crashing the (border-top: 0) tab into the topbar. The smaller\n \"bottom: 2px\" keeps the 14px tab vertically centered in the 18px\n strip with 2px margins on either side. */\n.pict-modal-shell-panel-drawer.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab\n{\n\tbottom: 2px !important;\n}\n/* Chevron inside the tab: point UP when expanded (the drawer\n collapses UP / out of view, so the arrow indicates \"click me to\n send the drawer up\"), DOWN when collapsed (the drawer expands DOWN\n into view). Rotations come from the existing top-panel chevron\n table: rotate(-135deg) \u2192 UP arrow, rotate(45deg) \u2192 DOWN arrow. */\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-collapse-tab::before\n{\n\ttransform: rotate(-135deg) !important;\n}\n.pict-modal-shell-panel-drawer.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before\n{\n\ttransform: rotate(45deg) !important;\n}\n/* The collapse tab's existing title-text span is hidden when reduced\n to a pill \u2014 there's no horizontal room. The chevron alone reads\n correctly. */\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-collapse-tab .pict-modal-shell-panel-collapse-tab-title,\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-collapse-tab .pict-modal-shell-panel-collapse-tab-icon\n{\n\tdisplay: none;\n}\n\n/* Drag-active state \u2014 disable text selection + change cursor globally\n so resize feels solid even when the cursor briefly leaves the handle. */\n.pict-modal-shell-dragging-x, .pict-modal-shell-dragging-y { user-select: none; }\n.pict-modal-shell-dragging-x * { cursor: col-resize !important; }\n.pict-modal-shell-dragging-y * { cursor: row-resize !important; }\n\n/* Per-panel resize-active state \u2014 kills the panel's collapse/expand\n width/height transition for the duration of a drag. Without this,\n every pointermove starts a fresh 140 ms transition and the resize\n visibly lags behind the cursor (\"choppy\"). With it disabled the\n panel snaps to the new size on the same frame as the pointer, which\n feels native. */\n.pict-modal-shell-panel-resizing { transition: none !important; }\n.pict-modal-shell-panel-resizing > .pict-modal-shell-panel-resize-handle\n{\n\tbackground: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\topacity: 0.5;\n}\n\n/* Panel popup-attention flash \u2014 fires when popup() is called on an\n already-open panel. Brief brand-colored inset glow so the user sees\n that their click landed even though the panel didn't change shape.\n Class is added by the shell, auto-removed after ~700 ms. */\n@keyframes pict-modal-shell-panel-flash\n{\n\t0% { box-shadow: inset 0 0 0 0 transparent; }\n\t30% { box-shadow: inset 0 0 0 3px var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb)); }\n\t100% { box-shadow: inset 0 0 0 0 transparent; }\n}\n.pict-modal-shell-panel-flash\n{\n\tanimation: pict-modal-shell-panel-flash 600ms ease-out;\n}\n"};},{}],170:[function(require,module,exports){const libPictViewClass=require('pict-view');const libPictModalOverlay=require('./Pict-Modal-Overlay.js');const libPictModalConfirm=require('./Pict-Modal-Confirm.js');const libPictModalWindow=require('./Pict-Modal-Window.js');const libPictModalToast=require('./Pict-Modal-Toast.js');const libPictModalTooltip=require('./Pict-Modal-Tooltip.js');const libPictModalPanel=require('./Pict-Modal-Panel.js');const libPictModalDropdown=require('./Pict-Modal-Dropdown.js');const libPictModalShell=require('./Pict-Modal-Shell.js');const _DefaultConfiguration=require('./Pict-Section-Modal-DefaultConfiguration.js');class PictSectionModal extends libPictViewClass{constructor(pFable,pOptions,pServiceHash){let tmpOptions=Object.assign({},_DefaultConfiguration,pOptions);super(pFable,tmpOptions,pServiceHash);this._activeModals=[];this._activeTooltips=[];this._activeToasts=[];this._idCounter=0;this._overlay=new libPictModalOverlay(this);this._confirm=new libPictModalConfirm(this);this._window=new libPictModalWindow(this);this._toast=new libPictModalToast(this);this._tooltip=new libPictModalTooltip(this);this._panel=new libPictModalPanel(this);this._dropdown=new libPictModalDropdown(this);this._shell=new libPictModalShell(this);}onBeforeInitialize(){super.onBeforeInitialize();// Ensure the root class is on the body for CSS variable scoping
7250
+ */_escapeHTML(pText){if(typeof pText!=='string'){return'';}return pText.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}}module.exports=PictModalWindow;},{}],169:[function(require,module,exports){module.exports={"AutoInitialize":true,"AutoRender":false,"AutoSolveWithApp":false,"ViewIdentifier":"Pict-Section-Modal","OverlayClickDismisses":true,"DefaultConfirmOptions":{"title":"Confirm","confirmLabel":"OK","cancelLabel":"Cancel","dangerous":false,"unbounded":false},"DefaultDoubleConfirmOptions":{"title":"Are you sure?","confirmLabel":"Confirm","cancelLabel":"Cancel","phrasePrompt":"Type \"{phrase}\" to confirm:","confirmPhrase":"","unbounded":false},"DefaultModalOptions":{"title":"","content":"","buttons":[],"closeable":true,"width":"480px","unbounded":false},"DefaultTooltipOptions":{"position":"top","delay":200,"maxWidth":"300px","interactive":false},"DefaultToastOptions":{"type":"info","duration":3000,"position":"top-right","dismissible":true},"DefaultPanelOptions":{"position":"right","width":340,"minWidth":200,"maxWidth":600,"collapsible":true,"collapsed":false,"persist":false,"persistKey":""},"Templates":[],"Renderables":[],"CSS":/*css*/"\n/* pict-section-modal */\n.pict-modal-root\n{\n\t/* Defaults are routed through pict-provider-theme tokens so apps\n\t using the theme provider get themed modals automatically. Each\n\t var() carries its original hex as the fallback so apps that don't\n\t install pict-provider-theme look exactly as before. Apps may\n\t still override any --pict-modal-* var directly to layer over the\n\t theme-driven defaults. */\n\n\t/* Overlay */\n\t--pict-modal-overlay-bg: rgba(0, 0, 0, 0.5);\n\n\t/* Dialog */\n\t--pict-modal-bg: var(--theme-color-background-panel, #ffffff);\n\t--pict-modal-fg: var(--theme-color-text-primary, #1a1a1a);\n\t--pict-modal-border: var(--theme-color-border-default, #e0e0e0);\n\t--pict-modal-border-radius: 8px;\n\t--pict-modal-shadow: 0 4px 24px rgba(0, 0, 0, 0.15);\n\t--pict-modal-header-bg: var(--theme-color-background-secondary, #f5f5f5);\n\t--pict-modal-header-fg: var(--theme-color-text-primary, #1a1a1a);\n\t--pict-modal-header-border: var(--theme-color-border-default, #e0e0e0);\n\n\t/* Buttons */\n\t--pict-modal-btn-bg: var(--theme-color-background-secondary, #e0e0e0);\n\t--pict-modal-btn-fg: var(--theme-color-text-primary, #1a1a1a);\n\t--pict-modal-btn-hover-bg: var(--theme-color-background-hover, #d0d0d0);\n\t--pict-modal-btn-primary-bg: var(--theme-color-brand-primary, #2563eb);\n\t--pict-modal-btn-primary-fg: var(--theme-color-text-on-brand, #ffffff);\n\t--pict-modal-btn-primary-hover-bg:var(--theme-color-brand-primary-hover,#1d4ed8);\n\t--pict-modal-btn-danger-bg: var(--theme-color-status-error, #dc2626);\n\t--pict-modal-btn-danger-fg: var(--theme-color-text-on-brand, #ffffff);\n\t--pict-modal-btn-danger-hover-bg: var(--theme-color-status-error, #b91c1c);\n\t--pict-modal-btn-border-radius: 4px;\n\n\t/* Toast */\n\t--pict-modal-toast-bg: var(--theme-color-background-panel, #333333);\n\t--pict-modal-toast-fg: var(--theme-color-text-primary, #ffffff);\n\t--pict-modal-toast-success-bg: var(--theme-color-status-success, #16a34a);\n\t--pict-modal-toast-warning-bg: var(--theme-color-status-warning, #d97706);\n\t--pict-modal-toast-error-bg: var(--theme-color-status-error, #dc2626);\n\t--pict-modal-toast-info-bg: var(--theme-color-status-info, #2563eb);\n\t--pict-modal-toast-border-radius: 6px;\n\t--pict-modal-toast-shadow: 0 2px 12px rgba(0, 0, 0, 0.15);\n\n\t/* Tooltip */\n\t--pict-modal-tooltip-bg: var(--theme-color-background-tertiary,#1a1a1a);\n\t--pict-modal-tooltip-fg: var(--theme-color-text-primary, #ffffff);\n\t--pict-modal-tooltip-border-radius:4px;\n\t--pict-modal-tooltip-shadow: 0 2px 8px rgba(0, 0, 0, 0.15);\n\n\t/* Dropdown */\n\t--pict-modal-dropdown-bg: var(--theme-color-background-panel, #ffffff);\n\t--pict-modal-dropdown-fg: var(--theme-color-text-primary, #1a1a1a);\n\t--pict-modal-dropdown-border: var(--theme-color-border-default, #e0e0e0);\n\t--pict-modal-dropdown-border-radius: 6px;\n\t--pict-modal-dropdown-shadow: 0 6px 18px rgba(0, 0, 0, 0.18);\n\t--pict-modal-dropdown-item-hover-bg: var(--theme-color-background-hover, rgba(37, 99, 235, 0.10));\n\t--pict-modal-dropdown-item-hover-fg: var(--theme-color-text-primary, #1a1a1a);\n\t--pict-modal-dropdown-item-disabled-fg: var(--theme-color-text-muted, #9aa0a6);\n\t--pict-modal-dropdown-separator: var(--theme-color-border-light, #e8e8e8);\n\t--pict-modal-dropdown-header-fg: var(--theme-color-text-secondary, #6b7280);\n\t--pict-modal-dropdown-danger-fg: var(--theme-color-status-error, #dc2626);\n\t--pict-modal-dropdown-primary-fg: var(--theme-color-brand-primary, #2563eb);\n\n\t/* Typography */\n\t--pict-modal-font-family: var(--theme-typography-family-sans, system-ui, -apple-system, sans-serif);\n\t--pict-modal-font-size: 14px;\n\t--pict-modal-title-font-size: 16px;\n\n\t/* Animation */\n\t--pict-modal-transition-duration: 200ms;\n}\n\n/* Overlay */\n.pict-modal-overlay\n{\n\tposition: fixed;\n\ttop: 0;\n\tleft: 0;\n\twidth: 100%;\n\theight: 100%;\n\tz-index: 1000;\n\tbackground: var(--pict-modal-overlay-bg);\n\topacity: 0;\n\ttransition: opacity var(--pict-modal-transition-duration) ease;\n}\n\n.pict-modal-overlay.pict-modal-visible\n{\n\topacity: 1;\n}\n\n/* Dialog */\n.pict-modal-dialog\n{\n\tposition: fixed;\n\tz-index: 1010;\n\ttop: 50%;\n\tleft: 50%;\n\ttransform: translate(-50%, -50%) translateY(-20px);\n\topacity: 0;\n\ttransition: opacity var(--pict-modal-transition-duration) ease,\n\t transform var(--pict-modal-transition-duration) ease;\n\n\tmax-width: 90vw;\n\tmax-height: 90vh;\n\tdisplay: flex;\n\tflex-direction: column;\n\n\tbackground: var(--pict-modal-bg);\n\tcolor: var(--pict-modal-fg);\n\tborder: 1px solid var(--pict-modal-border);\n\tborder-radius: var(--pict-modal-border-radius);\n\tbox-shadow: var(--pict-modal-shadow);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: var(--pict-modal-font-size);\n}\n\n.pict-modal-dialog.pict-modal-visible\n{\n\topacity: 1;\n\ttransform: translate(-50%, -50%) translateY(0);\n}\n\n/* Unbounded modifier \u2014 lets callers opt out of the 90vh/90vw viewport cap.\n Use with caution: content taller than the viewport will push buttons\n below the fold. */\n.pict-modal-dialog.pict-modal-dialog--unbounded\n{\n\tmax-height: none;\n\tmax-width: none;\n}\n\n.pict-modal-dialog-header\n{\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: space-between;\n\tpadding: 12px 16px;\n\tbackground: var(--pict-modal-header-bg);\n\tcolor: var(--pict-modal-header-fg);\n\tborder-bottom: 1px solid var(--pict-modal-header-border);\n\tborder-radius: var(--pict-modal-border-radius) var(--pict-modal-border-radius) 0 0;\n}\n\n.pict-modal-dialog-title\n{\n\tfont-size: var(--pict-modal-title-font-size);\n\tfont-weight: 600;\n}\n\n.pict-modal-dialog-close\n{\n\tbackground: none;\n\tborder: none;\n\tfont-size: 20px;\n\tcursor: pointer;\n\tcolor: var(--pict-modal-fg);\n\tpadding: 0 4px;\n\tline-height: 1;\n\topacity: 0.6;\n}\n\n.pict-modal-dialog-close:hover\n{\n\topacity: 1;\n}\n\n.pict-modal-dialog-body\n{\n\tpadding: 16px;\n\toverflow-y: auto;\n\tflex: 1;\n}\n\n.pict-modal-dialog-footer\n{\n\tdisplay: flex;\n\tjustify-content: flex-end;\n\tgap: 8px;\n\tpadding: 12px 16px;\n\tborder-top: 1px solid var(--pict-modal-border);\n}\n\n/* Buttons */\n.pict-modal-btn\n{\n\tpadding: 8px 16px;\n\tborder: none;\n\tborder-radius: var(--pict-modal-btn-border-radius);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: var(--pict-modal-font-size);\n\tcursor: pointer;\n\tbackground: var(--pict-modal-btn-bg);\n\tcolor: var(--pict-modal-btn-fg);\n\ttransition: background var(--pict-modal-transition-duration) ease;\n}\n\n.pict-modal-btn:hover\n{\n\tbackground: var(--pict-modal-btn-hover-bg);\n}\n\n.pict-modal-btn:disabled\n{\n\topacity: 0.5;\n\tcursor: not-allowed;\n}\n\n.pict-modal-btn--primary\n{\n\tbackground: var(--pict-modal-btn-primary-bg);\n\tcolor: var(--pict-modal-btn-primary-fg);\n}\n\n.pict-modal-btn--primary:hover\n{\n\tbackground: var(--pict-modal-btn-primary-hover-bg);\n}\n\n.pict-modal-btn--danger\n{\n\tbackground: var(--pict-modal-btn-danger-bg);\n\tcolor: var(--pict-modal-btn-danger-fg);\n}\n\n.pict-modal-btn--danger:hover\n{\n\tbackground: var(--pict-modal-btn-danger-hover-bg);\n}\n\n/* Double confirm input */\n.pict-modal-confirm-input\n{\n\twidth: 100%;\n\tpadding: 8px 12px;\n\tmargin-top: 12px;\n\tborder: 1px solid var(--pict-modal-border);\n\tborder-radius: var(--pict-modal-btn-border-radius);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: var(--pict-modal-font-size);\n\tbox-sizing: border-box;\n}\n\n.pict-modal-confirm-input:focus\n{\n\toutline: 2px solid var(--pict-modal-btn-primary-bg);\n\toutline-offset: -1px;\n}\n\n.pict-modal-confirm-prompt\n{\n\tmargin-top: 12px;\n\tfont-size: 13px;\n\tcolor: var(--pict-modal-fg);\n\topacity: 0.7;\n}\n\n/* Toast container */\n.pict-modal-toast-container\n{\n\tposition: fixed;\n\tz-index: 1030;\n\tdisplay: flex;\n\tflex-direction: column;\n\tgap: 8px;\n\tpointer-events: none;\n\tmax-width: 400px;\n}\n\n.pict-modal-toast-container--top-right\n{\n\ttop: 16px;\n\tright: 16px;\n}\n\n.pict-modal-toast-container--top-left\n{\n\ttop: 16px;\n\tleft: 16px;\n}\n\n.pict-modal-toast-container--bottom-right\n{\n\tbottom: 16px;\n\tright: 16px;\n}\n\n.pict-modal-toast-container--bottom-left\n{\n\tbottom: 16px;\n\tleft: 16px;\n}\n\n.pict-modal-toast-container--top-center\n{\n\ttop: 16px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n}\n\n.pict-modal-toast-container--bottom-center\n{\n\tbottom: 16px;\n\tleft: 50%;\n\ttransform: translateX(-50%);\n}\n\n/* Toast */\n.pict-modal-toast\n{\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 10px;\n\tpadding: 12px 16px;\n\tborder-radius: var(--pict-modal-toast-border-radius);\n\tbox-shadow: var(--pict-modal-toast-shadow);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: var(--pict-modal-font-size);\n\tbackground: var(--pict-modal-toast-bg);\n\tcolor: var(--pict-modal-toast-fg);\n\tpointer-events: auto;\n\topacity: 0;\n\ttransform: translateX(100%);\n\ttransition: opacity var(--pict-modal-transition-duration) ease,\n\t transform var(--pict-modal-transition-duration) ease;\n}\n\n.pict-modal-toast.pict-modal-visible\n{\n\topacity: 1;\n\ttransform: translateX(0);\n}\n\n.pict-modal-toast.pict-modal-toast-exit\n{\n\topacity: 0;\n\ttransform: translateX(100%);\n}\n\n.pict-modal-toast--info\n{\n\tbackground: var(--pict-modal-toast-info-bg);\n}\n\n.pict-modal-toast--success\n{\n\tbackground: var(--pict-modal-toast-success-bg);\n}\n\n.pict-modal-toast--warning\n{\n\tbackground: var(--pict-modal-toast-warning-bg);\n}\n\n.pict-modal-toast--error\n{\n\tbackground: var(--pict-modal-toast-error-bg);\n}\n\n.pict-modal-toast-message\n{\n\tflex: 1;\n}\n\n.pict-modal-toast-dismiss\n{\n\tbackground: none;\n\tborder: none;\n\tcolor: inherit;\n\tfont-size: 18px;\n\tcursor: pointer;\n\tpadding: 0 2px;\n\tline-height: 1;\n\topacity: 0.7;\n}\n\n.pict-modal-toast-dismiss:hover\n{\n\topacity: 1;\n}\n\n/* Tooltip */\n.pict-modal-tooltip\n{\n\tposition: fixed;\n\tz-index: 1020;\n\tpadding: 6px 10px;\n\tborder-radius: var(--pict-modal-tooltip-border-radius);\n\tbox-shadow: var(--pict-modal-tooltip-shadow);\n\tbackground: var(--pict-modal-tooltip-bg);\n\tcolor: var(--pict-modal-tooltip-fg);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: 13px;\n\tpointer-events: none;\n\topacity: 0;\n\ttransition: opacity var(--pict-modal-transition-duration) ease;\n\twhite-space: normal;\n\tword-wrap: break-word;\n}\n\n.pict-modal-tooltip.pict-modal-tooltip-interactive\n{\n\tpointer-events: auto;\n}\n\n.pict-modal-tooltip.pict-modal-visible\n{\n\topacity: 1;\n}\n\n.pict-modal-tooltip-arrow\n{\n\tposition: absolute;\n\twidth: 8px;\n\theight: 8px;\n\tbackground: var(--pict-modal-tooltip-bg);\n\ttransform: rotate(45deg);\n}\n\n.pict-modal-tooltip--top .pict-modal-tooltip-arrow\n{\n\tbottom: -4px;\n\tleft: 50%;\n\tmargin-left: -4px;\n}\n\n.pict-modal-tooltip--bottom .pict-modal-tooltip-arrow\n{\n\ttop: -4px;\n\tleft: 50%;\n\tmargin-left: -4px;\n}\n\n.pict-modal-tooltip--left .pict-modal-tooltip-arrow\n{\n\tright: -4px;\n\ttop: 50%;\n\tmargin-top: -4px;\n}\n\n.pict-modal-tooltip--right .pict-modal-tooltip-arrow\n{\n\tleft: -4px;\n\ttop: 50%;\n\tmargin-top: -4px;\n}\n\n/* \u2500\u2500 Dropdown \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Anchor-positioned menu (no overlay). Used for nav menus and\n \"split button\" addenda \u2014 see Pict-Modal-Dropdown.js.\n*/\n.pict-modal-dropdown\n{\n\tposition: fixed;\n\tz-index: 1025;\n\tmin-width: 160px;\n\tmax-width: 360px;\n\tmax-height: 60vh;\n\toverflow-y: auto;\n\tbackground: var(--pict-modal-dropdown-bg);\n\tcolor: var(--pict-modal-dropdown-fg);\n\tborder: 1px solid var(--pict-modal-dropdown-border);\n\tborder-radius: var(--pict-modal-dropdown-border-radius);\n\tbox-shadow: var(--pict-modal-dropdown-shadow);\n\tfont-family: var(--pict-modal-font-family);\n\tfont-size: var(--pict-modal-font-size);\n\tpadding: 4px 0;\n\topacity: 0;\n\ttransform: translateY(-4px);\n\ttransition: opacity var(--pict-modal-transition-duration) ease,\n\t transform var(--pict-modal-transition-duration) ease;\n}\n\n.pict-modal-dropdown.pict-modal-dropdown--above { transform: translateY(4px); }\n\n.pict-modal-dropdown.pict-modal-visible\n{\n\topacity: 1;\n\ttransform: translateY(0);\n}\n\n.pict-modal-dropdown-item\n{\n\tdisplay: flex;\n\talign-items: center;\n\tgap: 8px;\n\tpadding: 7px 14px;\n\tcursor: pointer;\n\tuser-select: none;\n\tcolor: inherit;\n\toutline: none;\n}\n\n.pict-modal-dropdown-item:hover,\n.pict-modal-dropdown-item:focus\n{\n\tbackground: var(--pict-modal-dropdown-item-hover-bg);\n\tcolor: var(--pict-modal-dropdown-item-hover-fg);\n}\n\n.pict-modal-dropdown-item--disabled\n{\n\tcursor: not-allowed;\n\tcolor: var(--pict-modal-dropdown-item-disabled-fg);\n}\n\n.pict-modal-dropdown-item--disabled:hover,\n.pict-modal-dropdown-item--disabled:focus\n{\n\tbackground: transparent;\n\tcolor: var(--pict-modal-dropdown-item-disabled-fg);\n}\n\n.pict-modal-dropdown-item--primary { color: var(--pict-modal-dropdown-primary-fg); }\n.pict-modal-dropdown-item--danger { color: var(--pict-modal-dropdown-danger-fg); }\n\n.pict-modal-dropdown-item-icon\n{\n\tflex: 0 0 auto;\n\tdisplay: inline-flex;\n\talign-items: center;\n\tjustify-content: center;\n\twidth: 16px;\n\theight: 16px;\n}\n\n.pict-modal-dropdown-item-icon svg { width: 100%; height: 100%; display: block; }\n\n.pict-modal-dropdown-item-label { flex: 1 1 auto; min-width: 0; }\n\n.pict-modal-dropdown-item-hint\n{\n\tflex: 0 0 auto;\n\tfont-size: 11px;\n\topacity: 0.6;\n\tmargin-left: 12px;\n}\n\n.pict-modal-dropdown-separator\n{\n\theight: 1px;\n\tbackground: var(--pict-modal-dropdown-separator);\n\tmargin: 4px 0;\n}\n\n.pict-modal-dropdown-header\n{\n\tpadding: 6px 14px 2px;\n\tfont-size: 11px;\n\tfont-weight: 600;\n\ttext-transform: uppercase;\n\tletter-spacing: 0.04em;\n\tcolor: var(--pict-modal-dropdown-header-fg);\n}\n\n/* \u2500\u2500 Resizable / Collapsible Panels \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pict-panel\n{\n\tposition: relative;\n\ttransition: width 0.2s ease;\n\tflex-shrink: 0;\n\toverflow: visible;\n}\n.pict-panel-collapsed\n{\n\twidth: 0 !important;\n\tmin-width: 0 !important;\n\toverflow: visible;\n}\n.pict-panel-collapsed > *:not(.pict-panel-edge)\n{\n\tdisplay: none;\n}\n\n/* Edge container \u2014 zero-width flex sibling of the panel.\n Sits next to the panel in the flex layout; children\n use absolute positioning to overlap the panel boundary. */\n.pict-panel-edge\n{\n\tposition: relative;\n\twidth: 0;\n\tflex-shrink: 0;\n\tz-index: 50;\n\toverflow: visible;\n}\n\n/* Resize handle \u2014 thin strip on the panel boundary */\n.pict-panel-resize\n{\n\tposition: absolute;\n\ttop: 0;\n\tbottom: 0;\n\twidth: 4px;\n\tcursor: col-resize;\n\tbackground: transparent;\n\ttransition: background 0.15s, width 0.15s;\n}\n.pict-panel-edge-right .pict-panel-resize\n{\n\tright: 0;\n\tborder-right: 1px solid var(--pict-panel-border, #DDD6CA);\n}\n.pict-panel-edge-left .pict-panel-resize\n{\n\tleft: 0;\n\tborder-left: 1px solid var(--pict-panel-border, #DDD6CA);\n}\n.pict-panel-resize:hover,\n.pict-panel-edge:hover .pict-panel-resize\n{\n\twidth: 5px;\n\tbackground: var(--pict-panel-accent, #2E7D74);\n\topacity: 0.5;\n}\n.pict-panel-resize.dragging\n{\n\twidth: 5px;\n\tbackground: var(--pict-panel-accent, #2E7D74);\n\topacity: 1;\n\ttransition: none;\n}\n.pict-panel-edge-collapsed .pict-panel-resize\n{\n\tdisplay: none;\n}\n\n/* Collapse tab \u2014 tucked sliver at rest, slides out on hover */\n.pict-panel-tab\n{\n\tposition: absolute;\n\ttop: 8px;\n\twidth: 8px;\n\theight: 24px;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\toverflow: hidden;\n\tbackground: var(--pict-panel-border, #DDD6CA);\n\tborder: 1px solid var(--pict-panel-border, #DDD6CA);\n\tcursor: pointer;\n\tcolor: var(--pict-panel-fg, #8A7F72);\n\tfont-size: 10px;\n\tline-height: 1;\n\topacity: 0.5;\n\ttransition: opacity 0.25s, width 0.2s ease, height 0.2s ease, left 0.2s ease, right 0.2s ease, background 0.2s;\n\tz-index: 51;\n}\n.pict-panel-edge:hover .pict-panel-tab,\n.pict-panel-tab:hover\n{\n\twidth: 20px;\n\theight: 32px;\n\topacity: 1;\n\toverflow: visible;\n\tbackground: var(--pict-panel-bg, #FAF8F4);\n}\n/* Right panel: tab to the left of the edge */\n.pict-panel-edge-right .pict-panel-tab\n{\n\tright: 0;\n\tborder-right: none;\n\tborder-radius: 4px 0 0 4px;\n}\n.pict-panel-edge-right:hover .pict-panel-tab,\n.pict-panel-edge-right .pict-panel-tab:hover\n{\n\tright: 0;\n}\n/* Left panel: tab to the right of the edge */\n.pict-panel-edge-left .pict-panel-tab\n{\n\tleft: 0;\n\tborder-left: none;\n\tborder-radius: 0 4px 4px 0;\n}\n.pict-panel-edge-left:hover .pict-panel-tab,\n.pict-panel-edge-left .pict-panel-tab:hover\n{\n\tleft: 0;\n}\n/* When collapsed \u2014 more visible */\n.pict-panel-edge-collapsed .pict-panel-tab\n{\n\twidth: 10px;\n\theight: 28px;\n\topacity: 0.6;\n}\n.pict-panel-edge-collapsed .pict-panel-tab:hover,\n.pict-panel-edge-collapsed:hover .pict-panel-tab\n{\n\twidth: 20px;\n\theight: 32px;\n\topacity: 1;\n\toverflow: visible;\n\tbackground: var(--pict-panel-bg, #FAF8F4);\n}\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n * Pict-Modal-Shell \u2014 viewport-managing layout for top / right /\n * bottom / left panels around a center.\n * \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n\n.pict-modal-shell-host { display: block; height: 100%; min-height: 0; }\n.pict-modal-shell\n{\n\tdisplay: flex;\n\tflex-direction: column;\n\twidth: 100%;\n\theight: 100%;\n\tmin-height: 0;\n\tposition: relative;\n\tcolor: var(--pict-modal-fg, var(--theme-color-text-primary, #1a1a1a));\n\tbackground: var(--theme-color-background-primary, transparent);\n}\n.pict-modal-shell-row { display: flex; min-width: 0; min-height: 0; }\n/* \"First added = at the edge\" convention is held by reversing the\n flex-direction on the bottom row + right side. That way, for ALL\n four sides, calling addPanel() N times stacks panel #1 against\n the viewport edge, panel #2 just inside it, panel #3 further in,\n and so on. Without these reverses, top + left worked that way but\n bottom + right inverted (first-added at content side, last-added\n at edge), which surprised callers. */\n.pict-modal-shell-row-top { flex: 0 0 auto; flex-direction: column; }\n.pict-modal-shell-row-bottom { flex: 0 0 auto; flex-direction: column-reverse; }\n.pict-modal-shell-row-middle\n{\n\tflex: 1 1 0;\n\tflex-direction: row;\n\tmin-height: 0;\n\tposition: relative;\n}\n.pict-modal-shell-side\n{\n\tdisplay: flex;\n\tflex: 0 0 auto;\n\tmin-height: 0;\n}\n.pict-modal-shell-side-left { flex-direction: row; }\n.pict-modal-shell-side-right { flex-direction: row-reverse; }\n.pict-modal-shell-center\n{\n\tflex: 1 1 0;\n\tmin-width: 0;\n\tmin-height: 0;\n\toverflow: auto;\n\tposition: relative;\n}\n.pict-modal-shell-center-content\n{\n\tmin-height: 100%;\n}\n/* Center column gains this class when at least one Scope:'center'\n panel is added. The center stops scrolling internally \u2014 that job\n moves to the content destination \u2014 and switches to a vertical flex\n so the destination and any inner panels stack cleanly. */\n.pict-modal-shell-center.pict-modal-shell-center-with-inner-panel\n{\n\tdisplay: flex;\n\tflex-direction: column;\n\toverflow: hidden;\n}\n.pict-modal-shell-center.pict-modal-shell-center-with-inner-panel > .pict-modal-shell-center-content\n{\n\tflex: 1 1 0;\n\tmin-height: 0;\n\toverflow: auto;\n}\n.pict-modal-shell-center.pict-modal-shell-center-with-inner-panel > .pict-modal-shell-panel\n{\n\tflex: 0 0 auto;\n\twidth: 100%;\n}\n\n/* Panels \u2014 base */\n.pict-modal-shell-panel\n{\n\t/* How far the collapse-tab's panel-bg \"merge bar\" extends INTO\n\t the panel past the tab's geometric edge. Painted via box-shadow\n\t on the tab (no DOM impact), it masks any 1px theme border on an\n\t inner element, content padding offset, or resize-handle hover\n\t bleed in the strip between the tab's panel-facing edge and the\n\t first real pixel of panel content. Consumers can bump this for\n\t themes with thicker (2+px) inner borders. */\n\t--pict-modal-collapse-tab-merge: 2px;\n\tposition: relative;\n\tdisplay: flex;\n\tflex-direction: column;\n\tbox-sizing: border-box;\n\tbackground: var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff));\n\tcolor: inherit;\n\tmin-width: 0;\n\tmin-height: 0;\n\ttransition: width 140ms ease, height 140ms ease;\n}\n.pict-modal-shell-panel-content\n{\n\tflex: 1 1 auto;\n\tmin-width: 0;\n\tmin-height: 0;\n\toverflow: auto;\n}\n/* Fixed-mode panels are pure chrome (topbars, status rows). Their\n content should fit the configured Size exactly \u2014 never scroll. The\n 1px border that .pict-modal-shell-panel-mode-fixed adds on the\n inner edge shaves 1px off the content's available height, which\n then triggers a sliver-scrollbar on any inner widget with\n min-height matching the panel Size. overflow:hidden here suppresses\n that without affecting resizable/collapsible panels (sidebars,\n drawers) where scrollable content is the whole point. */\n.pict-modal-shell-panel-mode-fixed > .pict-modal-shell-panel-content\n{\n\toverflow: hidden;\n}\n.pict-modal-shell-panel-content-inner\n{\n\tmin-height: 100%;\n}\n/* Panel boundary \u2014 fixed-mode panels get a hairline border for explicit\n demarcation. Collapsible / resizable panels DROP the boundary border\n (background contrast separates them from the center anyway) so the\n collapse tab can pull out cleanly without a hairline cutting across\n it. The host stylesheet still gets full control via the panel's own\n background. */\n.pict-modal-shell-panel-mode-fixed.pict-modal-shell-panel-top { border-bottom: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #e0e0e0)); }\n.pict-modal-shell-panel-mode-fixed.pict-modal-shell-panel-bottom { border-top: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #e0e0e0)); }\n.pict-modal-shell-panel-mode-fixed.pict-modal-shell-panel-left { border-right: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #e0e0e0)); }\n.pict-modal-shell-panel-mode-fixed.pict-modal-shell-panel-right { border-left: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #e0e0e0)); }\n\n/* Resize handle \u2014 absolute on the inner edge of each panel. */\n.pict-modal-shell-panel-resize-handle\n{\n\tposition: absolute;\n\tbackground: transparent;\n\tz-index: 5;\n\ttransition: background-color 120ms ease;\n}\n/* Resize handle hover \u2014 use the active brand's mode-aware primary\n color (set by pict-section-theme's Brand provider as\n --brand-color-primary-mode) so the resize affordance picks up the\n app's wordmark color. Falls back to the theme's brand-primary\n token if no brand is registered. */\n.pict-modal-shell-panel-resize-handle:hover\n{\n\tbackground: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\topacity: 0.4;\n}\n.pict-modal-shell-panel-left .pict-modal-shell-panel-resize-handle { right: -3px; top: 0; bottom: 0; width: 6px; cursor: col-resize; }\n.pict-modal-shell-panel-right .pict-modal-shell-panel-resize-handle { left: -3px; top: 0; bottom: 0; width: 6px; cursor: col-resize; }\n.pict-modal-shell-panel-top .pict-modal-shell-panel-resize-handle { bottom:-3px; left: 0; right: 0; height: 6px; cursor: row-resize; }\n.pict-modal-shell-panel-bottom .pict-modal-shell-panel-resize-handle { top: -3px; left: 0; right: 0; height: 6px; cursor: row-resize; }\n\n/* Collapse tab \u2014 slim sliver flush on the panel's OUTER boundary\n (where the resize handle sits), modelled on retold-content-system's\n sidebar tab. At rest it's a 6\xD728 px sliver; hover expands to\n 18\xD736 px without overlapping the panel's own content. The tab is\n positioned with its center on the boundary so half pokes into the\n adjacent area \u2014 the only place we can safely take over without\n stepping on app UI inside the panel. Title text only renders in the\n collapsed state where there's room for it. */\n.pict-modal-shell-panel-collapse-tab\n{\n\tposition: absolute;\n\tdisplay: flex; /* not inline-flex \u2014 avoids baseline alignment quirks */\n\talign-items: center;\n\tjustify-content: center;\n\toverflow: hidden;\n\tborder: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #d0d7de));\n\tbackground: var(--pict-modal-bg, var(--theme-color-background-panel, #ffffff));\n\tcolor: var(--theme-color-text-muted, #6b7280);\n\tfont: inherit;\n\tfont-size: 10px;\n\tletter-spacing: 0.4px;\n\ttext-transform: uppercase;\n\tcursor: pointer;\n\tz-index: 50;\n\topacity: 0.55;\n\tpadding: 0;\n\tbox-sizing: border-box;\n\tline-height: 0; /* keep child boxes from inflating around the rotated chevron */\n\t/* Geometry (width/height/right/left) is intentionally NOT animated.\n\t Sliding the tab's outer edge inward on hover-out makes it look like\n\t the tab is \"sliding into\" the panel content \u2014 weird visual.\n\t Snapping the size change instead, and animating only the appearance\n\t (opacity/color/shadow), gives a clean fade-in/out with no boundary\n\t weirdness. */\n\ttransition: opacity 160ms ease,\n\t background-color 160ms ease, color 160ms ease,\n\t border-color 160ms ease, box-shadow 160ms ease;\n}\n/* Hover state pulls accent color from the active brand (mode-aware,\n so it's legible in both light + dark) with theme brand-primary as\n fallback. The whole point of brand colors is that they show up\n across the app's chrome. */\n.pict-modal-shell-panel-collapse-tab:hover,\n.pict-modal-shell-panel:hover > .pict-modal-shell-panel-collapse-tab\n{\n\topacity: 1;\n\tcolor: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\tborder-color: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n}\n/* Drop shadow casts AWAY from the panel so the tab feels pulled out\n (extension of the panel) rather than floating across the boundary.\n The tab itself is now positioned fully OUTSIDE the panel boundary\n (see the per-side rules below), so we don't need a merge-bar shadow\n to mask any in-panel overlap \u2014 only the drop shadow remains. */\n.pict-modal-shell-panel-left:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-left > .pict-modal-shell-panel-collapse-tab:hover\n{\n\tbox-shadow: 3px 0 6px -2px rgba(0, 0, 0, 0.18);\n}\n.pict-modal-shell-panel-right:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-right > .pict-modal-shell-panel-collapse-tab:hover\n{\n\tbox-shadow: -3px 0 6px -2px rgba(0, 0, 0, 0.18);\n}\n.pict-modal-shell-panel-top:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-top > .pict-modal-shell-panel-collapse-tab:hover\n{\n\tbox-shadow: 0 3px 6px -2px rgba(0, 0, 0, 0.18);\n}\n.pict-modal-shell-panel-bottom:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab:hover\n{\n\tbox-shadow: 0 -3px 6px -2px rgba(0, 0, 0, 0.18);\n}\n\n/* Per-side base positioning \u2014 the tab lives entirely OUTSIDE the\n panel's outer boundary. Its panel-facing edge touches the boundary\n (offset = -tabThickness) and the rest of the tab pokes out into the\n adjacent area (center / sibling panel). Border on the panel-facing\n edge is dropped so the tab looks attached to the panel rather than\n floating beside it.\n Why fully-outside? Earlier iterations had the tab straddling the\n boundary (1px inside + 4px outside) with a panel-bg-colored merge-bar\n masking the in-panel half \u2014 that worked geometrically but visually\n read as \"tab pinned into the panel,\" and any rendering inside the\n panel (especially custom borders or hover bleeds) could clip against\n the in-panel half. Fully-external positioning eliminates the overlap\n class of bugs and lets the tab live entirely in the adjacent area\n where there's no app content to step on. */\n.pict-modal-shell-panel-left > .pict-modal-shell-panel-collapse-tab\n{\n\tright: -6px; top: 14px; width: 6px; height: 28px;\n\tborder-radius: 0 4px 4px 0;\n\tborder-left: 0;\n}\n.pict-modal-shell-panel-right > .pict-modal-shell-panel-collapse-tab\n{\n\tleft: -6px; top: 14px; width: 6px; height: 28px;\n\tborder-radius: 4px 0 0 4px;\n\tborder-right: 0;\n}\n.pict-modal-shell-panel-top > .pict-modal-shell-panel-collapse-tab\n{\n\tbottom: -6px; right: 14px; width: 28px; height: 6px;\n\tborder-radius: 0 0 4px 4px;\n\tborder-top: 0;\n}\n.pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab\n{\n\ttop: -6px; right: 14px; width: 28px; height: 6px;\n\tborder-radius: 4px 4px 0 0;\n\tborder-bottom: 0;\n}\n\n/* Hover: tab grows OUTWARD into the adjacent area. The panel-facing\n edge stays glued to the boundary (offset = -tabThickness), so the\n tab still looks attached on hover \u2014 only its outer dimension grows.\n For side panels the height also grows (28 \u2192 36) downward; for top\n /bottom panels the width grows (28 \u2192 36) \u2014 see the next block for\n the perpendicular-axis offsets. */\n.pict-modal-shell-panel-left:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-left > .pict-modal-shell-panel-collapse-tab:hover\n{\n\twidth: 18px; height: 36px; right: -18px;\n}\n.pict-modal-shell-panel-right:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-right > .pict-modal-shell-panel-collapse-tab:hover\n{\n\twidth: 18px; height: 36px; left: -18px;\n}\n.pict-modal-shell-panel-top:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-top > .pict-modal-shell-panel-collapse-tab:hover\n{\n\twidth: 36px; height: 18px; bottom: -18px;\n}\n.pict-modal-shell-panel-bottom:hover > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab:hover\n{\n\twidth: 36px; height: 18px; top: -18px;\n}\n\n.pict-modal-shell-panel-collapse-tab-title { display: none; white-space: nowrap; }\n\n/* Auto-generated chevron glyph inside the tab \u2014 only visible once the\n tab is wide / tall enough to show it (i.e. hover state, or when the\n panel is collapsed). Direction follows side + state.\n Sized 5\xD75 (down from 6) so even with rotation the visual stays\n well clear of the tab's overflow:hidden bounds at 18\xD736 hover and\n the 24px collapsed tab strip width. flex-shrink:0 ensures the\n pseudo never collapses to zero in tight tab dimensions. */\n.pict-modal-shell-panel-collapse-tab::before\n{\n\tcontent: '';\n\tdisplay: block;\n\twidth: 5px; height: 5px;\n\tflex-shrink: 0;\n\topacity: 0;\n\tborder-right: 1.5px solid currentColor;\n\tborder-bottom: 1.5px solid currentColor;\n\ttransform: rotate(135deg);\n\ttransform-origin: center center;\n\ttransition: opacity 160ms ease, transform 160ms ease;\n}\n.pict-modal-shell-panel:hover > .pict-modal-shell-panel-collapse-tab::before,\n.pict-modal-shell-panel-collapse-tab:hover::before,\n.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before\n{\n\topacity: 1;\n}\n.pict-modal-shell-panel-right > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(-45deg); }\n.pict-modal-shell-panel-top > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(-135deg); }\n.pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(45deg); }\n.pict-modal-shell-panel-left.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(-45deg); }\n.pict-modal-shell-panel-right.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(135deg); }\n.pict-modal-shell-panel-top.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(45deg); }\n.pict-modal-shell-panel-bottom.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before { transform: rotate(-135deg); }\n\n/* Collapsed state \u2014 content disappears, only the collapse tab remains. */\n.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-content\n{\n\tdisplay: none;\n}\n.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-resize-handle\n{\n\tdisplay: none;\n}\n.pict-modal-shell-panel-left.pict-modal-shell-panel-collapsed,\n.pict-modal-shell-panel-right.pict-modal-shell-panel-collapsed\n{\n\t/* When collapsed, side panels rotate the title for vertical reading. */\n\toverflow: hidden;\n}\n/* When collapsed: the entire panel becomes the tab strip \u2014 full width\n for sides, full height for top/bottom \u2014 with the title visible\n vertically (sides) or horizontally (top/bottom). The little sliver\n tab on the boundary disappears (we don't need it anymore \u2014 clicking\n anywhere on the panel toggles it back open). */\n.pict-modal-shell-panel-left.pict-modal-shell-panel-collapsed,\n.pict-modal-shell-panel-right.pict-modal-shell-panel-collapsed,\n.pict-modal-shell-panel-top.pict-modal-shell-panel-collapsed,\n.pict-modal-shell-panel-bottom.pict-modal-shell-panel-collapsed\n{\n\toverflow: hidden;\n}\n.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab\n{\n\t/* Promote the tab to FILL the collapsed panel (not just hug its\n\t content) so the centered chevron + title group sits in the middle\n\t of the panel. Without explicit width/height: 100%, the position:\n\t absolute element shrinks to its natural content size and the\n\t group ends up flush at the top of the panel \u2014 where the chevron\n\t gets clipped by the topbar. */\n\tposition: absolute !important;\n\ttop: 0 !important; right: 0 !important; bottom: 0 !important; left: 0 !important;\n\twidth: 100% !important;\n\theight: 100% !important;\n\tborder: 0;\n\tborder-radius: 0;\n\tbackground: transparent;\n\topacity: 0.85;\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n\tgap: 8px;\n\tpadding: 12px 4px; /* keeps chevron + title clear of edges */\n\tbox-shadow: none;\n\tcolor: var(--theme-color-text-muted, #6b7280);\n\tbox-sizing: border-box;\n\toverflow: hidden;\n}\n.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab:hover\n{\n\tbackground: var(--theme-color-background-hover, var(--pict-modal-bg, #fff));\n\tcolor: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\tbox-shadow: none;\n}\n/* Side panels (collapsed): rotate the title for vertical reading. */\n.pict-modal-shell-panel-left.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-right.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab\n{\n\twriting-mode: vertical-rl;\n\ttext-orientation: mixed;\n}\n.pict-modal-shell-panel-collapsed .pict-modal-shell-panel-collapse-tab-title\n{\n\tdisplay: inline;\n}\n\n/* Hidden panels \u2014 when Hidden:true is passed to addPanel, the collapsed\n state has zero footprint: no collapse tab (the tab is never built),\n the panel root is display:none, and the resize handle vanishes. The\n only path to the open state is a programmatic expand()/toggle() from\n somewhere else in the app (e.g. a topbar gear button). When expanded,\n the panel renders normally \u2014 so resize/drag handles continue to work\n while the panel is open. */\n.pict-modal-shell-panel-hidden.pict-modal-shell-panel-collapsed\n{\n\tdisplay: none !important;\n}\n\n/* Overlay panels \u2014 float over the middle row instead of taking layout\n space. The overlay layer is positioned absolutely inside the middle\n row; individual overlay panels stack with positive z-index. */\n.pict-modal-shell-overlay-layer\n{\n\tposition: absolute;\n\tinset: 0;\n\tpointer-events: none;\n\tz-index: 10;\n}\n.pict-modal-shell-overlay-layer .pict-modal-shell-panel\n{\n\tpointer-events: auto;\n\tposition: absolute;\n\tbox-shadow: 0 4px 24px rgba(0, 0, 0, 0.18);\n}\n.pict-modal-shell-overlay-layer .pict-modal-shell-panel-left { left: 0; top: 0; bottom: 0; }\n.pict-modal-shell-overlay-layer .pict-modal-shell-panel-right { right: 0; top: 0; bottom: 0; }\n.pict-modal-shell-overlay-layer .pict-modal-shell-panel-top { top: 0; left: 0; right: 0; }\n.pict-modal-shell-overlay-layer .pict-modal-shell-panel-bottom { bottom: 0; left: 0; right: 0; }\n\n/* \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\n Responsive drawer mode \u2014 .pict-modal-shell-drawer-active toggles\n onto the middle row when any panel with ResponsiveDrawer crosses\n below its breakpoint. Flips the row's flex-direction from row to\n column, stacking side panels above the center and stretching them\n to full width. Each opted-in panel itself gets the\n .pict-modal-shell-panel-drawer class so per-panel rules below\n target only the drawer-mode panels (right + non-drawer panels in\n the same row are unaffected). The drawer height is read from a\n per-panel --pict-modal-drawer-height CSS variable (default\n 33vh, set in JS from the DrawerHeight option).\n \u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500\u2500 */\n.pict-modal-shell-row-middle.pict-modal-shell-drawer-active\n{\n\tflex-direction: column;\n\t/* The drawer tab lives outside the drawer's bottom edge \u2014 ancestor\n\t chain MUST allow it to escape clip. */\n\toverflow: visible;\n}\n.pict-modal-shell-row-middle.pict-modal-shell-drawer-active .pict-modal-shell-side\n{\n\t/* Side stacks stretch full-width and lay out their panels as a\n\t horizontal row of stacked drawers (so two drawers from the same\n\t side don't end up overlapping). overflow: visible so the\n\t per-panel tab can extend below the side stack into the workspace. */\n\twidth: 100% !important;\n\tflex-direction: column;\n\toverflow: visible;\n}\n/* The drawer-tagged panel itself: kill the inline width set by\n _applySize (we override with !important since the inline style has\n higher specificity than a class selector), then size by height\n from the CSS variable. Resize handle is hidden in drawer mode\n because horizontal dragging doesn't translate to vertical sizing\n and the user already has the collapse tab to dismiss / restore.\n\n padding-bottom reserves an 18px strip at the bottom of the panel\n for the tab. The tab sits INSIDE the drawer's footprint \u2014 never\n below it \u2014 so the workspace header below the drawer is never in\n the same vertical band as the tab. (Previously the tab hung\n below the drawer's bottom edge into the workspace's top padding;\n that made the tab visually compete with the workspace header,\n even when the tab box-model bounds technically cleared the\n header.) box-sizing: border-box so the padding eats from the\n 33vh, not adding to it. */\n.pict-modal-shell-panel-drawer\n{\n\twidth: 100% !important;\n\tmax-width: 100% !important;\n\theight: var(--pict-modal-drawer-height, 33vh);\n\ttransition: height 140ms ease;\n\tpadding-bottom: 18px;\n\tbox-sizing: border-box;\n\toverflow: visible !important;\n\t/* Clip the panel bg to its CONTENT area only \u2014 the 18px\n\t padding-bottom reserve (where the tab lives) becomes\n\t transparent, so the middle row's primary background shows\n\t through. Without this the reserve would render with the\n\t panel's chrome bg, creating a visible \"strip\" between the\n\t drawer content above and the workspace below \u2014 the tab would\n\t look like it's sitting on its own miscoloured band rather\n\t than at the seam between drawer and workspace. */\n\tbackground-clip: content-box;\n}\n.pict-modal-shell-panel-drawer.pict-modal-shell-panel-collapsed\n{\n\t/* Collapsed = \"just the tab strip is visible\". 18px matches the\n\t panel's tab reserve so the height is consistent across states.\n\t When this is 0 the tab would have nowhere to render and the\n\t user couldn't reopen the drawer. */\n\theight: 18px !important;\n\tpadding-bottom: 0 !important;\n\t/* Drop the panel's bg in collapsed state \u2014 without this the 18px\n\t strip shows the --pict-modal-bg (panel chrome) which doesn't\n\t match the workspace --theme-color-background-primary below it,\n\t creating a visible \"drawer band\" around the tab that breaks the\n\t illusion of the tab belonging to the workspace area. With\n\t transparent bg the middle row's primary background shows\n\t through, the strip blends with the workspace, and the tab pill\n\t reads as a free-floating handle. */\n\tbackground: transparent !important;\n}\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-resize-handle\n{\n\tdisplay: none;\n}\n/* The drawer's collapse tab is a horizontal pill protruding from the\n bottom of the drawer (rather than the inner edge of a side panel).\n Override the side-panel positioning rules from above so the tab\n always sits at the drawer's bottom-center seam, in both expanded\n and collapsed states. The expand-from-zero affordance: when\n collapsed (height: 0), the tab still hangs below \"where the\n drawer would be\" \u2014 a small handle the user can click to pull\n the drawer back down. */\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-collapse-tab,\n.pict-modal-shell-panel-drawer.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab\n{\n\tposition: absolute !important;\n\t/* Anchored to the panel's BOTTOM edge \u2014 the tab lives INSIDE the\n\t drawer's footprint (in the 18px reserve at the bottom), never\n\t below it into the workspace. This means the workspace below\n\t the drawer is never sharing a vertical band with the tab, so\n\t the workspace header doesn't optically compete with it.\n\t bottom: 4px aligns the tab's top edge exactly with the panel's\n\t CONTENT-AREA bottom (panel.height \u2212 padding-bottom 18px). With\n\t border-top: 0 on the tab, the seam between the drawer content\n\t above and the tab body is invisible \u2014 they share --pict-modal-bg\n\t and merge into one shape, the tab reading as a labelled\n\t extension of the drawer hanging downward. Collapsed state\n\t keeps the smaller offset (overridden below) because its panel\n\t has no padding-bottom, so the math doesn't apply. */\n\ttop: auto !important;\n\tbottom: 4px !important;\n\tleft: 50% !important;\n\tright: auto !important;\n\ttransform: translate(-50%, 0) !important;\n\twidth: 64px !important;\n\theight: 14px !important;\n\t/* CRITICAL: border-box + padding: 0 \u2014 the collapsed-state base\n\t rule inherits \"padding: 12px 4px\" (so the chevron clears the\n\t edges of a tab that fills a 24px-wide side strip). In drawer\n\t mode the tab is a 14px tall pill, NOT a strip-fill, so that\n\t 12px vertical padding would balloon the tab's outer height to\n\t ~38px and crash into the workspace header text. The chevron\n\t is centered via flex anyway. */\n\tbox-sizing: border-box !important;\n\tpadding: 0 !important;\n\t/* Rounded BOTTOM corners + no top border \u2014 the tab looks like a\n\t traditional drawer-handle/tab hanging from above. Its rounded\n\t bottom curves face the workspace (the \"open downward\" affordance\n\t for a top drawer). border-top: 0 lets the tab visually merge\n\t with whatever's directly above it inside the panel (sidebar\n\t content when expanded, the panel background when collapsed). */\n\tborder-radius: 0 0 8px 8px;\n\tborder: 1px solid var(--pict-modal-border, var(--theme-color-border-default, #cfd5dd));\n\tborder-top: 0;\n\tbackground: var(--pict-modal-bg, var(--theme-color-background-panel, #fff));\n\topacity: 0.95;\n\tz-index: 20;\n\t/* The default side-panel hover-grow values would yank the tab off\n\t to the wrong spot in drawer mode \u2014 neutralise. */\n\tdisplay: flex;\n\talign-items: center;\n\tjustify-content: center;\n}\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-collapse-tab:hover,\n.pict-modal-shell-panel-drawer.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab:hover\n{\n\topacity: 1;\n\twidth: 96px !important;\n\t/* height stays at 14px \u2014 the tab is anchored with bottom, so any\n\t height growth would push the tab's TOP edge UPWARD past the\n\t space available above it. In EXPANDED state that crashes into\n\t the drawer content above; in COLLAPSED state it crashes into\n\t the topbar's brand stripes. Width-only growth (64 to 96, +50%)\n\t still gives the \"tab is reaching toward me\" affordance without\n\t the encroachment. */\n\tcolor: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\tborder-color: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\tbox-shadow: 0 3px 6px -2px rgba(0, 0, 0, 0.18);\n}\n/* Collapsed-state bottom-offset override. Expanded panels have an\n 18px padding-bottom reserve, and \"bottom: 4px\" anchors the tab's\n top edge exactly at the content-area boundary (so it merges\n visually with the drawer above). Collapsed panels have\n padding-bottom: 0 and a total height of 18px \u2014 \"bottom: 4px\"\n there would put the tab's top at the panel's actual top edge,\n crashing the (border-top: 0) tab into the topbar. The smaller\n \"bottom: 2px\" keeps the 14px tab vertically centered in the 18px\n strip with 2px margins on either side. */\n.pict-modal-shell-panel-drawer.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab\n{\n\tbottom: 2px !important;\n}\n/* Chevron inside the tab: point UP when expanded (the drawer\n collapses UP / out of view, so the arrow indicates \"click me to\n send the drawer up\"), DOWN when collapsed (the drawer expands DOWN\n into view). Rotations come from the existing top-panel chevron\n table: rotate(-135deg) \u2192 UP arrow, rotate(45deg) \u2192 DOWN arrow. */\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-collapse-tab::before\n{\n\ttransform: rotate(-135deg) !important;\n}\n.pict-modal-shell-panel-drawer.pict-modal-shell-panel-collapsed > .pict-modal-shell-panel-collapse-tab::before\n{\n\ttransform: rotate(45deg) !important;\n}\n/* The collapse tab's existing title-text span is hidden when reduced\n to a pill \u2014 there's no horizontal room. The chevron alone reads\n correctly. */\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-collapse-tab .pict-modal-shell-panel-collapse-tab-title,\n.pict-modal-shell-panel-drawer > .pict-modal-shell-panel-collapse-tab .pict-modal-shell-panel-collapse-tab-icon\n{\n\tdisplay: none;\n}\n\n/* Drag-active state \u2014 disable text selection + change cursor globally\n so resize feels solid even when the cursor briefly leaves the handle. */\n.pict-modal-shell-dragging-x, .pict-modal-shell-dragging-y { user-select: none; }\n.pict-modal-shell-dragging-x * { cursor: col-resize !important; }\n.pict-modal-shell-dragging-y * { cursor: row-resize !important; }\n\n/* Per-panel resize-active state \u2014 kills the panel's collapse/expand\n width/height transition for the duration of a drag. Without this,\n every pointermove starts a fresh 140 ms transition and the resize\n visibly lags behind the cursor (\"choppy\"). With it disabled the\n panel snaps to the new size on the same frame as the pointer, which\n feels native. */\n.pict-modal-shell-panel-resizing { transition: none !important; }\n.pict-modal-shell-panel-resizing > .pict-modal-shell-panel-resize-handle\n{\n\tbackground: var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb));\n\topacity: 0.5;\n}\n\n/* Panel popup-attention flash \u2014 fires when popup() is called on an\n already-open panel. Brief brand-colored inset glow so the user sees\n that their click landed even though the panel didn't change shape.\n Class is added by the shell, auto-removed after ~700 ms. */\n@keyframes pict-modal-shell-panel-flash\n{\n\t0% { box-shadow: inset 0 0 0 0 transparent; }\n\t30% { box-shadow: inset 0 0 0 3px var(--brand-color-primary-mode, var(--theme-color-brand-primary, #2563eb)); }\n\t100% { box-shadow: inset 0 0 0 0 transparent; }\n}\n.pict-modal-shell-panel-flash\n{\n\tanimation: pict-modal-shell-panel-flash 600ms ease-out;\n}\n"};},{}],170:[function(require,module,exports){const libPictViewClass=require('pict-view');const libPictModalOverlay=require('./Pict-Modal-Overlay.js');const libPictModalConfirm=require('./Pict-Modal-Confirm.js');const libPictModalWindow=require('./Pict-Modal-Window.js');const libPictModalToast=require('./Pict-Modal-Toast.js');const libPictModalTooltip=require('./Pict-Modal-Tooltip.js');const libPictModalPanel=require('./Pict-Modal-Panel.js');const libPictModalDropdown=require('./Pict-Modal-Dropdown.js');const libPictModalShell=require('./Pict-Modal-Shell.js');const _DefaultConfiguration=require('./Pict-Section-Modal-DefaultConfiguration.js');class PictSectionModal extends libPictViewClass{constructor(pFable,pOptions,pServiceHash){let tmpOptions=Object.assign({},_DefaultConfiguration,pOptions);super(pFable,tmpOptions,pServiceHash);this._activeModals=[];this._activeTooltips=[];this._activeToasts=[];this._idCounter=0;this._overlay=new libPictModalOverlay(this);this._confirm=new libPictModalConfirm(this);this._window=new libPictModalWindow(this);this._toast=new libPictModalToast(this);this._tooltip=new libPictModalTooltip(this);this._panel=new libPictModalPanel(this);this._dropdown=new libPictModalDropdown(this);this._shell=new libPictModalShell(this);}onBeforeInitialize(){super.onBeforeInitialize();// Ensure the root class is on the body for CSS variable scoping
7202
7251
  if(typeof document!=='undefined'&&document.body){if(!document.body.classList.contains('pict-modal-root')){document.body.classList.add('pict-modal-root');}}return super.onBeforeInitialize();}/**
7203
7252
  * Generate a unique ID for DOM elements.
7204
7253
  *
@@ -12652,7 +12701,7 @@ try{if(!global.localStorage)return false;}catch(_){return false;}var val=global.
12652
12701
  // presumably different callback function.
12653
12702
  // This makes sure that own properties are retained, so that
12654
12703
  // decorations and such are not lost along the way.
12655
- module.exports=wrappy;function wrappy(fn,cb){if(fn&&cb)return wrappy(fn)(cb);if(typeof fn!=='function')throw new TypeError('need wrapper function');Object.keys(fn).forEach(function(k){wrapper[k]=fn[k];});return wrapper;function wrapper(){var args=new Array(arguments.length);for(var i=0;i<args.length;i++){args[i]=arguments[i];}var ret=fn.apply(this,args);var cb=args[args.length-1];if(typeof ret==='function'&&ret!==cb){Object.keys(cb).forEach(function(k){ret[k]=cb[k];});}return ret;}}},{}],346:[function(require,module,exports){module.exports=extend;var hasOwnProperty=Object.prototype.hasOwnProperty;function extend(){var target={};for(var i=0;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;}},{}],347:[function(require,module,exports){module.exports={"name":"pict-docuserve","version":"1.4.0","description":"Pict Documentation Server - A single-page documentation viewer built on Pict","main":"source/Pict-Application-Docuserve.js","bin":{"pict-docuserve":"source/cli/Docuserve-CLI-Run.js"},"files":["source/","dist/","html/"],"scripts":{"start":"node source/cli/Docuserve-CLI-Run.js serve","brand":"node node_modules/pict-section-theme/bin/pict-section-theme-brand.js --manifest ../../../Retold-Modules-Manifest.json --module pict-docuserve","prebuild":"npm run brand","build":"npx quack build && npx quack copy","prebuild-docs":"npm run brand","build-docs":"npx quack build && npx quack copy && node source/cli/Docuserve-CLI-Run.js inject ./docs && node example_applications/build-examples.js stage-docs","serve-docs":"node source/cli/Docuserve-CLI-Run.js serve ./docs","serve-examples":"node example_applications/build-examples.js","test":"npx quack test","tests":"npx quack test -g","coverage":"npx quack coverage","prepublishOnly":"npm run build"},"author":"steven velozo <steven@velozo.com>","license":"MIT","dependencies":{"fable-serviceproviderbase":"^3.0.19","lunr":"^2.3.9","pict":"^1.0.372","pict-application":"^1.0.34","pict-provider":"^1.0.13","pict-section-code":"^1.0.11","pict-section-content":"^1.0.4","pict-section-histogram":"^1.0.1","pict-section-modal":"^1.1.3","pict-section-theme":"^1.0.6","pict-service-commandlineutility":"^1.0.19","pict-view":"^1.0.68"},"devDependencies":{"pict-docuserve":"^1.3.3","quackage":"^1.2.4"},"copyFilesSettings":{"whenFileExists":"overwrite"},"copyFiles":[{"from":"./html/*","to":"./dist/"}],"mocha":{"diff":true,"extension":["js"],"package":"./package.json","reporter":"spec","slow":"75","timeout":"5000","ui":"tdd","watch-files":["source/**/*.js","test/**/*.js"],"watch-ignore":["lib/vendor"]},"retold":{"brand":{"Hash":"pict-docuserve","Name":"Pict Docuserve","Tagline":"A documentation viewer built on Pict","Palette":"default","Icon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-pict-docuserve-filled-light\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\" fill=\"#692bbf\"/>\n\t\t<g clip-path=\"url(#frame-pict-docuserve-filled-light)\"><rect x=\"18\" y=\"30\" width=\"48\" height=\"48\" rx=\"8\" fill=\"#c13ccd\" opacity=\"0.9\"/>\n\t\t\t\t\t<rect x=\"30\" y=\"18\" width=\"48\" height=\"48\" rx=\"8\" fill=\"rgba(255,255,255,0.18)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"38\" font-weight=\"600\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">PD</text>\n\t</svg>","IconType":"svg","Favicon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-pict-docuserve-light\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\" fill=\"#692bbf\"/>\n\t\t<g clip-path=\"url(#fav-pict-docuserve-light)\"><rect x=\"28\" y=\"16\" width=\"52\" height=\"52\" rx=\"9\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">P</text>\n\t</svg>","FaviconDark":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-pict-docuserve-dark\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\" fill=\"#9a6fd8\"/>\n\t\t<g clip-path=\"url(#fav-pict-docuserve-dark)\"><rect x=\"28\" y=\"16\" width=\"52\" height=\"52\" rx=\"9\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">P</text>\n\t</svg>","Colors":{"Primary":"#692bbf","Secondary":"#c13ccd","PrimaryLight":"#692bbf","PrimaryDark":"#9a6fd8","SecondaryLight":"#c13ccd","SecondaryDark":"#d48adb"}}}};},{}],348:[function(require,module,exports){/**
12704
+ module.exports=wrappy;function wrappy(fn,cb){if(fn&&cb)return wrappy(fn)(cb);if(typeof fn!=='function')throw new TypeError('need wrapper function');Object.keys(fn).forEach(function(k){wrapper[k]=fn[k];});return wrapper;function wrapper(){var args=new Array(arguments.length);for(var i=0;i<args.length;i++){args[i]=arguments[i];}var ret=fn.apply(this,args);var cb=args[args.length-1];if(typeof ret==='function'&&ret!==cb){Object.keys(cb).forEach(function(k){ret[k]=cb[k];});}return ret;}}},{}],346:[function(require,module,exports){module.exports=extend;var hasOwnProperty=Object.prototype.hasOwnProperty;function extend(){var target={};for(var i=0;i<arguments.length;i++){var source=arguments[i];for(var key in source){if(hasOwnProperty.call(source,key)){target[key]=source[key];}}}return target;}},{}],347:[function(require,module,exports){module.exports={"name":"pict-docuserve","version":"1.4.2","description":"Pict Documentation Server - A single-page documentation viewer built on Pict","main":"source/Pict-Application-Docuserve.js","bin":{"pict-docuserve":"source/cli/Docuserve-CLI-Run.js"},"files":["source/","dist/","html/"],"scripts":{"start":"node source/cli/Docuserve-CLI-Run.js serve","brand":"node node_modules/pict-section-theme/bin/pict-section-theme-brand.js --manifest ../../../Retold-Modules-Manifest.json --module pict-docuserve","build":"npx quack build && npx quack copy","build-docs":"npx quack build && npx quack copy && node source/cli/Docuserve-CLI-Run.js inject ./docs && node example_applications/build-examples.js stage-docs","serve-docs":"node source/cli/Docuserve-CLI-Run.js serve ./docs","serve-examples":"node example_applications/build-examples.js","test":"npx quack test","tests":"npx quack test -g","coverage":"npx quack coverage","prepublishOnly":"npm run build"},"author":"steven velozo <steven@velozo.com>","license":"MIT","dependencies":{"fable-serviceproviderbase":"^3.0.19","lunr":"^2.3.9","pict":"^1.0.372","pict-application":"^1.0.34","pict-provider":"^1.0.13","pict-section-code":"^1.0.11","pict-section-content":"^1.0.5","pict-section-histogram":"^1.0.1","pict-section-modal":"^1.1.4","pict-section-theme":"^1.0.6","pict-service-commandlineutility":"^1.0.19","pict-view":"^1.0.68"},"devDependencies":{"pict-docuserve":"^1.4.1","quackage":"^1.2.5"},"copyFilesSettings":{"whenFileExists":"overwrite"},"copyFiles":[{"from":"./html/*","to":"./dist/"}],"mocha":{"diff":true,"extension":["js"],"package":"./package.json","reporter":"spec","slow":"75","timeout":"5000","ui":"tdd","watch-files":["source/**/*.js","test/**/*.js"],"watch-ignore":["lib/vendor"]},"retold":{"brand":{"Hash":"pict-docuserve","Name":"Pict Docuserve","Tagline":"A documentation viewer built on Pict","Palette":"default","Icon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"frame-pict-docuserve-filled-light\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\" fill=\"#692bbf\"/>\n\t\t<g clip-path=\"url(#frame-pict-docuserve-filled-light)\"><rect x=\"18\" y=\"30\" width=\"48\" height=\"48\" rx=\"8\" fill=\"#c13ccd\" opacity=\"0.9\"/>\n\t\t\t\t\t<rect x=\"30\" y=\"18\" width=\"48\" height=\"48\" rx=\"8\" fill=\"rgba(255,255,255,0.18)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"38\" font-weight=\"600\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">PD</text>\n\t</svg>","IconType":"svg","Favicon":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-pict-docuserve-light\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\" fill=\"#692bbf\"/>\n\t\t<g clip-path=\"url(#fav-pict-docuserve-light)\"><rect x=\"28\" y=\"16\" width=\"52\" height=\"52\" rx=\"9\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#ffffff\" letter-spacing=\"-1\">P</text>\n\t</svg>","FaviconDark":"<svg xmlns=\"http://www.w3.org/2000/svg\" viewBox=\"0 0 96 96\" width=\"96\" height=\"96\">\n\t\t<defs>\n\t\t\t<clipPath id=\"fav-pict-docuserve-dark\">\n\t\t\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\"/>\n\t\t\t</clipPath>\n\t\t</defs>\n\t\t<path d=\"M 2 48\n\t\t\tC 2 18.0222416, 18.0222416 2, 48 2\n\t\t\tC 77.9777584 2, 94 18.0222416, 94 48\n\t\t\tC 94 77.9777584, 77.9777584 94, 48 94\n\t\t\tC 18.0222416 94, 2 77.9777584, 2 48 Z\" fill=\"#9a6fd8\"/>\n\t\t<g clip-path=\"url(#fav-pict-docuserve-dark)\"><rect x=\"28\" y=\"16\" width=\"52\" height=\"52\" rx=\"9\" fill=\"rgba(255,255,255,0.22)\"/></g>\n\t\t<text x=\"48\" y=\"50\" text-anchor=\"middle\" dominant-baseline=\"central\"\n\t\t\tfont-family=\"-apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif\"\n\t\t\tfont-size=\"60\" font-weight=\"800\"\n\t\t\tfill=\"#101418\" letter-spacing=\"-1\">P</text>\n\t</svg>","Colors":{"Primary":"#692bbf","Secondary":"#c13ccd","PrimaryLight":"#692bbf","PrimaryDark":"#9a6fd8","SecondaryLight":"#c13ccd","SecondaryDark":"#d48adb"}}}};},{}],348:[function(require,module,exports){/**
12656
12705
  * Docuserve-Brand — docuserve's own wordmark, used only as a fallback.
12657
12706
  *
12658
12707
  * Docuserve is a viewer: the docs being served dictate the brand, not
@@ -12689,7 +12738,7 @@ const libPictSectionModal=require('pict-section-modal');const libPictSectionThem
12689
12738
  // `npm run brand` from Retold-Modules-Manifest.json + this module's
12690
12739
  // `retold.brand` package.json block.
12691
12740
  const libDocuserveBrand=require('./Docuserve-Brand.js');// Views
12692
- const libViewLayout=require('./views/PictView-Docuserve-Layout.js');const libViewTopBarNav=require('./views/PictView-Docuserve-TopBar-Nav.js');const libViewTopBarUser=require('./views/PictView-Docuserve-TopBar-User.js');const libViewSidebar=require('./views/PictView-Docuserve-Sidebar.js');const libViewSplash=require('./views/PictView-Docuserve-Splash.js');const libViewContent=require('./views/PictView-Docuserve-Content.js');const libViewSearch=require('./views/PictView-Docuserve-Search.js');const libViewDemo=require('./views/PictView-Docuserve-Demo.js');const libViewFablePlayground=require('./views/PictView-Docuserve-Fable-Playground.js');class DocuserveApplication extends libPictApplication{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);// Add the documentation provider
12741
+ const libViewLayout=require('./views/PictView-Docuserve-Layout.js');const libViewTopBarNav=require('./views/PictView-Docuserve-TopBar-Nav.js');const libViewTopBarUser=require('./views/PictView-Docuserve-TopBar-User.js');const libViewSidebar=require('./views/PictView-Docuserve-Sidebar.js');const libViewSplash=require('./views/PictView-Docuserve-Splash.js');const libViewContent=require('./views/PictView-Docuserve-Content.js');const libViewSearch=require('./views/PictView-Docuserve-Search.js');const libViewDemo=require('./views/PictView-Docuserve-Demo.js');const libViewFablePlayground=require('./views/PictView-Docuserve-Fable-Playground.js');const libViewSectionPlayground=require('./views/PictView-Docuserve-Section-Playground.js');class DocuserveApplication extends libPictApplication{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);// Add the documentation provider
12693
12742
  this.pict.addProvider('Docuserve-Documentation',libDocumentationProvider.default_configuration,libDocumentationProvider);// Add the demos registry provider. Libraries that ship demos
12694
12743
  // (e.g. pict-section-form, pict-section-code) call
12695
12744
  // `pict.providers['Docuserve-Demos'].registerAll([...])` at
@@ -12699,7 +12748,7 @@ this.pict.addProvider('Docuserve-Demos',libDemosProvider.default_configuration,l
12699
12748
  this.pict.addView('Pict-Section-Modal',libPictSectionModal.default_configuration,libPictSectionModal);// Add views — the layout, sidebar, splash, content, search are
12700
12749
  // docuserve's own content surfaces. The two TopBar-* slot views
12701
12750
  // fill the Theme-TopBar's Nav and User slots.
12702
- this.pict.addView('Docuserve-Layout',libViewLayout.default_configuration,libViewLayout);this.pict.addView('Docuserve-TopBar-Nav',libViewTopBarNav.default_configuration,libViewTopBarNav);this.pict.addView('Docuserve-TopBar-User',libViewTopBarUser.default_configuration,libViewTopBarUser);this.pict.addView('Docuserve-Sidebar',libViewSidebar.default_configuration,libViewSidebar);this.pict.addView('Docuserve-Splash',libViewSplash.default_configuration,libViewSplash);this.pict.addView('Docuserve-Content',libViewContent.default_configuration,libViewContent);this.pict.addView('Docuserve-Search',libViewSearch.default_configuration,libViewSearch);this.pict.addView('Docuserve-Demo',libViewDemo.default_configuration,libViewDemo);this.pict.addView('Docuserve-Fable-Playground',libViewFablePlayground.default_configuration,libViewFablePlayground);// Theme-Section is added later from onAfterInitializeAsync, after
12751
+ this.pict.addView('Docuserve-Layout',libViewLayout.default_configuration,libViewLayout);this.pict.addView('Docuserve-TopBar-Nav',libViewTopBarNav.default_configuration,libViewTopBarNav);this.pict.addView('Docuserve-TopBar-User',libViewTopBarUser.default_configuration,libViewTopBarUser);this.pict.addView('Docuserve-Sidebar',libViewSidebar.default_configuration,libViewSidebar);this.pict.addView('Docuserve-Splash',libViewSplash.default_configuration,libViewSplash);this.pict.addView('Docuserve-Content',libViewContent.default_configuration,libViewContent);this.pict.addView('Docuserve-Search',libViewSearch.default_configuration,libViewSearch);this.pict.addView('Docuserve-Demo',libViewDemo.default_configuration,libViewDemo);this.pict.addView('Docuserve-Fable-Playground',libViewFablePlayground.default_configuration,libViewFablePlayground);this.pict.addView('Docuserve-Section-Playground',libViewSectionPlayground.default_configuration,libViewSectionPlayground);// Theme-Section is added later from onAfterInitializeAsync, after
12703
12752
  // the brand has been resolved. Docuserve is a viewer — the docs
12704
12753
  // being served dictate the brand, not docuserve itself. See
12705
12754
  // `_resolveBrand()` for the resolution order.
@@ -12752,9 +12801,15 @@ this.pict.views['Docuserve-Layout'].render();return super.onAfterInitializeAsync
12752
12801
  let tmpDocPath=tmpParts.slice(1).join('/');this.navigateToPage(tmpDocPath);return;}if(tmpParts[0]==='doc'&&tmpParts.length>=3){let tmpGroup=tmpParts[1];let tmpModule=tmpParts[2];if(tmpParts.length>=4){let tmpPath=tmpParts.slice(3).join('/');this.navigateToModulePath(tmpGroup,tmpModule,tmpPath);}else{this.navigateToModule(tmpGroup,tmpModule);}return;}// #/demo/<group>/<module>/<hash> — interactive demo registered
12753
12802
  // with Docuserve-Demos. Mounts the demo's view into the content
12754
12803
  // area + renders any Sources tabs alongside.
12755
- if(tmpParts[0]==='demo'&&tmpParts.length>=4){let tmpGroup=tmpParts[1];let tmpModule=tmpParts[2];let tmpHash=tmpParts.slice(3).join('/');this.navigateToDemo(tmpGroup,tmpModule,tmpHash);return;}// #/playground/<kind> — live editor + sandbox for trying Fable
12756
- // (eventually Pict too).
12757
- if(tmpParts[0]==='playground'&&tmpParts.length>=2){this.navigateToPlayground(tmpParts[1]);return;}// Unknown route treat as a page
12804
+ if(tmpParts[0]==='demo'&&tmpParts.length>=4){let tmpGroup=tmpParts[1];let tmpModule=tmpParts[2];let tmpHash=tmpParts.slice(3).join('/');this.navigateToDemo(tmpGroup,tmpModule,tmpHash);return;}// #/playground/<kind> — live editor + sandbox. Three shapes:
12805
+ // #/playground/fable — Fable JS REPL (bottom drawer)
12806
+ // #/playground/section section playground for the
12807
+ // current module (standalone-mode
12808
+ // docs site)
12809
+ // #/playground/section/<group>/<module> — section playground for a
12810
+ // specific module (catalog-mode
12811
+ // docs site serving multiple)
12812
+ if(tmpParts[0]==='playground'&&tmpParts.length>=2){if(tmpParts[1]==='section'){let tmpGroup=tmpParts.length>=4?tmpParts[2]:this.pict.AppData.Docuserve.CurrentGroup||'';let tmpModule=tmpParts.length>=4?tmpParts[3]:this.pict.AppData.Docuserve.CurrentModule||'';this.navigateToSectionPlayground(tmpGroup,tmpModule);return;}this.navigateToPlayground(tmpParts[1]);return;}// Unknown route — treat as a page
12758
12813
  this.navigateToPage(tmpHash);}/**
12759
12814
  * Navigate to an interactive demo registered with Docuserve-Demos.
12760
12815
  *
@@ -12776,6 +12831,17 @@ if(tmpSidebarView){tmpSidebarView.renderSidebarGroups();if(typeof tmpSidebarView
12776
12831
  this.navigateToPage('fable-playground');if(tmpLayout&&typeof tmpLayout.setPlaygroundEnabled==='function'){tmpLayout.setPlaygroundEnabled(true);}if(tmpLayout&&typeof tmpLayout.expandPlayground==='function'){tmpLayout.expandPlayground();}return;}// Unknown playground kind — fall back to a friendly notice in the
12777
12832
  // content area rather than silently dropping the navigation.
12778
12833
  let tmpContentView=this.pict.views['Docuserve-Content'];if(tmpContentView&&typeof tmpContentView.displayContent==='function'){tmpContentView.render();tmpContentView.displayContent('<h1>Playground not available</h1><p>No playground is registered for <code>'+pKind+'</code>.</p>');}}/**
12834
+ * Open the section playground for `<group>/<module>`. Unlike the
12835
+ * Fable playground (which lives in the bottom drawer), the section
12836
+ * playground takes over the main content area — it needs full
12837
+ * vertical space for its four editor tabs + iframe pane.
12838
+ *
12839
+ * @param {string} pGroup
12840
+ * @param {string} pModule
12841
+ */navigateToSectionPlayground(pGroup,pModule){this.pict.AppData.Docuserve.CurrentGroup=pGroup;this.pict.AppData.Docuserve.CurrentModule=pModule;this.pict.AppData.Docuserve.CurrentDemo='';this.pict.AppData.Docuserve.CurrentPath='section-playground';// Hide the bottom playground drawer — the section playground
12842
+ // is the whole show on this route.
12843
+ let tmpLayout=this.pict.views['Docuserve-Layout'];if(tmpLayout&&typeof tmpLayout.setPlaygroundEnabled==='function'){tmpLayout.setPlaygroundEnabled(false);}let tmpPlayground=this.pict.views['Docuserve-Section-Playground'];if(!tmpPlayground||typeof tmpPlayground.openPlayground!=='function'){let tmpContentView=this.pict.views['Docuserve-Content'];if(tmpContentView&&typeof tmpContentView.displayContent==='function'){tmpContentView.render();tmpContentView.displayContent('<h1>Section playground unavailable</h1><p>The Section Playground view is not registered.</p>');}return;}tmpPlayground.openPlayground(pGroup,pModule);// Keep the sidebar in sync — show the module's nav + active item.
12844
+ let tmpSidebarView=this.pict.views['Docuserve-Sidebar'];if(tmpSidebarView){tmpSidebarView.renderSidebarGroups();if(typeof tmpSidebarView.renderModuleNav==='function'){tmpSidebarView.renderModuleNav(pGroup,pModule);}}}/**
12779
12845
  * Navigate to a hash route.
12780
12846
  *
12781
12847
  * Sets window.location.hash, which triggers the hashchange listener in the
@@ -12793,15 +12859,22 @@ this.pict.views['Docuserve-Sidebar'].clearModuleNav();this.pict.views['Docuserve
12793
12859
  * its _sidebar.md / catalog Sidebar). Invoked at the tail of every
12794
12860
  * navigation method so the panel doesn't reserve space on modules
12795
12861
  * that haven't opted in.
12796
- */_syncPlaygroundVisibility(){let tmpLayout=this.pict.views['Docuserve-Layout'];let tmpDoc=this.pict.providers['Docuserve-Documentation'];if(!tmpLayout||typeof tmpLayout.setPlaygroundEnabled!=='function'){return;}let tmpGroup=this.pict.AppData.Docuserve.CurrentGroup;let tmpModule=this.pict.AppData.Docuserve.CurrentModule;let tmpEnabled=tmpDoc&&typeof tmpDoc.isPlaygroundEnabled==='function'?tmpDoc.isPlaygroundEnabled(tmpGroup,tmpModule):false;tmpLayout.setPlaygroundEnabled(tmpEnabled);if(typeof tmpLayout.setPlaygroundTitle==='function'){tmpLayout.setPlaygroundTitle(tmpModule?'JS Playground: '+tmpModule:'JS Playground');}// Load the module's _playground.json (cached after first load).
12797
- // Stash the config in AppData so the playground view's require
12798
- // shim and the per-run capture logic can consult it. We don't
12799
- // gate the playground on the config landing — it's purely
12800
- // informative right now since all fable modules are bundled.
12801
- if(tmpEnabled&&tmpDoc&&typeof tmpDoc.loadPlaygroundConfig==='function'){tmpDoc.loadPlaygroundConfig(tmpGroup,tmpModule).then(pConfig=>{if(!this.pict.AppData.Docuserve.Playground){this.pict.AppData.Docuserve.Playground={};}this.pict.AppData.Docuserve.Playground.Config=pConfig||null;// Config controls DOM-sandbox pane visibility; let the
12862
+ */_syncPlaygroundVisibility(){let tmpLayout=this.pict.views['Docuserve-Layout'];let tmpDoc=this.pict.providers['Docuserve-Documentation'];if(!tmpLayout||typeof tmpLayout.setPlaygroundEnabled!=='function'){return;}let tmpGroup=this.pict.AppData.Docuserve.CurrentGroup;let tmpModule=this.pict.AppData.Docuserve.CurrentModule;let tmpEnabled=tmpDoc&&typeof tmpDoc.isPlaygroundEnabled==='function'?tmpDoc.isPlaygroundEnabled(tmpGroup,tmpModule):false;tmpLayout.setPlaygroundEnabled(tmpEnabled);if(typeof tmpLayout.setPlaygroundTitle==='function'){tmpLayout.setPlaygroundTitle(tmpModule?'JS Playground: '+tmpModule:'JS Playground');}// Load the module's _playground.json. Two reasons to always do
12863
+ // this (regardless of tmpEnabled):
12864
+ // 1. The async `Kind` check inside isPlaygroundEnabled needs
12865
+ // the cache populated. If the config declares Kind:
12866
+ // "section", we have to re-call setPlaygroundEnabled(false)
12867
+ // to hide the Fable drawer that the sync sidebar-based
12868
+ // check just turned on.
12869
+ // 2. Apps still consult AppData.Docuserve.Playground.Config
12870
+ // (DOM-sandbox pane visibility etc.).
12871
+ if(tmpDoc&&typeof tmpDoc.loadPlaygroundConfig==='function'){tmpDoc.loadPlaygroundConfig(tmpGroup,tmpModule).then(pConfig=>{if(!this.pict.AppData.Docuserve.Playground){this.pict.AppData.Docuserve.Playground={};}this.pict.AppData.Docuserve.Playground.Config=pConfig||null;// Re-evaluate the drawer's enabled state now that the
12872
+ // cache is populated — a Kind: "section" config flips
12873
+ // it from true back to false.
12874
+ if(typeof tmpDoc.isPlaygroundEnabled==='function'){let tmpReEnabled=tmpDoc.isPlaygroundEnabled(tmpGroup,tmpModule);tmpLayout.setPlaygroundEnabled(tmpReEnabled);}// Config controls DOM-sandbox pane visibility; let the
12802
12875
  // playground view re-evaluate the moment it lands. No-op
12803
12876
  // if the view hasn't been mounted yet.
12804
- let tmpPlaygroundView=this.pict.views['Docuserve-Fable-Playground'];if(tmpPlaygroundView&&typeof tmpPlaygroundView._applySandboxMode==='function'){tmpPlaygroundView._applySandboxMode();}});}else{if(this.pict.AppData.Docuserve.Playground){this.pict.AppData.Docuserve.Playground.Config=null;}let tmpPlaygroundView=this.pict.views['Docuserve-Fable-Playground'];if(tmpPlaygroundView&&typeof tmpPlaygroundView._applySandboxMode==='function'){tmpPlaygroundView._applySandboxMode();}}}/**
12877
+ let tmpPlaygroundView=this.pict.views['Docuserve-Fable-Playground'];if(tmpPlaygroundView&&typeof tmpPlaygroundView._applySandboxMode==='function'){tmpPlaygroundView._applySandboxMode();}});}}/**
12805
12878
  * Navigate to a module's documentation.
12806
12879
  *
12807
12880
  * @param {string} pGroup - The group key
@@ -12841,7 +12914,7 @@ tmpContentView.displayContent(pHTML);},'','',tmpPath);}/**
12841
12914
  */navigateToSearch(pQuery){let tmpSidebarView=this.pict.views['Docuserve-Sidebar'];let tmpSearchView=this.pict.views['Docuserve-Search'];// Update state
12842
12915
  this.pict.AppData.Docuserve.CurrentGroup='';this.pict.AppData.Docuserve.CurrentModule='';this.pict.AppData.Docuserve.CurrentPath='';// Clear module-specific sidebar nav
12843
12916
  tmpSidebarView.clearModuleNav();tmpSidebarView.renderSidebarGroups();// Render the search view with the query
12844
- tmpSearchView.render();tmpSearchView.showSearch(pQuery||'');this._syncPlaygroundVisibility();}}module.exports=DocuserveApplication;module.exports.default_configuration=require('./Pict-Application-Docuserve-Configuration.json');},{"./Docuserve-Brand.js":348,"./Pict-Application-Docuserve-Configuration.json":349,"./providers/Pict-Provider-Docuserve-Demos.js":351,"./providers/Pict-Provider-Docuserve-Documentation.js":352,"./views/PictView-Docuserve-Content.js":353,"./views/PictView-Docuserve-Demo.js":354,"./views/PictView-Docuserve-Fable-Playground.js":355,"./views/PictView-Docuserve-Layout.js":356,"./views/PictView-Docuserve-Search.js":357,"./views/PictView-Docuserve-Sidebar.js":358,"./views/PictView-Docuserve-Splash.js":359,"./views/PictView-Docuserve-TopBar-Nav.js":360,"./views/PictView-Docuserve-TopBar-User.js":361,"pict-application":141,"pict-section-modal":170,"pict-section-theme":171}],351:[function(require,module,exports){const libPictProvider=require('pict-provider');/**
12917
+ tmpSearchView.render();tmpSearchView.showSearch(pQuery||'');this._syncPlaygroundVisibility();}}module.exports=DocuserveApplication;module.exports.default_configuration=require('./Pict-Application-Docuserve-Configuration.json');},{"./Docuserve-Brand.js":348,"./Pict-Application-Docuserve-Configuration.json":349,"./providers/Pict-Provider-Docuserve-Demos.js":351,"./providers/Pict-Provider-Docuserve-Documentation.js":352,"./views/PictView-Docuserve-Content.js":353,"./views/PictView-Docuserve-Demo.js":354,"./views/PictView-Docuserve-Fable-Playground.js":355,"./views/PictView-Docuserve-Layout.js":356,"./views/PictView-Docuserve-Search.js":357,"./views/PictView-Docuserve-Section-Playground.js":358,"./views/PictView-Docuserve-Sidebar.js":359,"./views/PictView-Docuserve-Splash.js":360,"./views/PictView-Docuserve-TopBar-Nav.js":361,"./views/PictView-Docuserve-TopBar-User.js":362,"pict-application":141,"pict-section-modal":170,"pict-section-theme":171}],351:[function(require,module,exports){const libPictProvider=require('pict-provider');/**
12845
12918
  * Highest demo-entry schema version this provider understands.
12846
12919
  *
12847
12920
  * Each demo entry declares `DemoSchemaVersion` (defaults to 1 when
@@ -13317,23 +13390,33 @@ for(let i=0;i<this._Catalog.Groups.length;i++){let tmpGroup=this._Catalog.Groups
13317
13390
  * @param {string} pModule - The module name
13318
13391
  * @returns {Array|null} The sidebar entries or null
13319
13392
  */getModuleSidebar(pGroup,pModule){if(!this._Catalog){return null;}for(let i=0;i<this._Catalog.Groups.length;i++){let tmpGroup=this._Catalog.Groups[i];if(tmpGroup.Key!==pGroup){continue;}for(let j=0;j<tmpGroup.Modules.length;j++){let tmpModule=tmpGroup.Modules[j];if(tmpModule.Name!==pModule){continue;}return tmpModule.Sidebar||null;}}return null;}/**
13320
- * Decide whether the playground panel should be enabled for the
13321
- * given group/module.
13322
- *
13323
- * Opt-in signal: a module's `_sidebar.md` (baked into the catalog as
13324
- * `module.Sidebar`) contains an entry whose Path matches
13325
- * `playground.md` (case-insensitive, anywhere in the tree). When the
13326
- * sidebar contains that entry, code blocks in the module's docs get
13327
- * the "Try in Playground" button and the bottom drawer/tab strip
13328
- * becomes visible; otherwise the drawer is suppressed entirely.
13329
- *
13330
- * Falls back to the root SidebarGroups (standalone mode — docuserve
13331
- * serving a single module's docs directly without a catalog).
13393
+ * Decide whether the **Fable bottom-drawer** playground panel should
13394
+ * be enabled for the given group/module.
13395
+ *
13396
+ * Resolution order:
13397
+ * 1. If `_playground.json` is cached AND its `Kind` is `"section"`,
13398
+ * return false. Section-playground modules use the full-page
13399
+ * `#/playground/section` route and explicitly do NOT want the
13400
+ * Fable JS REPL drawer popping up on every doc page.
13401
+ * 2. Otherwise the opt-in signal is a `playground.md` entry in the
13402
+ * module's sidebar (catalog mode) or the root SidebarGroups
13403
+ * (standalone mode). Presence of that entry drawer + tab
13404
+ * strip + "Try in Playground" buttons on code blocks.
13405
+ *
13406
+ * The cache is populated by `loadPlaygroundConfig()` (called on each
13407
+ * navigation by `_syncPlaygroundVisibility`). On the first visit to
13408
+ * a module, the cache may not yet be populated — this method
13409
+ * conservatively falls through to the sidebar check, and the caller
13410
+ * re-invokes once the async config load resolves.
13332
13411
  *
13333
13412
  * @param {string} [pGroup] - Current group key (may be empty)
13334
13413
  * @param {string} [pModule] - Current module name (may be empty)
13335
13414
  * @returns {boolean}
13336
- */isPlaygroundEnabled(pGroup,pModule){// Per-module sidebar (catalog mode).
13415
+ */isPlaygroundEnabled(pGroup,pModule){// Check the _playground.json cache for an explicit Kind: 'section'
13416
+ // declaration — that module uses the full-page playground and
13417
+ // the Fable drawer must stay out of its way on every doc page,
13418
+ // not just on the playground route itself.
13419
+ let tmpCacheKey=(pGroup||'')+'/'+(pModule||'');if(Object.prototype.hasOwnProperty.call(this._PlaygroundConfigCache,tmpCacheKey)){let tmpConfig=this._PlaygroundConfigCache[tmpCacheKey];if(tmpConfig&&tmpConfig.Kind==='section'){return false;}}// Per-module sidebar (catalog mode).
13337
13420
  if(pGroup&&pModule){let tmpSidebar=this.getModuleSidebar(pGroup,pModule);if(Array.isArray(tmpSidebar)&&this._sidebarEntriesIncludePlayground(tmpSidebar)){return true;}}// Root sidebar (standalone-mode fallback) — checks both group-level
13338
13421
  // Route entries and per-module Route entries for a playground link.
13339
13422
  let tmpGroups=this.pict.AppData.Docuserve.SidebarGroups;if(Array.isArray(tmpGroups)&&this._sidebarGroupsIncludePlayground(tmpGroups)){return true;}return false;}/**
@@ -13891,7 +13974,274 @@ let tmpContentContainer=document.getElementById('Docuserve-Content-Container');i
13891
13974
  */performSearch(pQuery){let tmpDocuserve=this.pict.AppData.Docuserve;if(!pQuery||!pQuery.trim()){this._setIdleStatus(pQuery);tmpDocuserve.SearchResults=[];this._renderResultsRegion();this._renderStatusRegion();return;}let tmpDocProvider=this.pict.providers['Docuserve-Documentation'];let tmpResults=tmpDocProvider.search(pQuery);if(tmpResults.length===0){tmpDocuserve.SearchResults=[];tmpDocuserve.SearchStatus='No results found for \''+this._escapeHTML(pQuery)+'\'.';this._renderResultsRegion();this._renderStatusRegion();return;}let tmpRecords=[];for(let i=0;i<tmpResults.length;i++){let tmpResult=tmpResults[i];tmpRecords.push({Title:tmpResult.Title,Route:tmpResult.Route,Group:tmpResult.Group||'',Module:tmpResult.Module||'',BreadcrumbSlot:tmpResult.Group&&tmpResult.Module?[{Group:tmpResult.Group,Module:tmpResult.Module}]:[],PathSlot:tmpResult.DocPath?[{DocPath:tmpResult.DocPath}]:[],DocPath:tmpResult.DocPath||''});}tmpDocuserve.SearchResults=tmpRecords;tmpDocuserve.SearchStatus=tmpResults.length+' result'+(tmpResults.length!==1?'s':'')+' for \''+this._escapeHTML(pQuery)+'\'';this._renderResultsRegion();this._renderStatusRegion();}// ─────────────────────────────────────────────
13892
13975
  // Private helpers
13893
13976
  // ─────────────────────────────────────────────
13894
- _setIdleStatus(pQuery){let tmpDocCount=this.pict.AppData.Docuserve.KeywordDocumentCount||0;this.pict.AppData.Docuserve.SearchStatus=tmpDocCount>0?'Search across '+tmpDocCount+' documents.':'Enter a search term to find documentation.';}_renderResultsRegion(){let tmpHTML=this.pict.parseTemplateByHash('Docuserve-Search-ResultsBody-Template',{});this.pict.ContentAssignment.assignContent('#Docuserve-Search-Results',tmpHTML);}_renderStatusRegion(){this.pict.ContentAssignment.assignContent('#Docuserve-Search-Status',this.pict.AppData.Docuserve.SearchStatus||'');}_escapeHTML(pText){if(!pText){return'';}return String(pText).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;').replace(/'/g,'&#39;');}}module.exports=DocuserveSearchView;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":231}],358:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"Docuserve-Sidebar",DefaultRenderable:"Docuserve-Sidebar-Content",DefaultDestinationAddress:"#Docuserve-Sidebar-Container",AutoRender:false,CSS:/*css*/"\n\t\t.docuserve-sidebar {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tbackground: var(--theme-color-background-secondary, #FAF7F1);\n\t\t\tborder-right: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tpadding: 1em 0;\n\t\t\tpadding-top: 0;\n\t\t\tmin-height: 100%;\n\t\t\tposition: relative;\n\t\t\ttransition: background-color 0.15s ease;\n\t\t}\n\t\t.docuserve-sidebar-header {\n\t\t\tdisplay: none;\n\t\t\tjustify-content: flex-end;\n\t\t\tpadding: 0.4em 0.5em 0;\n\t\t}\n\t\t/* The \"X\" close button is only useful when the sidebar is acting\n\t\t as a responsive drawer (narrow viewports where the panel slid\n\t\t in over the content area). In docked desktop mode the\n\t\t pict-section-modal collapse tab on the panel's outer edge is\n\t\t the canonical collapse affordance \u2014 a second X inside the\n\t\t panel competes with it and looks messy. Show the X only in\n\t\t drawer mode. */\n\t\t.pict-modal-shell-panel-drawer .docuserve-sidebar-header {\n\t\t\tdisplay: flex;\n\t\t}\n\t\t.docuserve-sidebar-close {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tbackground: none;\n\t\t\tborder: none;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tfont-size: 1.1em;\n\t\t\tcursor: pointer;\n\t\t\tpadding: 0.2em 0.4em;\n\t\t\tline-height: 1;\n\t\t}\n\t\t.docuserve-sidebar-close:hover {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-search {\n\t\t\tpadding: 0 1em 1em 1em;\n\t\t\tborder-bottom: 1px solid var(--theme-color-border-light, #E5DED1);\n\t\t\tmargin-bottom: 0.5em;\n\t\t}\n\t\t.docuserve-sidebar-search input {\n\t\t\twidth: 100%;\n\t\t\tpadding: 0.5em 0.75em;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tcolor: var(--theme-color-text-primary, #2A241E);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tborder-radius: 4px;\n\t\t\tfont-size: 0.85em;\n\t\t\toutline: none;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\t\t.docuserve-sidebar-search input:focus {\n\t\t\tborder-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-search-results {\n\t\t\tmargin-top: 0.5em;\n\t\t}\n\t\t.docuserve-sidebar-search-results a {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.4em 0.5em;\n\t\t\tcolor: var(--theme-color-text-primary, #423D37);\n\t\t\ttext-decoration: none;\n\t\t\tfont-size: 0.82em;\n\t\t\tborder-radius: 3px;\n\t\t\ttransition: background-color 0.1s;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.docuserve-sidebar-search-results a:hover {\n\t\t\tbackground-color: var(--theme-color-background-hover, #EAE3D8);\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-search-result-title {\n\t\t\tfont-weight: 600;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t}\n\t\t.docuserve-sidebar-search-results a:hover .docuserve-sidebar-search-result-title {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-search-result-meta {\n\t\t\tfont-size: 0.9em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t}\n\t\t.docuserve-sidebar-search-all {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.4em 0.5em;\n\t\t\tfont-size: 0.82em;\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\ttext-decoration: none;\n\t\t\tfont-weight: 600;\n\t\t\tcursor: pointer;\n\t\t\tborder-top: 1px solid var(--theme-color-border-light, #E5DED1);\n\t\t\tmargin-top: 0.25em;\n\t\t\tpadding-top: 0.5em;\n\t\t}\n\t\t.docuserve-sidebar-search-all:hover {\n\t\t\ttext-decoration: underline;\n\t\t}\n\t\t.docuserve-sidebar-search-empty {\n\t\t\tpadding: 0.4em 0.5em;\n\t\t\tfont-size: 0.82em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t}\n\t\t.docuserve-sidebar-home {\n\t\t\tpadding: 0.5em 1.25em;\n\t\t\tfont-weight: 600;\n\t\t\tfont-size: 0.85em;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.03em;\n\t\t}\n\t\t.docuserve-sidebar-home a {\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\ttext-decoration: none;\n\t\t\tcursor: pointer;\n\t\t\tuser-select: none;\n\t\t}\n\t\t.docuserve-sidebar-home a:hover {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-group {\n\t\t\tmargin-top: 0.25em;\n\t\t}\n\t\t.docuserve-sidebar-group-title {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.5em 1.25em;\n\t\t\tfont-weight: 600;\n\t\t\tfont-size: 0.85em;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\ttext-decoration: none;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.03em;\n\t\t\tcursor: pointer;\n\t\t\tuser-select: none;\n\t\t\ttransition: background-color 0.1s, color 0.1s;\n\t\t}\n\t\t.docuserve-sidebar-group-title:hover {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tbackground-color: var(--theme-color-background-hover, #EAE3D8);\n\t\t}\n\t\ta.docuserve-sidebar-group-title.active {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tbackground-color: var(--theme-color-background-tertiary, #E5DED1);\n\t\t}\n\t\t.docuserve-sidebar-modules {\n\t\t\tlist-style: none;\n\t\t\tmargin: 0;\n\t\t\tpadding: 0;\n\t\t}\n\t\t.docuserve-sidebar-modules li {\n\t\t\tpadding: 0;\n\t\t}\n\t\t.docuserve-sidebar-modules a {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.3em 1.25em 0.3em 2em;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\ttext-decoration: none;\n\t\t\tfont-size: 0.85em;\n\t\t\ttransition: background-color 0.1s, color 0.1s;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.docuserve-sidebar-modules a:hover {\n\t\t\tbackground-color: var(--theme-color-background-hover, #EAE3D8);\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-modules a.active {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tfont-weight: 600;\n\t\t\tbackground-color: var(--theme-color-background-tertiary, #E5DED1);\n\t\t}\n\t\t.docuserve-sidebar-modules .no-docs {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.3em 1.25em 0.3em 2em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tfont-size: 0.85em;\n\t\t}\n\t\t.docuserve-sidebar-module-nav {\n\t\t\tborder-top: 1px solid var(--theme-color-border-light, #E5DED1);\n\t\t\tmargin-top: 0.5em;\n\t\t\tpadding-top: 0.5em;\n\t\t}\n\t\t.docuserve-sidebar-module-nav:empty {\n\t\t\tdisplay: none;\n\t\t}\n\t\t.docuserve-sidebar-module-nav-section {\n\t\t\tpadding: 0.4em 1.25em;\n\t\t\tfont-weight: 600;\n\t\t\tfont-size: 0.8em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.02em;\n\t\t}\n\t\t.docuserve-sidebar-module-nav a {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.25em 1.25em 0.25em 2.25em;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\ttext-decoration: none;\n\t\t\tfont-size: 0.82em;\n\t\t\ttransition: background-color 0.1s, color 0.1s;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.docuserve-sidebar-module-nav a:hover {\n\t\t\tbackground-color: var(--theme-color-background-hover, #EAE3D8);\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-module-nav a.active {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tfont-weight: 600;\n\t\t\tbackground-color: var(--theme-color-background-tertiary, #E5DED1);\n\t\t}\n\t\t.docuserve-sidebar-footer {\n\t\t\tmargin-top: auto;\n\t\t\tpadding: 0.9em 1.25em 1em 1.25em;\n\t\t\tborder-top: 1px solid var(--theme-color-border-light, #E5DED1);\n\t\t}\n\t\t.docuserve-sidebar-footer:empty {\n\t\t\tdisplay: none;\n\t\t}\n\t\t.docuserve-version-placard {\n\t\t\tfont-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n\t\t\tline-height: 1.35;\n\t\t}\n\t\t.docuserve-version-name {\n\t\t\tfont-size: 0.78em;\n\t\t\tfont-weight: 600;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tletter-spacing: 0.02em;\n\t\t}\n\t\t.docuserve-version-number {\n\t\t\tfont-size: 0.82em;\n\t\t\tfont-weight: 500;\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-version-meta {\n\t\t\tfont-size: 0.7em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tmargin-top: 0.15em;\n\t\t}\n\t",Templates:[{Hash:"Docuserve-Sidebar-Template",Template:/*html*/"\n<div class=\"docuserve-sidebar\">\n\t<div class=\"docuserve-sidebar-header\">\n\t\t<button class=\"docuserve-sidebar-close\" onclick=\"{~P~}.views['Docuserve-Sidebar'].toggleSidebar()\" aria-label=\"Close sidebar\">{~I:Close~}</button>\n\t</div>\n\t{~TS:Docuserve-Sidebar-Search-Slot-Template:AppData.Docuserve.SidebarSearchSlot~}\n\t<div class=\"docuserve-sidebar-home\">\n\t\t<a onclick=\"{~P~}.PictApplication.navigateTo('/Home')\">Home</a>\n\t</div>\n\t<div id=\"Docuserve-Sidebar-Groups\">\n\t\t{~TS:Docuserve-Sidebar-Group-Template:AppData.Docuserve.SidebarGroupRecords~}\n\t</div>\n\t<div id=\"Docuserve-Sidebar-ModuleNav\" class=\"docuserve-sidebar-module-nav\">\n\t\t{~TS:Docuserve-Sidebar-ModuleNav-Section-Template:AppData.Docuserve.ModuleNavSections~}\n\t</div>\n\t<div class=\"docuserve-sidebar-footer\">\n\t\t{~TS:Docuserve-Sidebar-Footer-Template:AppData.Docuserve.FooterSlot~}\n\t</div>\n</div>\n"},{Hash:"Docuserve-Sidebar-Search-Slot-Template",Template:/*html*/"<div id=\"Docuserve-Sidebar-Search\" class=\"docuserve-sidebar-search\">\n\t<input type=\"text\" placeholder=\"Search docs...\" id=\"Docuserve-Sidebar-Search-Input\" oninput=\"{~P~}.views['Docuserve-Sidebar'].onSidebarSearchInput(this.value)\">\n\t<div id=\"Docuserve-Sidebar-Search-Results\" class=\"docuserve-sidebar-search-results\"></div>\n</div>"},{Hash:"Docuserve-Sidebar-Group-Template",Template:/*html*/"<div class=\"docuserve-sidebar-group\">\n\t{~TS:Docuserve-Sidebar-Group-Title-Link-Template:Record.TitleLink~}{~TS:Docuserve-Sidebar-Group-Title-Plain-Template:Record.TitlePlain~}\n\t<ul class=\"docuserve-sidebar-modules\">\n\t\t{~TS:Docuserve-Sidebar-Module-Doc-Template:Record.Modules~}\n\t</ul>\n</div>"},{Hash:"Docuserve-Sidebar-Group-Title-Link-Template",Template:/*html*/"<a class=\"docuserve-sidebar-group-title{~D:Record.ActiveClass~}\" href=\"{~D:Record.Route~}\">{~D:Record.Name~}</a>"},{Hash:"Docuserve-Sidebar-Group-Title-Plain-Template",Template:/*html*/"<div class=\"docuserve-sidebar-group-title\">{~D:Record.Name~}</div>"},{Hash:"Docuserve-Sidebar-Module-Doc-Template",Template:/*html*/"<li>{~TS:Docuserve-Sidebar-Module-Link-Template:Record.LinkSlot~}{~TS:Docuserve-Sidebar-Module-NoDoc-Template:Record.NoDocSlot~}</li>"},{Hash:"Docuserve-Sidebar-Module-Link-Template",Template:/*html*/"<a class=\"{~D:Record.ActiveClass~}\" href=\"{~D:Record.Route~}\">{~D:Record.Name~}</a>"},{Hash:"Docuserve-Sidebar-Module-NoDoc-Template",Template:/*html*/"<span class=\"no-docs\">{~D:Record.Name~}</span>"},{Hash:"Docuserve-Sidebar-ModuleNav-Section-Template",Template:/*html*/"{~TS:Docuserve-Sidebar-ModuleNav-SectionTitle-Template:Record.TitleSlot~}{~TS:Docuserve-Sidebar-ModuleNav-Item-Template:Record.Items~}"},{Hash:"Docuserve-Sidebar-ModuleNav-SectionTitle-Template",Template:/*html*/"<div class=\"docuserve-sidebar-module-nav-section\">{~D:Record.Title~}</div>"},{Hash:"Docuserve-Sidebar-ModuleNav-Item-Template",Template:/*html*/"<a class=\"{~D:Record.ActiveClass~}\" href=\"{~D:Record.Route~}\">{~D:Record.Title~}</a>"},{Hash:"Docuserve-Sidebar-Footer-Template",Template:/*html*/"<div class=\"docuserve-version-placard\">\n\t{~TS:Docuserve-Sidebar-Footer-Name-Template:Record.NameSlot~}\n\t<div class=\"docuserve-version-number\">v{~D:Record.Version~}</div>\n\t{~TS:Docuserve-Sidebar-Footer-Meta-Template:Record.MetaSlot~}\n</div>"},{Hash:"Docuserve-Sidebar-Footer-Name-Template",Template:/*html*/"<div class=\"docuserve-version-name\">{~D:Record.Name~}</div>"},{Hash:"Docuserve-Sidebar-Footer-Meta-Template",Template:/*html*/"<div class=\"docuserve-version-meta\">{~D:Record.Meta~}</div>"},{Hash:"Docuserve-Sidebar-Search-ResultsBody-Template",Template:/*html*/"{~TS:Docuserve-Sidebar-Search-Result-Template:AppData.Docuserve.SidebarSearchResults~}{~TS:Docuserve-Sidebar-Search-Overflow-Template:AppData.Docuserve.SidebarSearchOverflow~}{~TS:Docuserve-Sidebar-Search-Empty-Template:AppData.Docuserve.SidebarSearchEmpty~}"},{Hash:"Docuserve-Sidebar-Search-Result-Template",Template:/*html*/"<a href=\"{~D:Record.Route~}\">\n\t<div class=\"docuserve-sidebar-search-result-title\">{~D:Record.Title~}</div>\n\t{~TS:Docuserve-Sidebar-Search-Result-Meta-Template:Record.MetaSlot~}\n</a>"},{Hash:"Docuserve-Sidebar-Search-Result-Meta-Template",Template:/*html*/"<div class=\"docuserve-sidebar-search-result-meta\">{~D:Record.Meta~}</div>"},{Hash:"Docuserve-Sidebar-Search-Overflow-Template",Template:/*html*/"<a class=\"docuserve-sidebar-search-all\" href=\"#/search/{~D:Record.EncodedQuery~}\">See all {~D:Record.TotalCount~} results</a>"},{Hash:"Docuserve-Sidebar-Search-Empty-Template",Template:/*html*/"<div class=\"docuserve-sidebar-search-empty\">No results found.</div>"}],Renderables:[{RenderableHash:"Docuserve-Sidebar-Content",TemplateHash:"Docuserve-Sidebar-Template",DestinationAddress:"#Docuserve-Sidebar-Container",RenderMethod:"replace"}]};class DocusserveSidebarView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this._SidebarSearchDebounceTimer=null;}onBeforeRender(pRenderable){// Derive every template-iteration record from raw AppData state.
13977
+ _setIdleStatus(pQuery){let tmpDocCount=this.pict.AppData.Docuserve.KeywordDocumentCount||0;this.pict.AppData.Docuserve.SearchStatus=tmpDocCount>0?'Search across '+tmpDocCount+' documents.':'Enter a search term to find documentation.';}_renderResultsRegion(){let tmpHTML=this.pict.parseTemplateByHash('Docuserve-Search-ResultsBody-Template',{});this.pict.ContentAssignment.assignContent('#Docuserve-Search-Results',tmpHTML);}_renderStatusRegion(){this.pict.ContentAssignment.assignContent('#Docuserve-Search-Status',this.pict.AppData.Docuserve.SearchStatus||'');}_escapeHTML(pText){if(!pText){return'';}return String(pText).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;').replace(/'/g,'&#39;');}}module.exports=DocuserveSearchView;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":231}],358:[function(require,module,exports){const libPictView=require('pict-view');const libPictSectionCode=require('pict-section-code');// CodeJar (used by pict-section-code) ships as an ES module. Browserify
13978
+ // can't `require()` it, so we lazy-load from jsDelivr via dynamic import
13979
+ // the same way Pict-Docuserve's Fable playground does, then hand the
13980
+ // constructor to each editor via connectCodeJarPrototype().
13981
+ const _CodeJarCDN='https://cdn.jsdelivr.net/npm/codejar@4.2.0/dist/codejar.min.js';/**
13982
+ * Docuserve-Section-Playground — a multi-editor + iframe sandbox for
13983
+ * trying section configurations (manifests, app configs, AppData, ...)
13984
+ * against any pict-section-* UI library and seeing the result live.
13985
+ *
13986
+ * ┌─────────────────────────────────────────────────────────────────┐
13987
+ * │ [Manifest] [Pict] [App] [AppData] [▶ Run] [⤴ Reset] │ toolbar
13988
+ * ├─────────────────────────────────────────────────────────────────┤
13989
+ * │ │
13990
+ * │ pict-section-code editor for the active tab │
13991
+ * │ (one per tab; the others are display:none'd, not torn down) │
13992
+ * │ │
13993
+ * ├══════════════════ resize handle ════════════════════════════════│
13994
+ * │ │
13995
+ * │ <iframe srcdoc=...> │
13996
+ * │ loads pict + the section's UMD + a theme picker, │
13997
+ * │ bootstraps an application from the user's edited configs, │
13998
+ * │ renders the section. Theme switching is fully scoped to │
13999
+ * │ the iframe. │
14000
+ * │ │
14001
+ * └─────────────────────────────────────────────────────────────────┘
14002
+ *
14003
+ * The playground is configured per-module via `docs/_playground.json`
14004
+ * with `Kind: "section"`. Each entry in the `Editors` array declares
14005
+ * one tab (Hash, Label, Language, optional DefaultPath pointing at a
14006
+ * starter JSON file under docs/playground/).
14007
+ *
14008
+ * On Run, the view:
14009
+ * 1. Pulls the latest text from each editor's CodeDataAddress.
14010
+ * 2. Validates JSON / JS as appropriate (errors surface in a toast
14011
+ * and the Run is short-circuited so the iframe doesn't blank out
14012
+ * on a typo).
14013
+ * 3. Builds the iframe srcdoc from the configured BootstrapTemplate
14014
+ * with the verbatim configs inlined as JSON literals.
14015
+ * 4. Replaces the iframe's srcdoc. Each Run is a clean slate —
14016
+ * no in-place state to invalidate.
14017
+ *
14018
+ * Edits are persisted to localStorage scoped to `<group>/<module>` so
14019
+ * the user's session survives reloads and route navigations.
14020
+ */// AppData root for the playground state. Per-module: each module's
14021
+ // playground reuses the same address (the view re-mounts on every
14022
+ // navigation, so there's only one live instance at a time).
14023
+ const _AppDataRoot='AppData.Docuserve.SectionPlayground';const _ContentDestinationId='Docuserve-Section-Playground-Container';// Persistence key prefix — final key is
14024
+ // `docuserve-section-playground:<group>/<module>:<editorHash>`.
14025
+ const _LocalStorageKeyPrefix='docuserve-section-playground';const _ViewConfiguration={ViewIdentifier:"Docuserve-Section-Playground",DefaultRenderable:"Docuserve-Section-Playground-Content",DefaultDestinationAddress:'#Docuserve-Content-Container',AutoRender:false,CSS:/*css*/"\n\t\t/* The content container is provisioned by the layout shell as\n\t\t flex: 1 1 auto with min-height: 0. Promote it to a flex\n\t\t column so the playground inside can use flex: 1 to fill. */\n\t\t#Docuserve-Content-Container.docuserve-section-playground-host {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tpadding: 0;\n\t\t}\n\t\t.docuserve-section-playground {\n\t\t\tflex: 1 1 0;\n\t\t\tmin-height: 0;\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tcolor: var(--theme-color-text-primary, #2A241E);\n\t\t\tbackground: var(--theme-color-background-primary, #FDFBF7);\n\t\t}\n\n\t\t/* Toolbar \u2014 tabs on the left, action buttons on the right. */\n\t\t.docuserve-section-playground-toolbar {\n\t\t\tflex: 0 0 auto;\n\t\t\tdisplay: flex;\n\t\t\talign-items: stretch;\n\t\t\tjustify-content: space-between;\n\t\t\tgap: 0.5em;\n\t\t\tpadding: 0 0.5em;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tborder-bottom: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t}\n\t\t.docuserve-section-playground-tabs {\n\t\t\tdisplay: flex;\n\t\t\tgap: 0;\n\t\t}\n\t\t.docuserve-section-playground-tab {\n\t\t\tpadding: 0.55em 0.95em;\n\t\t\tfont-size: 0.85em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tbackground: transparent;\n\t\t\tborder: 0;\n\t\t\tborder-bottom: 2px solid transparent;\n\t\t\tcursor: pointer;\n\t\t\ttransition: color 0.12s, border-color 0.12s, background-color 0.12s;\n\t\t}\n\t\t.docuserve-section-playground-tab:hover {\n\t\t\tcolor: var(--theme-color-text-primary, #2A241E);\n\t\t\tbackground: var(--theme-color-background-hover, #EAE3D8);\n\t\t}\n\t\t.docuserve-section-playground-tab.active {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tborder-bottom-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tfont-weight: 600;\n\t\t}\n\t\t.docuserve-section-playground-tab-dirty::after {\n\t\t\tcontent: '*';\n\t\t\tmargin-left: 0.25em;\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-section-playground-actions {\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.25em;\n\t\t\tpadding: 0.25em 0;\n\t\t}\n\n\t\t/* Icon button \u2014 same visual language as the Fable playground for\n\t\t continuity. Run is brighter to draw the eye. */\n\t\t.docuserve-section-playground-iconbtn {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.35em;\n\t\t\tpadding: 0.35em 0.7em;\n\t\t\tfont-size: 0.82em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tbackground: transparent;\n\t\t\tborder: 1px solid transparent;\n\t\t\tborder-radius: 4px;\n\t\t\tcursor: pointer;\n\t\t\ttransition: color 0.12s, background-color 0.12s, border-color 0.12s, opacity 0.12s;\n\t\t\topacity: 0.75;\n\t\t}\n\t\t.docuserve-section-playground-iconbtn:hover {\n\t\t\topacity: 1;\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tbackground: var(--theme-color-background-hover, #EAE3D8);\n\t\t\tborder-color: var(--theme-color-border-default, #DDD6CA);\n\t\t}\n\t\t.docuserve-section-playground-iconbtn svg {\n\t\t\twidth: 1em;\n\t\t\theight: 1em;\n\t\t\tdisplay: block;\n\t\t}\n\t\t.docuserve-section-playground-iconbtn-run {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\topacity: 0.9;\n\t\t}\n\t\t.docuserve-section-playground-iconbtn-run:hover {\n\t\t\tbackground: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tcolor: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tborder-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t\topacity: 1;\n\t\t}\n\t\t.docuserve-section-playground-iconbtn-run svg { fill: currentColor; stroke: none; }\n\n\t\t/* Body \u2014 pict-section-modal shell with the editor stack in the\n\t\t center and the iframe sandbox as a resizable + collapsible\n\t\t bottom panel. Layout, drag-to-resize, collapse-tab, and\n\t\t persistence are all owned by the shell; this view just hosts\n\t\t it inside the playground's content area. */\n\t\t.docuserve-section-playground-shell-mount {\n\t\t\tflex: 1 1 0;\n\t\t\tmin-height: 0;\n\t\t\tposition: relative;\n\t\t}\n\t\t.docuserve-section-playground-shell-mount .pict-modal-shell-host { height: 100%; }\n\n\t\t/* Editor stack (the shell's center). The tab-slot divs are\n\t\t stacked; only the active one is display:flex. pict-section-code\n\t\t itself draws the editor surface. */\n\t\t.docuserve-section-playground-editor-mount {\n\t\t\theight: 100%;\n\t\t\tmin-height: 0;\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t}\n\t\t.docuserve-section-playground-editor {\n\t\t\tflex: 1 1 0;\n\t\t\tmin-height: 0;\n\t\t\tdisplay: none;\n\t\t}\n\t\t.docuserve-section-playground-editor.active {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t}\n\t\t.docuserve-section-playground-editor > * {\n\t\t\tflex: 1 1 0;\n\t\t\tmin-height: 0;\n\t\t}\n\n\t\t/* Iframe pane \u2014 the rendered section + its theme switcher.\n\t\t Lives inside the shell's bottom panel; the panel owns its\n\t\t own border + sizing chrome. */\n\t\t.docuserve-section-playground-iframe-pane {\n\t\t\theight: 100%;\n\t\t\tmin-height: 0;\n\t\t\tposition: relative;\n\t\t\tbackground: var(--theme-color-background-secondary, #F6F3EE);\n\t\t}\n\t\t.docuserve-section-playground-iframe {\n\t\t\twidth: 100%;\n\t\t\theight: 100%;\n\t\t\tborder: 0;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t}\n\t\t.docuserve-section-playground-status {\n\t\t\tposition: absolute;\n\t\t\ttop: 0.5em;\n\t\t\tright: 0.7em;\n\t\t\tfont-size: 0.7em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tpadding: 0.15em 0.5em;\n\t\t\tborder-radius: 4px;\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tpointer-events: none;\n\t\t\topacity: 0;\n\t\t\ttransition: opacity 0.2s;\n\t\t}\n\t\t.docuserve-section-playground-status.show { opacity: 0.85; }\n\t\t.docuserve-section-playground-status.error {\n\t\t\tcolor: var(--theme-color-status-error, #B43A2E);\n\t\t\tborder-color: var(--theme-color-status-error, #B43A2E);\n\t\t}\n\n\t\t/* Empty state for the iframe pane before the first Run. */\n\t\t.docuserve-section-playground-emptystate {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\theight: 100%;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tfont-size: 0.9em;\n\t\t\ttext-align: center;\n\t\t\tpadding: 2em;\n\t\t}\n\t\t.docuserve-section-playground-emptystate-title {\n\t\t\tfont-size: 1.1em;\n\t\t\tfont-weight: 600;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tmargin-bottom: 0.4em;\n\t\t}\n\n\t\t/* Wider middle-positioned collapse tab on the sandbox panel \u2014\n\t\t replaces the stock 28\xD76 right-anchored sliver with a labelled\n\t\t \"Sandbox\" pill centered above the panel's top edge. The pill\n\t\t is wide enough to read at a glance and lives at the boundary\n\t\t between editor and sandbox so the user's eye finds it\n\t\t immediately. */\n\t\t.docuserve-section-playground-shell-mount .pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab\n\t\t{\n\t\t\t/* Geometry: wide pill positioned fully ABOVE the panel's\n\t\t\t top edge (matches the section-modal default of \"tab\n\t\t\t entirely outside the panel\"; top = -height places the\n\t\t\t tab's bottom edge flush against the panel boundary). */\n\t\t\twidth: 160px;\n\t\t\theight: 18px;\n\t\t\tleft: 50%;\n\t\t\tright: auto;\n\t\t\ttop: -18px;\n\t\t\tmargin-left: -80px;\n\t\t\tborder-radius: 5px 5px 0 0;\n\t\t\tborder-bottom: 0;\n\t\t\t/* Visual: always readable, not just on hover. */\n\t\t\topacity: 0.95;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tbackground: var(--theme-color-background-secondary, #F6F3EE);\n\t\t\tborder-color: var(--theme-color-border-default, #DDD6CA);\n\t\t\tpadding: 0 10px;\n\t\t\tgap: 6px;\n\t\t\tline-height: 16px;\n\t\t\tfont-size: 10px;\n\t\t\tfont-weight: 600;\n\t\t\tletter-spacing: 0.08em;\n\t\t\ttext-transform: uppercase;\n\t\t}\n\t\t/* Title text always visible (the stock CSS only shows it when\n\t\t collapsed); the chevron pseudo is hidden \u2014 the label carries\n\t\t the affordance. */\n\t\t.docuserve-section-playground-shell-mount .pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab .pict-modal-shell-panel-collapse-tab-title\n\t\t{\n\t\t\tdisplay: inline;\n\t\t}\n\t\t.docuserve-section-playground-shell-mount .pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab::before\n\t\t{\n\t\t\tdisplay: none;\n\t\t}\n\t\t/* Keep the size stable on hover (stock CSS grows it to 36\xD718) \u2014\n\t\t only color shifts so the user knows it's interactive. */\n\t\t.docuserve-section-playground-shell-mount .pict-modal-shell-panel-bottom:hover > .pict-modal-shell-panel-collapse-tab,\n\t\t.docuserve-section-playground-shell-mount .pict-modal-shell-panel-bottom > .pict-modal-shell-panel-collapse-tab:hover\n\t\t{\n\t\t\twidth: 160px;\n\t\t\theight: 18px;\n\t\t\ttop: -18px;\n\t\t\tmargin-left: -80px;\n\t\t\topacity: 1;\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tborder-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t",CSSPriority:500,Templates:[{Hash:"Docuserve-Section-Playground-Template",Template:/*html*/"\n<div class=\"docuserve-section-playground\">\n\t<div class=\"docuserve-section-playground-toolbar\">\n\t\t<div class=\"docuserve-section-playground-tabs\" id=\"Docuserve-Section-Playground-Tabs\">\n\t\t\t{~TS:Docuserve-Section-Playground-Tab-Template:AppData.Docuserve.SectionPlayground.Editors~}\n\t\t</div>\n\t\t<div class=\"docuserve-section-playground-actions\">\n\t\t\t<button type=\"button\" class=\"docuserve-section-playground-iconbtn\"\n\t\t\t\ttitle=\"Reset all editors to their starter content\"\n\t\t\t\tonclick=\"{~P~}.views['Docuserve-Section-Playground'].resetAll()\">\n\t\t\t\t{~I:Refresh~} Reset\n\t\t\t</button>\n\t\t\t<button type=\"button\" class=\"docuserve-section-playground-iconbtn docuserve-section-playground-iconbtn-run\"\n\t\t\t\ttitle=\"Run \u2014 reload the iframe with the current editor contents\"\n\t\t\t\tonclick=\"{~P~}.views['Docuserve-Section-Playground'].run()\">\n\t\t\t\t<svg viewBox=\"0 0 24 24\" aria-hidden=\"true\"><polygon points=\"6 4 20 12 6 20\"/></svg>\n\t\t\t\tRun\n\t\t\t</button>\n\t\t</div>\n\t</div>\n\t<!-- pict-section-modal shell mount. _mountAndRender() calls\n\t modal.shell(thisDiv) and addPanel() for the bottom sandbox\n\t panel + center() for the editor stack. The shell builds its\n\t own destination divs (#Section-Playground-Editor-Mount and\n\t #Section-Playground-Iframe-Mount) inside this wrapper. -->\n\t<div class=\"docuserve-section-playground-shell-mount\" id=\"Docuserve-Section-Playground-Shell-Mount\"></div>\n</div>"},{Hash:"Docuserve-Section-Playground-Tab-Template",Template:/*html*/"<button type=\"button\"\n\tclass=\"docuserve-section-playground-tab{~D:Record.ActiveClass~}\"\n\tonclick=\"{~P~}.views['Docuserve-Section-Playground'].selectTab('{~D:Record.Hash~}')\"\n>{~D:Record.Label~}</button>"},{Hash:"Docuserve-Section-Playground-Editor-Slot-Template",Template:/*html*/"<div class=\"docuserve-section-playground-editor{~D:Record.ActiveClass~}\"\n\tid=\"Docuserve-Section-Playground-Editor-{~D:Record.Hash~}\"\n\tdata-editor-hash=\"{~D:Record.Hash~}\"></div>"}],Renderables:[{RenderableHash:"Docuserve-Section-Playground-Content",TemplateHash:"Docuserve-Section-Playground-Template",ContentDestinationAddress:"#Docuserve-Content-Container",RenderMethod:"replace"}]};// ────────────────────────────────────────────────────────────────────────
14026
+ // Iframe srcdoc — the page loaded inside the sandbox iframe.
14027
+ //
14028
+ // Loads the runtime pieces from jsDelivr @1 (so the playground tracks
14029
+ // the same major version as the docs site), wires up an instance of
14030
+ // the configured `SectionType`, mounts a theme picker, and renders.
14031
+ // Configs are inlined as JSON literals at srcdoc build time — no
14032
+ // postMessage required.
14033
+ // ────────────────────────────────────────────────────────────────────────
14034
+ function buildIframeSrcdoc(pConfig,pSpec,pBaseURL){// Defaults if the per-module _playground.json doesn't override.
14035
+ let tmpDefaults={SectionType:'pict-section-form',ApplicationGlobal:'PictFormApplication',ApplicationModule:'PictSectionForm',ManifestKey:'DefaultFormManifest',// WrapperKind controls whether the resolved class is treated as a
14036
+ // PictApplication subclass (default) or as a PictView subclass that
14037
+ // the bootstrap will wrap in a synthesized PictApplication.
14038
+ // - "application": `window[ApplicationModule][ApplicationGlobal]`
14039
+ // already IS the PictApplication. (pict-section-form's pattern.)
14040
+ // - "view": the resolved class is a PictView; the bootstrap
14041
+ // synthesizes a wrapper PictApplication that registers it under
14042
+ // `ViewName` with config from `pictConfig[ViewConfigKey]`. This
14043
+ // is the path most UI-control modules take — they ship a view,
14044
+ // not an application, and don't need to author a wrapper class.
14045
+ WrapperKind:'application',ViewName:'Section-Playground-View',ViewConfigKey:'ViewConfig',// Optional DOM id where the section should mount. When set, the
14046
+ // iframe template includes <div id="<MountID>"></div> next to the
14047
+ // default #Section-Playground-Mount, AND the wrapper-synthesizer's
14048
+ // auto-target uses it instead of #Section-Playground-Mount. Lets
14049
+ // sections whose DefaultDestinationAddress doesn't already match
14050
+ // either the iframe slots or #Section-Playground-Mount declare
14051
+ // their own ID without overriding Renderables by hand.
14052
+ MountID:'',// Optional method on the view to call once after initialization
14053
+ // with seeded data. Use this for sections whose data is loaded
14054
+ // imperatively (e.g. pict-editor-timeline's `loadStoryboard`,
14055
+ // pict-section-equation's `setSolveResult`) rather than via a
14056
+ // `<X>DataAddress` config option. The value at
14057
+ // `BootstrapSeedAddress` (in `pict.AppData`) is the argument.
14058
+ BootstrapMethod:'',BootstrapSeedAddress:'',// Imports — each one is { Name, Source: 'cdn'|'bundled'|'local'|'esm', Version?, Path?, URL?, GlobalName?, ExportName? }.
14059
+ // Loading shapes:
14060
+ // cdn — <script src="https://cdn.jsdelivr.net/npm/<Name>@<Version>/dist/<Name>.min.js"></script>
14061
+ // local — <script src="<Path>"></script>; Path resolves against the docs root
14062
+ // esm — <script type="module">import { <ExportName> } from "<URL>"; window["<GlobalName>"] = <ExportName>;</script>
14063
+ // Use for ES-module-only packages (CodeJar 4.x, etc.) that
14064
+ // can't be loaded via plain <script src>. Bootstrap waits
14065
+ // on `window.<GlobalName>` before running the application.
14066
+ // Order matters: pict first, then anything that depends on it
14067
+ // (pict-application before any wrapper that needs synthesis),
14068
+ // then the section module last.
14069
+ Imports:[],// Stylesheets — each is { Source: 'cdn'|'local', Name?, Version?, Path? }.
14070
+ // Emitted as <link rel="stylesheet"> tags in the iframe head. Used by
14071
+ // sections that wrap external libraries with CSS (Toast UI Grid, KaTeX,
14072
+ // Mermaid pre-styled themes, …) so module authors don't have to inject
14073
+ // <link> tags from Application Code. Local sources are staged by the
14074
+ // `stage-playground` command alongside Imports.
14075
+ Stylesheets:[]};let tmpSpec=Object.assign({},tmpDefaults,pSpec||{});// Default Imports if none provided — minimum needed for a pict-section-form
14076
+ // playground. Most callers will override this in _playground.json.
14077
+ let tmpImports=tmpSpec.Imports&&tmpSpec.Imports.length>0?tmpSpec.Imports:[{Name:'pict',Source:'cdn'},{Name:'pict-application',Source:'cdn'},{Name:'pict-section-form',Source:'cdn'},{Name:'pict-section-modal',Source:'cdn'},{Name:'pict-section-theme',Source:'cdn'}];// Build script + stylesheet tags for every Import / Stylesheet.
14078
+ //
14079
+ // Imports — four sources:
14080
+ // cdn — jsDelivr URL built from Name + Version
14081
+ // local — Path relative to the docs root (resolved via <base href> tag
14082
+ // we emit below, so the iframe's about:srcdoc origin doesn't
14083
+ // break relative paths)
14084
+ // esm — ES-module dynamic import emitted as <script type="module">; the
14085
+ // bootstrap waits on `window[GlobalName]` before running the app.
14086
+ // bundled — legacy alias, treated as cdn for compatibility.
14087
+ //
14088
+ // Stylesheets — same Source values minus 'esm' (CSS has no ESM concept).
14089
+ let tmpScriptTags='';let tmpESMImports=[];for(let i=0;i<tmpImports.length;i++){let tmpImport=tmpImports[i];if(tmpImport.Source==='esm'){// Defer to a single coalesced <script type="module"> at the
14090
+ // bottom so we can wait on all ESM globals before app init.
14091
+ tmpESMImports.push(tmpImport);continue;}let tmpSrc;if(tmpImport.Source==='local'){tmpSrc=tmpImport.Path;}else{let tmpVersion=tmpImport.Version||'1';tmpSrc='https://cdn.jsdelivr.net/npm/'+tmpImport.Name+'@'+tmpVersion+'/dist/'+tmpImport.Name+'.min.js';}tmpScriptTags+='<script src="'+tmpSrc+'"></script>\n';}// Stylesheet <link> tags — emitted into <head> before the script tags so
14092
+ // the section's first paint already has its external styles applied.
14093
+ let tmpStylesheets=Array.isArray(tmpSpec.Stylesheets)?tmpSpec.Stylesheets:[];let tmpLinkTags='';for(let i=0;i<tmpStylesheets.length;i++){let tmpStyle=tmpStylesheets[i];let tmpHref;if(tmpStyle.Source==='local'){tmpHref=tmpStyle.Path;}else{let tmpVersion=tmpStyle.Version||'1';let tmpStylePath=tmpStyle.Path||'dist/'+tmpStyle.Name+'.min.css';tmpHref='https://cdn.jsdelivr.net/npm/'+tmpStyle.Name+'@'+tmpVersion+'/'+tmpStylePath;}tmpLinkTags+='<link rel="stylesheet" href="'+tmpHref+'">\n';}// ESM imports — coalesced into one <script type="module"> that imports
14094
+ // each module, stamps the named export onto window[GlobalName], and
14095
+ // signals readiness via a single flag the bootstrap waits on.
14096
+ let tmpESMScript='';if(tmpESMImports.length>0){tmpESMScript+='<script type="module">\n';tmpESMScript+='window.__SectionPlaygroundESMReady = (async () => {\n';for(let i=0;i<tmpESMImports.length;i++){let tmpESM=tmpESMImports[i];let tmpURL=tmpESM.URL;if(!tmpURL&&tmpESM.Name){let tmpVersion=tmpESM.Version||'1';tmpURL='https://cdn.jsdelivr.net/npm/'+tmpESM.Name+'@'+tmpVersion+'/dist/'+tmpESM.Name+'.min.js';}let tmpExportName=tmpESM.ExportName||tmpESM.GlobalName||tmpESM.Name;let tmpGlobalName=tmpESM.GlobalName||tmpESM.ExportName||tmpESM.Name;tmpESMScript+=' try {\n';tmpESMScript+=' const mod = await import('+JSON.stringify(tmpURL)+');\n';tmpESMScript+=' window['+JSON.stringify(tmpGlobalName)+'] = mod['+JSON.stringify(tmpExportName)+'] || mod.default || mod;\n';tmpESMScript+=' } catch (err) {\n';tmpESMScript+=' console.error("ESM import failed for " + '+JSON.stringify(tmpURL)+', err);\n';tmpESMScript+=' throw err;\n';tmpESMScript+=' }\n';}tmpESMScript+='})();\n';tmpESMScript+='</script>\n';}// Caller passes an absolute base URL so local Imports + asset paths
14097
+ // resolve against the parent's docs root. An about:srcdoc iframe
14098
+ // has no base of its own — without the <base> tag, "playground/runtime/
14099
+ // pict.min.js" 404s as "about:srcdoc/playground/runtime/pict.min.js".
14100
+ let tmpBaseHref=pBaseURL||'';// JSON-encode each user config. We embed them verbatim in a <script>
14101
+ // block so the iframe boots from in-memory literals — no need for the
14102
+ // iframe to call back to the parent.
14103
+ function encode(pValue){// JSON.stringify of undefined → undefined; coerce to empty object.
14104
+ let tmpEncoded=JSON.stringify(pValue===undefined?{}:pValue);// Defang </script> just in case a user pastes one in.
14105
+ return tmpEncoded.replace(/<\/script>/g,'<\\/script>');}let tmpManifestJSON=encode(pConfig.manifest);let tmpPictConfigJSON=encode(pConfig.pictConfig);let tmpAppConfigJSON=encode(pConfig.appConfig);let tmpAppDataJSON=encode(pConfig.appData);// Application Code editor — optional raw JS that runs as the body
14106
+ // of a function `(Base) => class`. Encoded as a JSON string so it
14107
+ // survives the srcdoc round-trip; the iframe wraps it with
14108
+ // `new Function('Base', source)` and expects a class back.
14109
+ let tmpApplicationJS=typeof pConfig.application==='string'?pConfig.application:'';let tmpApplicationJSON=JSON.stringify(tmpApplicationJS).replace(/<\/script>/g,'<\\/script>');// HTML. Theme picker is rendered into a slim topbar inside the iframe
14110
+ // so the user can switch themes without leaving the page. The section
14111
+ // itself mounts into the main content div below it.
14112
+ return'<!DOCTYPE html>\n'+'<html lang="en">\n'+'<head>\n'+'<meta charset="UTF-8">\n'+'<title>Section Playground</title>\n'+(tmpBaseHref?'<base href="'+tmpBaseHref+'">\n':'')+'<style>\n'+' html, body { height: 100%; margin: 0; }\n'+' body { display: flex; flex-direction: column; font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, sans-serif; }\n'+' #playground-topbar { flex: 0 0 auto; display: flex; align-items: center; justify-content: space-between; gap: 8px; padding: 8px 14px; border-bottom: 1px solid var(--theme-color-border-default, #DDD6CA); background: var(--theme-color-background-panel, #FFFFFF); }\n'+' #playground-topbar-title { font-size: 11px; text-transform: uppercase; letter-spacing: 0.07em; color: var(--theme-color-text-muted, #8A7F72); }\n'+' #playground-topbar-controls { display: flex; align-items: center; gap: 8px; }\n'+' #playground-content { flex: 1 1 auto; min-height: 0; overflow: auto; padding: 16px; background: var(--theme-color-background-primary, #FDFBF7); }\n'+' #playground-error { display: none; padding: 14px 18px; background: #FFF4F2; color: #B43A2E; border-bottom: 1px solid #B43A2E; font-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace; font-size: 12px; white-space: pre-wrap; }\n'+' #playground-error.show { display: block; }\n'+'</style>\n'+tmpLinkTags+tmpScriptTags+tmpESMScript+'</head>\n'+'<body>\n'+'<div id="playground-error"></div>\n'+'<div id="playground-topbar">\n'+' <div id="playground-topbar-title">Section Sandbox</div>\n'+' <div id="playground-topbar-controls">\n'+' <div id="Theme-Picker"></div>\n'+' <div id="Theme-ModeToggle"></div>\n'+' <div id="Theme-ScaleSelect"></div>\n'+' </div>\n'+'</div>\n'+'<div id="playground-content">\n'+' <!-- The section-form metacontroller renders into #Pict-Form-Container by default. -->\n'+' <!-- Other section types may use a different default; the spec drives the markup. -->\n'+' <div id="Pict-Form-Container"></div>\n'+' <div id="Section-Playground-Mount"></div>\n'+(tmpSpec.MountID?' <div id="'+tmpSpec.MountID+'"></div>\n':'')+'</div>\n'+'<script>\n'+'(function() {\n'+' var manifest = '+tmpManifestJSON+';\n'+' var pictConfig = '+tmpPictConfigJSON+';\n'+' var appConfig = '+tmpAppConfigJSON+';\n'+' var appData = '+tmpAppDataJSON+';\n'+' var applicationSource = '+tmpApplicationJSON+';\n'+' var sectionType = '+JSON.stringify(tmpSpec.SectionType)+';\n'+' var applicationModule = '+JSON.stringify(tmpSpec.ApplicationModule)+';\n'+' var applicationGlobal = '+JSON.stringify(tmpSpec.ApplicationGlobal)+';\n'+' var manifestKey = '+JSON.stringify(tmpSpec.ManifestKey)+';\n'+' var wrapperKind = '+JSON.stringify(tmpSpec.WrapperKind)+';\n'+' var viewName = '+JSON.stringify(tmpSpec.ViewName)+';\n'+' var viewConfigKey = '+JSON.stringify(tmpSpec.ViewConfigKey)+';\n'+' var mountID = '+JSON.stringify(tmpSpec.MountID)+';\n'+' var bootstrapMethod = '+JSON.stringify(tmpSpec.BootstrapMethod)+';\n'+' var bootstrapSeedAddr = '+JSON.stringify(tmpSpec.BootstrapSeedAddress)+';\n'+'\n'+' function showError(msg) {\n'+' var el = document.getElementById("playground-error");\n'+' if (el) { el.textContent = msg; el.classList.add("show"); }\n'+' try { parent.postMessage({ type: "section-playground-error", message: msg }, "*"); } catch(e) {}\n'+' }\n'+'\n'+' function ready(fn) {\n'+' if (document.readyState !== "loading") { fn(); }\n'+' else { document.addEventListener("DOMContentLoaded", fn); }\n'+' }\n'+'\n'+' function awaitESM() {\n'+' return (window.__SectionPlaygroundESMReady && typeof window.__SectionPlaygroundESMReady.then === "function")\n'+' ? window.__SectionPlaygroundESMReady\n'+' : Promise.resolve();\n'+' }\n'+'\n'+' ready(function() {\n'+' awaitESM().then(function() { try {\n'+' if (typeof Pict === "undefined") { throw new Error("pict bundle did not load — check the CDN imports in _playground.json"); }\n'+' var libSectionModule = window[applicationModule];\n'+' if (!libSectionModule) { throw new Error("Section module " + applicationModule + " is not loaded; check the Imports in _playground.json"); }\n'+' var ResolvedClass = libSectionModule[applicationGlobal] || libSectionModule;\n'+' if (typeof ResolvedClass !== "function") { throw new Error("Could not resolve " + applicationGlobal + " on " + applicationModule); }\n'+'\n'+' // Wrapper resolution. Two paths:\n'+' // 1. WrapperKind: "application" (default) — the resolved class\n'+' // is already a PictApplication subclass; use it directly.\n'+' // pict-section-form\'s pattern.\n'+' // 2. WrapperKind: "view" — the resolved class is a PictView; the\n'+' // bootstrap synthesizes a PictApplication subclass that\n'+' // registers the view under `viewName` with config drawn\n'+' // from pictConfig[viewConfigKey]. This is the no-wrapper\n'+' // path: section modules ship just their view class and a\n'+' // _playground.json — no per-module Application file needed.\n'+' var BaseApplicationClass;\n'+' if (wrapperKind === "view") {\n'+' if (typeof window.PictApplication !== "function") { throw new Error("WrapperKind: \\"view\\" requires pict-application to be loaded — add it to Imports in _playground.json"); }\n'+' var ViewClass = ResolvedClass;\n'+' // PictApplication is an ES6 class, so the wrapper MUST be one\n'+' // too — ES6 classes throw "cannot be invoked without new" when\n'+' // called via `.call(this, ...)`, so the prototype-style pattern\n'+' // (function + Object.create) silently fails at construction.\n'+' // Build the class via a Function constructor so we can keep\n'+' // closure access to viewName / viewConfigKey / mountID / etc.\n'+' var BuildWrapperClass = new Function(\n'+' "PictApplication", "ViewClass", "pictConfig", "viewName", "viewConfigKey", "mountID", "bootstrapMethod", "bootstrapSeedAddr",\n'+' "return class ViewWrapperApplication extends PictApplication {"\n'+' + " constructor(pFable, pOptions, pServiceHash) {"\n'+' + " super(pFable, pOptions, pServiceHash);"\n'+' + " var tmpDefaultViewConfig = (ViewClass.default_configuration || {});"\n'+' + " var tmpInjectedViewConfig = (pictConfig && pictConfig[viewConfigKey]) || {};"\n'+' + " var tmpMergedViewConfig = Object.assign({}, tmpDefaultViewConfig, tmpInjectedViewConfig);"\n'+' + " var tmpAutoMount = \\"#\\" + (mountID || \\"Section-Playground-Mount\\");"\n'+' + " if (typeof tmpInjectedViewConfig.DefaultDestinationAddress === \\"undefined\\") {"\n'+' + " tmpMergedViewConfig.DefaultDestinationAddress = tmpAutoMount;"\n'+' + " if (Array.isArray(tmpDefaultViewConfig.Renderables)) {"\n'+' + " tmpMergedViewConfig.Renderables = tmpDefaultViewConfig.Renderables.map(function(pRenderable) {"\n'+' + " return Object.assign({}, pRenderable, { DestinationAddress: tmpAutoMount });"\n'+' + " });"\n'+' + " }"\n'+' + " }"\n'+' + " this.pict.addView(viewName, tmpMergedViewConfig, ViewClass);"\n'+' + " }"\n'+' + " onAfterInitialize() {"\n'+' + " super.onAfterInitialize();"\n'+' + " var tmpView = this.pict.views[viewName];"\n'+' + " if (bootstrapMethod && tmpView && typeof tmpView[bootstrapMethod] === \\"function\\") {"\n'+' + " try {"\n'+' + " var tmpSeed;"\n'+' + " if (bootstrapSeedAddr && this.pict && this.pict.manifest && typeof this.pict.manifest.getValueByHash === \\"function\\") {"\n'+' + " tmpSeed = this.pict.manifest.getValueByHash(this.pict.AppData, bootstrapSeedAddr);"\n'+' + " }"\n'+' + " tmpView[bootstrapMethod](tmpSeed);"\n'+' + " } catch (seedErr) { console.warn(\\"BootstrapMethod \\" + bootstrapMethod + \\" threw:\\", seedErr); }"\n'+' + " }"\n'+' + " if (tmpView && typeof tmpView.render === \\"function\\") { tmpView.render(); }"\n'+' + " }"\n'+' + "};"\n'+' );\n'+' BaseApplicationClass = BuildWrapperClass(window.PictApplication, ViewClass, pictConfig, viewName, viewConfigKey, mountID, bootstrapMethod, bootstrapSeedAddr);\n'+' // Carry through whatever defaults the view itself ships, so\n'+' // pict_configuration / Product / Hash stay sensible if the\n'+' // user has not provided their own appConfig / pictConfig.\n'+' BaseApplicationClass.default_configuration = (ViewClass.default_configuration && ViewClass.default_configuration.pict_configuration)\n'+' ? ViewClass.default_configuration\n'+' : { pict_configuration: {} };\n'+' } else {\n'+' BaseApplicationClass = ResolvedClass;\n'+' }\n'+'\n'+' // Subclass. If the user supplied Application Code,\n'+' // wrap it as `function (Base) { ...userBody... }` and\n'+' // expect it to return a class. Otherwise fall back to\n'+' // a no-op extends-Base subclass. class extends handles\n'+' // both ES6 classes and old-style prototype constructors.\n'+' var PlaygroundApplication;\n'+' if (typeof applicationSource === "string" && applicationSource.trim().length > 0) {\n'+' try {\n'+' var customizerFn = new Function("Base", applicationSource);\n'+' var customizerResult = customizerFn(BaseApplicationClass);\n'+' if (typeof customizerResult !== "function") {\n'+' throw new Error("Application Code must `return` a class. Got " + (typeof customizerResult) + ".");\n'+' }\n'+' PlaygroundApplication = customizerResult;\n'+' } catch (customizerErr) {\n'+' throw new Error("Application Code error: " + (customizerErr && customizerErr.message ? customizerErr.message : customizerErr));\n'+' }\n'+' } else {\n'+' PlaygroundApplication = class extends BaseApplicationClass {};\n'+' }\n'+'\n'+' // Precedence: Base class defaults < user-class defaults\n'+' // (if Application Code set its own) < the four editor tabs.\n'+' // The editor tabs are what the playground exists to drive,\n'+' // so they always win.\n'+' var userDefault = PlaygroundApplication.default_configuration || BaseApplicationClass.default_configuration || {};\n'+' var basePict = userDefault.pict_configuration || {};\n'+' var mergedPict = Object.assign({}, basePict, pictConfig);\n'+' mergedPict[manifestKey] = manifest;\n'+' if (appData !== undefined) { mergedPict.DefaultAppData = appData; }\n'+'\n'+' var defaultConfig = Object.assign({}, userDefault, appConfig);\n'+' defaultConfig.pict_configuration = mergedPict;\n'+' PlaygroundApplication.default_configuration = defaultConfig;\n'+'\n'+' // Pict.safeLoadPictApplication will instantiate and run lifecycle.\n'+' Pict.safeOnDocumentReady(function() {\n'+' Pict.safeLoadPictApplication(PlaygroundApplication, 2);\n'+' // Mount the theme controls once the app is up.\n'+' setTimeout(function() {\n'+' try {\n'+' if (window.PictSectionTheme && window._Pict && typeof window._Pict.addProvider === "function") {\n'+' if (!window._Pict.providers || !window._Pict.providers["Theme-Section"]) {\n'+' window._Pict.addProvider("Theme-Section", { ApplyDefault: "pict-default", DefaultMode: "system", DefaultScale: 1.0, Views: ["Picker", "ModeToggle", "ScaleSelect"] }, window.PictSectionTheme);\n'+' window._Pict.views["Theme-Picker"].render();\n'+' if (window._Pict.views["Theme-ModeToggle"]) { window._Pict.views["Theme-ModeToggle"].render(); }\n'+' if (window._Pict.views["Theme-ScaleSelect"]) { window._Pict.views["Theme-ScaleSelect"].render(); }\n'+' }\n'+' }\n'+' } catch (themeErr) { /* theme bootstrap is best-effort */ }\n'+' }, 50);\n'+' try { parent.postMessage({ type: "section-playground-ready" }, "*"); } catch(e) {}\n'+' });\n'+' } catch (err) {\n'+' showError(String(err && err.stack ? err.stack : err));\n'+' } }).catch(function(esmErr) {\n'+' showError("ESM import failed: " + String(esmErr && esmErr.message ? esmErr.message : esmErr));\n'+' });\n'+' });\n'+'}());\n'+'</script>\n'+'</body>\n'+'</html>';}class DocuserveSectionPlaygroundView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);// Editor metadata — populated when the playground is opened for
14113
+ // a specific module. Each entry mirrors the _playground.json
14114
+ // Editors[] descriptor + activation state.
14115
+ this._editors=[];this._activeHash=null;// (group, module) currently mounted; used to scope localStorage.
14116
+ this._scope={Group:'',Module:''};}// ────────────────────────────────────────────────────────────────
14117
+ // Public API — called by the application's router.
14118
+ // ────────────────────────────────────────────────────────────────
14119
+ /**
14120
+ * Open the playground for `<group>/<module>`. Reads the module's
14121
+ * `_playground.json`, hydrates editors from starter files or
14122
+ * localStorage, renders the layout, and mounts a pict-section-code
14123
+ * view per editor tab.
14124
+ *
14125
+ * @param {string} pGroup
14126
+ * @param {string} pModule
14127
+ */openPlayground(pGroup,pModule){this._scope={Group:pGroup,Module:pModule};let tmpDoc=this.pict.providers['Docuserve-Documentation'];if(!tmpDoc||typeof tmpDoc.loadPlaygroundConfig!=='function'){this._renderError('Documentation provider is not registered.');return;}let tmpSelf=this;tmpDoc.loadPlaygroundConfig(pGroup,pModule).then(function(pConfig){if(!pConfig||pConfig.Kind!=='section'){tmpSelf._renderError('This module does not have a section playground configured. Add `Kind: "section"` to `docs/_playground.json` and declare an `Editors` array.');return;}tmpSelf._spec=pConfig;tmpSelf._loadEditors(pGroup,pModule,pConfig).then(function(){tmpSelf._mountAndRender();});}).catch(function(pError){tmpSelf._renderError('Failed to load _playground.json: '+(pError&&pError.message?pError.message:pError));});}/**
14128
+ * Switch the visible editor tab. Each tab is a separate
14129
+ * pict-section-code instance mounted into its own slot div; we
14130
+ * just toggle the .active class.
14131
+ */selectTab(pHash){this._activeHash=pHash;this._refreshEditorRecords();// Toggle active class on the live DOM without re-rendering the
14132
+ // whole view (editor mounts must stay stable so CodeJar keeps
14133
+ // its state).
14134
+ let tmpTabs=document.querySelectorAll('.docuserve-section-playground-tab');for(let i=0;i<tmpTabs.length;i++){tmpTabs[i].classList.remove('active');}let tmpEditors=document.querySelectorAll('.docuserve-section-playground-editor');for(let j=0;j<tmpEditors.length;j++){tmpEditors[j].classList.remove('active');}for(let k=0;k<this._editors.length;k++){let tmpEd=this._editors[k];if(tmpEd.Hash===pHash){let tmpTabEl=document.querySelector('.docuserve-section-playground-tab[onclick*="\''+tmpEd.Hash+'\'"]');if(tmpTabEl){tmpTabEl.classList.add('active');}let tmpEditorEl=document.getElementById('Docuserve-Section-Playground-Editor-'+tmpEd.Hash);if(tmpEditorEl){tmpEditorEl.classList.add('active');}}}}/**
14135
+ * "Run" — read each editor's current value, validate, build a
14136
+ * fresh srcdoc, and replace the iframe contents.
14137
+ */run(){let tmpConfig;try{tmpConfig=this._readAndValidateEditors();}catch(pError){this._setStatus(pError.message,true);return;}this._setStatus('running…',false);let tmpIframe=document.getElementById('Docuserve-Section-Playground-Iframe');if(!tmpIframe){return;}// Compute an absolute base href for the iframe's <base> tag.
14138
+ // The iframe lives at about:srcdoc — relative URLs there don't
14139
+ // resolve to the parent's docs root, so we anchor a real URL.
14140
+ let tmpBaseURL='';try{// Trim hash off the parent location so the base resolves to the
14141
+ // docs directory, not the SPA route.
14142
+ let tmpHref=window.location.href.split('#')[0];// Strip the final 'index.html' if present so the base is the dir.
14143
+ tmpBaseURL=tmpHref.replace(/index\.html$/,'');}catch(pErr){tmpBaseURL='';}let tmpSrcdoc=buildIframeSrcdoc(tmpConfig,this._spec||{},tmpBaseURL);tmpIframe.srcdoc=tmpSrcdoc;// One-shot ready listener — re-attached each Run.
14144
+ let tmpSelf=this;let tmpListener=function tmpListener(pEvent){if(!pEvent||!pEvent.data)return;if(pEvent.data.type==='section-playground-ready'){tmpSelf._setStatus('rendered',false);}else if(pEvent.data.type==='section-playground-error'){tmpSelf._setStatus('error in sandbox',true);}};window.addEventListener('message',tmpListener);// Auto-cleanup after a generous timeout so we don't leak.
14145
+ setTimeout(function(){window.removeEventListener('message',tmpListener);},30000);}/**
14146
+ * Reset every editor back to its starter content (DefaultPath JSON
14147
+ * file or the inline Default in the spec). Clears the matching
14148
+ * localStorage entries so subsequent reloads re-read the starters.
14149
+ */resetAll(){let tmpModal=this.pict.views['Pict-Section-Modal'];let tmpSelf=this;let tmpProceed=function tmpProceed(){for(let i=0;i<tmpSelf._editors.length;i++){let tmpEd=tmpSelf._editors[i];tmpEd.Code=tmpEd.StarterCode||'';let tmpKey=tmpSelf._storageKey(tmpEd.Hash);try{window.localStorage.removeItem(tmpKey);}catch(e){/* */}let tmpAddress=tmpSelf._editorCodeAddress(tmpEd.Hash);tmpSelf.pict.manifest.setValueByHash(tmpSelf.pict.AppData,tmpAddress,tmpEd.Code);let tmpEditorView=tmpSelf.pict.views[tmpSelf._editorViewIdentifier(tmpEd.Hash)];if(tmpEditorView&&typeof tmpEditorView.setCode==='function'){tmpEditorView.setCode(tmpEd.Code);}}tmpSelf._setStatus('reset to starters',false);};if(tmpModal&&typeof tmpModal.confirm==='function'){tmpModal.confirm('Reset all editors to their starter content? Your current edits will be lost.',{title:'Reset playground',confirmLabel:'Reset',cancelLabel:'Keep edits',dangerous:true}).then(function(pOK){if(pOK)tmpProceed();});}else{tmpProceed();}}// ────────────────────────────────────────────────────────────────
14150
+ // Internals
14151
+ // ────────────────────────────────────────────────────────────────
14152
+ _storageKey(pEditorHash){return _LocalStorageKeyPrefix+':'+this._scope.Group+'/'+this._scope.Module+':'+pEditorHash;}_editorViewIdentifier(pEditorHash){return'Docuserve-Section-Playground-Editor-View-'+pEditorHash;}_editorCodeAddress(pEditorHash){return _AppDataRoot+'.Code.'+pEditorHash;}/**
14153
+ * Hydrate `this._editors` from the spec + starters + localStorage.
14154
+ * Returns a Promise so callers can await all fetches.
14155
+ */_loadEditors(pGroup,pModule,pSpec){let tmpEditors=pSpec.Editors||[];let tmpDoc=this.pict.providers['Docuserve-Documentation'];let tmpSelf=this;this._editors=[];let tmpPromises=[];for(let i=0;i<tmpEditors.length;i++){(function(pEditorSpec,pIndex){let tmpEntry={Hash:pEditorSpec.Hash,Label:pEditorSpec.Label||pEditorSpec.Hash,Language:pEditorSpec.Language||'json',StarterCode:pEditorSpec.Default||'',Code:''};// Try localStorage first (user's last edits).
14156
+ let tmpStored=null;try{tmpStored=window.localStorage.getItem(tmpSelf._storageKey(pEditorSpec.Hash));}catch(e){tmpStored=null;}// Then fetch the starter file if DefaultPath is set.
14157
+ //
14158
+ // URL resolution has two modes:
14159
+ // * Catalog mode (group + module + Catalog provider) — use
14160
+ // resolveDocumentURL() which routes to the right GitHub
14161
+ // pages site for the target module.
14162
+ // * Standalone mode (no group/module, or empty strings) —
14163
+ // the docs site IS the module's own docs, so a
14164
+ // docs-root-relative path resolves correctly as-is.
14165
+ let tmpStarterPromise;if(pEditorSpec.DefaultPath){let tmpURL=null;if(pGroup&&pModule&&tmpDoc&&typeof tmpDoc.resolveDocumentURL==='function'){tmpURL=tmpDoc.resolveDocumentURL(pGroup,pModule,pEditorSpec.DefaultPath);}if(!tmpURL){let tmpDocsBase=tmpSelf.pict.AppData.Docuserve.DocsBaseURL||'';tmpURL=tmpDocsBase+pEditorSpec.DefaultPath;}tmpStarterPromise=fetch(tmpURL).then(function(pResponse){if(!pResponse.ok){return'';}return pResponse.text();}).catch(function(){return'';});}else{tmpStarterPromise=Promise.resolve(tmpEntry.StarterCode);}tmpPromises.push(tmpStarterPromise.then(function(pStarter){tmpEntry.StarterCode=pStarter||tmpEntry.StarterCode;tmpEntry.Code=tmpStored!==null&&tmpStored!==undefined?tmpStored:tmpEntry.StarterCode;// Park in the same slot so re-mounts preserve order.
14166
+ tmpSelf._editors[pIndex]=tmpEntry;}));})(tmpEditors[i],i);}return Promise.all(tmpPromises).then(function(){// Compact in case any slot ended up undefined.
14167
+ tmpSelf._editors=tmpSelf._editors.filter(function(e){return!!e;});if(tmpSelf._editors.length>0){tmpSelf._activeHash=tmpSelf._editors[0].Hash;}});}_refreshEditorRecords(){let tmpRecords=[];for(let i=0;i<this._editors.length;i++){let tmpEd=this._editors[i];tmpRecords.push({Hash:tmpEd.Hash,Label:tmpEd.Label,ActiveClass:tmpEd.Hash===this._activeHash?' active':''});}this.pict.AppData.Docuserve=this.pict.AppData.Docuserve||{};this.pict.AppData.Docuserve.SectionPlayground=this.pict.AppData.Docuserve.SectionPlayground||{};this.pict.AppData.Docuserve.SectionPlayground.Editors=tmpRecords;// Seed each editor's Code address so pict-section-code finds the
14168
+ // initial value when it mounts.
14169
+ this.pict.AppData.Docuserve.SectionPlayground.Code=this.pict.AppData.Docuserve.SectionPlayground.Code||{};for(let j=0;j<this._editors.length;j++){let tmpEd=this._editors[j];this.pict.AppData.Docuserve.SectionPlayground.Code[tmpEd.Hash]=tmpEd.Code;}}/**
14170
+ * Build the pict-section-modal shell that hosts the editor stack
14171
+ * (center) + iframe sandbox (resizable + collapsible bottom panel).
14172
+ *
14173
+ * The shell creates two destination divs inside its mount:
14174
+ * * #Docuserve-Section-Playground-Editor-Mount (center)
14175
+ * * #Docuserve-Section-Playground-Iframe-Mount (bottom panel)
14176
+ *
14177
+ * Once the shell is up, we stamp the editor slot divs (one per tab)
14178
+ * into the editor mount and the iframe + status badge into the
14179
+ * sandbox mount. pict-section-code instances mount into the per-
14180
+ * tab slots from there.
14181
+ *
14182
+ * Re-entrant: a second call after teardown rebuilds the shell on
14183
+ * the same mount div. PersistenceKey scopes the saved split size
14184
+ * per-module so each playground remembers its own layout.
14185
+ */_buildShell(){let tmpModal=this.pict.views['Pict-Section-Modal'];let tmpMountEl=document.getElementById('Docuserve-Section-Playground-Shell-Mount');if(!tmpModal||typeof tmpModal.shell!=='function'||!tmpMountEl){// Shell isn't available — fall back to a static layout so the
14186
+ // playground still works (no resize/collapse) without the
14187
+ // section-modal dependency.
14188
+ tmpMountEl.innerHTML=''+'<div class="docuserve-section-playground-editor-mount" id="Docuserve-Section-Playground-Editor-Mount" style="height:55%;border-bottom:1px solid var(--theme-color-border-default,#DDD6CA)"></div>'+'<div class="docuserve-section-playground-iframe-pane" id="Docuserve-Section-Playground-Iframe-Mount" style="height:45%"></div>';this._populateShellDestinations();return;}// Per-module persistence key so each module remembers its own
14189
+ // editor/sandbox split independently.
14190
+ let tmpPersistenceKey='docuserve-section-playground:'+this._scope.Group+'/'+this._scope.Module+':split';this._shell=tmpModal.shell(tmpMountEl,{PersistenceKey:tmpPersistenceKey});// Bottom panel — the iframe sandbox. Resizable + collapsible
14191
+ // (handled by the shell). CSS at the top of this view widens
14192
+ // the collapse tab and centers it horizontally; the Title text
14193
+ // renders inside it as the always-visible label.
14194
+ this._shell.addPanel({Hash:'sandbox',Side:'bottom',Mode:'resizable',Size:360,MinSize:140,MaxSize:1000,Title:'Sandbox',ContentDestinationId:'Docuserve-Section-Playground-Iframe-Mount'});// Center — the editor stack (one slot per tab; only the active
14195
+ // slot is display:flex). No ContentView; we DOM-inject the
14196
+ // per-tab slot divs below.
14197
+ this._shell.center({ContentDestinationId:'Docuserve-Section-Playground-Editor-Mount'});this._populateShellDestinations();}/**
14198
+ * Fill the shell's two destinations with their per-render content:
14199
+ * * editor mount → one slot div per editor (active tab has .active)
14200
+ * * sandbox mount → the iframe + the status badge
14201
+ *
14202
+ * Called from _buildShell on first mount AND from the static
14203
+ * fallback layout when the shell isn't available.
14204
+ */_populateShellDestinations(){// Editor slot divs — one per configured editor. Tag the mount
14205
+ // with our flex-column class so the active slot fills the
14206
+ // shell's center area instead of collapsing to its content
14207
+ // height (pict-section-code itself has zero intrinsic height).
14208
+ let tmpEditorMount=document.getElementById('Docuserve-Section-Playground-Editor-Mount');if(tmpEditorMount){tmpEditorMount.classList.add('docuserve-section-playground-editor-mount');let tmpSlotsHTML='';for(let i=0;i<this._editors.length;i++){let tmpEd=this._editors[i];let tmpActive=tmpEd.Hash===this._activeHash?' active':'';tmpSlotsHTML+='<div class="docuserve-section-playground-editor'+tmpActive+'"'+' id="Docuserve-Section-Playground-Editor-'+tmpEd.Hash+'"'+' data-editor-hash="'+tmpEd.Hash+'"></div>';}tmpEditorMount.innerHTML=tmpSlotsHTML;}// Iframe + status badge. The status badge is absolute-positioned
14209
+ // inside the sandbox pane so it overlays the iframe.
14210
+ let tmpSandboxMount=document.getElementById('Docuserve-Section-Playground-Iframe-Mount');if(tmpSandboxMount){tmpSandboxMount.classList.add('docuserve-section-playground-iframe-pane');tmpSandboxMount.innerHTML=''+'<iframe id="Docuserve-Section-Playground-Iframe"'+' class="docuserve-section-playground-iframe"'+' title="Section playground sandbox"'+' sandbox="allow-scripts allow-same-origin allow-modals allow-popups"></iframe>'+'<div id="Docuserve-Section-Playground-Status" class="docuserve-section-playground-status">ready</div>';}}/**
14211
+ * Render the layout + mount one pict-section-code instance per
14212
+ * editor tab. Each editor's view gets its own ViewIdentifier so
14213
+ * pict.views[] stays distinct per tab.
14214
+ */_mountAndRender(){// Tag the container so our flex CSS applies.
14215
+ let tmpContainer=document.getElementById('Docuserve-Content-Container');if(tmpContainer){tmpContainer.classList.add('docuserve-section-playground-host');}this._refreshEditorRecords();this.render();// Build the shell — center holds the editor stack, bottom panel
14216
+ // holds the iframe sandbox with a wider middle-tab collapse
14217
+ // affordance. Persistence is scoped per-module so each
14218
+ // playground remembers its split independently.
14219
+ this._buildShell();// Mount editor views. Each is a fresh pict-section-code subclass
14220
+ // that persists on change.
14221
+ let tmpSelf=this;for(let i=0;i<this._editors.length;i++){let tmpEd=this._editors[i];let tmpViewId=this._editorViewIdentifier(tmpEd.Hash);let tmpAddress=this._editorCodeAddress(tmpEd.Hash);let tmpDestId='Docuserve-Section-Playground-Editor-'+tmpEd.Hash;// If a previous mount left a view around, dispose it first
14222
+ // so we don't double-mount inside the same destination.
14223
+ if(this.pict.views[tmpViewId]){try{delete this.pict.views[tmpViewId];}catch(e){/* */}if(this.pict.servicesMap&&this.pict.servicesMap.PictView){try{delete this.pict.servicesMap.PictView[tmpViewId];}catch(e){/* */}}}// pict-section-code needs Templates + Renderables wired to the
14224
+ // mount slot so its onAfterRender can find the destination.
14225
+ // We register a no-op container template per editor and tie
14226
+ // the renderable to the per-tab slot.
14227
+ let tmpTemplateHash='Section-Playground-CodeMount-'+tmpEd.Hash;let tmpEditorOpts=Object.assign({},libPictSectionCode.default_configuration,{ViewIdentifier:tmpViewId,DefaultDestinationAddress:'#'+tmpDestId,TargetElementAddress:'#'+tmpDestId,Templates:[{Hash:tmpTemplateHash,Template:'<!-- pict-section-code mount: '+tmpEd.Hash+' -->'}],Renderables:[{RenderableHash:'Section-Playground-CodeRenderable-'+tmpEd.Hash,TemplateHash:tmpTemplateHash,DestinationAddress:'#'+tmpDestId}],Language:tmpEd.Language||'json',ReadOnly:false,LineNumbers:true,Tab:'\t',AddClosing:true,CatchTab:true,DefaultCode:tmpEd.Code,CodeDataAddress:tmpAddress,// Defer render — we connect the CodeJar prototype first
14228
+ // (loaded from CDN in _loadCodeJar), then call render() on
14229
+ // each editor once.
14230
+ AutoRender:false,RenderOnLoad:false});// Subclass that persists on every change.
14231
+ let SectionPlaygroundEditor=class extends libPictSectionCode{onCodeChange(pCode){super.onCodeChange(pCode);if(this._lsTimer){clearTimeout(this._lsTimer);}let tmpEditorHash=this.options.ViewIdentifier.replace('Docuserve-Section-Playground-Editor-View-','');this._lsTimer=setTimeout(()=>{this._lsTimer=null;try{let tmpView=this.fable.pict.views['Docuserve-Section-Playground'];let tmpKey=tmpView&&typeof tmpView._storageKey==='function'?tmpView._storageKey(tmpEditorHash):_LocalStorageKeyPrefix+':'+tmpEditorHash;window.localStorage.setItem(tmpKey,pCode);if(tmpView&&typeof tmpView._setStatus==='function'){tmpView._setStatus('saved',false);}}catch(pError){/* quota or no LS — silent */}},500);}};this.pict.addView(tmpViewId,tmpEditorOpts,SectionPlaygroundEditor);}// Lazy-load CodeJar from CDN, then connect + render each editor.
14232
+ // pict-section-code can't initialize without a CodeJar prototype.
14233
+ this._loadCodeJar().then(function(pCodeJar){for(let n=0;n<tmpSelf._editors.length;n++){let tmpEd=tmpSelf._editors[n];let tmpEditorView=tmpSelf.pict.views[tmpSelf._editorViewIdentifier(tmpEd.Hash)];if(!tmpEditorView){continue;}if(!tmpEditorView._codeJarPrototype){tmpEditorView.connectCodeJarPrototype(pCodeJar);}try{tmpEditorView.render();}catch(pError){/* best effort */}}tmpSelf._setStatus('press Run to render',false,2500);}).catch(function(pError){tmpSelf._setStatus('CodeJar failed to load — editors disabled',true,6000);});}/**
14234
+ * Dynamic-import CodeJar from jsDelivr. Memoized. Wrapped in
14235
+ * `new Function('u','return import(u)')` so browserify doesn't try to
14236
+ * rewrite the import() at build time.
14237
+ */_loadCodeJar(){if(this._codeJarPromise){return this._codeJarPromise;}this._codeJarPromise=new Function('u','return import(u)')(_CodeJarCDN).then(function(pModule){if(!pModule||typeof pModule.CodeJar!=='function'){throw new Error('CodeJar export not found in module');}return pModule.CodeJar;});return this._codeJarPromise;}/**
14238
+ * Read every editor's current text out of AppData (it's kept up to
14239
+ * date by pict-section-code's CodeDataAddress wiring). JSON-language
14240
+ * editors are parsed and validated; others are returned verbatim.
14241
+ *
14242
+ * @throws Error on a parse failure — caller surfaces to the UI.
14243
+ */_readAndValidateEditors(){let tmpOut={manifest:undefined,pictConfig:undefined,appConfig:undefined,appData:undefined};for(let i=0;i<this._editors.length;i++){let tmpEd=this._editors[i];let tmpAddress=this._editorCodeAddress(tmpEd.Hash);let tmpRaw=this.pict.manifest.getValueByHash(this.pict.AppData,tmpAddress);if(typeof tmpRaw!=='string'){tmpRaw=tmpEd.Code||'';}let tmpValue;if((tmpEd.Language||'json').toLowerCase()==='json'){if(tmpRaw.trim()===''){tmpValue={};}else{try{tmpValue=JSON.parse(tmpRaw);}catch(pError){throw new Error('JSON parse error in "'+tmpEd.Label+'": '+pError.message);}}}else{tmpValue=tmpRaw;}// Map editor hash to a known config slot, or carry through unchanged.
14244
+ if(tmpOut.hasOwnProperty(tmpEd.Hash)){tmpOut[tmpEd.Hash]=tmpValue;}else{tmpOut[tmpEd.Hash]=tmpValue;}}return tmpOut;}_setStatus(pMessage,pIsError,pAutoHideMs){let tmpEl=document.getElementById('Docuserve-Section-Playground-Status');if(!tmpEl)return;tmpEl.textContent=pMessage;tmpEl.classList.add('show');if(pIsError){tmpEl.classList.add('error');}else{tmpEl.classList.remove('error');}if(this._statusTimer){clearTimeout(this._statusTimer);}let tmpDelay=typeof pAutoHideMs==='number'?pAutoHideMs:2500;this._statusTimer=setTimeout(function(){tmpEl.classList.remove('show');tmpEl.classList.remove('error');},tmpDelay);}_renderError(pMessage){let tmpHTML='<div class="docuserve-section-playground-emptystate">'+'<div class="docuserve-section-playground-emptystate-title">Playground unavailable</div>'+'<div>'+this._escape(pMessage)+'</div>'+'</div>';this.pict.ContentAssignment.assignContent('#Docuserve-Content-Container',tmpHTML);}_escape(pText){return String(pText||'').replace(/[&<>"']/g,function(pChar){return{'&':'&amp;','<':'&lt;','>':'&gt;','"':'&quot;',"'":'&#39;'}[pChar];});}onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent){this.pict.CSSMap.injectCSS();return super.onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent);}}module.exports=DocuserveSectionPlaygroundView;module.exports.default_configuration=_ViewConfiguration;},{"pict-section-code":151,"pict-view":231}],359:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"Docuserve-Sidebar",DefaultRenderable:"Docuserve-Sidebar-Content",DefaultDestinationAddress:"#Docuserve-Sidebar-Container",AutoRender:false,CSS:/*css*/"\n\t\t.docuserve-sidebar {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\tbackground: var(--theme-color-background-secondary, #FAF7F1);\n\t\t\tborder-right: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tpadding: 1em 0;\n\t\t\tpadding-top: 0;\n\t\t\tmin-height: 100%;\n\t\t\tposition: relative;\n\t\t\ttransition: background-color 0.15s ease;\n\t\t}\n\t\t.docuserve-sidebar-header {\n\t\t\tdisplay: none;\n\t\t\tjustify-content: flex-end;\n\t\t\tpadding: 0.4em 0.5em 0;\n\t\t}\n\t\t/* The \"X\" close button is only useful when the sidebar is acting\n\t\t as a responsive drawer (narrow viewports where the panel slid\n\t\t in over the content area). In docked desktop mode the\n\t\t pict-section-modal collapse tab on the panel's outer edge is\n\t\t the canonical collapse affordance \u2014 a second X inside the\n\t\t panel competes with it and looks messy. Show the X only in\n\t\t drawer mode. */\n\t\t.pict-modal-shell-panel-drawer .docuserve-sidebar-header {\n\t\t\tdisplay: flex;\n\t\t}\n\t\t.docuserve-sidebar-close {\n\t\t\tdisplay: inline-flex;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tbackground: none;\n\t\t\tborder: none;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tfont-size: 1.1em;\n\t\t\tcursor: pointer;\n\t\t\tpadding: 0.2em 0.4em;\n\t\t\tline-height: 1;\n\t\t}\n\t\t.docuserve-sidebar-close:hover {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-search {\n\t\t\tpadding: 0 1em 1em 1em;\n\t\t\tborder-bottom: 1px solid var(--theme-color-border-light, #E5DED1);\n\t\t\tmargin-bottom: 0.5em;\n\t\t}\n\t\t.docuserve-sidebar-search input {\n\t\t\twidth: 100%;\n\t\t\tpadding: 0.5em 0.75em;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tcolor: var(--theme-color-text-primary, #2A241E);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tborder-radius: 4px;\n\t\t\tfont-size: 0.85em;\n\t\t\toutline: none;\n\t\t\tbox-sizing: border-box;\n\t\t}\n\t\t.docuserve-sidebar-search input:focus {\n\t\t\tborder-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-search-results {\n\t\t\tmargin-top: 0.5em;\n\t\t}\n\t\t.docuserve-sidebar-search-results a {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.4em 0.5em;\n\t\t\tcolor: var(--theme-color-text-primary, #423D37);\n\t\t\ttext-decoration: none;\n\t\t\tfont-size: 0.82em;\n\t\t\tborder-radius: 3px;\n\t\t\ttransition: background-color 0.1s;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.docuserve-sidebar-search-results a:hover {\n\t\t\tbackground-color: var(--theme-color-background-hover, #EAE3D8);\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-search-result-title {\n\t\t\tfont-weight: 600;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t}\n\t\t.docuserve-sidebar-search-results a:hover .docuserve-sidebar-search-result-title {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-search-result-meta {\n\t\t\tfont-size: 0.9em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t}\n\t\t.docuserve-sidebar-search-all {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.4em 0.5em;\n\t\t\tfont-size: 0.82em;\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\ttext-decoration: none;\n\t\t\tfont-weight: 600;\n\t\t\tcursor: pointer;\n\t\t\tborder-top: 1px solid var(--theme-color-border-light, #E5DED1);\n\t\t\tmargin-top: 0.25em;\n\t\t\tpadding-top: 0.5em;\n\t\t}\n\t\t.docuserve-sidebar-search-all:hover {\n\t\t\ttext-decoration: underline;\n\t\t}\n\t\t.docuserve-sidebar-search-empty {\n\t\t\tpadding: 0.4em 0.5em;\n\t\t\tfont-size: 0.82em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t}\n\t\t.docuserve-sidebar-home {\n\t\t\tpadding: 0.5em 1.25em;\n\t\t\tfont-weight: 600;\n\t\t\tfont-size: 0.85em;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.03em;\n\t\t}\n\t\t.docuserve-sidebar-home a {\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\ttext-decoration: none;\n\t\t\tcursor: pointer;\n\t\t\tuser-select: none;\n\t\t}\n\t\t.docuserve-sidebar-home a:hover {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-group {\n\t\t\tmargin-top: 0.25em;\n\t\t}\n\t\t.docuserve-sidebar-group-title {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.5em 1.25em;\n\t\t\tfont-weight: 600;\n\t\t\tfont-size: 0.85em;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\ttext-decoration: none;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.03em;\n\t\t\tcursor: pointer;\n\t\t\tuser-select: none;\n\t\t\ttransition: background-color 0.1s, color 0.1s;\n\t\t}\n\t\t.docuserve-sidebar-group-title:hover {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tbackground-color: var(--theme-color-background-hover, #EAE3D8);\n\t\t}\n\t\ta.docuserve-sidebar-group-title.active {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tbackground-color: var(--theme-color-background-tertiary, #E5DED1);\n\t\t}\n\t\t.docuserve-sidebar-modules {\n\t\t\tlist-style: none;\n\t\t\tmargin: 0;\n\t\t\tpadding: 0;\n\t\t}\n\t\t.docuserve-sidebar-modules li {\n\t\t\tpadding: 0;\n\t\t}\n\t\t.docuserve-sidebar-modules a {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.3em 1.25em 0.3em 2em;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\ttext-decoration: none;\n\t\t\tfont-size: 0.85em;\n\t\t\ttransition: background-color 0.1s, color 0.1s;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.docuserve-sidebar-modules a:hover {\n\t\t\tbackground-color: var(--theme-color-background-hover, #EAE3D8);\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-modules a.active {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tfont-weight: 600;\n\t\t\tbackground-color: var(--theme-color-background-tertiary, #E5DED1);\n\t\t}\n\t\t.docuserve-sidebar-modules .no-docs {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.3em 1.25em 0.3em 2em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tfont-size: 0.85em;\n\t\t}\n\t\t.docuserve-sidebar-module-nav {\n\t\t\tborder-top: 1px solid var(--theme-color-border-light, #E5DED1);\n\t\t\tmargin-top: 0.5em;\n\t\t\tpadding-top: 0.5em;\n\t\t}\n\t\t.docuserve-sidebar-module-nav:empty {\n\t\t\tdisplay: none;\n\t\t}\n\t\t.docuserve-sidebar-module-nav-section {\n\t\t\tpadding: 0.4em 1.25em;\n\t\t\tfont-weight: 600;\n\t\t\tfont-size: 0.8em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.02em;\n\t\t}\n\t\t.docuserve-sidebar-module-nav a {\n\t\t\tdisplay: block;\n\t\t\tpadding: 0.25em 1.25em 0.25em 2.25em;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\ttext-decoration: none;\n\t\t\tfont-size: 0.82em;\n\t\t\ttransition: background-color 0.1s, color 0.1s;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.docuserve-sidebar-module-nav a:hover {\n\t\t\tbackground-color: var(--theme-color-background-hover, #EAE3D8);\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-sidebar-module-nav a.active {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tfont-weight: 600;\n\t\t\tbackground-color: var(--theme-color-background-tertiary, #E5DED1);\n\t\t}\n\t\t.docuserve-sidebar-footer {\n\t\t\tmargin-top: auto;\n\t\t\tpadding: 0.9em 1.25em 1em 1.25em;\n\t\t\tborder-top: 1px solid var(--theme-color-border-light, #E5DED1);\n\t\t}\n\t\t.docuserve-sidebar-footer:empty {\n\t\t\tdisplay: none;\n\t\t}\n\t\t.docuserve-version-placard {\n\t\t\tfont-family: ui-monospace, SFMono-Regular, Menlo, Consolas, monospace;\n\t\t\tline-height: 1.35;\n\t\t}\n\t\t.docuserve-version-name {\n\t\t\tfont-size: 0.78em;\n\t\t\tfont-weight: 600;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tletter-spacing: 0.02em;\n\t\t}\n\t\t.docuserve-version-number {\n\t\t\tfont-size: 0.82em;\n\t\t\tfont-weight: 500;\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-version-meta {\n\t\t\tfont-size: 0.7em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tmargin-top: 0.15em;\n\t\t}\n\t",Templates:[{Hash:"Docuserve-Sidebar-Template",Template:/*html*/"\n<div class=\"docuserve-sidebar\">\n\t<div class=\"docuserve-sidebar-header\">\n\t\t<button class=\"docuserve-sidebar-close\" onclick=\"{~P~}.views['Docuserve-Sidebar'].toggleSidebar()\" aria-label=\"Close sidebar\">{~I:Close~}</button>\n\t</div>\n\t{~TS:Docuserve-Sidebar-Search-Slot-Template:AppData.Docuserve.SidebarSearchSlot~}\n\t<div class=\"docuserve-sidebar-home\">\n\t\t<a onclick=\"{~P~}.PictApplication.navigateTo('/Home')\">Home</a>\n\t</div>\n\t<div id=\"Docuserve-Sidebar-Groups\">\n\t\t{~TS:Docuserve-Sidebar-Group-Template:AppData.Docuserve.SidebarGroupRecords~}\n\t</div>\n\t<div id=\"Docuserve-Sidebar-ModuleNav\" class=\"docuserve-sidebar-module-nav\">\n\t\t{~TS:Docuserve-Sidebar-ModuleNav-Section-Template:AppData.Docuserve.ModuleNavSections~}\n\t</div>\n\t<div class=\"docuserve-sidebar-footer\">\n\t\t{~TS:Docuserve-Sidebar-Footer-Template:AppData.Docuserve.FooterSlot~}\n\t</div>\n</div>\n"},{Hash:"Docuserve-Sidebar-Search-Slot-Template",Template:/*html*/"<div id=\"Docuserve-Sidebar-Search\" class=\"docuserve-sidebar-search\">\n\t<input type=\"text\" placeholder=\"Search docs...\" id=\"Docuserve-Sidebar-Search-Input\" oninput=\"{~P~}.views['Docuserve-Sidebar'].onSidebarSearchInput(this.value)\">\n\t<div id=\"Docuserve-Sidebar-Search-Results\" class=\"docuserve-sidebar-search-results\"></div>\n</div>"},{Hash:"Docuserve-Sidebar-Group-Template",Template:/*html*/"<div class=\"docuserve-sidebar-group\">\n\t{~TS:Docuserve-Sidebar-Group-Title-Link-Template:Record.TitleLink~}{~TS:Docuserve-Sidebar-Group-Title-Plain-Template:Record.TitlePlain~}\n\t<ul class=\"docuserve-sidebar-modules\">\n\t\t{~TS:Docuserve-Sidebar-Module-Doc-Template:Record.Modules~}\n\t</ul>\n</div>"},{Hash:"Docuserve-Sidebar-Group-Title-Link-Template",Template:/*html*/"<a class=\"docuserve-sidebar-group-title{~D:Record.ActiveClass~}\" href=\"{~D:Record.Route~}\">{~D:Record.Name~}</a>"},{Hash:"Docuserve-Sidebar-Group-Title-Plain-Template",Template:/*html*/"<div class=\"docuserve-sidebar-group-title\">{~D:Record.Name~}</div>"},{Hash:"Docuserve-Sidebar-Module-Doc-Template",Template:/*html*/"<li>{~TS:Docuserve-Sidebar-Module-Link-Template:Record.LinkSlot~}{~TS:Docuserve-Sidebar-Module-NoDoc-Template:Record.NoDocSlot~}</li>"},{Hash:"Docuserve-Sidebar-Module-Link-Template",Template:/*html*/"<a class=\"{~D:Record.ActiveClass~}\" href=\"{~D:Record.Route~}\">{~D:Record.Name~}</a>"},{Hash:"Docuserve-Sidebar-Module-NoDoc-Template",Template:/*html*/"<span class=\"no-docs\">{~D:Record.Name~}</span>"},{Hash:"Docuserve-Sidebar-ModuleNav-Section-Template",Template:/*html*/"{~TS:Docuserve-Sidebar-ModuleNav-SectionTitle-Template:Record.TitleSlot~}{~TS:Docuserve-Sidebar-ModuleNav-Item-Template:Record.Items~}"},{Hash:"Docuserve-Sidebar-ModuleNav-SectionTitle-Template",Template:/*html*/"<div class=\"docuserve-sidebar-module-nav-section\">{~D:Record.Title~}</div>"},{Hash:"Docuserve-Sidebar-ModuleNav-Item-Template",Template:/*html*/"<a class=\"{~D:Record.ActiveClass~}\" href=\"{~D:Record.Route~}\">{~D:Record.Title~}</a>"},{Hash:"Docuserve-Sidebar-Footer-Template",Template:/*html*/"<div class=\"docuserve-version-placard\">\n\t{~TS:Docuserve-Sidebar-Footer-Name-Template:Record.NameSlot~}\n\t<div class=\"docuserve-version-number\">v{~D:Record.Version~}</div>\n\t{~TS:Docuserve-Sidebar-Footer-Meta-Template:Record.MetaSlot~}\n</div>"},{Hash:"Docuserve-Sidebar-Footer-Name-Template",Template:/*html*/"<div class=\"docuserve-version-name\">{~D:Record.Name~}</div>"},{Hash:"Docuserve-Sidebar-Footer-Meta-Template",Template:/*html*/"<div class=\"docuserve-version-meta\">{~D:Record.Meta~}</div>"},{Hash:"Docuserve-Sidebar-Search-ResultsBody-Template",Template:/*html*/"{~TS:Docuserve-Sidebar-Search-Result-Template:AppData.Docuserve.SidebarSearchResults~}{~TS:Docuserve-Sidebar-Search-Overflow-Template:AppData.Docuserve.SidebarSearchOverflow~}{~TS:Docuserve-Sidebar-Search-Empty-Template:AppData.Docuserve.SidebarSearchEmpty~}"},{Hash:"Docuserve-Sidebar-Search-Result-Template",Template:/*html*/"<a href=\"{~D:Record.Route~}\">\n\t<div class=\"docuserve-sidebar-search-result-title\">{~D:Record.Title~}</div>\n\t{~TS:Docuserve-Sidebar-Search-Result-Meta-Template:Record.MetaSlot~}\n</a>"},{Hash:"Docuserve-Sidebar-Search-Result-Meta-Template",Template:/*html*/"<div class=\"docuserve-sidebar-search-result-meta\">{~D:Record.Meta~}</div>"},{Hash:"Docuserve-Sidebar-Search-Overflow-Template",Template:/*html*/"<a class=\"docuserve-sidebar-search-all\" href=\"#/search/{~D:Record.EncodedQuery~}\">See all {~D:Record.TotalCount~} results</a>"},{Hash:"Docuserve-Sidebar-Search-Empty-Template",Template:/*html*/"<div class=\"docuserve-sidebar-search-empty\">No results found.</div>"}],Renderables:[{RenderableHash:"Docuserve-Sidebar-Content",TemplateHash:"Docuserve-Sidebar-Template",DestinationAddress:"#Docuserve-Sidebar-Container",RenderMethod:"replace"}]};class DocusserveSidebarView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);this._SidebarSearchDebounceTimer=null;}onBeforeRender(pRenderable){// Derive every template-iteration record from raw AppData state.
13895
14245
  // Each refresh writes a single AppData address that drives one
13896
14246
  // {~TS:~} tag in the template tree. Doing this here keeps the
13897
14247
  // public surface tiny — callers just set the navigation state
@@ -13940,9 +14290,23 @@ let tmpGroupRoute=tmpGroup.Route||'';if(!tmpGroupRoute){for(let k=0;k<tmpGroup.M
13940
14290
  // new section each time the title changes.
13941
14291
  if(tmpSidebar&&tmpSidebar.length>0){let tmpCurrentSection=null;for(let i=0;i<tmpSidebar.length;i++){let tmpEntry=tmpSidebar[i];if(tmpEntry.Children){tmpCurrentSection={TitleSlot:[{Title:tmpEntry.Title}],Items:[]};tmpSections.push(tmpCurrentSection);for(let j=0;j<tmpEntry.Children.length;j++){let tmpChild=tmpEntry.Children[j];if(tmpChild.Path){tmpCurrentSection.Items.push({Title:tmpChild.Title,Route:tmpRoutePrefix+tmpChild.Path,ActiveClass:''});}}}else if(tmpEntry.Path){if(!tmpCurrentSection||tmpCurrentSection.TitleSlot.length>0){tmpCurrentSection={TitleSlot:[],Items:[]};tmpSections.push(tmpCurrentSection);}tmpCurrentSection.Items.push({Title:tmpEntry.Title,Route:tmpRoutePrefix+tmpEntry.Path,ActiveClass:''});}}}// Demos sub-section: titled, with active state mirroring the
13942
14292
  // current demo route.
13943
- if(tmpDemos.length>0){let tmpDemoSection={TitleSlot:[{Title:'Demos'}],Items:[]};for(let i=0;i<tmpDemos.length;i++){let tmpDemo=tmpDemos[i];tmpDemoSection.Items.push({Title:tmpDemo.Name||tmpDemo.Hash,Route:tmpDemoPrefix+tmpDemo.Hash,ActiveClass:tmpDemo.Hash===tmpCurrentDemo?'active':''});}tmpSections.push(tmpDemoSection);}this.pict.AppData.Docuserve.ModuleNavSections=tmpSections;}_refreshSearchResults(pQuery){let tmpDocuserve=this.pict.AppData.Docuserve;if(!pQuery||!pQuery.trim()){tmpDocuserve.SidebarSearchResults=[];tmpDocuserve.SidebarSearchOverflow=[];tmpDocuserve.SidebarSearchEmpty=[];return;}let tmpDocProvider=this.pict.providers['Docuserve-Documentation'];let tmpResults=tmpDocProvider.search(pQuery);if(tmpResults.length===0){tmpDocuserve.SidebarSearchResults=[];tmpDocuserve.SidebarSearchOverflow=[];tmpDocuserve.SidebarSearchEmpty=[{}];return;}let tmpMaxResults=8;let tmpDisplayResults=[];for(let i=0;i<tmpResults.length&&i<tmpMaxResults;i++){let tmpResult=tmpResults[i];let tmpMeta=tmpResult.Group&&tmpResult.Module?tmpResult.Group+' / '+tmpResult.Module:'';tmpDisplayResults.push({Title:tmpResult.Title,Route:tmpResult.Route,MetaSlot:tmpMeta?[{Meta:tmpMeta}]:[]});}tmpDocuserve.SidebarSearchResults=tmpDisplayResults;tmpDocuserve.SidebarSearchEmpty=[];if(tmpResults.length>tmpMaxResults){tmpDocuserve.SidebarSearchOverflow=[{EncodedQuery:encodeURIComponent(pQuery),TotalCount:tmpResults.length}];}else{tmpDocuserve.SidebarSearchOverflow=[];}}}module.exports=DocusserveSidebarView;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":231}],359:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"Docuserve-Splash",DefaultRenderable:"Docuserve-Splash-Content",DefaultDestinationAddress:"#Docuserve-Content-Container",AutoRender:false,CSS:/*css*/"\n\t\t.docuserve-splash {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tmin-height: calc(100vh - 56px);\n\t\t\tpadding: 3em 2em;\n\t\t\ttext-align: center;\n\t\t\tbackground: var(--theme-color-background-primary, #FDFBF7);\n\t\t}\n\t\t.docuserve-splash h1 {\n\t\t\tfont-size: 3em;\n\t\t\tfont-weight: 700;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tmargin: 0 0 0.25em 0;\n\t\t}\n\t\t.docuserve-splash h1 small {\n\t\t\tfont-size: 0.4em;\n\t\t\tfont-weight: 400;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tvertical-align: middle;\n\t\t\tmargin-left: 0.15em;\n\t\t}\n\t\t.docuserve-splash-tagline {\n\t\t\tfont-size: 1.25em;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tmargin-bottom: 1.5em;\n\t\t\tfont-style: italic;\n\t\t}\n\t\t.docuserve-splash-description {\n\t\t\tfont-size: 1em;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tmax-width: 600px;\n\t\t\tline-height: 1.7;\n\t\t\tmargin-bottom: 2em;\n\t\t}\n\t\t.docuserve-splash-highlights {\n\t\t\tdisplay: grid;\n\t\t\tgrid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n\t\t\tgap: 1.25em;\n\t\t\tmax-width: 900px;\n\t\t\twidth: 100%;\n\t\t\tmargin-bottom: 2.5em;\n\t\t}\n\t\t.docuserve-splash-highlight-card {\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tborder-radius: 8px;\n\t\t\tpadding: 1.25em;\n\t\t\ttext-align: left;\n\t\t\ttransition: box-shadow 0.2s, border-color 0.2s;\n\t\t}\n\t\t.docuserve-splash-highlight-card:hover {\n\t\t\tbox-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n\t\t\tborder-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-splash-highlight-card h3 {\n\t\t\tmargin: 0 0 0.5em 0;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tfont-size: 1em;\n\t\t}\n\t\t.docuserve-splash-highlight-card p {\n\t\t\tmargin: 0;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tfont-size: 0.85em;\n\t\t\tline-height: 1.5;\n\t\t}\n\t\t.docuserve-splash-actions {\n\t\t\tdisplay: flex;\n\t\t\tgap: 1em;\n\t\t\tflex-wrap: wrap;\n\t\t\tjustify-content: center;\n\t\t}\n\t\t.docuserve-splash-actions a {\n\t\t\tdisplay: inline-block;\n\t\t\tpadding: 0.7em 1.5em;\n\t\t\tborder-radius: 6px;\n\t\t\tfont-size: 0.95em;\n\t\t\tfont-weight: 600;\n\t\t\ttext-decoration: none;\n\t\t\ttransition: background-color 0.15s, color 0.15s;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.docuserve-splash-actions .primary {\n\t\t\tbackground-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t\t/* text-on-brand falls to a fixed light hex \u2014 never to background-panel,\n\t\t\t which inverts contrast in dark themes (dark text on brand bg). */\n\t\t\tcolor: var(--theme-color-text-on-brand, #fff);\n\t\t}\n\t\t.docuserve-splash-actions .primary:hover {\n\t\t\tbackground-color: var(--theme-color-brand-primary-hover, #236660);\n\t\t}\n\t\t.docuserve-splash-actions .secondary {\n\t\t\tbackground-color: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tborder: 2px solid var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-splash-actions .secondary:hover {\n\t\t\tborder-color: var(--theme-color-brand-primary-hover, #236660);\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-splash-examples {\n\t\t\tmax-width: 900px;\n\t\t\twidth: 100%;\n\t\t\tmargin-bottom: 2.5em;\n\t\t}\n\t\t/* No staged examples \u2014 collapse the section entirely. */\n\t\t.docuserve-splash-examples:empty {\n\t\t\tdisplay: none;\n\t\t\tmargin: 0;\n\t\t}\n\t\t.docuserve-splash-examples-heading {\n\t\t\tfont-size: 0.95em;\n\t\t\tfont-weight: 700;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.08em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tmargin: 0 0 0.85em 0;\n\t\t}\n\t\t.docuserve-splash-examples table {\n\t\t\twidth: 100%;\n\t\t\tborder-collapse: collapse;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tborder-radius: 8px;\n\t\t\toverflow: hidden;\n\t\t}\n\t\t.docuserve-splash-examples thead th {\n\t\t\ttext-align: left;\n\t\t\tfont-size: 0.72em;\n\t\t\tfont-weight: 700;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.06em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tpadding: 0.7em 1.1em;\n\t\t\tbackground: var(--theme-color-background-tertiary, #F4EFE6);\n\t\t}\n\t\t.docuserve-splash-examples tbody td {\n\t\t\tpadding: 0.7em 1.1em;\n\t\t\tborder-top: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tfont-size: 0.9em;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\ttext-align: left;\n\t\t}\n\t\t.docuserve-splash-examples tbody tr:hover td {\n\t\t\tbackground: var(--theme-color-background-tertiary, #F4EFE6);\n\t\t}\n\t\t.docuserve-splash-examples a {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tfont-weight: 600;\n\t\t\ttext-decoration: none;\n\t\t}\n\t\t.docuserve-splash-examples a:hover {\n\t\t\ttext-decoration: underline;\n\t\t}\n\t\t/* docs/README.md content rendered beneath the hero. */\n\t\t.docuserve-splash-readme {\n\t\t\tmax-width: 820px;\n\t\t\tmargin: 0 auto;\n\t\t\tpadding: 3.5em 2em 5em 2em;\n\t\t\ttext-align: left;\n\t\t}\n\t\t.docuserve-splash-readme:empty {\n\t\t\tdisplay: none;\n\t\t}\n\t",Templates:[{Hash:"Docuserve-Splash-Template",Template:/*html*/"\n<div class=\"docuserve-splash\">\n\t<h1 id=\"Docuserve-Splash-Title\"></h1>\n\t<div class=\"docuserve-splash-tagline\" id=\"Docuserve-Splash-Tagline\"></div>\n\t<div class=\"docuserve-splash-description\" id=\"Docuserve-Splash-Description\"></div>\n\t<div class=\"docuserve-splash-highlights\" id=\"Docuserve-Splash-Highlights\"></div>\n\t<div class=\"docuserve-splash-examples\" id=\"Docuserve-Splash-Examples\"></div>\n\t<div class=\"docuserve-splash-actions\" id=\"Docuserve-Splash-Actions\"></div>\n</div>\n<div class=\"docuserve-splash-readme\" id=\"Docuserve-Splash-Readme\"></div>\n"}],Renderables:[{RenderableHash:"Docuserve-Splash-Content",TemplateHash:"Docuserve-Splash-Template",DestinationAddress:"#Docuserve-Content-Container",RenderMethod:"replace"}]};class DocusserveSplashView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);}onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent){let tmpDocuserve=this.pict.AppData.Docuserve;if(tmpDocuserve.CoverLoaded&&tmpDocuserve.Cover){this.renderFromCover(tmpDocuserve.Cover);this.renderExamples(tmpDocuserve.Cover);}else{this.renderFromCatalog(tmpDocuserve);}// Render docs/README.md beneath the hero the splash fills the
14293
+ if(tmpDemos.length>0){let tmpDemoSection={TitleSlot:[{Title:'Demos'}],Items:[]};for(let i=0;i<tmpDemos.length;i++){let tmpDemo=tmpDemos[i];tmpDemoSection.Items.push({Title:tmpDemo.Name||tmpDemo.Hash,Route:tmpDemoPrefix+tmpDemo.Hash,ActiveClass:tmpDemo.Hash===tmpCurrentDemo?'active':''});}tmpSections.push(tmpDemoSection);}this.pict.AppData.Docuserve.ModuleNavSections=tmpSections;}_refreshSearchResults(pQuery){let tmpDocuserve=this.pict.AppData.Docuserve;if(!pQuery||!pQuery.trim()){tmpDocuserve.SidebarSearchResults=[];tmpDocuserve.SidebarSearchOverflow=[];tmpDocuserve.SidebarSearchEmpty=[];return;}let tmpDocProvider=this.pict.providers['Docuserve-Documentation'];let tmpResults=tmpDocProvider.search(pQuery);if(tmpResults.length===0){tmpDocuserve.SidebarSearchResults=[];tmpDocuserve.SidebarSearchOverflow=[];tmpDocuserve.SidebarSearchEmpty=[{}];return;}let tmpMaxResults=8;let tmpDisplayResults=[];for(let i=0;i<tmpResults.length&&i<tmpMaxResults;i++){let tmpResult=tmpResults[i];let tmpMeta=tmpResult.Group&&tmpResult.Module?tmpResult.Group+' / '+tmpResult.Module:'';tmpDisplayResults.push({Title:tmpResult.Title,Route:tmpResult.Route,MetaSlot:tmpMeta?[{Meta:tmpMeta}]:[]});}tmpDocuserve.SidebarSearchResults=tmpDisplayResults;tmpDocuserve.SidebarSearchEmpty=[];if(tmpResults.length>tmpMaxResults){tmpDocuserve.SidebarSearchOverflow=[{EncodedQuery:encodeURIComponent(pQuery),TotalCount:tmpResults.length}];}else{tmpDocuserve.SidebarSearchOverflow=[];}}}module.exports=DocusserveSidebarView;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":231}],360:[function(require,module,exports){const libPictView=require('pict-view');const _ViewConfiguration={ViewIdentifier:"Docuserve-Splash",DefaultRenderable:"Docuserve-Splash-Content",DefaultDestinationAddress:"#Docuserve-Content-Container",AutoRender:false,CSS:/*css*/"\n\t\t.docuserve-splash {\n\t\t\tdisplay: flex;\n\t\t\tflex-direction: column;\n\t\t\talign-items: center;\n\t\t\tjustify-content: center;\n\t\t\tmin-height: calc(100vh - 56px);\n\t\t\tpadding: 3em 2em;\n\t\t\ttext-align: center;\n\t\t\tbackground: var(--theme-color-background-primary, #FDFBF7);\n\t\t}\n\t\t.docuserve-splash h1 {\n\t\t\tfont-size: 3em;\n\t\t\tfont-weight: 700;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tmargin: 0 0 0.25em 0;\n\t\t}\n\t\t.docuserve-splash h1 small {\n\t\t\tfont-size: 0.4em;\n\t\t\tfont-weight: 400;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tvertical-align: middle;\n\t\t\tmargin-left: 0.15em;\n\t\t}\n\t\t.docuserve-splash-tagline {\n\t\t\tfont-size: 1.25em;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tmargin-bottom: 1.5em;\n\t\t\tfont-style: italic;\n\t\t}\n\t\t.docuserve-splash-description {\n\t\t\tfont-size: 1em;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tmax-width: 600px;\n\t\t\tline-height: 1.7;\n\t\t\tmargin-bottom: 2em;\n\t\t}\n\t\t.docuserve-splash-highlights {\n\t\t\tdisplay: grid;\n\t\t\tgrid-template-columns: repeat(auto-fit, minmax(200px, 1fr));\n\t\t\tgap: 1.25em;\n\t\t\tmax-width: 900px;\n\t\t\twidth: 100%;\n\t\t\tmargin-bottom: 2.5em;\n\t\t}\n\t\t.docuserve-splash-highlight-card {\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tborder-radius: 8px;\n\t\t\tpadding: 1.25em;\n\t\t\ttext-align: left;\n\t\t\ttransition: box-shadow 0.2s, border-color 0.2s;\n\t\t}\n\t\t.docuserve-splash-highlight-card:hover {\n\t\t\tbox-shadow: 0 4px 16px rgba(0, 0, 0, 0.12);\n\t\t\tborder-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-splash-highlight-card h3 {\n\t\t\tmargin: 0 0 0.5em 0;\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tfont-size: 1em;\n\t\t}\n\t\t.docuserve-splash-highlight-card p {\n\t\t\tmargin: 0;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\tfont-size: 0.85em;\n\t\t\tline-height: 1.5;\n\t\t}\n\t\t.docuserve-splash-actions {\n\t\t\tdisplay: flex;\n\t\t\tgap: 1em;\n\t\t\tflex-wrap: wrap;\n\t\t\tjustify-content: center;\n\t\t}\n\t\t.docuserve-splash-actions a {\n\t\t\tdisplay: inline-block;\n\t\t\tpadding: 0.7em 1.5em;\n\t\t\tborder-radius: 6px;\n\t\t\tfont-size: 0.95em;\n\t\t\tfont-weight: 600;\n\t\t\ttext-decoration: none;\n\t\t\ttransition: background-color 0.15s, color 0.15s;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.docuserve-splash-actions .primary {\n\t\t\tbackground-color: var(--theme-color-brand-primary, #2E7D74);\n\t\t\t/* text-on-brand falls to a fixed light hex \u2014 never to background-panel,\n\t\t\t which inverts contrast in dark themes (dark text on brand bg). */\n\t\t\tcolor: var(--theme-color-text-on-brand, #fff);\n\t\t}\n\t\t.docuserve-splash-actions .primary:hover {\n\t\t\tbackground-color: var(--theme-color-brand-primary-hover, #236660);\n\t\t}\n\t\t.docuserve-splash-actions .secondary {\n\t\t\tbackground-color: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tcolor: var(--theme-color-text-primary, #3D3229);\n\t\t\tborder: 2px solid var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-splash-actions .secondary:hover {\n\t\t\tborder-color: var(--theme-color-brand-primary-hover, #236660);\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t}\n\t\t.docuserve-splash-examples {\n\t\t\tmax-width: 900px;\n\t\t\twidth: 100%;\n\t\t\tmargin-bottom: 2.5em;\n\t\t}\n\t\t/* No staged examples \u2014 collapse the section entirely. */\n\t\t.docuserve-splash-examples:empty {\n\t\t\tdisplay: none;\n\t\t\tmargin: 0;\n\t\t}\n\t\t.docuserve-splash-examples-heading {\n\t\t\tfont-size: 0.95em;\n\t\t\tfont-weight: 700;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.08em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tmargin: 0 0 0.85em 0;\n\t\t}\n\t\t.docuserve-splash-examples table {\n\t\t\twidth: 100%;\n\t\t\tborder-collapse: collapse;\n\t\t\tbackground: var(--theme-color-background-panel, #FFFFFF);\n\t\t\tborder: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tborder-radius: 8px;\n\t\t\toverflow: hidden;\n\t\t}\n\t\t.docuserve-splash-examples thead th {\n\t\t\ttext-align: left;\n\t\t\tfont-size: 0.72em;\n\t\t\tfont-weight: 700;\n\t\t\ttext-transform: uppercase;\n\t\t\tletter-spacing: 0.06em;\n\t\t\tcolor: var(--theme-color-text-muted, #8A7F72);\n\t\t\tpadding: 0.7em 1.1em;\n\t\t\tbackground: var(--theme-color-background-tertiary, #F4EFE6);\n\t\t}\n\t\t.docuserve-splash-examples tbody td {\n\t\t\tpadding: 0.7em 1.1em;\n\t\t\tborder-top: 1px solid var(--theme-color-border-default, #DDD6CA);\n\t\t\tfont-size: 0.9em;\n\t\t\tcolor: var(--theme-color-text-secondary, #5E5549);\n\t\t\ttext-align: left;\n\t\t}\n\t\t.docuserve-splash-examples tbody tr:hover td {\n\t\t\tbackground: var(--theme-color-background-tertiary, #F4EFE6);\n\t\t}\n\t\t.docuserve-splash-examples a {\n\t\t\tcolor: var(--theme-color-brand-primary, #2E7D74);\n\t\t\tfont-weight: 600;\n\t\t\ttext-decoration: none;\n\t\t}\n\t\t.docuserve-splash-examples a:hover {\n\t\t\ttext-decoration: underline;\n\t\t}\n\t\t/* docs/README.md content rendered beneath the hero. */\n\t\t.docuserve-splash-readme {\n\t\t\tmax-width: 820px;\n\t\t\tmargin: 0 auto;\n\t\t\tpadding: 3.5em 2em 5em 2em;\n\t\t\ttext-align: left;\n\t\t}\n\t\t.docuserve-splash-readme:empty {\n\t\t\tdisplay: none;\n\t\t}\n\t",Templates:[{Hash:"Docuserve-Splash-Template",Template:/*html*/"\n<div class=\"docuserve-splash\">\n\t<h1 id=\"Docuserve-Splash-Title\"></h1>\n\t<div class=\"docuserve-splash-tagline\" id=\"Docuserve-Splash-Tagline\"></div>\n\t<div class=\"docuserve-splash-description\" id=\"Docuserve-Splash-Description\"></div>\n\t<div class=\"docuserve-splash-highlights\" id=\"Docuserve-Splash-Highlights\"></div>\n\t<div class=\"docuserve-splash-examples\" id=\"Docuserve-Splash-Examples\"></div>\n\t<div class=\"docuserve-splash-actions\" id=\"Docuserve-Splash-Actions\"></div>\n</div>\n<div class=\"docuserve-splash-readme\" id=\"Docuserve-Splash-Readme\"></div>\n"}],Renderables:[{RenderableHash:"Docuserve-Splash-Content",TemplateHash:"Docuserve-Splash-Template",DestinationAddress:"#Docuserve-Content-Container",RenderMethod:"replace"}]};class DocusserveSplashView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);}onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent){let tmpDocuserve=this.pict.AppData.Docuserve;if(tmpDocuserve.CoverLoaded&&tmpDocuserve.Cover){this.renderFromCover(tmpDocuserve.Cover);this.renderExamples(tmpDocuserve.Cover);}else{this.renderFromCatalog(tmpDocuserve);}// Conditionally append a "Playground" button to the action row when
14294
+ // the current module ships a _playground.json. Async — the button
14295
+ // pops in once the config resolves.
14296
+ this.renderPlaygroundButton();// Render docs/README.md beneath the hero — the splash fills the
13944
14297
  // viewport above the fold, the README content follows on scroll.
13945
14298
  this.renderReadme();return super.onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent);}/**
14299
+ * Append a "Playground" button to the splash action row when the
14300
+ * current module declares a playground in `_playground.json`. The
14301
+ * route depends on `Kind`:
14302
+ * - Kind: "section" → full-page section playground
14303
+ * - anything else → Fable JS REPL drawer
14304
+ *
14305
+ * When no `_playground.json` exists (loadPlaygroundConfig resolves
14306
+ * to null), no button is added — the existing GitHub / Get Started
14307
+ * buttons stand on their own.
14308
+ */renderPlaygroundButton(){let tmpDocProvider=this.pict.providers['Docuserve-Documentation'];if(!tmpDocProvider||typeof tmpDocProvider.loadPlaygroundConfig!=='function'){return;}let tmpAppData=this.pict.AppData.Docuserve||{};let tmpGroup=tmpAppData.CurrentGroup||'';let tmpModule=tmpAppData.CurrentModule||'';tmpDocProvider.loadPlaygroundConfig(tmpGroup,tmpModule).then(pConfig=>{if(!pConfig){return;}let tmpRoute;if(pConfig.Kind==='section'){tmpRoute=tmpGroup&&tmpModule?'#/playground/section/'+tmpGroup+'/'+tmpModule:'#/playground/section';}else{tmpRoute='#/playground/fable';}let tmpButtonHTML='<a class="secondary" href="'+this.escapeHTML(tmpRoute)+'">Playground</a>';this.pict.ContentAssignment.projectContent('append','#Docuserve-Splash-Actions',tmpButtonHTML);}).catch(()=>{// Soft failure — no button is added when the config can't load.
14309
+ });}/**
13946
14310
  * Render the splash screen from parsed _cover.md data.
13947
14311
  *
13948
14312
  * @param {Object} pCover - The parsed cover data { Title, Tagline, Description, Highlights, Actions }
@@ -13982,14 +14346,14 @@ return this.escapeHTML(pText).replace(/&lt;small&gt;/gi,'<small>').replace(/&lt;
13982
14346
  *
13983
14347
  * @param {string} pText - The text to escape
13984
14348
  * @returns {string} The escaped text
13985
- */escapeHTML(pText){if(!pText){return'';}return pText.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}}module.exports=DocusserveSplashView;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":231}],360:[function(require,module,exports){const libPictView=require('pict-view');/**
14349
+ */escapeHTML(pText){if(!pText){return'';}return pText.replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;');}}module.exports=DocusserveSplashView;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":231}],361:[function(require,module,exports){const libPictView=require('pict-view');/**
13986
14350
  * PictView-Docuserve-TopBar-Nav — slot view rendered into Theme-TopBar's
13987
14351
  * NavView slot. Hosts navigation links (Home + any links declared in
13988
14352
  * _topbar.md) and the version chip (sourced from _version.json).
13989
14353
  *
13990
14354
  * Re-renders on demand when AppData.Docuserve.TopBar / Version data
13991
14355
  * is loaded by the documentation provider.
13992
- */const _ViewConfiguration={ViewIdentifier:"Docuserve-TopBar-Nav",DefaultRenderable:"Docuserve-TopBar-Nav-Display",DefaultDestinationAddress:"#Theme-TopBar-Nav",AutoRender:false,CSS:/*css*/"\n\t\t.docuserve-nav\n\t\t{\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\theight: 100%;\n\t\t\tgap: 0.6em;\n\t\t\tpadding: 0 0.75em;\n\t\t\tcolor: var(--theme-color-text-on-brand, var(--theme-color-text-primary, #E8E0D4));\n\t\t}\n\t\t.docuserve-nav-links\n\t\t{\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.25em;\n\t\t}\n\t\t.docuserve-nav-links a\n\t\t{\n\t\t\tcolor: var(--theme-color-text-on-brand, var(--theme-color-text-primary, #E8E0D4));\n\t\t\ttext-decoration: none;\n\t\t\tpadding: 0.45em 0.7em;\n\t\t\tborder-radius: 4px;\n\t\t\tfont-size: 0.9em;\n\t\t\ttransition: background-color 0.15s, color 0.15s;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.docuserve-nav-links a:hover\n\t\t{\n\t\t\tbackground-color: var(--theme-color-background-hover, rgba(255, 255, 255, 0.06));\n\t\t\t/* Keep the text token chain on hover \u2014 falling to background-panel\n\t\t\t here inverts contrast (dark text on dark hover) in themes that\n\t\t\t don't define text-on-brand (e.g. night, twilight). */\n\t\t\tcolor: var(--theme-color-text-on-brand, var(--theme-color-text-primary, #ffffff));\n\t\t}\n\t\t.docuserve-nav-version\n\t\t{\n\t\t\tfont-size: 0.72em;\n\t\t\tfont-weight: 500;\n\t\t\tcolor: var(--theme-color-text-on-brand, var(--theme-color-text-muted, #B5AA9A));\n\t\t\tbackground: var(--theme-color-background-hover, rgba(255, 255, 255, 0.06));\n\t\t\tborder: 1px solid var(--theme-color-border-light, rgba(255, 255, 255, 0.08));\n\t\t\tpadding: 0.12em 0.55em;\n\t\t\tborder-radius: 10px;\n\t\t\tfont-family: var(--theme-typography-family-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);\n\t\t\tletter-spacing: 0.02em;\n\t\t\twhite-space: nowrap;\n\t\t}\n\t\t.docuserve-nav-version:empty\n\t\t{\n\t\t\tdisplay: none;\n\t\t}\n\t",Templates:[{Hash:"Docuserve-TopBar-Nav-Template",Template:/*html*/"\n<div class=\"docuserve-nav\">\n\t<div id=\"Docuserve-Nav-Links\" class=\"docuserve-nav-links\"></div>\n\t<span id=\"Docuserve-Nav-Version\" class=\"docuserve-nav-version\" title=\"\"></span>\n</div>"}],Renderables:[{RenderableHash:"Docuserve-TopBar-Nav-Display",TemplateHash:"Docuserve-TopBar-Nav-Template",DestinationAddress:"#Theme-TopBar-Nav",RenderMethod:"replace"}]};class DocuserveTopBarNavView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);}onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent){this.pict.CSSMap.injectCSS();this._renderNavLinks();this._renderVersionChip();return super.onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent);}_renderNavLinks(){let tmpDocuserve=this.pict.AppData.Docuserve||{};let tmpLinksEl=document.getElementById('Docuserve-Nav-Links');if(!tmpLinksEl){return;}let tmpHTML='<a href="#/Home">Home</a>';if(tmpDocuserve.TopBarLoaded&&tmpDocuserve.TopBar&&Array.isArray(tmpDocuserve.TopBar.NavLinks)){for(let i=0;i<tmpDocuserve.TopBar.NavLinks.length;i++){let tmpLink=tmpDocuserve.TopBar.NavLinks[i];tmpHTML+='<a href="'+this._escapeHTML(tmpLink.Href||'#')+'">'+this._escapeHTML(tmpLink.Text||'')+'</a>';}}tmpLinksEl.innerHTML=tmpHTML;}_renderVersionChip(){let tmpDocuserve=this.pict.AppData.Docuserve||{};let tmpEl=document.getElementById('Docuserve-Nav-Version');if(!tmpEl){return;}if(!tmpDocuserve.VersionLoaded||!tmpDocuserve.Version||!tmpDocuserve.Version.Version){tmpEl.innerHTML='';tmpEl.setAttribute('title','');return;}let tmpVersion=tmpDocuserve.Version;tmpEl.innerHTML='v'+this._escapeHTML(tmpVersion.Version);let tmpTooltipParts=[];tmpTooltipParts.push((tmpVersion.Name?tmpVersion.Name+' ':'')+'v'+tmpVersion.Version);if(tmpVersion.GeneratedAt){let tmpMatch=String(tmpVersion.GeneratedAt).match(/^(\d{4}-\d{2}-\d{2})/);tmpTooltipParts.push('built '+(tmpMatch?tmpMatch[1]:tmpVersion.GeneratedAt));}if(tmpVersion.GitCommit){tmpTooltipParts.push(tmpVersion.GitCommit);}tmpEl.setAttribute('title',tmpTooltipParts.join(' · '));}_escapeHTML(pText){if(pText==null){return'';}return String(pText).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;').replace(/'/g,'&#39;');}}module.exports=DocuserveTopBarNavView;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":231}],361:[function(require,module,exports){const libPictView=require('pict-view');/**
14356
+ */const _ViewConfiguration={ViewIdentifier:"Docuserve-TopBar-Nav",DefaultRenderable:"Docuserve-TopBar-Nav-Display",DefaultDestinationAddress:"#Theme-TopBar-Nav",AutoRender:false,CSS:/*css*/"\n\t\t.docuserve-nav\n\t\t{\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\theight: 100%;\n\t\t\tgap: 0.6em;\n\t\t\tpadding: 0 0.75em;\n\t\t\tcolor: var(--theme-color-text-on-brand, var(--theme-color-text-primary, #E8E0D4));\n\t\t}\n\t\t.docuserve-nav-links\n\t\t{\n\t\t\tdisplay: flex;\n\t\t\talign-items: center;\n\t\t\tgap: 0.25em;\n\t\t}\n\t\t.docuserve-nav-links a\n\t\t{\n\t\t\tcolor: var(--theme-color-text-on-brand, var(--theme-color-text-primary, #E8E0D4));\n\t\t\ttext-decoration: none;\n\t\t\tpadding: 0.45em 0.7em;\n\t\t\tborder-radius: 4px;\n\t\t\tfont-size: 0.9em;\n\t\t\ttransition: background-color 0.15s, color 0.15s;\n\t\t\tcursor: pointer;\n\t\t}\n\t\t.docuserve-nav-links a:hover\n\t\t{\n\t\t\tbackground-color: var(--theme-color-background-hover, rgba(255, 255, 255, 0.06));\n\t\t\t/* Keep the text token chain on hover \u2014 falling to background-panel\n\t\t\t here inverts contrast (dark text on dark hover) in themes that\n\t\t\t don't define text-on-brand (e.g. night, twilight). */\n\t\t\tcolor: var(--theme-color-text-on-brand, var(--theme-color-text-primary, #ffffff));\n\t\t}\n\t\t.docuserve-nav-version\n\t\t{\n\t\t\tfont-size: 0.72em;\n\t\t\tfont-weight: 500;\n\t\t\tcolor: var(--theme-color-text-on-brand, var(--theme-color-text-muted, #B5AA9A));\n\t\t\tbackground: var(--theme-color-background-hover, rgba(255, 255, 255, 0.06));\n\t\t\tborder: 1px solid var(--theme-color-border-light, rgba(255, 255, 255, 0.08));\n\t\t\tpadding: 0.12em 0.55em;\n\t\t\tborder-radius: 10px;\n\t\t\tfont-family: var(--theme-typography-family-mono, ui-monospace, SFMono-Regular, Menlo, Consolas, monospace);\n\t\t\tletter-spacing: 0.02em;\n\t\t\twhite-space: nowrap;\n\t\t}\n\t\t.docuserve-nav-version:empty\n\t\t{\n\t\t\tdisplay: none;\n\t\t}\n\t",Templates:[{Hash:"Docuserve-TopBar-Nav-Template",Template:/*html*/"\n<div class=\"docuserve-nav\">\n\t<div id=\"Docuserve-Nav-Links\" class=\"docuserve-nav-links\"></div>\n\t<span id=\"Docuserve-Nav-Version\" class=\"docuserve-nav-version\" title=\"\"></span>\n</div>"}],Renderables:[{RenderableHash:"Docuserve-TopBar-Nav-Display",TemplateHash:"Docuserve-TopBar-Nav-Template",DestinationAddress:"#Theme-TopBar-Nav",RenderMethod:"replace"}]};class DocuserveTopBarNavView extends libPictView{constructor(pFable,pOptions,pServiceHash){super(pFable,pOptions,pServiceHash);}onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent){this.pict.CSSMap.injectCSS();this._renderNavLinks();this._renderVersionChip();return super.onAfterRender(pRenderable,pRenderDestinationAddress,pRecord,pContent);}_renderNavLinks(){let tmpDocuserve=this.pict.AppData.Docuserve||{};let tmpLinksEl=document.getElementById('Docuserve-Nav-Links');if(!tmpLinksEl){return;}let tmpHTML='<a href="#/Home">Home</a>';if(tmpDocuserve.TopBarLoaded&&tmpDocuserve.TopBar&&Array.isArray(tmpDocuserve.TopBar.NavLinks)){for(let i=0;i<tmpDocuserve.TopBar.NavLinks.length;i++){let tmpLink=tmpDocuserve.TopBar.NavLinks[i];tmpHTML+='<a href="'+this._escapeHTML(tmpLink.Href||'#')+'">'+this._escapeHTML(tmpLink.Text||'')+'</a>';}}tmpLinksEl.innerHTML=tmpHTML;}_renderVersionChip(){let tmpDocuserve=this.pict.AppData.Docuserve||{};let tmpEl=document.getElementById('Docuserve-Nav-Version');if(!tmpEl){return;}if(!tmpDocuserve.VersionLoaded||!tmpDocuserve.Version||!tmpDocuserve.Version.Version){tmpEl.innerHTML='';tmpEl.setAttribute('title','');return;}let tmpVersion=tmpDocuserve.Version;tmpEl.innerHTML='v'+this._escapeHTML(tmpVersion.Version);let tmpTooltipParts=[];tmpTooltipParts.push((tmpVersion.Name?tmpVersion.Name+' ':'')+'v'+tmpVersion.Version);if(tmpVersion.GeneratedAt){let tmpMatch=String(tmpVersion.GeneratedAt).match(/^(\d{4}-\d{2}-\d{2})/);tmpTooltipParts.push('built '+(tmpMatch?tmpMatch[1]:tmpVersion.GeneratedAt));}if(tmpVersion.GitCommit){tmpTooltipParts.push(tmpVersion.GitCommit);}tmpEl.setAttribute('title',tmpTooltipParts.join(' · '));}_escapeHTML(pText){if(pText==null){return'';}return String(pText).replace(/&/g,'&amp;').replace(/</g,'&lt;').replace(/>/g,'&gt;').replace(/"/g,'&quot;').replace(/'/g,'&#39;');}}module.exports=DocuserveTopBarNavView;module.exports.default_configuration=_ViewConfiguration;},{"pict-view":231}],362:[function(require,module,exports){const libPictView=require('pict-view');/**
13993
14357
  * PictView-Docuserve-TopBar-User — slot view rendered into Theme-TopBar's
13994
14358
  * UserView slot. Hosts the Search link (when a keyword index is loaded)
13995
14359
  * and any external links declared in _topbar.md.