domma-cms 0.95.0 → 0.97.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -1 +1 @@
1
- .dashboard-layout{display:flex;flex-direction:column;height:100vh;min-height:100vh;overflow:hidden}.dashboard-wrapper{display:flex;flex:1;min-height:0;overflow:hidden}.dashboard-main{flex:1;min-width:0;overflow-y:auto}#admin-sidebar.dashboard-sidebar{display:flex;flex-direction:column;flex-shrink:0;overflow:hidden}#admin-sidebar .dm-admin-sidebar{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--dm-border) transparent}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar{width:8px}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-track{background:transparent}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-thumb{background:var(--dm-border);border-radius:4px}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-thumb:hover{background:var(--dm-text-muted)}.view-container{padding:1.5rem 2rem;max-width:1200px}.view-container:has(>.dm-plugin-shell){max-width:100%}.view-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem}.view-header h1{font-size:1.5rem;font-weight:700;margin:0;display:flex;align-items:center;gap:.5rem}.view-header-actions{display:flex;gap:.75rem;flex-wrap:wrap}.view-header-actions .btn-primary,.view-header-actions .btn-success,.view-header-actions .btn-danger{margin-left:.5rem}.stat-card .card-body{display:flex;align-items:center;gap:1rem}.stat-icon{width:44px;height:44px;border-radius:8px;background:color-mix(in srgb,var(--dm-primary) 14%,transparent);color:var(--dm-primary, #5b8cff);display:flex;align-items:center;justify-content:center;font-size:1.25rem;flex-shrink:0}.stat-icon--success{background:color-mix(in srgb,var(--dm-success) 15%,transparent);color:var(--dm-success)}.stat-icon--warning{background:color-mix(in srgb,var(--dm-warning) 15%,transparent);color:var(--dm-warning)}.stat-value{font-size:1.75rem;font-weight:700;line-height:1}.stat-label{font-size:.8rem;color:var(--dm-text-muted, #888);margin-top:.25rem}.toolbar{display:flex;align-items:center;gap:.75rem}.form-check-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.9rem}.form-hint{display:block;font-size:.8rem;color:var(--dm-text-muted, #888);margin-top:.25rem}.dashboard-main:has(#editor-meta-tabs){overflow:hidden}.view-container:has(#editor-meta-tabs){display:flex;flex-direction:column;height:calc(100dvh - 60px);max-width:100%;padding-bottom:0}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell{flex:1;min-height:0;display:flex;flex-direction:column}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell>.dm-plugin-banner,.view-container:has(#editor-meta-tabs) .pex-bar{flex:none}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell>.dm-plugin-body{flex:1;min-height:0;display:flex;flex-direction:column}.view-container:has(#block-editor-body){max-width:100%}.view-container:has(#ep-editor-tabs){max-width:100%}.ep-editor-grid{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr) minmax(0,1.3fr);gap:1rem;align-items:start}.ep-editor-grid>.ep-tryit-col,.ep-editor-grid>.ep-results-col{position:sticky;top:1rem;display:flex;flex-direction:column;gap:1rem;min-width:0}@media(max-width:1500px){.ep-editor-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.ep-editor-grid>:first-child{grid-column:1 / -1}.ep-editor-grid>.ep-tryit-col,.ep-editor-grid>.ep-results-col{position:static}}@media(max-width:1024px){.ep-editor-grid{grid-template-columns:minmax(0,1fr)}}#editor-meta-tabs{flex:1;min-height:0;display:flex;flex-direction:column}#editor-meta-tabs .tab-content{flex:1;min-height:0;overflow:hidden}#editor-meta-tabs .tab-panel{height:100%;overflow-y:auto}#editor-meta-tabs .tab-panel:has(.editor-card),#live-preview-panel{overflow:hidden}.live-preview-bar{display:flex;align-items:center;gap:var(--dm-space-4);flex-wrap:wrap;padding:var(--dm-space-2) 0;border-bottom:1px solid var(--dm-border);margin-bottom:var(--dm-space-2)}.live-preview-widths{display:inline-flex;border:1px solid var(--dm-border);border-radius:var(--dm-radius-sm);overflow:hidden}.live-preview-width{display:inline-flex;align-items:center;justify-content:center;padding:.3rem .55rem;border:none;background:transparent;color:inherit;cursor:pointer;line-height:1}.live-preview-width+.live-preview-width{border-left:1px solid var(--dm-border)}.live-preview-width:hover{background:var(--dm-hover-bg)}.live-preview-width.active{background:var(--dm-active-bg)}.live-preview-status{flex:1 1 auto;font-size:.8rem;opacity:.75}.live-preview-actions{display:flex;gap:var(--dm-space-1)}.live-preview-wrap{display:flex;flex-direction:column;height:100%;min-height:0}.live-preview-wrap>.live-preview-bar{flex:none}.live-preview-stage{display:flex;justify-content:center;flex:1;min-height:0;overflow:auto;background:var(--dm-background-alt);border-radius:var(--dm-radius-md)}.page-live-preview-frame{display:block;width:100%;max-width:100%;height:100%;border:none;border-radius:6px;background:var(--dm-background);transition:max-width .18s ease}.page-live-preview-frame[data-width="1024"]{max-width:1024px}.page-live-preview-frame[data-width="390"]{max-width:390px}.page-live-preview-frame[data-width="1024"],.page-live-preview-frame[data-width="390"]{border-left:1px solid var(--dm-border);border-right:1px solid var(--dm-border)}.editor-card{display:flex;flex-direction:column;height:100%}.editor-card .card-body{display:flex;flex-direction:column;flex:1;min-height:0;padding:0!important}.editor-toolbar{display:flex;align-items:center;gap:2px;padding:6px 10px;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .08));flex-wrap:wrap;flex-shrink:0}.editor-toolbar-btn{background:none;border:none;color:var(--dm-text-muted, #888);padding:6px 8px;border-radius:4px;cursor:pointer;display:flex;align-items:center;transition:color .15s,background .15s}.editor-toolbar-btn:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.editor-toolbar-sep{width:1px;height:20px;background:var(--dm-border, rgba(255, 255, 255, .08));margin:0 4px;flex-shrink:0}.editor-toolbar-right{margin-left:auto;display:flex;align-items:center;gap:2px}.editor-view-btn{background:none;border:none;color:var(--dm-text-muted, #888);padding:6px 8px;border-radius:4px;cursor:pointer;display:flex;align-items:center;transition:color .15s,background .15s}.editor-view-btn:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.editor-view-btn.active{color:var(--dm-primary, #5b8cff);background:color-mix(in srgb,var(--dm-primary) 14%,transparent)}.editor-body{display:flex;flex:1;min-height:0;--dm-editor-split: 50%}@media(min-width:769px){.editor-body:not(.editor-mode-write):not(.editor-mode-preview) .editor-pane--write{flex:0 0 var(--dm-editor-split, 50%)}.editor-body:not(.editor-mode-write):not(.editor-mode-preview) .editor-pane--preview{flex:1 1 0}}.editor-pane{flex:1;display:flex;flex-direction:column;min-width:0}.editor-pane--write,.editor-pane--preview{overflow:hidden}.editor-pane--write{flex-direction:row}.editor-line-numbers{padding:1rem .6rem 1rem .75rem;background:var(--dm-background-alt, rgba(0, 0, 0, .15));border-right:1px solid var(--dm-border, rgba(255, 255, 255, .08));color:var(--dm-text-muted, #666);font-family:Fira Code,Courier New,monospace;font-size:.9rem;line-height:1.6;text-align:right;user-select:none;white-space:pre;overflow:hidden;flex-shrink:0;min-width:2.5rem}.editor-line-numbers--foldable{padding:1rem 0;min-width:3rem;white-space:normal;text-align:left;display:flex;flex-direction:column}.editor-line-number-row{display:flex;align-items:center;justify-content:flex-end;padding-right:.6rem;gap:.15rem}.fold-toggle{display:inline-flex;align-items:center;justify-content:center;width:1em;font-size:.6rem;cursor:default;color:transparent}.fold-toggle--open,.fold-toggle--folded{cursor:pointer;color:var(--dm-text-muted, #666);transition:color .1s}.fold-toggle--open:hover,.fold-toggle--folded:hover{color:var(--dm-primary, #4a9eff)}.editor-line-num{min-width:1.5rem;text-align:right}.editor-mode-write .editor-pane--preview,.editor-mode-write .editor-divider,.editor-mode-preview .editor-pane--write,.editor-mode-preview .editor-divider{display:none}.editor-divider{width:7px;background:linear-gradient(to right,transparent 0,transparent 3px,var(--dm-border, rgba(255,255,255,.08)) 3px,var(--dm-border, rgba(255,255,255,.08)) 4px,transparent 4px,transparent 100%);cursor:col-resize;flex-shrink:0;touch-action:none;transition:background .12s ease}.editor-divider:hover,.editor-divider:focus-visible,.editor-divider.is-dragging{background:linear-gradient(to right,transparent 0,transparent 2px,var(--dm-primary, #5b8cff) 2px,var(--dm-primary, #5b8cff) 5px,transparent 5px,transparent 100%);outline:none}.editor-body.is-resizing .editor-pane{pointer-events:none}.editor-body.is-resizing{cursor:col-resize;user-select:none}.editor-textarea{flex:1;resize:none;border:none;border-radius:0;background:transparent;font-family:Fira Code,Courier New,monospace;font-size:.9rem;padding:1rem;outline:none;color:inherit;line-height:1.6}#editor-body .editor-textarea,#editor-body .editor-line-numbers{font-family:var(--pe-font, "Fira Code", "Courier New", monospace);font-size:var(--pe-size, .9rem);line-height:var(--pe-line, 1.6)}#editor-body.pe-nowrap .editor-textarea{white-space:pre;overflow-x:auto}.editor-preview{flex:1;display:block;width:100%;border:none;background:var(--dm-background)}.editor-fullscreen{position:fixed;inset:0;z-index:1000;border-radius:0;margin:0}.editor-fullscreen .card-body{height:100vh}.media-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:.75rem;max-height:400px;overflow-y:auto;padding:.25rem}.media-picker-item{cursor:pointer;border:2px solid transparent;border-radius:6px;overflow:hidden;transition:border-color .15s}.media-picker-item:hover{border-color:var(--dm-primary, #5b8cff)}.media-picker-item img{width:100%;height:80px;object-fit:cover;display:block}.media-picker-item span{display:block;font-size:.75rem;padding:4px 6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.docs-body h3{margin-top:1.25rem;margin-bottom:.5rem}.docs-body p{margin-bottom:.5rem;line-height:1.6}.docs-body ol,.docs-body ul{margin-bottom:.75rem;padding-left:1.25rem}.docs-body li{margin-bottom:.25rem}.docs-body hr{margin:1.25rem 0;border-color:var(--dm-border, rgba(255, 255, 255, .08))}.docs-body .table{margin-bottom:.75rem}.docs-body h2{margin-top:1.75rem;margin-bottom:.6rem;padding-bottom:.3rem;border-bottom:1px solid var(--dm-border)}.docs-body h2:first-child{margin-top:0}.docs-body blockquote{margin:.75rem 0;padding:.5rem .9rem;border-left:3px solid var(--dm-primary);background:var(--dm-surface);border-radius:var(--dm-radius, 6px)}.docs-body pre{margin-bottom:.75rem;overflow-x:auto}.pg-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:1rem;margin-top:1.5rem}.pg-grid>.card.pg-card{display:block;margin:0;text-decoration:none}.pg-card h3{margin-top:0}.pg-card .text-muted,.pg-card-pages{margin-bottom:0}.pg-card-pages{margin-top:.5rem;font-size:.8rem;color:var(--dm-text-muted)}.pg-actions{display:flex;gap:.5rem;flex-wrap:wrap}.pg-meta{margin-bottom:.75rem}.pg-pages{display:flex;flex-wrap:wrap;gap:.35rem;margin-bottom:1rem}.pg-body{max-width:80ch}.nav-items-header,.nav-item-row{display:flex;gap:.5rem;align-items:center;padding:.35rem .75rem}.nav-items-header{border-bottom:1px solid var(--dm-border, rgba(255,255,255,.08));padding-bottom:.4rem;margin-bottom:.25rem}.nav-item-row{border-bottom:1px solid var(--dm-border, rgba(255,255,255,.04))}.nav-item-row:last-child{border-bottom:none}.nav-col-indent{width:18px;flex-shrink:0;color:var(--dm-text-muted, #888);text-align:center;font-size:.85rem}.nav-col-main{flex:2;min-width:0}.nav-col-icon{flex:0 0 90px}.nav-col-parent{flex:2;min-width:0}.nav-col-action{flex-shrink:0}.nav-item-row--child{background:color-mix(in srgb,var(--dm-text) 3%,transparent)}.nav-col-action{display:flex;align-items:center;gap:.25rem}.nav-item-row--hidden{opacity:.45}.nav-item-row--hidden .item-text,.nav-item-row--hidden .footer-link-text{text-decoration:line-through}.btn-toggle-hidden{color:var(--dm-text-muted, #888)}.btn-toggle-hidden.active{color:var(--dm-warning, #f59e0b)}.fb-field-card.fb-drag-over{outline:2px dashed var(--dm-primary, #6366f1);outline-offset:-2px}.btn-ghost span[data-icon=trash]{color:var(--dm-danger, #dc2626)}.view-container:has(.fb-fields-layout){max-width:none}.fb-fields-layout{display:grid;grid-template-columns:minmax(0,6fr) minmax(320px,4fr);gap:1.25rem;align-items:start}.fb-preview-pane{position:sticky;top:1rem;min-width:0}@media(max-width:1100px){.fb-fields-layout{grid-template-columns:1fr}.fb-preview-pane{position:static}}.toggle-label{display:flex;align-items:center;gap:.4rem;font-size:.9rem;cursor:pointer;margin-right:1rem}.preset-toggles{display:flex;flex-wrap:wrap;margin-top:.75rem}.presets-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem}@media(max-width:900px){.presets-grid{grid-template-columns:repeat(2,1fr)}}@media(max-width:600px){.presets-grid{grid-template-columns:1fr}}.card-header{padding:.5rem 1rem}.card-header h2{margin:0;font-size:.9rem;font-weight:600;letter-spacing:.02em}.preset-card .card-header{display:flex;align-items:center;justify-content:space-between}.preset-card .card-header h3{margin:0;font-size:1rem}.media-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:1rem}.media-card{background:var(--dm-card-bg, rgba(255,255,255,.04));border:1px solid var(--dm-border, rgba(255,255,255,.08));border-radius:8px;overflow:hidden}.media-preview{height:130px;display:flex;align-items:center;justify-content:center;background:#0003;overflow:hidden}.media-thumb{width:100%;height:100%;object-fit:cover}.media-thumb--file{font-size:2rem;color:var(--dm-text-muted, #888)}.media-info{padding:.5rem .75rem;display:flex;flex-direction:column;gap:.15rem}.media-name{font-size:.8rem;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:default}.media-rename-input{width:100%;font-size:.8rem;font-weight:500;padding:.1rem .25rem;border:1px solid var(--dm-primary, #7c6af7);border-radius:3px;background:var(--dm-input-bg, transparent);color:inherit;outline:none}.media-size{font-size:.75rem;color:var(--dm-text-muted, #888)}.media-actions{padding:.5rem .75rem;display:flex;gap:.4rem;border-top:1px solid var(--dm-border, rgba(255,255,255,.08))}#admin-topbar{height:60px;display:flex;align-items:center;gap:1rem;padding:0 1.25rem;background:var(--dm-navbar-bg, rgba(0,0,0,.3));border-bottom:1px solid var(--dm-border, rgba(255,255,255,.08));position:sticky;top:0;z-index:200;flex-shrink:0}.topbar-brand{display:flex;align-items:center;gap:.5rem;font-weight:700;font-size:.95rem;color:inherit;flex-shrink:0;margin-right:.5rem}.topbar-brand span[data-icon],.topbar-brand svg{color:var(--dm-primary, #5b8cff);width:22px;height:22px}.topbar-brand-text{opacity:.85}.topbar-brand-logo{height:28px;width:auto;display:inline-block;vertical-align:middle;margin-right:.4em;object-fit:contain}.topbar-user{display:flex;align-items:center;gap:.6rem;flex:1}.topbar-user-name{font-size:.875rem;font-weight:500}.topbar-avatar{width:1.75rem;height:1.75rem;border-radius:50%;object-fit:cover;flex-shrink:0}.topbar-role-badge{font-size:.7rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;padding:.15rem .45rem;border-radius:4px}.topbar-role-badge--admin{background:color-mix(in srgb,var(--dm-primary) 15%,transparent);color:var(--dm-primary)}.topbar-role-badge--manager{background:color-mix(in srgb,var(--dm-success) 15%,transparent);color:var(--dm-success)}.topbar-role-badge--editor{background:color-mix(in srgb,var(--dm-warning) 15%,transparent);color:var(--dm-warning)}.topbar-role-badge--subscriber{background:color-mix(in srgb,var(--dm-text-muted) 15%,transparent);color:var(--dm-text-muted)}.topbar-actions{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.topbar-action-link{display:flex;align-items:center;gap:.35rem;font-size:.875rem;color:var(--dm-text-muted, #888);text-decoration:none;padding:.4rem .65rem;border-radius:6px;transition:color .15s,background .15s}.topbar-action-link:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.topbar-action-link span[data-icon],.topbar-action-link svg{width:16px;height:16px}.topbar-signout{display:flex;align-items:center;gap:.35rem;font-size:.875rem}.topbar-signout span[data-icon],.topbar-signout svg{width:16px;height:16px}.login-wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;padding:1rem;background:var(--dm-background, #0f1117);z-index:100;overflow-y:auto}.login-card{width:100%;max-width:460px}.ob-done-icon{font-size:3rem;color:var(--dm-success);margin-bottom:1rem;text-align:center}.btn-skip{display:block;text-align:center;margin-top:.75rem;font-size:.85rem;color:var(--dm-text-muted, #888);text-decoration:none}.btn-skip:hover{text-decoration:underline}.theme-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.6rem}.theme-swatch{border:2px solid var(--dm-border, rgba(255,255,255,.1));border-radius:8px;overflow:hidden;cursor:pointer;transition:border-color .15s,transform .1s}.theme-swatch:hover{border-color:var(--dm-primary, #5b8cff);transform:translateY(-1px)}.theme-swatch.selected{border-color:var(--dm-primary, #5b8cff);box-shadow:0 0 0 2px var(--dm-primary, #5b8cff)}.theme-swatch-preview{height:52px;position:relative;display:flex;align-items:flex-end;padding:.35rem}.theme-swatch-accent{width:28px;height:6px;border-radius:3px}.theme-swatch-label{display:flex;justify-content:space-between;align-items:center;padding:.3rem .45rem;font-size:.7rem;background:var(--dm-card-bg, rgba(255,255,255,.04))}.theme-swatch-mode{color:var(--dm-text-muted, #888);font-size:.65rem}.login-logo{display:flex;align-items:center;gap:.75rem;margin-bottom:1.75rem;font-size:1.5rem}.login-logo span[data-icon]{font-size:2rem;color:var(--dm-primary, #5b8cff)}.login-logo h1{margin:0;font-size:1.5rem;font-weight:700}.login-card [hidden]{display:none!important}.login-heading{font-size:1.1rem;font-weight:600;margin-bottom:1.25rem}.login-rules{margin:.25rem 0 .75rem;padding-left:1.1rem;color:var(--dm-danger);font-size:.85rem}.login-rules li+li{margin-top:.2rem}.login-small{font-size:.8rem;margin-top:.75rem}.login-icon-warn{color:var(--dm-warning)}.pwf{position:relative;display:block}.pwf>input{width:100%;padding-right:2.5rem}.pwf-toggle{position:absolute;top:50%;right:.35rem;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;border:0;border-radius:var(--dm-radius-sm);background:transparent;color:var(--dm-text-muted);cursor:pointer}.pwf-toggle:hover,.pwf-toggle:focus-visible{color:var(--dm-text);background:var(--dm-hover-bg)}.pwf-toggle svg{width:16px;height:16px}.pwf-toggle [data-icon=eye-off],.pwf.is-shown .pwf-toggle [data-icon=eye]{display:none}.pwf.is-shown .pwf-toggle [data-icon=eye-off]{display:inline-block}.pwf-caps{display:block;margin-top:.25rem;color:var(--dm-warning);font-size:.8rem}.pwf-caps[hidden]{display:none}.btn-block{width:100%}.plugins-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:1rem}.plugin-card{display:flex;flex-direction:column;--plugin-accent: var(--dm-primary, #5b8cff);position:relative;overflow:hidden;background-image:radial-gradient(120% 90% at 100% 0%,color-mix(in srgb,var(--plugin-accent) 13%,transparent) 0%,color-mix(in srgb,var(--plugin-accent) 4%,transparent) 42%,transparent 72%)}.plugin-card .plugin-icon{background:color-mix(in srgb,var(--plugin-accent) 16%,transparent);color:var(--plugin-accent)}.plugin-watermark{position:absolute;top:-34px;right:-30px;width:148px;height:148px;display:block;color:var(--plugin-accent);opacity:.09;pointer-events:none;z-index:0}.plugin-card>.card-body,.plugin-card>.plugin-footer{position:relative;z-index:1}.plugin-card:has(.badge-secondary) .plugin-watermark{opacity:.05}@media(prefers-reduced-motion:no-preference){.plugin-card{transition:background-image .2s ease}}.plugin-card .card-body{flex:1}.plugin-header{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:.75rem;flex-wrap:wrap}.plugin-icon{width:40px;height:40px;border-radius:8px;background:color-mix(in srgb,var(--dm-primary) 14%,transparent);color:var(--dm-primary, #5b8cff);display:flex;align-items:center;justify-content:center;flex-shrink:0}.plugin-meta{flex:1 1 140px;min-width:0}.plugin-name{font-weight:600;margin-bottom:.15rem}.plugin-version{font-size:.75rem;color:var(--dm-text-muted, #888)}.plugin-desc{font-size:.875rem;color:var(--dm-text-muted, #888);margin-bottom:1rem}.plugin-footer{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border-top:1px solid var(--dm-border, rgba(255,255,255,.08))}.plugin-footer-actions{display:flex;align-items:center;gap:.5rem}#admin-sidebar .sidebar-link{position:relative!important}#admin-sidebar .sidebar-badge{position:absolute!important;right:.75rem!important;top:50%!important;transform:translateY(-50%)!important;margin-left:0!important;padding-left:.45rem!important;padding-right:.45rem!important}#admin-sidebar .sidebar-text{padding-right:2rem!important}#admin-sidebar.sidebar-dark{background:var(--dm-surface);border-color:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-header{background:var(--dm-surface-raised);border-color:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-header-title{color:var(--dm-text)}#admin-sidebar.sidebar-dark .sidebar-link{color:var(--dm-text-muted)}#admin-sidebar.sidebar-dark .sidebar-link:hover{color:var(--dm-text);background:var(--dm-surface-overlay)}#admin-sidebar.sidebar-dark .sidebar-link.active{color:var(--dm-primary);background:color-mix(in srgb,var(--dm-primary) 14%,transparent);border-left-color:var(--dm-primary)}#admin-sidebar.sidebar-dark .sidebar-heading{color:var(--dm-text-muted)}#admin-sidebar.sidebar-dark .sidebar-divider{background:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-footer{background:var(--dm-surface-raised);border-color:var(--dm-border)}.sidebar-heading--collapsible{display:flex!important;align-items:center;justify-content:space-between;cursor:pointer;user-select:none}.sidebar-heading-toggle{display:flex;align-items:center;opacity:.5;flex-shrink:0;transition:transform .2s ease}.sidebar-heading--collapsible.is-collapsed .sidebar-heading-toggle{transform:rotate(-90deg)}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.p-0{padding:0!important}.text-muted{color:var(--dm-text-muted, #888)}@media(max-width:768px){.view-container{padding:1rem}.editor-body{flex-direction:column}.editor-divider{width:auto;height:1px;cursor:default;background:var(--dm-border, rgba(255,255,255,.08))}}.image-editor{display:flex;flex-direction:column;gap:0}.image-editor-toolbar{display:flex;flex-direction:row;align-items:center;gap:.25rem;padding:.5rem .75rem;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .1))}.image-editor-sep{display:inline-block;width:1px;height:1.5rem;background:var(--dm-border, rgba(255, 255, 255, .15));margin:0 .25rem;flex-shrink:0}.editor-toolbar-btn.active{color:var(--dm-primary, #7c6af7);background:color-mix(in srgb,var(--dm-primary, #7c6af7) 15%,transparent)}.editor-toolbar-caret{font-size:.6rem;line-height:1;margin-left:2px;opacity:.6}.editor-toolbar-dropdown{position:absolute;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:4px;min-width:160px;max-height:70vh;overflow-y:auto}.editor-toolbar-dropdown-heading{padding:6px 10px 3px;color:var(--dm-text-muted, #8a8a9a);font-size:.66rem;text-transform:uppercase;letter-spacing:.06em}.editor-toolbar-dropdown-item{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:none;border:none;color:var(--dm-text, #ddd);padding:7px 10px;border-radius:5px;cursor:pointer;font-size:.85rem;transition:background .12s,color .12s}.editor-toolbar-dropdown-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-toolbar-dropdown-item span[data-icon],.editor-toolbar-dropdown-item svg{width:15px;height:15px;flex-shrink:0;opacity:.75}.editor-toolbar{position:relative}.editor-effects-dropdown-menu{position:absolute;top:100%;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:6px;min-width:180px;max-height:340px;overflow-y:auto}.editor-effects-category{padding:6px 8px 3px;font-size:.7rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--dm-text-muted, #888)}.editor-effects-item{display:block;width:100%;text-align:left;background:none;border:none;color:var(--dm-text, #ddd);padding:6px 10px;border-radius:5px;cursor:pointer;font-size:.85rem;transition:background .12s,color .12s}.editor-effects-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-icon-picker{position:absolute;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:8px;width:320px}.editor-icon-picker-search{width:100%;margin-bottom:8px;font-size:.8rem}.editor-spacer-picker{position:absolute;z-index:9999;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, #333);border-radius:8px;padding:12px;width:240px;box-shadow:0 8px 24px #00000073}.editor-spacer-picker-label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--dm-text-muted, #888);margin-bottom:10px}.editor-spacer-picker-row{display:flex;align-items:center;gap:10px;margin-bottom:12px}.editor-spacer-slider{flex:1;accent-color:var(--dm-primary, #6366f1);cursor:pointer}.editor-spacer-slider-value{font-size:13px;font-weight:600;min-width:38px;text-align:right;color:var(--dm-text, #cdd6f4)}.editor-spacer-insert-btn{width:100%}.editor-icon-picker-size-row{display:flex;align-items:center;gap:8px;padding:0 8px 8px}.editor-icon-picker-size-row label{font-size:11px;color:var(--dm-text-muted, #888);white-space:nowrap}.editor-icon-picker-size{width:70px;font-size:12px;padding:3px 6px}.editor-icon-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(52px,1fr));gap:2px;max-height:280px;overflow-y:auto}.editor-icon-picker-item{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:6px 2px;border-radius:5px;cursor:pointer;background:none;border:none;color:var(--dm-text, #ddd);font-size:.58rem;text-align:center;gap:4px;overflow:hidden;transition:background .12s,color .12s}.editor-icon-picker-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-icon-picker-item span[data-icon],.editor-icon-picker-item svg{width:16px;height:16px;flex-shrink:0}.editor-icon-picker-item>span:last-child{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.2}.editor-icon-picker-empty{grid-column:1 / -1;text-align:center;color:var(--dm-text-muted, #888);font-size:.8rem;padding:1.5rem}.image-editor-canvas{min-height:320px;max-height:520px;background:#111;overflow:hidden;display:flex;align-items:center;justify-content:center}.image-editor-canvas img{display:block;max-width:100%;max-height:520px}.image-editor-resize{display:flex;flex-direction:row;align-items:center;gap:.5rem;padding:.6rem .75rem;border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1));font-size:.85rem}.image-editor-resize label{font-weight:600;color:var(--dm-text-muted, #888);font-size:.8rem}.image-editor-resize .form-input{width:5rem;padding:.25rem .5rem;font-size:.85rem}.image-editor-footer{display:flex;flex-direction:row;align-items:center;justify-content:space-between;padding:.75rem;border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1));gap:.5rem}.image-editor-effects{border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1))}.image-editor-tab-bar{display:flex;flex-direction:row;overflow-x:auto;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .1));scrollbar-width:none}.image-editor-tab-bar::-webkit-scrollbar{display:none}.image-editor-tab-btn{display:inline-flex;align-items:center;gap:.35rem;padding:.5rem .85rem;font-size:.8rem;font-weight:500;border:none;border-bottom:2px solid transparent;background:transparent;cursor:pointer;color:var(--dm-text-muted, #888);white-space:nowrap;transition:color .15s,border-color .15s;flex-shrink:0}.image-editor-tab-btn:hover{color:var(--dm-text, #eee)}.image-editor-tab-btn.active{color:var(--dm-primary, #7c6af7);border-bottom-color:var(--dm-primary, #7c6af7)}.image-editor-tab-panel{padding:.75rem;max-height:200px;overflow-y:auto}.ie-presets-grid{display:flex;flex-wrap:wrap;gap:.35rem;margin-bottom:.5rem}.ie-preset-btn.active{color:var(--dm-primary, #7c6af7);background:color-mix(in srgb,var(--dm-primary, #7c6af7) 15%,transparent);border-color:var(--dm-primary, #7c6af7)}.ie-server-note{font-size:.73rem;color:var(--dm-text-muted, #888);font-style:italic;margin:.25rem 0 0;line-height:1.4}.ie-slider-row{display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem}.ie-slider-label{width:6rem;font-size:.8rem;color:var(--dm-text-muted, #888);font-weight:600;flex-shrink:0}.ie-slider{flex:1;accent-color:var(--dm-primary, #7c6af7);cursor:pointer}.ie-slider-val{width:3rem;font-size:.8rem;text-align:right;color:var(--dm-text, #eee);flex-shrink:0}.ie-select{flex:1;font-size:.85rem;padding:.25rem .5rem}.ie-colour-input{width:40px;height:28px;padding:0;border:1px solid var(--dm-border, rgba(255, 255, 255, .15));border-radius:4px;cursor:pointer;background:transparent;flex-shrink:0}.ie-wm-preview-row{display:flex;align-items:center;gap:.5rem;margin:.4rem 0}.ie-wm-preview-img{width:48px;height:48px;object-fit:contain;border-radius:4px;background:var(--dm-surface-raised, rgba(255, 255, 255, .06));flex-shrink:0}.ie-wm-preview-name{font-size:.8rem;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dm-text, #eee)}.ie-media-picker{padding:.25rem 0}.ie-media-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(80px,1fr));gap:.5rem;max-height:300px;overflow-y:auto}.ie-media-thumb{display:flex;flex-direction:column;align-items:center;gap:.25rem;padding:.4rem;border-radius:6px;cursor:pointer;border:2px solid transparent;transition:border-color .15s,background .15s}.ie-media-thumb:hover{background:var(--dm-surface-raised, rgba(255, 255, 255, .08));border-color:var(--dm-primary, #7c6af7)}.ie-media-thumb img{width:72px;height:72px;object-fit:cover;border-radius:4px}.ie-media-thumb-name{font-size:.7rem;color:var(--dm-text-muted, #888);text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:72px}.dm-slideover-left,.dm-slideover-right{width:min(40rem,95vw)!important;min-width:min(36rem,100vw)!important;max-width:100vw!important}.dm-slideover-resizer{position:absolute;top:0;bottom:0;width:6px;cursor:col-resize;z-index:2;background:transparent}.dm-slideover-right>.dm-slideover-resizer{left:0}.dm-slideover-left>.dm-slideover-resizer{right:0}.dm-slideover-resizer:hover,.is-resizing>.dm-slideover-resizer{background:var(--dm-primary);opacity:.7}.dm-slideover.is-resizing{user-select:none;transition:none!important}.dm-slideover-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1.25rem;border-bottom:1px solid var(--dm-border, #333);flex-shrink:0}.dm-slideover-title{margin:0;font-size:1rem;font-weight:600}.dm-slideover-close{padding:.2rem .35rem!important;line-height:1;font-size:.75rem}.dm-slideover-body{flex:1;overflow:auto;overscroll-behavior:contain;min-height:0;padding:1.5rem!important;box-sizing:border-box}.dm-slideover-body:empty{flex:0 0 auto;padding:0!important}.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-body):not(.dm-slideover-close){padding:1.5rem!important;box-sizing:border-box;flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain}.dm-slideover-body,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close){scrollbar-width:thin;scrollbar-color:var(--dm-border) transparent}.dm-slideover-body::-webkit-scrollbar,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar{width:8px;height:8px}.dm-slideover-body::-webkit-scrollbar-track,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-track{background:transparent}.dm-slideover-body::-webkit-scrollbar-thumb,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-thumb{background:var(--dm-border);border-radius:4px}.dm-slideover-body::-webkit-scrollbar-thumb:hover,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-thumb:hover{background:var(--dm-text-muted)}.dm-slideover-body>div{padding-left:0!important;padding-right:0!important}.dm-slideover-body>button.btn:last-child{margin-top:.5rem}.dconfig-textarea{font-family:monospace;min-height:100px;resize:vertical}.dm-editor-line-numbers{white-space:pre}.dm-code-inline{font-family:Fira Code,Courier New,monospace;font-size:.82em;padding:.15em .35em;border-radius:3px;background:var(--dm-background-alt, rgba(0, 0, 0, .18));color:var(--dm-text, inherit);border:1px solid var(--dm-border, rgba(255, 255, 255, .08))}.dm-code-block{font-family:Fira Code,Courier New,monospace;font-size:.82rem;line-height:1.6;padding:.65rem .9rem;border-radius:6px;background:var(--dm-background-alt, rgba(0, 0, 0, .18));color:var(--dm-text, inherit);border:1px solid var(--dm-border, rgba(255, 255, 255, .08));white-space:pre;overflow-x:auto;display:block;margin:.4rem 0}.tabs-centered{text-align:center}.tabs-centered .tab-list{display:inline-flex}.tabs-centered .tab-content{text-align:left}@media(max-width:768px){.view-header{flex-direction:column;align-items:flex-start}.theme-grid{grid-template-columns:repeat(2,1fr)}.nav-item-row{flex-wrap:wrap}.nav-col-icon,.nav-col-parent{display:none}#admin-topbar{padding:0 .75rem}.topbar-brand-text{display:none}.image-editor-toolbar{flex-wrap:wrap}}#topbar-bell{position:relative}.topbar-action-link[hidden],.topbar-bell-badge[hidden]{display:none}.topbar-bell-badge{position:absolute;top:2px;right:2px;min-width:16px;height:16px;padding:0 4px;background:var(--dm-danger, #dc2626);color:var(--dm-danger-text, #fff);font-size:10px;font-weight:700;line-height:16px;border-radius:9999px;text-align:center;pointer-events:none}.cb-scaffolder{padding:1rem 1.1rem;background:var(--dm-background-alt);border:1px solid var(--dm-primary);border-radius:8px;color:var(--dm-text)}.cb-scaffolder-head{display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}.cb-scaffolder-head .cb-icon{flex-shrink:0;color:var(--dm-primary)}.cb-scaffolder-head h2{margin:0;font-size:1.05rem;font-weight:700;color:var(--dm-text)}.cb-scaffolder-blurb{margin:0 0 .75rem;font-size:.88rem;line-height:1.5;color:var(--dm-text-muted)}.cb-recipe-list{display:flex;flex-direction:column;gap:.5rem}.cb-recipe-card{display:flex;align-items:flex-start;gap:.75rem;text-align:left;padding:.75rem 1rem;background:var(--dm-surface);border:1px solid var(--dm-border);border-radius:6px;cursor:pointer;transition:border-color .12s;width:100%;color:var(--dm-text)}.cb-recipe-card:hover{border-color:var(--dm-primary)}.cb-recipe-card .cb-icon{flex-shrink:0;font-size:1.5rem;color:var(--dm-primary);margin-top:.1rem}.cb-recipe-meta{flex:1}.cb-recipe-name{font-weight:600;margin-bottom:.15rem;font-size:.95rem;color:var(--dm-text)}.cb-recipe-desc{font-size:.83rem;line-height:1.45;color:var(--dm-text-muted)}.cb-apply-panel{padding:1rem 1.1rem;background:var(--dm-surface);border:1px solid var(--dm-primary);border-radius:8px;color:var(--dm-text)}.cb-apply-head{display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}.cb-apply-head .cb-icon{color:var(--dm-primary);font-size:1.4rem}.cb-apply-head h3{margin:0;font-size:1rem;font-weight:600;color:var(--dm-text)}.cb-apply-desc,.cb-apply-hint{margin:.25rem 0 .75rem;font-size:.85rem;line-height:1.5;color:var(--dm-text-muted)}.cb-apply-hint{font-size:.75rem;margin-top:.2rem}.cb-apply-field{margin-bottom:.6rem}.cb-apply-field label{display:block;font-size:.82rem;font-weight:600;margin-bottom:.2rem;color:var(--dm-text)}.cb-apply-field input{width:100%;padding:.4rem .55rem;border:1px solid var(--dm-border);border-radius:4px;font-size:.88rem;background:var(--dm-surface);color:var(--dm-text)}.cb-apply-status{margin:.5rem 0;font-size:.85rem;min-height:1.2rem;color:var(--dm-text)}.cb-apply-status.cb-error{color:var(--dm-danger, #dc2626)}.cb-apply-buttons{display:flex;gap:.5rem;justify-content:flex-end;margin-top:.5rem}.cb-success-panel{padding:1rem 1.1rem;background:var(--dm-surface);border:1px solid var(--dm-success, #16a34a);border-radius:8px;color:var(--dm-text)}.cb-success-panel .cb-icon{color:var(--dm-success, #16a34a);font-size:1.4rem}.cb-success-summary{margin:.25rem 0 .5rem;padding-left:1.2rem;font-size:.86rem;line-height:1.6;color:var(--dm-text)}.cb-success-warning{margin:.5rem 0;padding:.5rem .75rem;background:var(--dm-background-alt);border-left:3px solid var(--dm-warning, #eab308);border-radius:0 4px 4px 0;font-size:.82rem;color:var(--dm-text-muted)}.cb-success-snippet-label{margin:0 0 .25rem;font-size:.82rem;font-weight:600;color:var(--dm-text)}.cb-success-actions{display:flex;gap:.5rem;margin-top:.5rem;flex-wrap:wrap}.cb-code{position:relative}.cb-code pre{background:var(--dm-background-alt);color:var(--dm-text);display:block;padding:.6rem 2.4rem .6rem .75rem;white-space:pre;overflow-x:auto;margin:0;border-radius:6px;font-size:.82em;font-family:monospace;line-height:1.45}.cb-code .cb-copy{position:absolute;top:.35rem;right:.35rem;background:none;border:none;cursor:pointer;opacity:.45;padding:.2rem;line-height:1;color:var(--dm-text)}.cb-code .cb-copy:hover{opacity:1}.cb-intro{padding:.75rem 1rem;border-left:3px solid var(--dm-primary);background:var(--dm-background-alt);border-radius:0 6px 6px 0}.cb-intro p{margin:0;font-size:.92rem;line-height:1.5;color:var(--dm-text)}.cb-tutorial-link{display:flex;align-items:center;gap:.6rem;padding:.65rem .85rem;border:1px solid var(--dm-border);border-radius:6px;text-decoration:none;color:var(--dm-text);font-size:.88rem;transition:border-color .12s}.cb-tutorial-link:hover{border-color:var(--dm-primary)}.cb-tutorial-link .cb-icon{flex-shrink:0;color:var(--dm-primary)}.cb-tutorial-link .cb-arrow{color:var(--dm-text-muted);font-size:1.1rem;margin-left:auto}.menu-tree-row{display:grid;grid-template-columns:16px 1.4fr 1.4fr .9fr .7fr .9fr repeat(6,auto);gap:6px;align-items:center;padding:4px 0;transition:opacity .15s ease}.menu-tree-row--hidden{opacity:.5}.menu-tree-row--tool .me-tool-badge{margin-left:.4rem;font-size:.7rem;vertical-align:middle}.menu-tree-row--default .me-row-label{font-style:italic;opacity:.8}.menu-tree-grip{cursor:grab;color:var(--dm-text-muted)}.menu-tree{padding:8px 0}.menu-tree-row--separator{display:grid;grid-template-columns:16px minmax(80px,1fr) repeat(7,auto);gap:6px;align-items:center;padding:2px 0;opacity:.85}.menu-tree-row--separator:hover{opacity:1}.menu-tree-row--separator .me-sep-line{display:flex;align-items:center;gap:10px;width:100%}.menu-tree-row--separator .me-sep-line:before,.menu-tree-row--separator .me-sep-line:after{content:"";flex:1;border-top:1px dashed var(--dm-border, rgba(128, 128, 128, .55))}.menu-tree-row--separator .me-sep-label{font-size:.66rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--dm-text-muted, #8a8a8a);white-space:nowrap}.dm-admin-sidebar .sidebar-divider{border:0;border-top:1px solid var(--dm-border, rgba(128, 128, 128, .5));margin:.5rem .75rem;opacity:.8}.dm-admin-sidebar .sidebar-spacer--xs{height:var(--dm-space-1, .25rem)}.dm-admin-sidebar .sidebar-spacer--sm{height:var(--dm-space-2, .5rem)}.dm-admin-sidebar .sidebar-spacer--md{height:var(--dm-space-4, 1rem)}.dm-admin-sidebar .sidebar-spacer--lg{height:var(--dm-space-6, 1.5rem)}.dm-admin-sidebar .sidebar-spacer--xl{height:var(--dm-space-10, 2.5rem)}.dm-admin-sidebar .sidebar-spacer--flex{flex:1 1 auto;min-height:var(--dm-space-4, 1rem)}.dm-admin-sidebar--has-flex-spacer{display:flex;flex-direction:column;min-height:100%}.menu-tree-row--spacer{display:grid;grid-template-columns:16px minmax(80px,1fr) repeat(7,auto);gap:6px;align-items:center;padding:2px 0;opacity:.85}.menu-tree-row--spacer:hover{opacity:1}.menu-tree-row--spacer .me-spacer-line{display:flex;align-items:center;gap:8px;width:100%}.menu-tree-row--spacer .me-spacer-line:before,.menu-tree-row--spacer .me-spacer-line:after{content:"";flex:1;border-top:1px dotted var(--dm-border, rgba(128, 128, 128, .55))}.menu-tree-row--spacer .me-spacer-label{font-size:.66rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--dm-text-muted, #8a8a8a);white-space:nowrap}.menu-tree-row--spacer .me-spacer-size{width:auto;min-width:5.5rem;height:26px;padding:0 .35rem;font-size:.75rem}.menu-tree-row .me-icon-wrap{display:flex;gap:2px}.menu-tree-row .me-icon-wrap .me-icon{flex:1;min-width:0}.menu-tree-row .me-icon-wrap .me-icon-pick{flex-shrink:0;padding:.2rem .45rem;font-size:.85em}.dm-admin-sidebar{display:flex;flex-direction:column;gap:2px;padding:8px 0;font-size:.875rem}.dm-admin-sidebar details{margin:0}.dm-admin-sidebar details>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:.5rem;padding:.4rem .75rem;border-radius:4px;user-select:none;font-size:.78rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--dm-text-muted, #888)}.dm-admin-sidebar details details>summary{font-size:.875rem;font-weight:500;text-transform:none;letter-spacing:0;color:inherit}.dm-admin-sidebar .dm-menu-badge{font-size:.7rem;font-weight:600}.dm-admin-sidebar details>summary::-webkit-details-marker{display:none}.dm-admin-sidebar details>summary:after{content:"\25b8";margin-left:auto;transition:transform .15s ease;color:var(--dm-text-muted, #999);font-size:.85em}.dm-admin-sidebar details[open]>summary:after{transform:rotate(90deg)}.dm-admin-sidebar details>div{padding-left:1rem;border-left:1px solid var(--dm-border-light, rgba(0, 0, 0, .08));margin-left:.95rem}.dm-admin-sidebar .sidebar-link{display:flex;align-items:center;gap:.5rem;padding:.35rem .75rem;text-decoration:none;color:var(--dm-text, inherit);border-radius:4px}.dm-admin-sidebar .sidebar-link:hover,.dm-admin-sidebar details>summary:hover{background:var(--dm-hover-bg, rgba(0, 0, 0, .05))}.dm-admin-sidebar .sidebar-link.active{background:var(--dm-active-bg, rgba(0, 0, 0, .08));font-weight:600}.dm-admin-sidebar .sidebar-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dm-admin-sidebar [data-icon]{flex-shrink:0}.dm-admin-sidebar-header{position:sticky;top:0;z-index:2;background:var(--dm-surface);display:flex;align-items:center;gap:.5rem;padding:.65rem .85rem;margin:0 0 .5rem;font-weight:600;font-size:.95rem;letter-spacing:.01em;color:var(--dm-text, inherit);border-bottom:1px solid var(--dm-border-light, rgba(0, 0, 0, .08))}.dm-admin-sidebar--dark .dm-admin-sidebar-header{background:#1a1d24}.dm-admin-sidebar--light .dm-admin-sidebar-header{background:#fff}.dm-admin-sidebar-header [data-icon]{color:var(--dm-text-muted, #999)}.dm-admin-sidebar .sidebar-badge{margin-left:auto;padding:0 .4rem;min-width:1.25rem;height:1.1rem;line-height:1.1rem;text-align:center;font-size:.7rem;font-weight:600;border-radius:999px;background:var(--dm-active-bg, rgba(0, 0, 0, .12));color:var(--dm-text-muted, #888)}.dm-admin-sidebar .sidebar-link.active .sidebar-badge{background:var(--dm-primary, #4a86e8);color:var(--dm-primary-text, #fff)}.dm-admin-sidebar .sidebar-children{overflow:hidden;transition:max-height .22s ease,opacity .18s ease}.dm-admin-sidebar details:not([open])>.sidebar-children{opacity:0}.dm-admin-sidebar{position:relative}.dm-admin-sidebar-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;background:transparent;z-index:10;transition:background .15s}.dm-admin-sidebar-handle:hover,.dm-admin-sidebar-handle:active{background:var(--dm-primary, #4a86e8);opacity:.35}.dm-admin-sidebar--dark{background:#1a1d24;color:#e3e6eb}.dm-admin-sidebar--dark .sidebar-link,.dm-admin-sidebar--dark summary{color:#e3e6eb}.dm-admin-sidebar--dark .sidebar-link:hover,.dm-admin-sidebar--dark details>summary:hover{background:#ffffff0f}.dm-admin-sidebar--dark .sidebar-link.active{background:#4a86e840}.dm-admin-sidebar--dark .sidebar-badge{background:#ffffff1f;color:#cbd0d8}.dm-admin-sidebar--light{background:#fff;color:#1a1d24;border-right:1px solid rgba(0,0,0,.08)}.dm-admin-sidebar--light .sidebar-link,.dm-admin-sidebar--light summary{color:#1a1d24}.dm-admin-sidebar--light .sidebar-link:hover,.dm-admin-sidebar--light details>summary:hover{background:#0000000a}.dm-admin-sidebar--light .sidebar-link.active{background:#4a86e826}.dm-admin-sidebar--transparent{background:transparent}.page-header{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin:0 0 1.25rem;padding-bottom:.75rem;border-bottom:1px solid var(--dm-border-light, rgba(0, 0, 0, .08))}.page-header h2{margin:0;display:flex;align-items:center;gap:.5rem;font-size:1.4rem;line-height:1.2}.page-header h2 [data-icon]{color:var(--dm-text-muted, #888)}.header-actions{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.card+.card,.card+p,p+.card,.card+.toolbar,.toolbar+.card,.card+.grid{margin-top:1rem}.toolbar{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin:0 0 1rem}.btn+.btn,.btn+a.btn,a.btn+.btn,a.btn+a.btn{margin-left:.35rem}[style*=inline-flex] .btn+.btn,[style*=inline-flex] .btn+a.btn,[style*=inline-flex] a.btn+.btn{margin-left:0}.card-body>[id$=-form],.card-body>form{margin:.25rem 0}.card-header{display:flex;align-items:center;gap:.5rem}.card-header h3{margin:0;font-size:1.05rem}.card-header [data-icon]{color:var(--dm-text-muted, #888)}.page-header+p.text-muted{margin:-.5rem 0 1rem}.dm-pe-grid{gap:.75rem 1rem}.dm-pe-grid .form-group{display:flex;flex-direction:column;gap:.25rem;margin:0}.dm-pe-grid .form-group.col-span-2{grid-column:1 / -1}.dm-pe-grid label{font-size:.85rem;font-weight:600;color:var(--dm-text, inherit)}.dm-pe-grid label .required{color:var(--dm-danger, #c33);margin-left:2px}.dm-pe-grid .form-hint{font-size:.75rem;color:var(--dm-text-muted, #888);margin-top:.1rem}.dm-pe-grid .form-input{width:100%;padding:.4rem .6rem}.dm-pe-grid textarea.form-input{resize:vertical;min-height:2.5rem}.dm-menu-badge{display:inline-block;margin-left:6px;padding:1px 7px;font-size:.7em;font-weight:700;line-height:1.4;border-radius:999px;background:var(--dm-text-muted);color:var(--dm-text-inverse, #fff);vertical-align:middle}.menu-tree-row--slim{display:grid;grid-template-columns:16px 1fr auto repeat(9,auto);gap:6px;align-items:center}.menu-tree-row--slim .me-row-label{font-weight:600}.menu-tree-row--slim .me-row-url{color:var(--dm-text-muted);font-size:.85em}.menu-tree-row.me-drop-above{box-shadow:inset 0 2px 0 0 var(--dm-primary)}.menu-tree-row.me-drop-below{box-shadow:inset 0 -2px 0 0 var(--dm-primary)}.menu-tree-row.me-drop-into{background:color-mix(in srgb,var(--dm-primary) 12%,transparent);box-shadow:inset 0 0 0 1px var(--dm-primary);border-radius:var(--dm-radius-sm, 4px)}.menu-tree-row[draggable=true] .menu-tree-grip{cursor:grabbing}.me-pages-picker{display:flex;gap:6px;align-items:center;margin-bottom:6px}.me-pages-picker .form-input{flex:1;min-width:0}.me-colour-control{display:flex;gap:6px;align-items:center}.me-colour-control .me-colour-hex{width:48px;height:32px;padding:2px;flex:none}.me-bind-summary{padding:.6rem .8rem;border:1px solid var(--dm-border, rgba(128, 128, 128, .35));border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-text) 4%,transparent);font-size:.9em}.me-bind-summary code{font-size:.9em}.me-item-form{display:flex;flex-direction:column;gap:10px;padding:4px 2px}.me-item-form .form-field{display:flex;flex-direction:column;gap:4px}.me-item-form .form-label{font-size:.85em;color:var(--dm-text-muted)}.me-form-section{margin:12px 0 2px;padding-top:10px;border-top:1px solid var(--dm-border-light, rgba(0,0,0,.15));font-size:.78em;text-transform:uppercase;letter-spacing:.06em;color:var(--dm-text-muted)}.me-item-form .me-form-section:first-child{margin-top:0;padding-top:0;border-top:0}.me-item-form .me-colour-hex{width:48px;height:32px;padding:2px}.me-item-form .me-field-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}.me-item-form .me-field-grid .form-field{margin:0}.me-item-form .me-icon-field{display:flex;align-items:center;gap:8px}.me-item-form .me-icon-field .form-input{flex:1}.me-item-form .me-icon-preview{width:24px;height:24px;flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;color:var(--dm-text-muted)}#admin-sidebar.dm-menu-floating{border:1px solid var(--dm-border);border-radius:var(--dm-radius-md, 8px);box-shadow:var(--dm-shadow-lg);overflow:hidden}@media(max-width:768px){#admin-sidebar.dm-menu-floating{position:static!important;inset:auto!important;max-height:none!important;transform:none!important}.dashboard-wrapper{padding-left:0!important;padding-right:0!important}}[data-logic-section]{border:1px solid var(--dm-border);border-radius:var(--dm-radius-md, 6px);padding:.9rem 1rem 1rem;margin-bottom:1rem;background:color-mix(in srgb,var(--dm-text) 3%,transparent)}[data-logic-section] .fb-logic-cond-row,[data-logic-section] .fb-logic-val-rule{padding:.55rem .65rem;border-radius:var(--dm-radius-sm, 4px);border:1px solid var(--dm-border);background:var(--dm-surface, transparent)}[data-logic-section] .fb-logic-cond-row:last-of-type,[data-logic-section] .fb-logic-val-rule:last-of-type{margin-bottom:.75rem}[data-logic-section]>.btn{margin-top:.15rem}[data-logic-section] textarea{min-height:5rem}.project-filter-notice{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;margin:0 0 1rem;padding:.6rem .85rem;border:1px solid var(--dm-border);border-left:3px solid var(--dm-info, var(--dm-primary));border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-info, var(--dm-primary)) 6%,transparent);font-size:.85rem;color:var(--dm-text-muted)}.project-filter-notice a{color:var(--dm-primary);font-weight:600}.ctx-help{display:inline-flex;align-items:center;justify-content:center;width:1.05rem;height:1.05rem;margin-left:.35rem;padding:0;border:1px solid var(--dm-border-dark, var(--dm-border));border-radius:var(--dm-radius-full, 9999px);background:transparent;color:var(--dm-text-muted);font-size:.68rem;font-weight:700;line-height:1;cursor:pointer;vertical-align:middle;flex-shrink:0}.ctx-help:hover,.ctx-help:focus-visible{border-color:var(--dm-primary);color:var(--dm-primary);outline:none}.card-header h3 .ctx-help{align-self:center}.ctx-preview-card{position:sticky;top:1rem}@media(max-width:1100px){.ctx-workspace>.col-8,.ctx-workspace>.col-4{flex:0 0 auto;width:100%}.ctx-preview-card{position:static}}.dm-plugin-shell{border:1px solid var(--dm-border);border-radius:var(--dm-radius-lg, 12px);background:var(--dm-surface);overflow:hidden}.dm-plugin-banner{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;padding:.7rem 1rem;background:var(--dm-background-alt);border-bottom:1px solid var(--dm-border)}.dm-plugin-banner-identity{display:flex;align-items:center;gap:.55rem;min-width:0;margin-right:auto}.dm-plugin-banner-actions{display:flex;align-items:center;gap:.25rem;flex:0 0 auto;margin-right:.15rem;padding-right:.4rem;border-right:1px solid var(--dm-border)}.dm-plugin-banner-action{padding:.25rem .4rem;line-height:1;color:var(--dm-text-muted)}.dm-plugin-banner-action:hover{color:var(--dm-primary)}.dm-plugin-banner-icon{display:inline-flex;align-items:center;color:var(--dm-primary);flex:0 0 auto}.dm-plugin-banner-name{margin:0;font-size:1.05rem;font-weight:600;letter-spacing:.01em;color:var(--dm-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dm-activity{display:inline-flex;align-items:center;flex:0 0 auto;margin-left:.35rem}.dm-activity domma-loader{display:inline-block;line-height:0}.dm-activity[hidden]{display:none!important}#admin-topbar>.dm-activity{margin:0 .75rem 0 0}.dm-plugin-banner-parent{font-weight:500;color:var(--dm-text-muted)}.dm-plugin-banner-sep{margin:0 .4rem;color:var(--dm-text-muted)}.dm-plugin-banner-facts{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap}.dm-plugin-fact{font-size:.72rem;line-height:1.6;padding:1px 8px;border-radius:999px;border:1px solid var(--dm-border);color:var(--dm-text-muted);background:var(--dm-surface);white-space:nowrap}.dm-plugin-fact--version{font-variant-numeric:tabular-nums;color:var(--dm-text)}.dm-plugin-fact--licence.is-included{color:var(--dm-info);border-color:var(--dm-info)}.dm-plugin-fact--licence.is-licensed{color:var(--dm-success);border-color:var(--dm-success)}.dm-plugin-fact--expiry{font-variant-numeric:tabular-nums}.dm-plugin-fact--expiry.is-warning{color:var(--dm-warning);border-color:var(--dm-warning)}.dm-plugin-fact--expiry.is-danger{color:var(--dm-danger);border-color:var(--dm-danger)}.dm-plugin-body{padding:1rem}.dm-plugin-body .card.dm-plugin-unwrap{border:0;background:none;box-shadow:none;margin:0}.dm-plugin-body .card.dm-plugin-unwrap>.card-body{padding:0}.dm-plugin-body>.p-4{padding:0}@media(max-width:640px){.dm-plugin-banner{align-items:flex-start;flex-direction:column;gap:.5rem}.dm-plugin-body{padding:.75rem}}.analytics-filter{max-width:240px}.dm-help-btn{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;margin-left:.3rem;padding:0;border:0;background:none;line-height:1;color:var(--dm-text-muted);opacity:.75;cursor:pointer}.dm-help-btn:hover,.dm-help-btn:focus-visible{color:var(--dm-primary);opacity:1}.dm-help-pop{position:fixed;z-index:10050;max-width:300px;padding:.6rem .75rem;background:var(--dm-surface, var(--dm-background));color:var(--dm-text);border:1px solid var(--dm-border);border-radius:var(--dm-radius-md);box-shadow:0 8px 24px #00000040;font-size:.85rem;line-height:1.45;text-align:left;font-weight:400}.dm-help-pop strong{display:block;margin-bottom:.2rem;font-weight:600}.dm-help-pop p{margin:0}.dm-admin-sidebar .sidebar-badge[data-badge-label]{cursor:help}.dm-admin-sidebar .sidebar-badge--danger,.dm-admin-sidebar .sidebar-link.active .sidebar-badge--danger{background:var(--dm-danger, #dc2626);color:#fff}.dm-admin-sidebar .sidebar-badge--live{background:color-mix(in srgb,var(--dm-success, #16a34a) 20%,transparent);color:var(--dm-success, #16a34a)}#admin-sidebar .sidebar-badge--live{padding-left:1.05rem!important}#admin-sidebar summary>.sidebar-badge--sum{position:static!important;transform:none!important;margin-left:auto!important;margin-right:.45rem;text-transform:none;letter-spacing:0}#admin-sidebar summary:has(>.sidebar-badge--sum):after{margin-left:0}#admin-sidebar details[open]>summary>.sidebar-badge--sum{display:none}.dm-admin-sidebar .sidebar-badge--live:before{content:"";position:absolute;left:.4rem;top:50%;width:.4rem;height:.4rem;margin-top:-.2rem;border-radius:50%;background:currentColor;animation:dm-badge-pulse 2s ease-in-out infinite}@keyframes dm-badge-pulse{50%{opacity:.35}}@media(prefers-reduced-motion:reduce){.dm-admin-sidebar .sidebar-badge--live:before{animation:none}}.dm-badge-pop{width:290px;max-width:calc(100vw - 16px);font-size:.8rem;pointer-events:none}.dm-badge-pop-title{display:block;font-size:.85rem}.dm-badge-pop-sub{margin:.1rem 0 .5rem;color:var(--dm-text-muted)}.dm-badge-pop-rows{display:grid;grid-template-columns:1fr auto;gap:.2rem .75rem;margin:0 0 .5rem;padding:.45rem 0;border-top:1px solid var(--dm-border);border-bottom:1px solid var(--dm-border)}.dm-badge-pop-rows dt{color:var(--dm-text-muted)}.dm-badge-pop-rows dd{margin:0;text-align:right;font-weight:600;font-variant-numeric:tabular-nums}.dm-badge-pop-items{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}.dm-badge-pop-items li{display:flex;flex-direction:column;min-width:0}.dm-badge-pop-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dm-badge-pop-meta{font-size:.72rem;color:var(--dm-text-muted)}.dm-badge-pop .is-danger,.dm-badge-pop li.is-danger .dm-badge-pop-meta{color:var(--dm-danger, #dc2626)}.dm-badge-pop-empty{margin:0;color:var(--dm-text-muted)}.dm-plugin-body,.dm-slideover{font-family:var(--dm-font-sans, inherit)}.dm-plugin-body :is(button,input,select,textarea,.btn,.form-input,.form-select,.form-textarea),.dm-slideover :is(button,input,select,textarea,.btn,.form-input,.form-select,.form-textarea){font-family:inherit}.dm-plugin-body :is(input,select,textarea,.form-input,.form-select,.form-textarea):not(.form-input-lg),.dm-slideover :is(input,select,textarea,.form-input,.form-select,.form-textarea):not(.form-input-lg){font-size:var(--dm-text-sm)}.dm-plugin-body .form-input-lg{font-size:var(--dm-text-base)}.dm-plugin-body :is(.font-mono,code,pre,kbd),.dm-slideover :is(.font-mono,code,pre,kbd){font-family:var(--dm-font-mono, monospace)}.dm-plugin-body .form-label,.dm-slideover .form-label{font-size:var(--dm-text-sm)}.related-box{display:flex;flex-direction:column;gap:.6rem;border-top:1px solid var(--dm-border);padding-top:.75rem}.related-box[hidden]{display:none}.related-head{display:flex;align-items:center;gap:.4rem}.related-head strong{flex:1}.related-list{list-style:none;margin:.3rem 0 0;padding:0;display:flex;flex-direction:column;gap:.25rem}.related-list li{display:flex;flex-direction:column}.related-list li.is-past{opacity:.7}.related-meta,.related-note,.related-loading{color:var(--dm-text-muted);font-size:var(--dm-text-xs);margin:0}.login-challenge{display:flex;flex-direction:column;gap:.6rem;margin-bottom:.75rem}.login-challenge #challenge-code{font-size:1.25rem;letter-spacing:.2em;text-align:center}.login-trust{display:flex;align-items:center;gap:.45rem;font-size:.875rem}.login-enrol{display:flex;flex-direction:column;align-items:center;gap:.6rem;margin-bottom:1rem}.login-enrol img{background:#fff;padding:.5rem;border-radius:.5rem}.login-secret{display:flex;flex-direction:column;align-items:center;gap:.25rem;text-align:center}.login-secret code{font-size:.95rem;letter-spacing:.08em;word-break:break-all}.usx-secret{display:flex;flex-direction:column;gap:.75rem;padding:1rem}.usx-secret-link{display:block;padding:.6rem .75rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-sm);background:var(--dm-background-alt);word-break:break-all;font-size:.8rem;user-select:all}.usx-secret-actions{display:flex;align-items:center;justify-content:flex-end;gap:.5rem}.usx-secret-actions .btn{display:inline-flex;align-items:center;gap:.35rem}.usx-secret-note{margin-right:auto;color:var(--dm-success)}.usx-secret-foot{color:var(--dm-text-muted);font-size:.8rem;margin:0}.uex-reset{display:flex;flex-wrap:wrap;align-items:center;gap:.35rem .5rem;margin-top:.5rem}.uex-reset>small:first-child{flex-basis:100%;color:var(--dm-text-muted)}.uex-reset .btn{display:inline-flex;align-items:center;gap:.35rem}.uex-reset-open{flex-basis:100%;color:var(--dm-info)}
1
+ .dashboard-layout{display:flex;flex-direction:column;height:100vh;min-height:100vh;overflow:hidden}.dashboard-wrapper{display:flex;flex:1;min-height:0;overflow:hidden}.dashboard-main{flex:1;min-width:0;overflow-y:auto}#admin-sidebar.dashboard-sidebar{display:flex;flex-direction:column;flex-shrink:0;overflow:hidden}#admin-sidebar .dm-admin-sidebar{flex:1;min-height:0;overflow-y:auto;overscroll-behavior:contain;scrollbar-width:thin;scrollbar-color:var(--dm-border) transparent}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar{width:8px}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-track{background:transparent}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-thumb{background:var(--dm-border);border-radius:4px}#admin-sidebar .dm-admin-sidebar::-webkit-scrollbar-thumb:hover{background:var(--dm-text-muted)}.view-container{padding:1.5rem 2rem;max-width:1200px}.view-container:has(>.dm-plugin-shell){max-width:100%}.view-header{display:flex;align-items:center;justify-content:space-between;margin-bottom:1.5rem;gap:1rem}.view-header h1{font-size:1.5rem;font-weight:700;margin:0;display:flex;align-items:center;gap:.5rem}.view-header-actions{display:flex;gap:.75rem;flex-wrap:wrap}.view-header-actions .btn-primary,.view-header-actions .btn-success,.view-header-actions .btn-danger{margin-left:.5rem}.stat-card .card-body{display:flex;align-items:center;gap:1rem}.stat-icon{width:44px;height:44px;border-radius:8px;background:color-mix(in srgb,var(--dm-primary) 14%,transparent);color:var(--dm-primary, #5b8cff);display:flex;align-items:center;justify-content:center;font-size:1.25rem;flex-shrink:0}.stat-icon--success{background:color-mix(in srgb,var(--dm-success) 15%,transparent);color:var(--dm-success)}.stat-icon--warning{background:color-mix(in srgb,var(--dm-warning) 15%,transparent);color:var(--dm-warning)}.stat-value{font-size:1.75rem;font-weight:700;line-height:1}.stat-label{font-size:.8rem;color:var(--dm-text-muted, #888);margin-top:.25rem}.toolbar{display:flex;align-items:center;gap:.75rem}.form-check-label{display:flex;align-items:center;gap:.5rem;cursor:pointer;font-size:.9rem}.form-hint{display:block;font-size:.8rem;color:var(--dm-text-muted, #888);margin-top:.25rem}.dashboard-main:has(#editor-meta-tabs){overflow:hidden}.view-container:has(#editor-meta-tabs){display:flex;flex-direction:column;height:calc(100dvh - 60px);max-width:100%;padding-bottom:0}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell{flex:1;min-height:0;display:flex;flex-direction:column}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell>.dm-plugin-banner,.view-container:has(#editor-meta-tabs) .pex-bar{flex:none}.view-container:has(#editor-meta-tabs)>.dm-plugin-shell>.dm-plugin-body{flex:1;min-height:0;display:flex;flex-direction:column}.view-container:has(#block-editor-body){max-width:100%}.view-container:has(#ep-editor-tabs){max-width:100%}.ep-editor-grid{display:grid;grid-template-columns:minmax(0,1.25fr) minmax(0,1fr) minmax(0,1.3fr);gap:1rem;align-items:start}.ep-editor-grid>.ep-tryit-col,.ep-editor-grid>.ep-results-col{position:sticky;top:1rem;display:flex;flex-direction:column;gap:1rem;min-width:0}@media(max-width:1500px){.ep-editor-grid{grid-template-columns:minmax(0,1fr) minmax(0,1fr)}.ep-editor-grid>:first-child{grid-column:1 / -1}.ep-editor-grid>.ep-tryit-col,.ep-editor-grid>.ep-results-col{position:static}}@media(max-width:1024px){.ep-editor-grid{grid-template-columns:minmax(0,1fr)}}#editor-meta-tabs{flex:1;min-height:0;display:flex;flex-direction:column}#editor-meta-tabs .tab-content{flex:1;min-height:0;overflow:hidden}#editor-meta-tabs .tab-panel{height:100%;overflow-y:auto}#editor-meta-tabs .tab-panel:has(.editor-card),#live-preview-panel{overflow:hidden}.live-preview-bar{display:flex;align-items:center;gap:var(--dm-space-4);flex-wrap:wrap;padding:var(--dm-space-2) 0;border-bottom:1px solid var(--dm-border);margin-bottom:var(--dm-space-2)}.live-preview-widths{display:inline-flex;border:1px solid var(--dm-border);border-radius:var(--dm-radius-sm);overflow:hidden}.live-preview-width{display:inline-flex;align-items:center;justify-content:center;padding:.3rem .55rem;border:none;background:transparent;color:inherit;cursor:pointer;line-height:1}.live-preview-width+.live-preview-width{border-left:1px solid var(--dm-border)}.live-preview-width:hover{background:var(--dm-hover-bg)}.live-preview-width.active{background:var(--dm-active-bg)}.live-preview-status{flex:1 1 auto;font-size:.8rem;opacity:.75}.live-preview-actions{display:flex;gap:var(--dm-space-1)}.live-preview-wrap{display:flex;flex-direction:column;height:100%;min-height:0}.live-preview-wrap>.live-preview-bar{flex:none}.live-preview-stage{display:flex;justify-content:center;flex:1;min-height:0;overflow:auto;background:var(--dm-background-alt);border-radius:var(--dm-radius-md)}.page-live-preview-frame{display:block;width:100%;max-width:100%;height:100%;border:none;border-radius:6px;background:var(--dm-background);transition:max-width .18s ease}.page-live-preview-frame[data-width="1024"]{max-width:1024px}.page-live-preview-frame[data-width="390"]{max-width:390px}.page-live-preview-frame[data-width="1024"],.page-live-preview-frame[data-width="390"]{border-left:1px solid var(--dm-border);border-right:1px solid var(--dm-border)}.editor-card{display:flex;flex-direction:column;height:100%}.editor-card .card-body{display:flex;flex-direction:column;flex:1;min-height:0;padding:0!important}.editor-toolbar{display:flex;align-items:center;gap:2px;padding:6px 10px;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .08));flex-wrap:wrap;flex-shrink:0}.editor-toolbar-btn{background:none;border:none;color:var(--dm-text-muted, #888);padding:6px 8px;border-radius:4px;cursor:pointer;display:flex;align-items:center;transition:color .15s,background .15s}.editor-toolbar-btn:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.editor-toolbar-sep{width:1px;height:20px;background:var(--dm-border, rgba(255, 255, 255, .08));margin:0 4px;flex-shrink:0}.editor-toolbar-right{margin-left:auto;display:flex;align-items:center;gap:2px}.editor-view-btn{background:none;border:none;color:var(--dm-text-muted, #888);padding:6px 8px;border-radius:4px;cursor:pointer;display:flex;align-items:center;transition:color .15s,background .15s}.editor-view-btn:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.editor-view-btn.active{color:var(--dm-primary, #5b8cff);background:color-mix(in srgb,var(--dm-primary) 14%,transparent)}.editor-body{display:flex;flex:1;min-height:0;--dm-editor-split: 50%}@media(min-width:769px){.editor-body:not(.editor-mode-write):not(.editor-mode-preview) .editor-pane--write{flex:0 0 var(--dm-editor-split, 50%)}.editor-body:not(.editor-mode-write):not(.editor-mode-preview) .editor-pane--preview{flex:1 1 0}}.editor-pane{flex:1;display:flex;flex-direction:column;min-width:0}.editor-pane--write,.editor-pane--preview{overflow:hidden}.editor-pane--write{flex-direction:row}.editor-line-numbers{padding:1rem .6rem 1rem .75rem;background:var(--dm-background-alt, rgba(0, 0, 0, .15));border-right:1px solid var(--dm-border, rgba(255, 255, 255, .08));color:var(--dm-text-muted, #666);font-family:Fira Code,Courier New,monospace;font-size:.9rem;line-height:1.6;text-align:right;user-select:none;white-space:pre;overflow:hidden;flex-shrink:0;min-width:2.5rem}.editor-line-numbers--foldable{padding:1rem 0;min-width:3rem;white-space:normal;text-align:left;display:flex;flex-direction:column}.editor-line-number-row{display:flex;align-items:center;justify-content:flex-end;padding-right:.6rem;gap:.15rem}.fold-toggle{display:inline-flex;align-items:center;justify-content:center;width:1em;font-size:.6rem;cursor:default;color:transparent}.fold-toggle--open,.fold-toggle--folded{cursor:pointer;color:var(--dm-text-muted, #666);transition:color .1s}.fold-toggle--open:hover,.fold-toggle--folded:hover{color:var(--dm-primary, #4a9eff)}.editor-line-num{min-width:1.5rem;text-align:right}.editor-mode-write .editor-pane--preview,.editor-mode-write .editor-divider,.editor-mode-preview .editor-pane--write,.editor-mode-preview .editor-divider{display:none}.editor-divider{width:7px;background:linear-gradient(to right,transparent 0,transparent 3px,var(--dm-border, rgba(255,255,255,.08)) 3px,var(--dm-border, rgba(255,255,255,.08)) 4px,transparent 4px,transparent 100%);cursor:col-resize;flex-shrink:0;touch-action:none;transition:background .12s ease}.editor-divider:hover,.editor-divider:focus-visible,.editor-divider.is-dragging{background:linear-gradient(to right,transparent 0,transparent 2px,var(--dm-primary, #5b8cff) 2px,var(--dm-primary, #5b8cff) 5px,transparent 5px,transparent 100%);outline:none}.editor-body.is-resizing .editor-pane{pointer-events:none}.editor-body.is-resizing{cursor:col-resize;user-select:none}.editor-textarea{flex:1;resize:none;border:none;border-radius:0;background:transparent;font-family:Fira Code,Courier New,monospace;font-size:.9rem;padding:1rem;outline:none;color:inherit;line-height:1.6}#editor-body .editor-textarea,#editor-body .editor-line-numbers{font-family:var(--pe-font, "Fira Code", "Courier New", monospace);font-size:var(--pe-size, .9rem);line-height:var(--pe-line, 1.6)}#editor-body.pe-nowrap .editor-textarea{white-space:pre;overflow-x:auto}.editor-preview{flex:1;display:block;width:100%;border:none;background:var(--dm-background)}.editor-fullscreen{position:fixed;inset:0;z-index:1000;border-radius:0;margin:0}.editor-fullscreen .card-body{height:100vh}.media-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(120px,1fr));gap:.75rem;max-height:400px;overflow-y:auto;padding:.25rem}.media-picker-item{cursor:pointer;border:2px solid transparent;border-radius:6px;overflow:hidden;transition:border-color .15s}.media-picker-item:hover{border-color:var(--dm-primary, #5b8cff)}.media-picker-item img{width:100%;height:80px;object-fit:cover;display:block}.media-picker-item span{display:block;font-size:.75rem;padding:4px 6px;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.docs-body h3{margin-top:1.25rem;margin-bottom:.5rem}.docs-body p{margin-bottom:.5rem;line-height:1.6}.docs-body ol,.docs-body ul{margin-bottom:.75rem;padding-left:1.25rem}.docs-body li{margin-bottom:.25rem}.docs-body hr{margin:1.25rem 0;border-color:var(--dm-border, rgba(255, 255, 255, .08))}.docs-body .table{margin-bottom:.75rem}.docs-body h2{margin-top:1.75rem;margin-bottom:.6rem;padding-bottom:.3rem;border-bottom:1px solid var(--dm-border)}.docs-body h2:first-child{margin-top:0}.docs-body blockquote{margin:.75rem 0;padding:.5rem .9rem;border-left:3px solid var(--dm-primary);background:var(--dm-surface);border-radius:var(--dm-radius, 6px)}.docs-body pre{margin-bottom:.75rem;overflow-x:auto}.pg-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(260px,1fr));gap:1rem;margin-top:1.5rem}.pg-grid>.card.pg-card{display:block;margin:0;text-decoration:none}.pg-card h3{margin-top:0}.pg-card .text-muted,.pg-card-pages{margin-bottom:0}.pg-card-pages{margin-top:.5rem;font-size:.8rem;color:var(--dm-text-muted)}.pg-actions{display:flex;gap:.5rem;flex-wrap:wrap}.pg-meta{margin-bottom:.75rem}.pg-pages{display:flex;flex-wrap:wrap;gap:.35rem;margin-bottom:1rem}.pg-body{max-width:80ch}.nav-items-header,.nav-item-row{display:flex;gap:.5rem;align-items:center;padding:.35rem .75rem}.nav-items-header{border-bottom:1px solid var(--dm-border, rgba(255,255,255,.08));padding-bottom:.4rem;margin-bottom:.25rem}.nav-item-row{border-bottom:1px solid var(--dm-border, rgba(255,255,255,.04))}.nav-item-row:last-child{border-bottom:none}.nav-col-indent{width:18px;flex-shrink:0;color:var(--dm-text-muted, #888);text-align:center;font-size:.85rem}.nav-col-main{flex:2;min-width:0}.nav-col-icon{flex:0 0 90px}.nav-col-parent{flex:2;min-width:0}.nav-col-action{flex-shrink:0}.nav-item-row--child{background:color-mix(in srgb,var(--dm-text) 3%,transparent)}.nav-col-action{display:flex;align-items:center;gap:.25rem}.nav-item-row--hidden{opacity:.45}.nav-item-row--hidden .item-text,.nav-item-row--hidden .footer-link-text{text-decoration:line-through}.btn-toggle-hidden{color:var(--dm-text-muted, #888)}.btn-toggle-hidden.active{color:var(--dm-warning, #f59e0b)}.fb-field-card.fb-drag-over{outline:2px dashed var(--dm-primary, #6366f1);outline-offset:-2px}.btn-ghost span[data-icon=trash]{color:var(--dm-danger, #dc2626)}.view-container:has(.fb-fields-layout){max-width:none}.fb-fields-layout{display:grid;grid-template-columns:minmax(0,6fr) minmax(320px,4fr);gap:1.25rem;align-items:start}.fb-preview-pane{position:sticky;top:1rem;min-width:0}@media(max-width:1100px){.fb-fields-layout{grid-template-columns:1fr}.fb-preview-pane{position:static}}.toggle-label{display:flex;align-items:center;gap:.4rem;font-size:.9rem;cursor:pointer;margin-right:1rem}.preset-toggles{display:flex;flex-wrap:wrap;margin-top:.75rem}.presets-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:1rem}@media(max-width:900px){.presets-grid{grid-template-columns:repeat(2,1fr)}}@media(max-width:600px){.presets-grid{grid-template-columns:1fr}}.card-header{padding:.5rem 1rem}.card-header h2{margin:0;font-size:.9rem;font-weight:600;letter-spacing:.02em}.preset-card .card-header{display:flex;align-items:center;justify-content:space-between}.preset-card .card-header h3{margin:0;font-size:1rem}.media-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(180px,1fr));gap:1rem}.media-card{background:var(--dm-card-bg, rgba(255,255,255,.04));border:1px solid var(--dm-border, rgba(255,255,255,.08));border-radius:8px;overflow:hidden}.media-preview{height:130px;display:flex;align-items:center;justify-content:center;background:#0003;overflow:hidden}.media-thumb{width:100%;height:100%;object-fit:cover}.media-thumb--file{font-size:2rem;color:var(--dm-text-muted, #888)}.media-info{padding:.5rem .75rem;display:flex;flex-direction:column;gap:.15rem}.media-name{font-size:.8rem;font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;cursor:default}.media-rename-input{width:100%;font-size:.8rem;font-weight:500;padding:.1rem .25rem;border:1px solid var(--dm-primary, #7c6af7);border-radius:3px;background:var(--dm-input-bg, transparent);color:inherit;outline:none}.media-size{font-size:.75rem;color:var(--dm-text-muted, #888)}.media-actions{padding:.5rem .75rem;display:flex;gap:.4rem;border-top:1px solid var(--dm-border, rgba(255,255,255,.08))}#admin-topbar{height:60px;display:flex;align-items:center;gap:1rem;padding:0 1.25rem;background:var(--dm-navbar-bg, rgba(0,0,0,.3));border-bottom:1px solid var(--dm-border, rgba(255,255,255,.08));position:sticky;top:0;z-index:200;flex-shrink:0}.topbar-brand{display:flex;align-items:center;gap:.5rem;font-weight:700;font-size:.95rem;color:inherit;flex-shrink:0;margin-right:.5rem}.topbar-brand span[data-icon],.topbar-brand svg{color:var(--dm-primary, #5b8cff);width:22px;height:22px}.topbar-brand-text{opacity:.85}.topbar-brand-logo{height:28px;width:auto;display:inline-block;vertical-align:middle;margin-right:.4em;object-fit:contain}.topbar-user{display:flex;align-items:center;gap:.6rem;flex:1}.topbar-user-name{font-size:.875rem;font-weight:500}.topbar-avatar{width:1.75rem;height:1.75rem;border-radius:50%;object-fit:cover;flex-shrink:0}.topbar-role-badge{font-size:.7rem;font-weight:600;letter-spacing:.04em;text-transform:uppercase;padding:.15rem .45rem;border-radius:4px}.topbar-role-badge--admin{background:color-mix(in srgb,var(--dm-primary) 15%,transparent);color:var(--dm-primary)}.topbar-role-badge--manager{background:color-mix(in srgb,var(--dm-success) 15%,transparent);color:var(--dm-success)}.topbar-role-badge--editor{background:color-mix(in srgb,var(--dm-warning) 15%,transparent);color:var(--dm-warning)}.topbar-role-badge--subscriber{background:color-mix(in srgb,var(--dm-text-muted) 15%,transparent);color:var(--dm-text-muted)}.topbar-actions{display:flex;align-items:center;gap:.5rem;flex-shrink:0}.topbar-action-link{display:flex;align-items:center;gap:.35rem;font-size:.875rem;color:var(--dm-text-muted, #888);text-decoration:none;padding:.4rem .65rem;border-radius:6px;transition:color .15s,background .15s}.topbar-action-link:hover{color:var(--dm-text, #eee);background:var(--dm-hover-bg)}.topbar-action-link span[data-icon],.topbar-action-link svg{width:16px;height:16px}.topbar-signout{display:flex;align-items:center;gap:.35rem;font-size:.875rem}.topbar-signout span[data-icon],.topbar-signout svg{width:16px;height:16px}.login-wrap{position:fixed;inset:0;display:flex;align-items:center;justify-content:center;padding:1rem;background:var(--dm-background, #0f1117);z-index:100;overflow-y:auto}.login-card{width:100%;max-width:460px}.ob-done-icon{font-size:3rem;color:var(--dm-success);margin-bottom:1rem;text-align:center}.btn-skip{display:block;text-align:center;margin-top:.75rem;font-size:.85rem;color:var(--dm-text-muted, #888);text-decoration:none}.btn-skip:hover{text-decoration:underline}.theme-grid{display:grid;grid-template-columns:repeat(3,1fr);gap:.6rem}.theme-swatch{border:2px solid var(--dm-border, rgba(255,255,255,.1));border-radius:8px;overflow:hidden;cursor:pointer;transition:border-color .15s,transform .1s}.theme-swatch:hover{border-color:var(--dm-primary, #5b8cff);transform:translateY(-1px)}.theme-swatch.selected{border-color:var(--dm-primary, #5b8cff);box-shadow:0 0 0 2px var(--dm-primary, #5b8cff)}.theme-swatch-preview{height:52px;position:relative;display:flex;align-items:flex-end;padding:.35rem}.theme-swatch-accent{width:28px;height:6px;border-radius:3px}.theme-swatch-label{display:flex;justify-content:space-between;align-items:center;padding:.3rem .45rem;font-size:.7rem;background:var(--dm-card-bg, rgba(255,255,255,.04))}.theme-swatch-mode{color:var(--dm-text-muted, #888);font-size:.65rem}.login-logo{display:flex;align-items:center;gap:.75rem;margin-bottom:1.75rem;font-size:1.5rem}.login-logo span[data-icon]{font-size:2rem;color:var(--dm-primary, #5b8cff)}.login-logo h1{margin:0;font-size:1.5rem;font-weight:700}.login-card [hidden]{display:none!important}.login-heading{font-size:1.1rem;font-weight:600;margin-bottom:1.25rem}.login-rules{margin:.25rem 0 .75rem;padding-left:1.1rem;color:var(--dm-danger);font-size:.85rem}.login-rules li+li{margin-top:.2rem}.login-small{font-size:.8rem;margin-top:.75rem}.login-icon-warn{color:var(--dm-warning)}.pwf{position:relative;display:block}.pwf>input{width:100%;padding-right:2.5rem}.pwf-toggle{position:absolute;top:50%;right:.35rem;transform:translateY(-50%);display:inline-flex;align-items:center;justify-content:center;width:2rem;height:2rem;padding:0;border:0;border-radius:var(--dm-radius-sm);background:transparent;color:var(--dm-text-muted);cursor:pointer}.pwf-toggle:hover,.pwf-toggle:focus-visible{color:var(--dm-text);background:var(--dm-hover-bg)}.pwf-toggle svg{width:16px;height:16px}.pwf-toggle [data-icon=eye-off],.pwf.is-shown .pwf-toggle [data-icon=eye]{display:none}.pwf.is-shown .pwf-toggle [data-icon=eye-off]{display:inline-block}.pwf-caps{display:block;margin-top:.25rem;color:var(--dm-warning);font-size:.8rem}.pwf-caps[hidden]{display:none}.btn-block{width:100%}.plugins-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(300px,1fr));gap:1rem}.plugin-card{display:flex;flex-direction:column;--plugin-accent: var(--dm-primary, #5b8cff);position:relative;overflow:hidden;background-image:radial-gradient(120% 90% at 100% 0%,color-mix(in srgb,var(--plugin-accent) 13%,transparent) 0%,color-mix(in srgb,var(--plugin-accent) 4%,transparent) 42%,transparent 72%)}.plugin-card .plugin-icon{background:color-mix(in srgb,var(--plugin-accent) 16%,transparent);color:var(--plugin-accent)}.plugin-watermark{position:absolute;top:-34px;right:-30px;width:148px;height:148px;display:block;color:var(--plugin-accent);opacity:.09;pointer-events:none;z-index:0}.plugin-card>.card-body,.plugin-card>.plugin-footer{position:relative;z-index:1}.plugin-card:has(.badge-secondary) .plugin-watermark{opacity:.05}@media(prefers-reduced-motion:no-preference){.plugin-card{transition:background-image .2s ease}}.plugin-card .card-body{flex:1}.plugin-header{display:flex;align-items:flex-start;gap:.75rem;margin-bottom:.75rem;flex-wrap:wrap}.plugin-icon{width:40px;height:40px;border-radius:8px;background:color-mix(in srgb,var(--dm-primary) 14%,transparent);color:var(--dm-primary, #5b8cff);display:flex;align-items:center;justify-content:center;flex-shrink:0}.plugin-meta{flex:1 1 140px;min-width:0}.plugin-name{font-weight:600;margin-bottom:.15rem}.plugin-version{font-size:.75rem;color:var(--dm-text-muted, #888)}.plugin-desc{font-size:.875rem;color:var(--dm-text-muted, #888);margin-bottom:1rem}.plugin-footer{display:flex;align-items:center;justify-content:space-between;padding:.75rem 1rem;border-top:1px solid var(--dm-border, rgba(255,255,255,.08))}.plugin-footer-actions{display:flex;align-items:center;gap:.5rem}#admin-sidebar .sidebar-link{position:relative!important}#admin-sidebar .sidebar-badge{position:absolute!important;right:.75rem!important;top:50%!important;transform:translateY(-50%)!important;margin-left:0!important;padding-left:.45rem!important;padding-right:.45rem!important}#admin-sidebar .sidebar-text{padding-right:2rem!important}#admin-sidebar.sidebar-dark{background:var(--dm-surface);border-color:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-header{background:var(--dm-surface-raised);border-color:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-header-title{color:var(--dm-text)}#admin-sidebar.sidebar-dark .sidebar-link{color:var(--dm-text-muted)}#admin-sidebar.sidebar-dark .sidebar-link:hover{color:var(--dm-text);background:var(--dm-surface-overlay)}#admin-sidebar.sidebar-dark .sidebar-link.active{color:var(--dm-primary);background:color-mix(in srgb,var(--dm-primary) 14%,transparent);border-left-color:var(--dm-primary)}#admin-sidebar.sidebar-dark .sidebar-heading{color:var(--dm-text-muted)}#admin-sidebar.sidebar-dark .sidebar-divider{background:var(--dm-border)}#admin-sidebar.sidebar-dark .sidebar-footer{background:var(--dm-surface-raised);border-color:var(--dm-border)}.sidebar-heading--collapsible{display:flex!important;align-items:center;justify-content:space-between;cursor:pointer;user-select:none}.sidebar-heading-toggle{display:flex;align-items:center;opacity:.5;flex-shrink:0;transition:transform .2s ease}.sidebar-heading--collapsible.is-collapsed .sidebar-heading-toggle{transform:rotate(-90deg)}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.p-0{padding:0!important}.text-muted{color:var(--dm-text-muted, #888)}@media(max-width:768px){.view-container{padding:1rem}.editor-body{flex-direction:column}.editor-divider{width:auto;height:1px;cursor:default;background:var(--dm-border, rgba(255,255,255,.08))}}.image-editor{display:flex;flex-direction:column;gap:0}.image-editor-toolbar{display:flex;flex-direction:row;align-items:center;gap:.25rem;padding:.5rem .75rem;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .1))}.image-editor-sep{display:inline-block;width:1px;height:1.5rem;background:var(--dm-border, rgba(255, 255, 255, .15));margin:0 .25rem;flex-shrink:0}.editor-toolbar-btn.active{color:var(--dm-primary, #7c6af7);background:color-mix(in srgb,var(--dm-primary, #7c6af7) 15%,transparent)}.editor-toolbar-caret{font-size:.6rem;line-height:1;margin-left:2px;opacity:.6}.editor-toolbar-dropdown{position:absolute;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:4px;min-width:160px;max-height:70vh;overflow-y:auto}.editor-toolbar-dropdown-heading{padding:6px 10px 3px;color:var(--dm-text-muted, #8a8a9a);font-size:.66rem;text-transform:uppercase;letter-spacing:.06em}.editor-toolbar-dropdown-item{display:flex;align-items:center;gap:8px;width:100%;text-align:left;background:none;border:none;color:var(--dm-text, #ddd);padding:7px 10px;border-radius:5px;cursor:pointer;font-size:.85rem;transition:background .12s,color .12s}.editor-toolbar-dropdown-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-toolbar-dropdown-item span[data-icon],.editor-toolbar-dropdown-item svg{width:15px;height:15px;flex-shrink:0;opacity:.75}.editor-toolbar{position:relative}.editor-effects-dropdown-menu{position:absolute;top:100%;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:6px;min-width:180px;max-height:340px;overflow-y:auto}.editor-effects-category{padding:6px 8px 3px;font-size:.7rem;font-weight:700;letter-spacing:.07em;text-transform:uppercase;color:var(--dm-text-muted, #888)}.editor-effects-item{display:block;width:100%;text-align:left;background:none;border:none;color:var(--dm-text, #ddd);padding:6px 10px;border-radius:5px;cursor:pointer;font-size:.85rem;transition:background .12s,color .12s}.editor-effects-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-icon-picker{position:absolute;z-index:1000;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, rgba(255, 255, 255, .1));border-radius:8px;box-shadow:0 8px 24px #0006;padding:8px;width:320px}.editor-icon-picker-search{width:100%;margin-bottom:8px;font-size:.8rem}.editor-spacer-picker{position:absolute;z-index:9999;background:var(--dm-surface, #1e1e2e);border:1px solid var(--dm-border, #333);border-radius:8px;padding:12px;width:240px;box-shadow:0 8px 24px #00000073}.editor-spacer-picker-label{font-size:11px;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--dm-text-muted, #888);margin-bottom:10px}.editor-spacer-picker-row{display:flex;align-items:center;gap:10px;margin-bottom:12px}.editor-spacer-slider{flex:1;accent-color:var(--dm-primary, #6366f1);cursor:pointer}.editor-spacer-slider-value{font-size:13px;font-weight:600;min-width:38px;text-align:right;color:var(--dm-text, #cdd6f4)}.editor-spacer-insert-btn{width:100%}.editor-icon-picker-size-row{display:flex;align-items:center;gap:8px;padding:0 8px 8px}.editor-icon-picker-size-row label{font-size:11px;color:var(--dm-text-muted, #888);white-space:nowrap}.editor-icon-picker-size{width:70px;font-size:12px;padding:3px 6px}.editor-icon-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(52px,1fr));gap:2px;max-height:280px;overflow-y:auto}.editor-icon-picker-item{display:flex;flex-direction:column;align-items:center;justify-content:center;padding:6px 2px;border-radius:5px;cursor:pointer;background:none;border:none;color:var(--dm-text, #ddd);font-size:.58rem;text-align:center;gap:4px;overflow:hidden;transition:background .12s,color .12s}.editor-icon-picker-item:hover{background:var(--dm-hover-bg);color:var(--dm-text, #fff)}.editor-icon-picker-item span[data-icon],.editor-icon-picker-item svg{width:16px;height:16px;flex-shrink:0}.editor-icon-picker-item>span:last-child{max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;line-height:1.2}.editor-icon-picker-empty{grid-column:1 / -1;text-align:center;color:var(--dm-text-muted, #888);font-size:.8rem;padding:1.5rem}.image-editor-canvas{min-height:320px;max-height:520px;background:#111;overflow:hidden;display:flex;align-items:center;justify-content:center}.image-editor-canvas img{display:block;max-width:100%;max-height:520px}.image-editor-resize{display:flex;flex-direction:row;align-items:center;gap:.5rem;padding:.6rem .75rem;border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1));font-size:.85rem}.image-editor-resize label{font-weight:600;color:var(--dm-text-muted, #888);font-size:.8rem}.image-editor-resize .form-input{width:5rem;padding:.25rem .5rem;font-size:.85rem}.image-editor-footer{display:flex;flex-direction:row;align-items:center;justify-content:space-between;padding:.75rem;border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1));gap:.5rem}.image-editor-effects{border-top:1px solid var(--dm-border, rgba(255, 255, 255, .1))}.image-editor-tab-bar{display:flex;flex-direction:row;overflow-x:auto;border-bottom:1px solid var(--dm-border, rgba(255, 255, 255, .1));scrollbar-width:none}.image-editor-tab-bar::-webkit-scrollbar{display:none}.image-editor-tab-btn{display:inline-flex;align-items:center;gap:.35rem;padding:.5rem .85rem;font-size:.8rem;font-weight:500;border:none;border-bottom:2px solid transparent;background:transparent;cursor:pointer;color:var(--dm-text-muted, #888);white-space:nowrap;transition:color .15s,border-color .15s;flex-shrink:0}.image-editor-tab-btn:hover{color:var(--dm-text, #eee)}.image-editor-tab-btn.active{color:var(--dm-primary, #7c6af7);border-bottom-color:var(--dm-primary, #7c6af7)}.image-editor-tab-panel{padding:.75rem;max-height:200px;overflow-y:auto}.ie-presets-grid{display:flex;flex-wrap:wrap;gap:.35rem;margin-bottom:.5rem}.ie-preset-btn.active{color:var(--dm-primary, #7c6af7);background:color-mix(in srgb,var(--dm-primary, #7c6af7) 15%,transparent);border-color:var(--dm-primary, #7c6af7)}.ie-server-note{font-size:.73rem;color:var(--dm-text-muted, #888);font-style:italic;margin:.25rem 0 0;line-height:1.4}.ie-slider-row{display:flex;align-items:center;gap:.5rem;margin-bottom:.4rem}.ie-slider-label{width:6rem;font-size:.8rem;color:var(--dm-text-muted, #888);font-weight:600;flex-shrink:0}.ie-slider{flex:1;accent-color:var(--dm-primary, #7c6af7);cursor:pointer}.ie-slider-val{width:3rem;font-size:.8rem;text-align:right;color:var(--dm-text, #eee);flex-shrink:0}.ie-select{flex:1;font-size:.85rem;padding:.25rem .5rem}.ie-colour-input{width:40px;height:28px;padding:0;border:1px solid var(--dm-border, rgba(255, 255, 255, .15));border-radius:4px;cursor:pointer;background:transparent;flex-shrink:0}.ie-wm-preview-row{display:flex;align-items:center;gap:.5rem;margin:.4rem 0}.ie-wm-preview-img{width:48px;height:48px;object-fit:contain;border-radius:4px;background:var(--dm-surface-raised, rgba(255, 255, 255, .06));flex-shrink:0}.ie-wm-preview-name{font-size:.8rem;flex:1;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;color:var(--dm-text, #eee)}.ie-media-picker{padding:.25rem 0}.ie-media-picker-grid{display:grid;grid-template-columns:repeat(auto-fill,minmax(80px,1fr));gap:.5rem;max-height:300px;overflow-y:auto}.ie-media-thumb{display:flex;flex-direction:column;align-items:center;gap:.25rem;padding:.4rem;border-radius:6px;cursor:pointer;border:2px solid transparent;transition:border-color .15s,background .15s}.ie-media-thumb:hover{background:var(--dm-surface-raised, rgba(255, 255, 255, .08));border-color:var(--dm-primary, #7c6af7)}.ie-media-thumb img{width:72px;height:72px;object-fit:cover;border-radius:4px}.ie-media-thumb-name{font-size:.7rem;color:var(--dm-text-muted, #888);text-align:center;overflow:hidden;text-overflow:ellipsis;white-space:nowrap;max-width:72px}.dm-slideover-left,.dm-slideover-right{width:min(40rem,95vw)!important;min-width:min(36rem,100vw)!important;max-width:100vw!important}.dm-slideover-resizer{position:absolute;top:0;bottom:0;width:6px;cursor:col-resize;z-index:2;background:transparent}.dm-slideover-right>.dm-slideover-resizer{left:0}.dm-slideover-left>.dm-slideover-resizer{right:0}.dm-slideover-resizer:hover,.is-resizing>.dm-slideover-resizer{background:var(--dm-primary);opacity:.7}.dm-slideover.is-resizing{user-select:none;transition:none!important}.dm-slideover-header{display:flex;align-items:center;justify-content:space-between;padding:1rem 1.25rem;border-bottom:1px solid var(--dm-border, #333);flex-shrink:0}.dm-slideover-title{margin:0;font-size:1rem;font-weight:600}.dm-slideover-close{padding:.2rem .35rem!important;line-height:1;font-size:.75rem}.dm-slideover-body{flex:1;overflow:auto;overscroll-behavior:contain;min-height:0;padding:1.5rem!important;box-sizing:border-box}.dm-slideover-body:empty{flex:0 0 auto;padding:0!important}.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-body):not(.dm-slideover-close){padding:1.5rem!important;box-sizing:border-box;flex:1 1 auto;min-height:0;overflow:auto;overscroll-behavior:contain}.dm-slideover-body,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close){scrollbar-width:thin;scrollbar-color:var(--dm-border) transparent}.dm-slideover-body::-webkit-scrollbar,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar{width:8px;height:8px}.dm-slideover-body::-webkit-scrollbar-track,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-track{background:transparent}.dm-slideover-body::-webkit-scrollbar-thumb,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-thumb{background:var(--dm-border);border-radius:4px}.dm-slideover-body::-webkit-scrollbar-thumb:hover,.dm-slideover>div:not(.dm-slideover-header):not(.dm-slideover-close)::-webkit-scrollbar-thumb:hover{background:var(--dm-text-muted)}.dm-slideover-body>div{padding-left:0!important;padding-right:0!important}.dm-slideover-body>button.btn:last-child{margin-top:.5rem}.dconfig-textarea{font-family:monospace;min-height:100px;resize:vertical}.dm-editor-line-numbers{white-space:pre}.dm-code-inline{font-family:Fira Code,Courier New,monospace;font-size:.82em;padding:.15em .35em;border-radius:3px;background:var(--dm-background-alt, rgba(0, 0, 0, .18));color:var(--dm-text, inherit);border:1px solid var(--dm-border, rgba(255, 255, 255, .08))}.dm-code-block{font-family:Fira Code,Courier New,monospace;font-size:.82rem;line-height:1.6;padding:.65rem .9rem;border-radius:6px;background:var(--dm-background-alt, rgba(0, 0, 0, .18));color:var(--dm-text, inherit);border:1px solid var(--dm-border, rgba(255, 255, 255, .08));white-space:pre;overflow-x:auto;display:block;margin:.4rem 0}.tabs-centered{text-align:center}.tabs-centered .tab-list{display:inline-flex}.tabs-centered .tab-content{text-align:left}@media(max-width:768px){.view-header{flex-direction:column;align-items:flex-start}.theme-grid{grid-template-columns:repeat(2,1fr)}.nav-item-row{flex-wrap:wrap}.nav-col-icon,.nav-col-parent{display:none}#admin-topbar{padding:0 .75rem}.topbar-brand-text{display:none}.image-editor-toolbar{flex-wrap:wrap}}#topbar-bell{position:relative}.topbar-action-link[hidden],.topbar-bell-badge[hidden]{display:none}.topbar-bell-badge{position:absolute;top:2px;right:2px;min-width:16px;height:16px;padding:0 4px;background:var(--dm-danger, #dc2626);color:var(--dm-danger-text, #fff);font-size:10px;font-weight:700;line-height:16px;border-radius:9999px;text-align:center;pointer-events:none}.cb-scaffolder{padding:1rem 1.1rem;background:var(--dm-background-alt);border:1px solid var(--dm-primary);border-radius:8px;color:var(--dm-text)}.cb-scaffolder-head{display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}.cb-scaffolder-head .cb-icon{flex-shrink:0;color:var(--dm-primary)}.cb-scaffolder-head h2{margin:0;font-size:1.05rem;font-weight:700;color:var(--dm-text)}.cb-scaffolder-blurb{margin:0 0 .75rem;font-size:.88rem;line-height:1.5;color:var(--dm-text-muted)}.cb-recipe-list{display:flex;flex-direction:column;gap:.5rem}.cb-recipe-card{display:flex;align-items:flex-start;gap:.75rem;text-align:left;padding:.75rem 1rem;background:var(--dm-surface);border:1px solid var(--dm-border);border-radius:6px;cursor:pointer;transition:border-color .12s;width:100%;color:var(--dm-text)}.cb-recipe-card:hover{border-color:var(--dm-primary)}.cb-recipe-card .cb-icon{flex-shrink:0;font-size:1.5rem;color:var(--dm-primary);margin-top:.1rem}.cb-recipe-meta{flex:1}.cb-recipe-name{font-weight:600;margin-bottom:.15rem;font-size:.95rem;color:var(--dm-text)}.cb-recipe-desc{font-size:.83rem;line-height:1.45;color:var(--dm-text-muted)}.cb-apply-panel{padding:1rem 1.1rem;background:var(--dm-surface);border:1px solid var(--dm-primary);border-radius:8px;color:var(--dm-text)}.cb-apply-head{display:flex;align-items:center;gap:.5rem;margin-bottom:.5rem}.cb-apply-head .cb-icon{color:var(--dm-primary);font-size:1.4rem}.cb-apply-head h3{margin:0;font-size:1rem;font-weight:600;color:var(--dm-text)}.cb-apply-desc,.cb-apply-hint{margin:.25rem 0 .75rem;font-size:.85rem;line-height:1.5;color:var(--dm-text-muted)}.cb-apply-hint{font-size:.75rem;margin-top:.2rem}.cb-apply-field{margin-bottom:.6rem}.cb-apply-field label{display:block;font-size:.82rem;font-weight:600;margin-bottom:.2rem;color:var(--dm-text)}.cb-apply-field input{width:100%;padding:.4rem .55rem;border:1px solid var(--dm-border);border-radius:4px;font-size:.88rem;background:var(--dm-surface);color:var(--dm-text)}.cb-apply-status{margin:.5rem 0;font-size:.85rem;min-height:1.2rem;color:var(--dm-text)}.cb-apply-status.cb-error{color:var(--dm-danger, #dc2626)}.cb-apply-buttons{display:flex;gap:.5rem;justify-content:flex-end;margin-top:.5rem}.cb-success-panel{padding:1rem 1.1rem;background:var(--dm-surface);border:1px solid var(--dm-success, #16a34a);border-radius:8px;color:var(--dm-text)}.cb-success-panel .cb-icon{color:var(--dm-success, #16a34a);font-size:1.4rem}.cb-success-summary{margin:.25rem 0 .5rem;padding-left:1.2rem;font-size:.86rem;line-height:1.6;color:var(--dm-text)}.cb-success-warning{margin:.5rem 0;padding:.5rem .75rem;background:var(--dm-background-alt);border-left:3px solid var(--dm-warning, #eab308);border-radius:0 4px 4px 0;font-size:.82rem;color:var(--dm-text-muted)}.cb-success-snippet-label{margin:0 0 .25rem;font-size:.82rem;font-weight:600;color:var(--dm-text)}.cb-success-actions{display:flex;gap:.5rem;margin-top:.5rem;flex-wrap:wrap}.cb-code{position:relative}.cb-code pre{background:var(--dm-background-alt);color:var(--dm-text);display:block;padding:.6rem 2.4rem .6rem .75rem;white-space:pre;overflow-x:auto;margin:0;border-radius:6px;font-size:.82em;font-family:monospace;line-height:1.45}.cb-code .cb-copy{position:absolute;top:.35rem;right:.35rem;background:none;border:none;cursor:pointer;opacity:.45;padding:.2rem;line-height:1;color:var(--dm-text)}.cb-code .cb-copy:hover{opacity:1}.cb-intro{padding:.75rem 1rem;border-left:3px solid var(--dm-primary);background:var(--dm-background-alt);border-radius:0 6px 6px 0}.cb-intro p{margin:0;font-size:.92rem;line-height:1.5;color:var(--dm-text)}.cb-tutorial-link{display:flex;align-items:center;gap:.6rem;padding:.65rem .85rem;border:1px solid var(--dm-border);border-radius:6px;text-decoration:none;color:var(--dm-text);font-size:.88rem;transition:border-color .12s}.cb-tutorial-link:hover{border-color:var(--dm-primary)}.cb-tutorial-link .cb-icon{flex-shrink:0;color:var(--dm-primary)}.cb-tutorial-link .cb-arrow{color:var(--dm-text-muted);font-size:1.1rem;margin-left:auto}.menu-tree-row{display:grid;grid-template-columns:26px 1.4fr 1.4fr .9fr .7fr .9fr repeat(6,auto);gap:6px;align-items:center;padding:4px 0;transition:opacity .15s ease}.menu-tree-row--hidden{opacity:.5}.menu-tree-row--tool .me-tool-badge{margin-left:.4rem;font-size:.7rem;vertical-align:middle}.menu-tree-row--default .me-row-label{font-style:italic;opacity:.8}.menu-tree-grip{cursor:grab;color:var(--dm-text-muted)}.menu-tree-grip:hover{color:var(--dm-text)}.menu-tree{padding:8px 0}.menu-tree-row--separator{display:grid;grid-template-columns:26px minmax(80px,1fr) repeat(7,auto);gap:6px;align-items:center;padding:2px 0;opacity:.85}.menu-tree-row--separator:hover{opacity:1}.menu-tree-row--separator .me-sep-line{display:flex;align-items:center;gap:10px;width:100%}.menu-tree-row--separator .me-sep-line:before,.menu-tree-row--separator .me-sep-line:after{content:"";flex:1;border-top:1px dashed var(--dm-border, rgba(128, 128, 128, .55))}.menu-tree-row--separator .me-sep-label{font-size:.66rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--dm-text-muted, #8a8a8a);white-space:nowrap}.dm-admin-sidebar .sidebar-divider{border:0;border-top:1px solid var(--dm-border, rgba(128, 128, 128, .5));margin:.5rem .75rem;opacity:.8}.dm-admin-sidebar .sidebar-spacer--xs{height:var(--dm-space-1, .25rem)}.dm-admin-sidebar .sidebar-spacer--sm{height:var(--dm-space-2, .5rem)}.dm-admin-sidebar .sidebar-spacer--md{height:var(--dm-space-4, 1rem)}.dm-admin-sidebar .sidebar-spacer--lg{height:var(--dm-space-6, 1.5rem)}.dm-admin-sidebar .sidebar-spacer--xl{height:var(--dm-space-10, 2.5rem)}.dm-admin-sidebar .sidebar-spacer--flex{flex:1 1 auto;min-height:var(--dm-space-4, 1rem)}.dm-admin-sidebar--has-flex-spacer{display:flex;flex-direction:column;min-height:100%}.menu-tree-row--spacer{display:grid;grid-template-columns:26px minmax(80px,1fr) repeat(7,auto);gap:6px;align-items:center;padding:2px 0;opacity:.85}.menu-tree-row--spacer:hover{opacity:1}.menu-tree-row--spacer .me-spacer-line{display:flex;align-items:center;gap:8px;width:100%}.menu-tree-row--spacer .me-spacer-line:before,.menu-tree-row--spacer .me-spacer-line:after{content:"";flex:1;border-top:1px dotted var(--dm-border, rgba(128, 128, 128, .55))}.menu-tree-row--spacer .me-spacer-label{font-size:.66rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase;color:var(--dm-text-muted, #8a8a8a);white-space:nowrap}.menu-tree-row--spacer .me-spacer-size{width:auto;min-width:5.5rem;height:26px;padding:0 .35rem;font-size:.75rem}.menu-tree-row .me-icon-wrap{display:flex;gap:2px}.menu-tree-row .me-icon-wrap .me-icon{flex:1;min-width:0}.menu-tree-row .me-icon-wrap .me-icon-pick{flex-shrink:0;padding:.2rem .45rem;font-size:.85em}.dm-admin-sidebar{display:flex;flex-direction:column;gap:2px;padding:8px 0;font-size:.875rem}.dm-admin-sidebar details{margin:0}.dm-admin-sidebar details>summary{list-style:none;cursor:pointer;display:flex;align-items:center;gap:.5rem;padding:.4rem .75rem;border-radius:4px;user-select:none;font-size:.78rem;font-weight:600;text-transform:uppercase;letter-spacing:.05em;color:var(--dm-text-muted, #888)}.dm-admin-sidebar details details>summary{font-size:.875rem;font-weight:500;text-transform:none;letter-spacing:0;color:inherit}.dm-admin-sidebar .dm-menu-badge{font-size:.7rem;font-weight:600}.dm-admin-sidebar details>summary::-webkit-details-marker{display:none}.dm-admin-sidebar details>summary:after{content:"\25b8";margin-left:auto;transition:transform .15s ease;color:var(--dm-text-muted, #999);font-size:.85em}.dm-admin-sidebar details[open]>summary:after{transform:rotate(90deg)}.dm-admin-sidebar details>div{padding-left:1rem;border-left:1px solid var(--dm-border-light, rgba(0, 0, 0, .08));margin-left:.95rem}.dm-admin-sidebar .sidebar-link{display:flex;align-items:center;gap:.5rem;padding:.35rem .75rem;text-decoration:none;color:var(--dm-text, inherit);border-radius:4px}.dm-admin-sidebar .sidebar-link:hover,.dm-admin-sidebar details>summary:hover{background:var(--dm-hover-bg, rgba(0, 0, 0, .05))}.dm-admin-sidebar .sidebar-link.active{background:var(--dm-active-bg, rgba(0, 0, 0, .08));font-weight:600}.dm-admin-sidebar .sidebar-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dm-admin-sidebar [data-icon]{flex-shrink:0}.dm-admin-sidebar-header{position:sticky;top:0;z-index:2;background:var(--dm-surface);display:flex;align-items:center;gap:.5rem;padding:.65rem .85rem;margin:0 0 .5rem;font-weight:600;font-size:.95rem;letter-spacing:.01em;color:var(--dm-text, inherit);border-bottom:1px solid var(--dm-border-light, rgba(0, 0, 0, .08))}.dm-admin-sidebar--dark .dm-admin-sidebar-header{background:#1a1d24}.dm-admin-sidebar--light .dm-admin-sidebar-header{background:#fff}.dm-admin-sidebar-header [data-icon]{color:var(--dm-text-muted, #999)}.dm-admin-sidebar-header .dm-admin-sidebar-arrange{margin-left:auto;padding:.2rem .35rem;color:var(--dm-text-muted, #999);line-height:1}.dm-admin-sidebar-header .dm-admin-sidebar-arrange:hover,.dm-admin-sidebar-header .dm-admin-sidebar-arrange:focus-visible{color:var(--dm-text)}.dm-admin-sidebar.is-arranging>:not(.dm-admin-sidebar-header):not(.sb-arrange):not(style){display:none!important}.dm-admin-sidebar.is-arranging .dm-admin-sidebar-arrange{display:none}.sb-arrange{box-sizing:border-box;max-width:100vw;padding:0 .5rem 1rem;animation:sb-arrange-in .18s cubic-bezier(.2,.8,.2,1)}@keyframes sb-arrange-in{0%{opacity:0;transform:translateY(-4px)}to{opacity:1;transform:none}}.sb-arrange-bar{position:sticky;top:2.6rem;z-index:2;display:flex;align-items:center;gap:.4rem;padding:.4rem .25rem;background:inherit}.sb-arrange-title{font-weight:600;margin-right:auto}.sb-arrange-hint{margin:0 .25rem .5rem;font-size:.78rem;line-height:1.35;color:var(--dm-text-muted)}.sb-arr-row{display:flex;align-items:center;gap:.45rem;padding:.35rem .4rem .35rem calc(.4rem + var(--sb-arr-depth, 0) * 1rem);border-radius:var(--dm-radius-sm, 4px);cursor:grab;user-select:none;font-size:.9rem}.sb-arr-row:hover{background:color-mix(in srgb,var(--dm-text) 6%,transparent)}.sb-arr-row:focus-visible{outline:2px solid var(--dm-primary);outline-offset:-2px}.sb-arr-row--folder .sb-arr-text{font-weight:600}.sb-arr-row--hidden .sb-arr-text,.sb-arr-row--hidden .sb-arr-icon{opacity:.45;text-decoration:line-through}.sb-arr-row--structural .sb-arr-text{font-size:.75rem;text-transform:uppercase;letter-spacing:.05em;color:var(--dm-text-muted)}.sb-arr-grip{color:var(--dm-text-muted);flex:none}.sb-arr-icon{width:16px;flex:none}.sb-arr-text{flex:1;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sb-arr-hide{flex:none;display:inline-flex;padding:.15rem;border:0;border-radius:var(--dm-radius-sm, 4px);background:transparent;color:var(--dm-text-muted);cursor:pointer}.sb-arr-hide:hover,.sb-arr-hide:focus-visible{color:var(--dm-text);background:color-mix(in srgb,var(--dm-text) 8%,transparent)}.sb-arr-lock{flex:none;color:var(--dm-text-muted);opacity:.6}.dm-admin-sidebar .sidebar-badge{margin-left:auto;padding:0 .4rem;min-width:1.25rem;height:1.1rem;line-height:1.1rem;text-align:center;font-size:.7rem;font-weight:600;border-radius:999px;background:var(--dm-active-bg, rgba(0, 0, 0, .12));color:var(--dm-text-muted, #888)}.dm-admin-sidebar .sidebar-link.active .sidebar-badge{background:var(--dm-primary, #4a86e8);color:var(--dm-primary-text, #fff)}.dm-admin-sidebar .sidebar-children{overflow:hidden;transition:max-height .22s ease,opacity .18s ease}.dm-admin-sidebar details:not([open])>.sidebar-children{opacity:0}.dm-admin-sidebar{position:relative}.dm-admin-sidebar-handle{position:absolute;top:0;right:0;width:6px;height:100%;cursor:col-resize;background:transparent;z-index:10;transition:background .15s}.dm-admin-sidebar-handle:hover,.dm-admin-sidebar-handle:active{background:var(--dm-primary, #4a86e8);opacity:.35}.dm-admin-sidebar--dark{background:#1a1d24;color:#e3e6eb}.dm-admin-sidebar--dark .sidebar-link,.dm-admin-sidebar--dark summary{color:#e3e6eb}.dm-admin-sidebar--dark .sidebar-link:hover,.dm-admin-sidebar--dark details>summary:hover{background:#ffffff0f}.dm-admin-sidebar--dark .sidebar-link.active{background:#4a86e840}.dm-admin-sidebar--dark .sidebar-badge{background:#ffffff1f;color:#cbd0d8}.dm-admin-sidebar--light{background:#fff;color:#1a1d24;border-right:1px solid rgba(0,0,0,.08)}.dm-admin-sidebar--light .sidebar-link,.dm-admin-sidebar--light summary{color:#1a1d24}.dm-admin-sidebar--light .sidebar-link:hover,.dm-admin-sidebar--light details>summary:hover{background:#0000000a}.dm-admin-sidebar--light .sidebar-link.active{background:#4a86e826}.dm-admin-sidebar--transparent{background:transparent}.page-header{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;margin:0 0 1.25rem;padding-bottom:.75rem;border-bottom:1px solid var(--dm-border-light, rgba(0, 0, 0, .08))}.page-header h2{margin:0;display:flex;align-items:center;gap:.5rem;font-size:1.4rem;line-height:1.2}.page-header h2 [data-icon]{color:var(--dm-text-muted, #888)}.header-actions{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap}.card+.card,.card+p,p+.card,.card+.toolbar,.toolbar+.card,.card+.grid{margin-top:1rem}.toolbar{display:flex;align-items:center;gap:.5rem;flex-wrap:wrap;margin:0 0 1rem}.btn+.btn,.btn+a.btn,a.btn+.btn,a.btn+a.btn{margin-left:.35rem}[style*=inline-flex] .btn+.btn,[style*=inline-flex] .btn+a.btn,[style*=inline-flex] a.btn+.btn{margin-left:0}.card-body>[id$=-form],.card-body>form{margin:.25rem 0}.card-header{display:flex;align-items:center;gap:.5rem}.card-header h3{margin:0;font-size:1.05rem}.card-header [data-icon]{color:var(--dm-text-muted, #888)}.page-header+p.text-muted{margin:-.5rem 0 1rem}.dm-pe-grid{gap:.75rem 1rem}.dm-pe-grid .form-group{display:flex;flex-direction:column;gap:.25rem;margin:0}.dm-pe-grid .form-group.col-span-2{grid-column:1 / -1}.dm-pe-grid label{font-size:.85rem;font-weight:600;color:var(--dm-text, inherit)}.dm-pe-grid label .required{color:var(--dm-danger, #c33);margin-left:2px}.dm-pe-grid .form-hint{font-size:.75rem;color:var(--dm-text-muted, #888);margin-top:.1rem}.dm-pe-grid .form-input{width:100%;padding:.4rem .6rem}.dm-pe-grid textarea.form-input{resize:vertical;min-height:2.5rem}.dm-menu-badge{display:inline-block;margin-left:6px;padding:1px 7px;font-size:.7em;font-weight:700;line-height:1.4;border-radius:999px;background:var(--dm-text-muted);color:var(--dm-text-inverse, #fff);vertical-align:middle}.menu-tree-row--slim{display:grid;grid-template-columns:26px 1fr auto repeat(9,auto);gap:6px;align-items:center}.menu-tree-row--slim .me-row-label{font-weight:600}.menu-tree-row--slim .me-row-url{color:var(--dm-text-muted);font-size:.85em}.me-pages-picker{display:flex;gap:6px;align-items:center;margin-bottom:6px}.me-pages-picker .form-input{flex:1;min-width:0}.me-colour-control{display:flex;gap:6px;align-items:center}.me-colour-control .me-colour-hex{width:48px;height:32px;padding:2px;flex:none}.me-bind-summary{padding:.6rem .8rem;border:1px solid var(--dm-border, rgba(128, 128, 128, .35));border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-text) 4%,transparent);font-size:.9em}.me-bind-summary code{font-size:.9em}.me-item-form{display:flex;flex-direction:column;gap:10px;padding:4px 2px}.me-item-form .form-field{display:flex;flex-direction:column;gap:4px}.me-item-form .form-label{font-size:.85em;color:var(--dm-text-muted)}.me-form-section{margin:12px 0 2px;padding-top:10px;border-top:1px solid var(--dm-border-light, rgba(0,0,0,.15));font-size:.78em;text-transform:uppercase;letter-spacing:.06em;color:var(--dm-text-muted)}.me-item-form .me-form-section:first-child{margin-top:0;padding-top:0;border-top:0}.me-item-form .me-colour-hex{width:48px;height:32px;padding:2px}.me-item-form .me-field-grid{display:grid;grid-template-columns:1fr 1fr;gap:10px}.me-item-form .me-field-grid .form-field{margin:0}.me-item-form .me-icon-field{display:flex;align-items:center;gap:8px}.me-item-form .me-icon-field .form-input{flex:1}.me-item-form .me-icon-preview{width:24px;height:24px;flex:0 0 auto;display:inline-flex;align-items:center;justify-content:center;color:var(--dm-text-muted)}#admin-sidebar.dm-menu-floating{border:1px solid var(--dm-border);border-radius:var(--dm-radius-md, 8px);box-shadow:var(--dm-shadow-lg);overflow:hidden}@media(max-width:768px){#admin-sidebar.dm-menu-floating{position:static!important;inset:auto!important;max-height:none!important;transform:none!important}.dashboard-wrapper{padding-left:0!important;padding-right:0!important}}[data-logic-section]{border:1px solid var(--dm-border);border-radius:var(--dm-radius-md, 6px);padding:.9rem 1rem 1rem;margin-bottom:1rem;background:color-mix(in srgb,var(--dm-text) 3%,transparent)}[data-logic-section] .fb-logic-cond-row,[data-logic-section] .fb-logic-val-rule{padding:.55rem .65rem;border-radius:var(--dm-radius-sm, 4px);border:1px solid var(--dm-border);background:var(--dm-surface, transparent)}[data-logic-section] .fb-logic-cond-row:last-of-type,[data-logic-section] .fb-logic-val-rule:last-of-type{margin-bottom:.75rem}[data-logic-section]>.btn{margin-top:.15rem}[data-logic-section] textarea{min-height:5rem}.project-filter-notice{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap;margin:0 0 1rem;padding:.6rem .85rem;border:1px solid var(--dm-border);border-left:3px solid var(--dm-info, var(--dm-primary));border-radius:var(--dm-radius-md, 6px);background:color-mix(in srgb,var(--dm-info, var(--dm-primary)) 6%,transparent);font-size:.85rem;color:var(--dm-text-muted)}.project-filter-notice a{color:var(--dm-primary);font-weight:600}.ctx-help{display:inline-flex;align-items:center;justify-content:center;width:1.05rem;height:1.05rem;margin-left:.35rem;padding:0;border:1px solid var(--dm-border-dark, var(--dm-border));border-radius:var(--dm-radius-full, 9999px);background:transparent;color:var(--dm-text-muted);font-size:.68rem;font-weight:700;line-height:1;cursor:pointer;vertical-align:middle;flex-shrink:0}.ctx-help:hover,.ctx-help:focus-visible{border-color:var(--dm-primary);color:var(--dm-primary);outline:none}.card-header h3 .ctx-help{align-self:center}.ctx-preview-card{position:sticky;top:1rem}@media(max-width:1100px){.ctx-workspace>.col-8,.ctx-workspace>.col-4{flex:0 0 auto;width:100%}.ctx-preview-card{position:static}}.dm-plugin-shell{border:1px solid var(--dm-border);border-radius:var(--dm-radius-lg, 12px);background:var(--dm-surface);overflow:hidden}.dm-plugin-banner{display:flex;align-items:center;justify-content:space-between;gap:1rem;flex-wrap:wrap;padding:.7rem 1rem;background:var(--dm-background-alt);border-bottom:1px solid var(--dm-border)}.dm-plugin-banner-identity{display:flex;align-items:center;gap:.55rem;min-width:0;margin-right:auto}.dm-plugin-banner-actions{display:flex;align-items:center;gap:.25rem;flex:0 0 auto;margin-right:.15rem;padding-right:.4rem;border-right:1px solid var(--dm-border)}.dm-plugin-banner-action{padding:.25rem .4rem;line-height:1;color:var(--dm-text-muted)}.dm-plugin-banner-action:hover{color:var(--dm-primary)}.dm-plugin-banner-icon{display:inline-flex;align-items:center;color:var(--dm-primary);flex:0 0 auto}.dm-plugin-banner-name{margin:0;font-size:1.05rem;font-weight:600;letter-spacing:.01em;color:var(--dm-text);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.dm-activity{display:inline-flex;align-items:center;flex:0 0 auto;margin-left:.35rem}.dm-activity domma-loader{display:inline-block;line-height:0}.dm-activity[hidden]{display:none!important}#admin-topbar>.dm-activity{margin:0 .75rem 0 0}.dm-plugin-banner-parent{font-weight:500;color:var(--dm-text-muted)}.dm-plugin-banner-sep{margin:0 .4rem;color:var(--dm-text-muted)}.dm-plugin-banner-facts{display:flex;align-items:center;gap:.4rem;flex-wrap:wrap}.dm-plugin-fact{font-size:.72rem;line-height:1.6;padding:1px 8px;border-radius:999px;border:1px solid var(--dm-border);color:var(--dm-text-muted);background:var(--dm-surface);white-space:nowrap}.dm-plugin-fact--version{font-variant-numeric:tabular-nums;color:var(--dm-text)}.dm-plugin-fact--licence.is-included{color:var(--dm-info);border-color:var(--dm-info)}.dm-plugin-fact--licence.is-licensed{color:var(--dm-success);border-color:var(--dm-success)}.dm-plugin-fact--expiry{font-variant-numeric:tabular-nums}.dm-plugin-fact--expiry.is-warning{color:var(--dm-warning);border-color:var(--dm-warning)}.dm-plugin-fact--expiry.is-danger{color:var(--dm-danger);border-color:var(--dm-danger)}.dm-plugin-body{padding:1rem}.dm-plugin-body .card.dm-plugin-unwrap{border:0;background:none;box-shadow:none;margin:0}.dm-plugin-body .card.dm-plugin-unwrap>.card-body{padding:0}.dm-plugin-body>.p-4{padding:0}@media(max-width:640px){.dm-plugin-banner{align-items:flex-start;flex-direction:column;gap:.5rem}.dm-plugin-body{padding:.75rem}}.analytics-filter{max-width:240px}.dm-help-btn{display:inline-flex;align-items:center;justify-content:center;vertical-align:middle;margin-left:.3rem;padding:0;border:0;background:none;line-height:1;color:var(--dm-text-muted);opacity:.75;cursor:pointer}.dm-help-btn:hover,.dm-help-btn:focus-visible{color:var(--dm-primary);opacity:1}.dm-help-pop{position:fixed;z-index:10050;max-width:300px;padding:.6rem .75rem;background:var(--dm-surface, var(--dm-background));color:var(--dm-text);border:1px solid var(--dm-border);border-radius:var(--dm-radius-md);box-shadow:0 8px 24px #00000040;font-size:.85rem;line-height:1.45;text-align:left;font-weight:400}.dm-help-pop strong{display:block;margin-bottom:.2rem;font-weight:600}.dm-help-pop p{margin:0}.dm-admin-sidebar .sidebar-badge[data-badge-label]{cursor:help}.dm-admin-sidebar .sidebar-badge--danger,.dm-admin-sidebar .sidebar-link.active .sidebar-badge--danger{background:var(--dm-danger, #dc2626);color:#fff}.dm-admin-sidebar .sidebar-badge--live{background:color-mix(in srgb,var(--dm-success, #16a34a) 20%,transparent);color:var(--dm-success, #16a34a)}#admin-sidebar .sidebar-badge--live{padding-left:1.05rem!important}#admin-sidebar summary>.sidebar-badge--sum{position:static!important;transform:none!important;margin-left:auto!important;margin-right:.45rem;text-transform:none;letter-spacing:0}#admin-sidebar summary:has(>.sidebar-badge--sum):after{margin-left:0}#admin-sidebar details[open]>summary>.sidebar-badge--sum{display:none}.dm-admin-sidebar .sidebar-badge--live:before{content:"";position:absolute;left:.4rem;top:50%;width:.4rem;height:.4rem;margin-top:-.2rem;border-radius:50%;background:currentColor;animation:dm-badge-pulse 2s ease-in-out infinite}@keyframes dm-badge-pulse{50%{opacity:.35}}@media(prefers-reduced-motion:reduce){.dm-admin-sidebar .sidebar-badge--live:before{animation:none}}.dm-badge-pop{width:290px;max-width:calc(100vw - 16px);font-size:.8rem;pointer-events:none}.dm-badge-pop-title{display:block;font-size:.85rem}.dm-badge-pop-sub{margin:.1rem 0 .5rem;color:var(--dm-text-muted)}.dm-badge-pop-rows{display:grid;grid-template-columns:1fr auto;gap:.2rem .75rem;margin:0 0 .5rem;padding:.45rem 0;border-top:1px solid var(--dm-border);border-bottom:1px solid var(--dm-border)}.dm-badge-pop-rows dt{color:var(--dm-text-muted)}.dm-badge-pop-rows dd{margin:0;text-align:right;font-weight:600;font-variant-numeric:tabular-nums}.dm-badge-pop-items{list-style:none;margin:0;padding:0;display:flex;flex-direction:column;gap:.4rem}.dm-badge-pop-items li{display:flex;flex-direction:column;min-width:0}.dm-badge-pop-text{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.dm-badge-pop-meta{font-size:.72rem;color:var(--dm-text-muted)}.dm-badge-pop .is-danger,.dm-badge-pop li.is-danger .dm-badge-pop-meta{color:var(--dm-danger, #dc2626)}.dm-badge-pop-empty{margin:0;color:var(--dm-text-muted)}.dm-plugin-body,.dm-slideover{font-family:var(--dm-font-sans, inherit)}.dm-plugin-body :is(button,input,select,textarea,.btn,.form-input,.form-select,.form-textarea),.dm-slideover :is(button,input,select,textarea,.btn,.form-input,.form-select,.form-textarea){font-family:inherit}.dm-plugin-body :is(input,select,textarea,.form-input,.form-select,.form-textarea):not(.form-input-lg),.dm-slideover :is(input,select,textarea,.form-input,.form-select,.form-textarea):not(.form-input-lg){font-size:var(--dm-text-sm)}.dm-plugin-body .form-input-lg{font-size:var(--dm-text-base)}.dm-plugin-body :is(.font-mono,code,pre,kbd),.dm-slideover :is(.font-mono,code,pre,kbd){font-family:var(--dm-font-mono, monospace)}.dm-plugin-body .form-label,.dm-slideover .form-label{font-size:var(--dm-text-sm)}.related-box{display:flex;flex-direction:column;gap:.6rem;border-top:1px solid var(--dm-border);padding-top:.75rem}.related-box[hidden]{display:none}.related-head{display:flex;align-items:center;gap:.4rem}.related-head strong{flex:1}.related-list{list-style:none;margin:.3rem 0 0;padding:0;display:flex;flex-direction:column;gap:.25rem}.related-list li{display:flex;flex-direction:column}.related-list li.is-past{opacity:.7}.related-meta,.related-note,.related-loading{color:var(--dm-text-muted);font-size:var(--dm-text-xs);margin:0}.login-challenge{display:flex;flex-direction:column;gap:.6rem;margin-bottom:.75rem}.login-challenge #challenge-code{font-size:1.25rem;letter-spacing:.2em;text-align:center}.login-trust{display:flex;align-items:center;gap:.45rem;font-size:.875rem}.login-enrol{display:flex;flex-direction:column;align-items:center;gap:.6rem;margin-bottom:1rem}.login-enrol img{background:#fff;padding:.5rem;border-radius:.5rem}.login-secret{display:flex;flex-direction:column;align-items:center;gap:.25rem;text-align:center}.login-secret code{font-size:.95rem;letter-spacing:.08em;word-break:break-all}.usx-secret{display:flex;flex-direction:column;gap:.75rem;padding:1rem}.usx-secret-link{display:block;padding:.6rem .75rem;border:1px solid var(--dm-border);border-radius:var(--dm-radius-sm);background:var(--dm-background-alt);word-break:break-all;font-size:.8rem;user-select:all}.usx-secret-actions{display:flex;align-items:center;justify-content:flex-end;gap:.5rem}.usx-secret-actions .btn{display:inline-flex;align-items:center;gap:.35rem}.usx-secret-note{margin-right:auto;color:var(--dm-success)}.usx-secret-foot{color:var(--dm-text-muted);font-size:.8rem;margin:0}.uex-reset{display:flex;flex-wrap:wrap;align-items:center;gap:.35rem .5rem;margin-top:.5rem}.uex-reset>small:first-child{flex-basis:100%;color:var(--dm-text-muted)}.uex-reset .btn{display:inline-flex;align-items:center;gap:.35rem}.uex-reset-open{flex-basis:100%;color:var(--dm-info)}
@@ -1,9 +1,9 @@
1
1
  /*!
2
- * Domma Tools CSS v0.44.9
2
+ * Domma Tools CSS v0.45.0
3
3
  * Dynamic Object Manipulation & Modeling API
4
4
  * (c) 2026 Darryl Waterhouse & DCBW-IT
5
- * Built: 2026-09-27T10:32:39.356Z
6
- * Commit: a754d37
5
+ * Built: 2026-09-27T18:03:07.363Z
6
+ * Commit: 224c5a0
7
7
  */
8
8
 
9
9
  /*!
@@ -1,9 +1,9 @@
1
1
  /*!
2
- * Domma Tools v0.44.9
2
+ * Domma Tools v0.45.0
3
3
  * Developer tools: Theme Roller & Page Roller
4
4
  * (c) 2026 Darryl Waterhouse & DCBW-IT
5
- * Built: 2026-09-27T10:32:24.534Z
6
- * Commit: a754d37
5
+ * Built: 2026-09-27T18:02:54.057Z
6
+ * Commit: 224c5a0
7
7
  *
8
8
  * Requires: domma.min.js
9
9
  */
@@ -0,0 +1 @@
1
+ import{applyDrop as d,isWithin as l}from"./menu-tree.js";import{isStructural as c}from"./menu-editor-arrange.js";const p={before:"above",after:"below",into:"into"};export function dropRow(o,r,u,f){const i=f==="after"?o.find(t=>t.parentId===u):null,n=i?i.id!==r&&d(o,r,i.id,"above"):d(o,r,u,p[f]);if(n){const t=o.find(e=>e.id===r);t&&(t.touched=!0)}return n}export function sortableMenuRows(o,r,u,{items:f,handle:i=null}){return typeof E.sortable!="function"?null:E.sortable(o,{items:f,handle:i,nest:!0,accepts(n,t,e){const s=r();return!(l(s,t.dataset.id,n.dataset.id)||e==="into"&&c(s.find(a=>a.id===t.dataset.id)))},onDrop({key:n,targetKey:t,zone:e}){return dropRow(r(),n,t,e)?(u(),!0):!1}})}
@@ -0,0 +1,7 @@
1
+ import{api as S}from"../api.js";import{flatten as D,nest as k}from"./menu-rows.js";import{ensureLockedTools as N,isLockedUrl as R,placeTools as T}from"./sidebar-grouping.js";import{indentRow as z,moveRow as L,outdentRow as M}from"./menu-editor-arrange.js";import{sortableMenuRows as O}from"./menu-drag.js";const $="admin-sidebar",g=n=>String(n??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");export function canArrange(n=[]){return n.includes("menus")||n.includes("menus.update")}export function arrangeButtonMarkup(){return'<button type="button" class="btn btn-sm btn-ghost dm-admin-sidebar-arrange" title="Arrange the sidebar - drag items to move them or put them in folders" aria-label="Arrange the sidebar"><span data-icon="grip-vertical" data-icon-size="16"></span></button>'}function j(n){const s=new Set,l=new Set,d=r=>{for(const o of n.filter(m=>m.parentId===r))!o.type&&R(o.url)&&!l.has(o.url)&&(l.add(o.url),s.add(o.id)),d(o.id)};return d(null),s}function I(n){const s=j(n),l=new Set(n.map(o=>o.parentId).filter(Boolean)),d=[],r=(o,m)=>{for(const e of n.filter(i=>i.parentId===o)){const i=` style="--sb-arr-depth:${m}"`;if(e.type==="separator"||e.type==="spacer"){d.push(`<div class="sb-arr-row sb-arr-row--structural" data-id="${g(e.id)}" tabindex="0"${i}>
2
+ <span class="sb-arr-grip" data-icon="grip-vertical" data-icon-size="14"></span>
3
+ <span class="sb-arr-text">${e.type==="separator"?"Separator":"Spacer"}</span></div>`);continue}const w=l.has(e.id),a=e.text||e.tool?.label||"(no label)",b=s.has(e.id)?'<span class="sb-arr-lock" data-icon="lock" data-icon-size="14" title="Always shown - it can be moved, not hidden"></span>':`<button type="button" class="sb-arr-hide" aria-pressed="${e.hidden?"true":"false"}" title="${e.hidden?"Hidden - click to show":"Hide"}" aria-label="${e.hidden?"Show":"Hide"} ${g(a)}"><span data-icon="${e.hidden?"eye-off":"eye"}" data-icon-size="14"></span></button>`;d.push(`<div class="sb-arr-row${w?" sb-arr-row--folder":""}${e.hidden?" sb-arr-row--hidden":""}" data-id="${g(e.id)}" tabindex="0" aria-label="${g(a)}"${i}>
4
+ <span class="sb-arr-grip" data-icon="grip-vertical" data-icon-size="14"></span>
5
+ ${e.icon?`<span class="sb-arr-icon" data-icon="${g(e.icon)}" data-icon-size="16"></span>`:'<span class="sb-arr-icon"></span>'}
6
+ <span class="sb-arr-text">${g(a)}</span>
7
+ ${b}</div>`),r(e.id,m+1)}};return r(null,0),d.join("")}export async function startArrange(n){const s=n.querySelector(".dm-admin-sidebar");if(!s||s.classList.contains("is-arranging"))return;let l,d;try{[l,d]=await Promise.all([S.menus.get($),H.get("/api/sidebar/registered-items").catch(()=>[])])}catch{E.toast("Could not load the sidebar menu to arrange.",{type:"error"});return}if(!l){E.toast("There is no admin sidebar menu to arrange yet - create one in Content > Menus.",{type:"warning"});return}let r=D(N(T(l.items||[],d||[],{forEditor:!0}),{leaveInHiddenFolders:!0}));const o=JSON.stringify(k(r)),m=()=>JSON.stringify(k(r))!==o,e=document.createElement("div");e.className="sb-arrange",e.setAttribute("role","region"),e.setAttribute("aria-label","Arrange the sidebar");const i=document.createElement("div");i.className="sb-arrange-bar",i.append(Object.assign(document.createElement("span"),{className:"sb-arrange-title",textContent:"Arrange"}),Object.assign(document.createElement("button"),{type:"button",className:"btn btn-sm btn-ghost sb-arrange-cancel",textContent:"Cancel"}),Object.assign(document.createElement("button"),{type:"button",className:"btn btn-sm btn-primary sb-arrange-done",textContent:"Done"}));const w=Object.assign(document.createElement("p"),{className:"sb-arrange-hint",textContent:"Drag an item to move it. Drop it on the middle of another to put it inside. The eye hides or shows it. Alt+arrow keys move the focused item."}),a=document.createElement("div");a.className="sb-arrange-list",e.append(i,w,a);const b=()=>{const p=document.createRange();p.selectNodeContents(a),a.replaceChildren(p.createContextualFragment(I(r))),Domma.icons.scan(a)},A=p=>requestAnimationFrame(()=>a.querySelector(`.sb-arr-row[data-id="${CSS.escape(p)}"]`)?.focus());e.style.width=`${Math.max(Math.round(s.getBoundingClientRect().width),240)}px`,s.classList.add("is-arranging"),s.querySelector(".dm-admin-sidebar-header")?.after(e),b();const f=O(a,()=>r,b,{items:".sb-arr-row",handle:null});return new Promise(p=>{let h=!1;const v=t=>{f?.destroy(),document.removeEventListener("keydown",C,!0),e.remove(),s.classList.remove("is-arranging"),t?document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild")):s.querySelector(".dm-admin-sidebar-arrange")?.focus(),p(t)},x=async()=>{h||m()&&!await E.confirm("Leave Arrange without saving? Your moves will be lost.",{title:"Discard changes?",confirmText:"Discard",cancelText:"Keep arranging"})||v(!1)},q=async()=>{if(!h){if(!m()){v(!1);return}h=!0,i.querySelectorAll("button").forEach(t=>{t.disabled=!0});try{const t=await S.menus.get($);await S.menus.update($,{...t,items:k(r)}),E.toast("Sidebar arranged.",{type:"success"}),v(!0)}catch(t){h=!1,i.querySelectorAll("button").forEach(u=>{u.disabled=!1}),E.toast(`Could not save the sidebar: ${t?.message||t}`,{type:"error"})}}};i.querySelector(".sb-arrange-cancel").addEventListener("click",x),i.querySelector(".sb-arrange-done").addEventListener("click",q),a.addEventListener("click",t=>{const u=t.target.closest(".sb-arr-hide");if(!u)return;const c=r.find(y=>y.id===u.closest(".sb-arr-row")?.dataset.id);c&&(c.hidden=!c.hidden,c.touched=!0,b(),A(c.id))}),a.addEventListener("keydown",t=>{const u=t.target.closest(".sb-arr-row");if(!u||t.target!==u||!t.altKey)return;const c=u.dataset.id,y={ArrowUp:()=>L(r,c,-1),ArrowDown:()=>L(r,c,1),ArrowRight:()=>z(r,c),ArrowLeft:()=>M(r,c)};y[t.key]&&(t.preventDefault(),y[t.key]()&&(f?f.animate(b):b(),A(c)))});function C(t){t.key!=="Escape"||f?.dragging||!e.contains(document.activeElement)&&document.activeElement!==document.body||(t.preventDefault(),t.stopPropagation(),setTimeout(x,0))}document.addEventListener("keydown",C,!0),a.querySelector(".sb-arr-row")?.focus()})}
@@ -1 +1 @@
1
- export const TOOLS_FOLDER_TEXT="Tools",MANAGE_PLUGINS_URL="#/plugins",MANAGE_PLUGINS_ITEM={text:"Marketplace",url:MANAGE_PLUGINS_URL,icon:"store",permission:"plugins"};export function stripItemByUrl(t,e){const n=[];for(const s of t||[]){if(!s||s.url===e)continue;const i={...s};Array.isArray(s.items)&&s.items.length&&(i.items=stripItemByUrl(s.items,e)),n.push(i)}return n}export function managePluginsItem(){return{...MANAGE_PLUGINS_ITEM}}export const TOOLS_FOLDER_KEY="tools";const E=["countUrl","core","permission"],c=t=>String(t??"").toLowerCase(),I=t=>t&&(t.type==="separator"||t.type==="spacer"),h=t=>t&&!I(t)&&!t.url;function S(t){return(t||[]).filter(Boolean).map(e=>Array.isArray(e.items)?{...e,items:S(e.items)}:{...e})}function F(t,e,n=[]){for(const s of t||[]){if(!s)continue;if(e(s))return[...n,s];const i=F(s.items,e,[...n,s]);if(i)return i}return null}function T(t,e,n=[],s=[]){for(const i of t||[])i&&(e(i)&&s.push([...n,i]),T(i.items,e,[...n,i],s));return s}const M=t=>!t.some(e=>e.hidden||e.restricted);function L(t,e){for(const n of t||[]){if(e(n))return n;const s=L(n?.items,e);if(s)return s}return null}export function findFolder(t,e){if(!e)return null;const n=c(e);return L(t,s=>h(s)&&c(s.key)===n)||L(t,s=>h(s)&&!s.key&&c(s.text)===n)}function w(t,e){const n={...e,...t};for(const s of E)e[s]!==void 0&&(n[s]=e[s]);return!(Array.isArray(t.items)&&t.items.length)&&Array.isArray(e.items)&&(n.items=e.items),t.text||(n.text=e.text),!t.icon&&e.icon&&(n.icon=e.icon),delete n.ref,delete n.folder,n}function _(t,{persisted:e,orphan:n=!1,node:s=null}){const i=t?.item||{};return{persisted:e,orphan:n,source:i.source||(i.core?"Built in":""),folder:t?.folder||TOOLS_FOLDER_KEY,defaults:n?{text:null,icon:null}:{text:i.text||"",icon:i.icon||""},...n&&s&&{label:s.text||s.url}}}export function placeTools(t,e,{forEditor:n=!1}={}){const s=S(t),i=(e||[]).filter(r=>r&&r.item&&typeof r.item.text=="string"),d=new Map;for(const r of i)r.item.url&&!d.has(r.item.url)&&d.set(r.item.url,r);const a=new Set,f=r=>{const o=[];for(const l of r){const p=l.url?d.get(l.url):null;if(p&&!a.has(l.url)){a.add(l.url);const y=w(l,p.item);Array.isArray(l.items)&&l.items.length?y.items=f(l.items):n&&(y.items=[]),n&&(y.$tool=_(p,{persisted:!0})),o.push(y);continue}if(l.ref){if(!n)continue;const{ref:y,...x}=l;o.push({...x,items:f(l.items||[]),$tool:_(null,{persisted:!0,orphan:!0,node:l})});continue}Array.isArray(l.items)&&(l.items=f(l.items)),o.push(l)}return o},u=f(s),A=new Set,g=r=>{for(const o of r||[])o.hidden&&o.text&&!o.url&&!(Array.isArray(o.items)&&o.items.length)&&A.add(c(o.text)),g(o.items)};g(u);let m=null;const k=()=>{const r=findFolder(u,TOOLS_FOLDER_KEY);if(r)return r;if(!m){m={text:TOOLS_FOLDER_TEXT,key:TOOLS_FOLDER_KEY,icon:"tool",items:[],synthesised:!0};const o=u.findIndex(l=>["system","documentation"].includes(c(l?.key||l?.text)));u.splice(o===-1?u.length:o,0,m)}return m};for(const r of i){const{item:o}=r;if(o.url&&a.has(o.url))continue;o.url&&a.add(o.url);const l=A.has(c(o.text));if(l&&!n)continue;const p=w({},o);n&&(p.items=[],p.$tool=_(r,{persisted:!1}),l&&(p.hidden=!0));const x=(r.parent?findFolder(u,r.parent)||L(u,O=>!I(O)&&c(O.text)===c(r.parent)):null)||findFolder(u,r.folder||o.folder)||k();x.items=Array.isArray(x.items)?x.items:[],x.items.push(p)}return u}export const LOCKED_TOOLS=[{folder:"overview",item:{text:"Dashboard",url:"#/",icon:"home"}},{folder:"content",item:{text:"Menus",url:"#/menus",icon:"menu",permission:"menus"}},{folder:"system",item:{text:"Users",url:"#/users",icon:"users",permission:"users"}},{folder:"system",item:{text:"My Profile",url:"#/my-profile",icon:"user"}}];export function isLockedUrl(t){return LOCKED_TOOLS.some(e=>e.item.url===t)}export function ensureLockedTools(t,{leaveInHiddenFolders:e=!1}={}){const n=S(t);for(const{folder:s,item:i}of LOCKED_TOOLS){const d=T(n,r=>r?.url===i.url),a=d.find(r=>!r.some(o=>o.restricted));if(!a&&d.length)continue;const f=a?.at(-1);if(f){if(f.hidden&&delete f.hidden,!a.slice(0,-1).some(l=>l.hidden)||e)continue;const o=a.at(-2);o.items=o.items.filter(l=>l!==f)}const u=c(s),A=T(n,r=>h(r)&&c(r.key)===u).filter(M),g=T(n,r=>h(r)&&!r.key&&c(r.text)===u).filter(M),m=(A[0]||g[0])?.at(-1)||null,k=f||{...i};m?(m.items=Array.isArray(m.items)?m.items:[],m.items.push(k)):n.push(k)}return n}export function insertFoldersBeforeSystem(t,e){const n=(e||[]).filter(Boolean);if(!n.length)return t;const s=["system","documentation"],i=t.findIndex(d=>s.includes(c(d?.key||d?.text)));return i===-1?[...t,...n]:[...t.slice(0,i),...n,...t.slice(i)]}export function pruneEmptyToolsFolder(t){return(t||[]).filter(e=>h(e)?!(c(e.key)===TOOLS_FOLDER_KEY||!e.key&&e.text===TOOLS_FOLDER_TEXT)||Array.isArray(e.items)&&e.items.length>0:!0)}
1
+ import{isPathAllowed as F}from"./admin-scope.js";export const TOOLS_FOLDER_TEXT="Tools",MANAGE_PLUGINS_URL="#/plugins",MANAGE_PLUGINS_ITEM={text:"Marketplace",url:MANAGE_PLUGINS_URL,icon:"store",permission:"plugins"};export function stripItemByUrl(e,t){const n=[];for(const r of e||[]){if(!r||r.url===t)continue;const s={...r};Array.isArray(r.items)&&r.items.length&&(s.items=stripItemByUrl(r.items,t)),n.push(s)}return n}export function managePluginsItem(){return{...MANAGE_PLUGINS_ITEM}}export const TOOLS_FOLDER_KEY="tools";const M=["countUrl","core","permission"],c=e=>String(e??"").toLowerCase();export function slugify(e){return c(e).trim().replace(/[^a-z0-9]+/g,"-").replace(/^-+|-+$/g,"")}export function groupKeyFor(e,t){return`${c(e)}.${slugify(t)}`}export const GROUP_ICON="folder";const P=e=>e&&(e.type==="separator"||e.type==="spacer"),A=e=>e&&!P(e)&&!e.url;function O(e){return(e||[]).filter(Boolean).map(t=>Array.isArray(t.items)?{...t,items:O(t.items)}:{...t})}function E(e,t,n=[]){for(const r of e||[]){if(!r)continue;if(t(r))return[...n,r];const s=E(r.items,t,[...n,r]);if(s)return s}return null}function I(e,t,n=[],r=[]){for(const s of e||[])s&&(t(s)&&r.push([...n,s]),I(s.items,t,[...n,s],r));return r}const U=e=>!e.some(t=>t.hidden||t.restricted);function $(e,t){for(const n of e||[]){if(t(n))return n;const r=$(n?.items,t);if(r)return r}return null}export function findFolder(e,t){if(!t)return null;const n=c(t);return $(e,r=>A(r)&&c(r.key)===n)||$(e,r=>A(r)&&!r.key&&c(r.text)===n)}function b(e,t){const n={...t,...e};for(const r of M)t[r]!==void 0&&(n[r]=t[r]);return!(Array.isArray(e.items)&&e.items.length)&&Array.isArray(t.items)&&(n.items=t.items),e.text||(n.text=t.text),!e.icon&&t.icon&&(n.icon=t.icon),delete n.ref,delete n.folder,delete n.group,n}function _(e,{persisted:t,orphan:n=!1,node:r=null}){const s=e?.item||{};return{persisted:t,orphan:n,source:s.source||(s.core?"Built in":""),folder:e?.folder||TOOLS_FOLDER_KEY,defaults:n?{text:null,icon:null}:{text:s.text||"",icon:s.icon||""},...n&&r&&{label:r.text||r.url},...(e?.group||e?.item?.group)&&{group:e.group||e.item.group}}}export function placeTools(e,t,{forEditor:n=!1}={}){const r=O(e),s=(t||[]).filter(o=>o&&o.item&&typeof o.item.text=="string"),d=new Map;for(const o of s)o.item.url&&!d.has(o.item.url)&&d.set(o.item.url,o);const y=new Set,m=o=>{const i=[];for(const u of o){const h=u.url?d.get(u.url):null;if(h&&!y.has(u.url)){y.add(u.url);const g=b(u,h.item);Array.isArray(u.items)&&u.items.length?g.items=m(u.items):n&&(g.items=[]),n&&(g.$tool=_(h,{persisted:!0})),i.push(g);continue}if(u.ref){if(!n)continue;const{ref:g,...f}=u;i.push({...f,items:m(u.items||[]),$tool:_(null,{persisted:!0,orphan:!0,node:u})});continue}Array.isArray(u.items)&&(u.items=m(u.items)),i.push(u)}return i},a=m(r),T=new Set,L=o=>{for(const i of o||[])i.hidden&&i.text&&!i.url&&!(Array.isArray(i.items)&&i.items.length)&&T.add(c(i.text)),L(i.items)};L(a);let x=null;const S=()=>{const o=findFolder(a,TOOLS_FOLDER_KEY);if(o)return o;if(!x){x={text:TOOLS_FOLDER_TEXT,key:TOOLS_FOLDER_KEY,icon:"tool",items:[],synthesised:!0};const i=a.findIndex(u=>["system","documentation"].includes(c(u?.key||u?.text)));a.splice(i===-1?a.length:i,0,x)}return x},l=new Set,k=(o,i)=>{const u=groupKeyFor(o.key||slugify(o.text),i),h=$(a,p=>A(p)&&c(p.key)===u)||(o.items||[]).find(p=>A(p)&&(!p.key||c(p.key)===u)&&c(p.text)===c(i));if(h)return h;const g={text:String(i),key:u,icon:GROUP_ICON,items:[],synthesised:!0},f=o.items.findIndex(p=>l.has(p));return o.items.splice(f===-1?o.items.length:f,0,g),g};for(const o of s){const{item:i}=o;if(i.url&&y.has(i.url))continue;i.url&&y.add(i.url);const u=T.has(c(i.text));if(u&&!n)continue;const h=b({},i);n&&(h.items=[],h.$tool=_(o,{persisted:!1}),u&&(h.hidden=!0));let f=(o.parent?findFolder(a,o.parent)||$(a,w=>!P(w)&&c(w.text)===c(o.parent)):null)||findFolder(a,o.folder||i.folder)||S();f.items=Array.isArray(f.items)?f.items:[];const p=typeof(o.group||i.group)=="string"?(o.group||i.group).trim():"";p&&slugify(p)&&(f=k(f,p),f.items=Array.isArray(f.items)?f.items:[]),f.items.push(h),l.add(h)}return a}export const LOCKED_TOOLS=[{folder:"overview",item:{text:"Dashboard",url:"#/",icon:"home"}},{folder:"content",item:{text:"Menus",url:"#/menus",icon:"menu",permission:"menus"}},{folder:"system",item:{text:"Users",url:"#/users",icon:"users",permission:"users"}},{folder:"system",item:{text:"My Profile",url:"#/my-profile",icon:"user"}}];export function isLockedUrl(e){return LOCKED_TOOLS.some(t=>t.item.url===e)}export function ensureLockedTools(e,{leaveInHiddenFolders:t=!1}={}){const n=O(e);for(const{folder:r,item:s}of LOCKED_TOOLS){const d=I(n,l=>l?.url===s.url),y=d.find(l=>!l.some(k=>k.restricted));if(!y&&d.length)continue;const m=y?.at(-1);if(m){if(m.hidden&&delete m.hidden,!y.slice(0,-1).some(o=>o.hidden)||t)continue;const k=y.at(-2);k.items=k.items.filter(o=>o!==m)}const a=c(r),T=I(n,l=>A(l)&&c(l.key)===a).filter(U),L=I(n,l=>A(l)&&!l.key&&c(l.text)===a).filter(U),x=(T[0]||L[0])?.at(-1)||null,S=m||{...s};x?(x.items=Array.isArray(x.items)?x.items:[],x.items.push(S)):n.push(S)}return n}export function insertFoldersBeforeSystem(e,t){const n=(t||[]).filter(Boolean);if(!n.length)return e;const r=["system","documentation"],s=e.findIndex(d=>r.includes(c(d?.key||d?.text)));return s===-1?[...e,...n]:[...e.slice(0,s),...n,...e.slice(s)]}export function canAny(e,t){return t?!e||!e.length?!1:e.includes(t)?!0:["read","create","update","delete"].some(n=>e.includes(`${t}.${n}`)):!0}export function filterByPermission(e,t,n=null){const r=[];for(const s of e){if(s.hidden||s.permission&&!canAny(t,s.permission))continue;const d=typeof s.url=="string"?s.url:"";if(n&&d.startsWith("#/")&&!F(n,d.slice(1)))continue;const y=Array.isArray(s.items)&&s.items.length>0,m=y?filterByPermission(s.items,t,n):[];y&&!m.length&&!d||r.push({...s,items:m})}return r}export function sidebarStateKey(e,t=null){const n=String(e?.text||"").replace(/\s*\(\d+\)\s*$/,"").toLowerCase().replace(/\s+/g,"-"),r=String(e?.url||"").match(/^#\/projects\/([^/]+)/);let s="";if(r)try{s=`project-${decodeURIComponent(r[1])}.`}catch{s=`project-${r[1]}.`}return t?e?.key?`sidebar.expanded.key.${c(e.key)}`:`${t}/${s}${n}`:`sidebar.expanded.${s}${n}`}export function pruneEmptyToolsFolder(e){return(e||[]).filter(t=>A(t)?!(c(t.key)===TOOLS_FOLDER_KEY||!t.key&&t.text===TOOLS_FOLDER_TEXT)||Array.isArray(t.items)&&t.items.length>0:!0)}
@@ -1,4 +1,4 @@
1
- import{api as p}from"../api.js";import{isPathAllowed as X}from"./admin-scope.js";import{colourToCss as K,applyFloat as ne,applyHighlight as se,itemHighlightAttrs as ie}from"/public/js/menu-decor.mjs?v=20260918-item-highlight";import{placeTools as oe,ensureLockedTools as ae,managePluginsItem as re,stripItemByUrl as le,insertFoldersBeforeSystem as ce,pruneEmptyToolsFolder as de,MANAGE_PLUGINS_URL as V}from"./sidebar-grouping.js";function h(t){return String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}const ue=[{text:"Dashboard",url:"#/",icon:"home"},{text:"Menus",url:"#/menus",icon:"menu",permission:"menus"}];function F(t,n){return n?!t||!t.length?!1:t.includes(n)?!0:["read","create","update","delete"].some(i=>t.includes(`${n}.${i}`)):!0}function G(t,n,i=null){const e=[];for(const s of t){if(s.hidden||s.permission&&!F(n,s.permission))continue;const l=typeof s.url=="string"?s.url:"";if(i&&l.startsWith("#/")&&!X(i,l.slice(1)))continue;const a=Array.isArray(s.items)&&s.items.length>0,o=a?G(s.items,n,i):[];a&&!o.length&&!l||e.push({...s,items:o})}return e}async function me(t){if(!F(t,"projects"))return[];let n=[];try{n=await p.projects.listWithCounts()}catch{return[]}if(!Array.isArray(n))return[];const i=[{key:"pages",text:"Pages",icon:"file-text",path:"/pages"},{key:"collections",text:"Collections",icon:"database",path:"/collections"},{key:"forms",text:"Forms",icon:"layout",path:"/forms"},{key:"actions",text:"Actions",icon:"zap",path:"/actions"},{key:"menus",text:"Menus",icon:"menu",path:"/menus"},{key:"blocks",text:"Blocks",icon:"box",path:"/blocks"},{key:"components",text:"Components",icon:"component",path:"/components"},{key:"views",text:"Views",icon:"eye",path:"/views"},{key:"roles",text:"Roles",icon:"shield",path:"/roles"},{key:"users",text:"Users",icon:"users",path:"/users"},{key:"apis",text:"APIs",icon:"code",path:"/apis"}];return n.map(e=>{const l="#/projects/"+encodeURIComponent(e.slug),a=e.counts||{},o=[{text:"Overview",url:l,icon:e.icon||"folder"}];for(const u of i){const m=Number(a[u.key])||0;m<=0||o.push({text:`${u.text} (${m})`,url:l+u.path,icon:u.icon})}o.push({text:"Settings",url:l+"/settings",icon:"settings"});const c=e.enabled===!1;return{text:e.name||e.slug,icon:e.icon||"folder",items:o,...c&&{colour:"neutral",badge:{text:"off"}}}})}function fe(t,n){for(const i of t)if(!i.hidden&&(i.key==="projects"||!i.key&&(i.text||"").toLowerCase()==="projects")){i.items=Array.isArray(i.items)?i.items.slice():[],i.items.push(...n);return}}function J(t,n){const i=Q.includes(n.tone)?n.tone:"info",e=n.label||String(n.count);n.details?N.set(t,n.details):N.delete(t);const s=!n.inventory&&C.some(l=>l.url===t&&!l.inventory)?" data-live":"";return`<span class="sidebar-badge sidebar-badge--${i}" data-count-for="${h(t)}"${s} data-badge-label="${h(e)}" aria-label="${h(e)}">${h(String(n.count))}</span>`}function Y(t){for(const n of t.querySelectorAll("details")){const i=n.querySelector(":scope > summary");if(!i)continue;let e=0,s=!1;const l=[];for(const m of n.querySelectorAll(":scope > .sidebar-children .sidebar-badge[data-live]")){const v=Number(m.textContent)||0;v&&(e+=v,s||(s=m.classList.contains("sidebar-badge--danger")),l.push({text:m.closest("a")?.querySelector(".sidebar-text")?.textContent.trim()??"",meta:m.dataset.badgeLabel,tone:m.classList.contains("sidebar-badge--danger")?"danger":void 0}))}const a=`folder:${n.dataset.stateKey||i.textContent.trim()}`;let o=i.querySelector(":scope > .sidebar-badge--sum");if(!e){o?.remove(),N.delete(a);continue}o||(o=document.createElement("span"),i.querySelector(".sidebar-text")?.after(o));const c=i.querySelector(".sidebar-text")?.textContent.trim()||"This folder",u=l.map(m=>`${m.text}: ${m.meta}`).join(" \xB7 ");o.className=`sidebar-badge sidebar-badge--sum sidebar-badge--${s?"danger":"info"}`,o.dataset.countFor=a,o.dataset.badgeLabel=u,o.setAttribute("aria-label",u),o.textContent=String(e),N.set(a,{title:c,items:l})}}const N=new Map;function pe(t,n){if(!t.url||!n)return"";const i=n[t.url];return!i||!(i.count>0)?"":J(t.url,i)}const Q=["info","attention","danger","live"],he={"#/pages":["page","pages"],"#/media":["file in the media library","files in the media library"],"#/menus":["menu","menus"],"#/context-menus":["context menu","context menus"],"#/theme":["element override in the theme","element overrides in the theme"],"#/collections":["collection","collections"],"#/forms":["form","forms"],"#/views":["view","views"],"#/actions":["action","actions"],"#/blocks":["block","blocks"],"#/components":["component","components"],"#/users":["user","users"],"#/plugins":["plugin installed","plugins installed"],"#/system/notifications":["unread notification","unread notifications"]};function W(t,{fallbackLabel:n="",tone:i="info"}={}){const e=Number(typeof t=="object"&&t!==null?t.count:t);if(!Number.isFinite(e)||e<0)return null;const s=typeof t?.label=="string"&&t.label||(n?`${e} - ${n}`:String(e)),l={count:Math.round(e),label:s,tone:Q.includes(t?.tone)?t.tone:i};return t?.details&&typeof t.details=="object"&&(l.details=t.details),t?.inventory===!0&&(l.inventory=!0),l}function ge(t){const n=(t.text||"").replace(/\s*\(\d+\)\s*$/,"").toLowerCase().replace(/\s+/g,"-"),i=(t.url||"").match(/^#\/projects\/([^/]+)/);return`sidebar.expanded.${i?`project-${decodeURIComponent(i[1])}.`:""}${n}`}function Z(t,n){if(t&&t.type==="separator")return'<hr class="sidebar-divider">';if(t&&t.type==="spacer"){const y=["xs","sm","md","lg","xl","flex"].includes(t.size)?t.size:"md";return`<div class="sidebar-spacer sidebar-spacer--${h(y)}" aria-hidden="true"></div>`}const i=t.icon?`<span data-icon="${h(t.icon)}"></span>`:"",e=h(t.text||""),s=t.url?h(t.url):"",l=Array.isArray(t.items)&&t.items.length>0,a=t.colour?K(t.colour):"",o=ie(t),c=[o.hover&&` data-menu-item-hover="${h(o.hover)}"`,o.active&&` data-menu-item-active="${h(o.active)}"`].filter(Boolean).join(""),u=[a&&`color:${h(a)}`,o.accent&&`--dm-menu-highlight:${h(o.accent)}`].filter(Boolean).join(";"),m=u?` style="${u}"`:"";let v="";if(t.badge&&t.badge.text!=null&&t.badge.text!==""){const y=t.badge.variant?K(t.badge.variant):"";v=`<span class="dm-menu-badge"${y?` style="background:${h(y)};color:var(--dm-text-inverse,#fff)"`:""}>${h(String(t.badge.text))}</span>`}if(l){const y=ge(t),L=S.get(y)!==!1,E=t.items.map(w=>Z(w,n)).join("");return`<details data-state-key="${h(y)}"${L?" open":""}>
2
- <summary${m}>${i} <span class="sidebar-text">${e}</span>${v}</summary>
3
- <div class="sidebar-children">${E}</div>
4
- </details>`}return`<a href="${s}" class="sidebar-link" data-url="${s}"${m}${c}>${i} <span class="sidebar-text">${e}</span>${pe(t,n)}${v}</a>`}async function be(t=[],n=[],i=null){const e=d=>d.then(g=>Array.isArray(g)?g.length:Array.isArray(g?.entries)?g.entries.length:0).catch(()=>0);C=xe(t,i);const s=new Set(C.map(d=>d.url)),l={pages:"#/pages",media:"#/media",menus:"#/menus","context-menus":"#/context-menus",theme:"#/theme",collections:"#/collections",forms:"#/forms",views:"#/views",actions:"#/actions",blocks:"#/blocks",components:"#/components",users:"#/users",plugins:"#/plugins",notifications:"#/system/notifications"},a=(d,g)=>F(n,d)&&!s.has(l[d])?g():Promise.resolve(0),[o,c,u,m,v,y,L,E,w,P,T,I,U,R]=await Promise.all([a("pages",()=>e(p.pages.list())),a("media",()=>e(p.media.list())),a("menus",()=>e(p.menus.list())),a("context-menus",()=>e(p.contextMenus.list())),a("theme",()=>p.theme.get().then(d=>(d?.overrides||[]).length).catch(()=>0)),a("collections",()=>e(p.collections.list())),a("forms",()=>e(p.forms.list())),a("views",()=>e(p.views.list())),a("actions",()=>e(p.actions.list())),a("blocks",()=>e(p.blocks.list())),a("components",()=>e(p.components.list())),a("users",()=>e(p.users.list())),a("plugins",()=>e(p.plugins.list())),a("notifications",()=>p.system?.notifications?.unreadCount?.().then(d=>d?.count??0).catch(()=>0)??Promise.resolve(0))]),_={};await Promise.all(C.map(async d=>{const g=await ee(d);g&&(_[d.url]=g)}));const A={"#/pages":o,"#/media":c,"#/menus":u,"#/context-menus":m,"#/theme":v,"#/collections":y,"#/forms":L,"#/views":E,"#/actions":w,"#/blocks":P,"#/components":T,"#/users":I,"#/plugins":U,"#/system/notifications":R},x={};for(const[d,g]of Object.entries(A)){if(s.has(d))continue;const[z,B]=he[d]??["item","items"],k=W(g);k&&(x[d]={...k,label:`${k.count} ${k.count===1?z:B}`})}return{...x,..._}}let C=[];const ye="dm:sidebar-count",ve=6e4;function xe(t=[],n=null){const i=[],e=s=>{if(s&&!(n&&typeof s.url=="string"&&s.url.startsWith("#/")&&!X(n,s.url.slice(1)))){s.url&&typeof s.countUrl=="string"&&s.countUrl&&i.push({url:s.url,countUrl:s.countUrl,text:s.text||"",countLabel:s.countLabel||"",inventory:s.inventory===!0});for(const l of[...s.children||[],...s.items||[]])e(l)}};for(const s of t??[])e(s?.item??s);return i}async function ee(t){try{const n=new Date,i=`${n.getFullYear()}-${String(n.getMonth()+1).padStart(2,"0")}-${String(n.getDate()).padStart(2,"0")}`,e=t.countUrl+(t.countUrl.includes("?")?"&":"?")+`today=${i}`;return W(await H.get(e),{fallbackLabel:t.countLabel||t.text})}catch{return null}}function te(t,n,i){const e=[...t.querySelectorAll("a.sidebar-link")].find(l=>l.dataset.url===n);if(!e)return;const s=e.querySelector(".sidebar-badge[data-count-for]");if(!i||!(i.count>0))s?.remove();else{const l=document.createRange();l.selectNodeContents(e);const a=l.createContextualFragment(J(n,i)).firstElementChild;s?s.replaceWith(a):e.querySelector(".sidebar-text")?.after(a)}O.set(n,i),Y(t)}const O=new Map;async function D(t,n=null){const i=n?C.filter(e=>e.url===n):C;await Promise.all(i.map(async e=>{const s=await ee(e),l=O.get(e.url);JSON.stringify(l??null)!==JSON.stringify(s)&&te(t,e.url,s)}))}function $e(t){t.dataset.liveCounts||(t.dataset.liveCounts="1",window.addEventListener(ye,n=>{const i=n.detail||{};if(i.url)if(i.count!==void 0){const e=C.find(s=>s.url===i.url);te(t,i.url,W(i,{fallbackLabel:e?.countLabel||e?.text||""}))}else D(t,i.url)}),setInterval(()=>{!document.hidden&&document.body.contains(t)&&D(t)},ve),document.addEventListener("visibilitychange",()=>{document.hidden||D(t)}),Se(t))}function Ce(t,n,i){const e=(a,o,c)=>{const u=document.createElement(a);return o&&(u.className=o),c!=null&&(u.textContent=String(c)),u};if(!i){t.textContent=n;return}t.appendChild(e("strong","dm-badge-pop-title",i.title||n)),(i.rows?.length||!i.items?.length)&&t.appendChild(e("p","dm-badge-pop-sub",n));const s=Array.isArray(i.rows)?i.rows.slice(0,6):[];if(s.length){const a=e("dl","dm-badge-pop-rows");for(const o of s)a.appendChild(e("dt",null,o.label)),a.appendChild(e("dd",o.tone==="danger"?"is-danger":null,o.value));t.appendChild(a)}const l=Array.isArray(i.items)?i.items.slice(0,6):[];if(l.length){const a=e("ul","dm-badge-pop-items");for(const o of l){const c=e("li",o.tone==="danger"?"is-danger":null);c.appendChild(e("span","dm-badge-pop-text",o.text)),o.meta&&c.appendChild(e("span","dm-badge-pop-meta",o.meta)),a.appendChild(c)}t.appendChild(a)}else i.empty&&t.appendChild(e("p","dm-badge-pop-empty",i.empty))}function Se(t){let n=null,i=null;const e=()=>{clearTimeout(i),n?.remove(),n=null},s=l=>{e();const a=l?.dataset.badgeLabel;a&&(i=setTimeout(()=>{n=document.createElement("div"),n.className="dm-help-pop dm-badge-pop",n.setAttribute("role","tooltip"),Ce(n,a,N.get(l.dataset.countFor)),document.body.appendChild(n);const o=l.getBoundingClientRect(),c=n.getBoundingClientRect(),u=Math.min(o.right+10,innerWidth-c.width-8);n.style.left=`${Math.max(8,u)}px`,n.style.top=`${Math.max(8,Math.min(o.top+o.height/2-c.height/2,innerHeight-c.height-8))}px`},150))};t.addEventListener("mouseover",l=>{const a=l.target.closest?.(".sidebar-badge[data-badge-label]");a&&s(a)}),t.addEventListener("mouseout",l=>{l.target.closest?.(".sidebar-badge[data-badge-label]")&&e()}),t.addEventListener("focusin",l=>{const a=l.target.closest?.("a, summary")?.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");a?s(a):e()}),t.addEventListener("focusout",e),window.addEventListener("scroll",e,!0),window.addEventListener("hashchange",e)}async function we(t=[]){if(!F(t,"settings"))return"Admin";try{const n=await p.settings.get();return n?.adminBrand?.title||n?.title||"Admin"}catch{return"Admin"}}export async function renderAdminSidebar({mount:t,permissions:n,adminScope:i=null}){const e=$(t).get(0);if(!e)return;let s,l=null,a=null,o=null,c=null,u=null;try{const r=await p.get("/sidebar/menu");s=Array.isArray(r?.items)?r.items:null,l=r?.variant||null,a=r?.position||null,o=r?.style||null,c=r?.float||null,u=r?.highlight||null}catch{s=null}(!s||!s.some(r=>r&&(!r.hidden||r.restricted)))&&(console.warn("[admin-sidebar] No admin-sidebar menu found; using fallback tree"),s=ue.slice());let m=[];try{m=await H.get("/api/sidebar/registered-items")||[]}catch{}s=le(s,V),s=oe(s,m.filter(r=>(r?.item??r)?.url!==V)),s=ae(s),s=ce(s,[re()]);const v=await me(n);v.length&&fe(s,v),s=G(s,n,i),s=de(s);const[y,L]=await Promise.all([be(m.filter(r=>F(n,r?.item?.permission)),n,i).catch(()=>({})),we(n)]),E=l?` dm-admin-sidebar--${h(l)}`:"";function w(r,b="px"){if(r==null)return r;const f=String(r).trim();return/^\d+(\.\d+)?$/.test(f)?`${f}${b}`:f}let P="";if(o){const r=[];o.fontFamily&&r.push(`font-family: ${o.fontFamily}, sans-serif`),o.fontSize&&r.push(`font-size: ${w(o.fontSize)}`),o.fontWeight&&r.push(`font-weight: ${o.fontWeight}`),o.letterSpacing&&r.push(`letter-spacing: ${w(o.letterSpacing,"em")}`);const b=[];if(r.length&&b.push(`#admin-sidebar .dm-admin-sidebar, #admin-sidebar .dm-admin-sidebar .sidebar-link, #admin-sidebar .dm-admin-sidebar summary, #admin-sidebar .dm-admin-sidebar .sidebar-text { ${r.join("; ")} }`),o.iconSize){const f=w(o.iconSize);b.push(`#admin-sidebar .dm-admin-sidebar [data-icon], #admin-sidebar .dm-admin-sidebar [data-icon] svg { width: ${f} !important; height: ${f} !important; }`)}b.length&&(P=`<style data-admin-sidebar-style>${b.join(" ")}</style>`)}const T=`<div class="dm-admin-sidebar-header"><span data-icon="layout"></span> ${h(L)}</div>`,I=s.some(r=>r&&r.type==="spacer"&&r.size==="flex")?" dm-admin-sidebar--has-flex-spacer":"",U=`${P}<nav class="dm-admin-sidebar${E}${I}">${T}${s.map(r=>Z(r,y)).join("")}</nav>`,R=document.createRange();R.selectNodeContents(e);const _=R.createContextualFragment(U);e.replaceChildren(_),Domma.icons.scan(e);for(const r of C)O.set(r.url,y[r.url]??null);Y(e),$e(e);const A=Number.parseInt(S.get("sidebar.width"),10);Number.isFinite(A)&&A>=180&&A<=480&&(e.style.width=A+"px"),e.removeAttribute("data-menu-hover"),e.removeAttribute("data-menu-active"),e.style.removeProperty("--dm-menu-highlight"),se(e,{highlight:u});const x=document.querySelector(".dashboard-wrapper");if(["position","top","bottom","left","right","zIndex","maxHeight","transform"].forEach(r=>{e.style[r]=""}),e.classList.remove("dm-menu-floating"),x&&(x.style.paddingLeft="",x.style.paddingRight=""),a==="floating"){ne(e,{position:"floating",float:c||{}});const b=c&&c.anchor||"TL",f=Number.isFinite(Number(c?.offsetX))?Number(c.offsetX):16,j=e.getBoundingClientRect().width||A||260;if(x){const q=Math.round(j+f*2)+"px";b==="R"||b==="TR"||b==="BR"?x.style.paddingRight=q:x.style.paddingLeft=q}}const d=document.createElement("div");d.className="dm-admin-sidebar-handle",d.setAttribute("aria-label","Resize sidebar"),e.appendChild(d),e.querySelectorAll("details").forEach(r=>{r.addEventListener("toggle",function(){const b=this.getAttribute("data-state-key");b&&S.set(b,this.open);const f=this.querySelector(":scope > .sidebar-children");if(f)if(this.open){const j=f.scrollHeight;f.style.maxHeight="0",requestAnimationFrame(()=>{f.style.maxHeight=j+"px",f.addEventListener("transitionend",function q(){f.style.maxHeight="none",f.removeEventListener("transitionend",q)})})}else{const j=f.scrollHeight;f.style.maxHeight=j+"px",requestAnimationFrame(()=>{f.style.maxHeight="0"})}})});let g=!1,z=0,B=0;d.addEventListener("mousedown",r=>{g=!0,z=r.clientX,B=e.getBoundingClientRect().width,document.body.style.cursor="col-resize",document.body.style.userSelect="none",r.preventDefault()}),e.dataset.resizeWired||(e.dataset.resizeWired="1",document.addEventListener("mousemove",r=>e.__dmResize?.move(r)),document.addEventListener("mouseup",()=>e.__dmResize?.up()),M.subscribe("router:afterChange",()=>e.__dmSetActive?.())),e.__dmResize={move(r){if(!g)return;const b=Math.max(180,Math.min(480,B+(r.clientX-z)));e.style.width=b+"px"},up(){g&&(g=!1,document.body.style.cursor="",document.body.style.userSelect="",S.set("sidebar.width",parseInt(e.style.width,10)))}};function k(){const r=location.hash||"#/";$(e).find(".sidebar-link").removeClass("active"),$(e).find(`.sidebar-link[data-url="${r}"]`).addClass("active")}k(),e.__dmSetActive=k}
1
+ import{api as g}from"../api.js";import{isPathAllowed as te}from"./admin-scope.js";import{colourToCss as K,applyFloat as ne,applyHighlight as se,itemHighlightAttrs as ie}from"/public/js/menu-decor.mjs?v=20260918-item-highlight";import{placeTools as oe,ensureLockedTools as ae,managePluginsItem as re,stripItemByUrl as le,insertFoldersBeforeSystem as ce,pruneEmptyToolsFolder as de,sidebarStateKey as ue,canAny as _,filterByPermission as me,MANAGE_PLUGINS_URL as V}from"./sidebar-grouping.js";import{arrangeButtonMarkup as fe,canArrange as ge,startArrange as pe}from"./sidebar-arrange.js";function p(t){return String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;")}const he=[{text:"Dashboard",url:"#/",icon:"home"},{text:"Menus",url:"#/menus",icon:"menu",permission:"menus"}];async function be(t){if(!_(t,"projects"))return[];let n=[];try{n=await g.projects.listWithCounts()}catch{return[]}if(!Array.isArray(n))return[];const i=[{key:"pages",text:"Pages",icon:"file-text",path:"/pages"},{key:"collections",text:"Collections",icon:"database",path:"/collections"},{key:"forms",text:"Forms",icon:"layout",path:"/forms"},{key:"actions",text:"Actions",icon:"zap",path:"/actions"},{key:"menus",text:"Menus",icon:"menu",path:"/menus"},{key:"blocks",text:"Blocks",icon:"box",path:"/blocks"},{key:"components",text:"Components",icon:"component",path:"/components"},{key:"views",text:"Views",icon:"eye",path:"/views"},{key:"roles",text:"Roles",icon:"shield",path:"/roles"},{key:"users",text:"Users",icon:"users",path:"/users"},{key:"apis",text:"APIs",icon:"code",path:"/apis"}];return n.map(e=>{const l="#/projects/"+encodeURIComponent(e.slug),r=e.counts||{},a=[{text:"Overview",url:l,icon:e.icon||"folder"}];for(const u of i){const m=Number(r[u.key])||0;m<=0||a.push({text:`${u.text} (${m})`,url:l+u.path,icon:u.icon})}a.push({text:"Settings",url:l+"/settings",icon:"settings"});const c=e.enabled===!1;return{text:e.name||e.slug,key:`project.${e.slug}`,icon:e.icon||"folder",items:a,...c&&{colour:"neutral",badge:{text:"off"}}}})}function ye(t,n){for(const i of t)if(!i.hidden&&(i.key==="projects"||!i.key&&(i.text||"").toLowerCase()==="projects")){i.items=Array.isArray(i.items)?i.items.slice():[],i.items.push(...n);return}}function G(t,n){const i=Y.includes(n.tone)?n.tone:"info",e=n.label||String(n.count);n.details?R.set(t,n.details):R.delete(t);const s=!n.inventory&&w.some(l=>l.url===t&&!l.inventory)?" data-live":"";return`<span class="sidebar-badge sidebar-badge--${i}" data-count-for="${p(t)}"${s} data-badge-label="${p(e)}" aria-label="${p(e)}">${p(String(n.count))}</span>`}function J(t){for(const n of t.querySelectorAll("details")){const i=n.querySelector(":scope > summary");if(!i)continue;let e=0,s=!1;const l=[];for(const m of n.querySelectorAll(":scope > .sidebar-children .sidebar-badge[data-live]")){const v=Number(m.textContent)||0;v&&(e+=v,s||(s=m.classList.contains("sidebar-badge--danger")),l.push({text:m.closest("a")?.querySelector(".sidebar-text")?.textContent.trim()??"",meta:m.dataset.badgeLabel,tone:m.classList.contains("sidebar-badge--danger")?"danger":void 0}))}const r=`folder:${n.dataset.stateKey||i.textContent.trim()}`;let a=i.querySelector(":scope > .sidebar-badge--sum");if(!e){a?.remove(),R.delete(r);continue}a||(a=document.createElement("span"),i.querySelector(".sidebar-text")?.after(a));const c=i.querySelector(".sidebar-text")?.textContent.trim()||"This folder",u=l.map(m=>`${m.text}: ${m.meta}`).join(" \xB7 ");a.className=`sidebar-badge sidebar-badge--sum sidebar-badge--${s?"danger":"info"}`,a.dataset.countFor=r,a.dataset.badgeLabel=u,a.setAttribute("aria-label",u),a.textContent=String(e),R.set(r,{title:c,items:l})}}const R=new Map;function ve(t,n){if(!t.url||!n)return"";const i=n[t.url];return!i||!(i.count>0)?"":G(t.url,i)}const Y=["info","attention","danger","live"],xe={"#/pages":["page","pages"],"#/media":["file in the media library","files in the media library"],"#/menus":["menu","menus"],"#/context-menus":["context menu","context menus"],"#/theme":["element override in the theme","element overrides in the theme"],"#/collections":["collection","collections"],"#/forms":["form","forms"],"#/views":["view","views"],"#/actions":["action","actions"],"#/blocks":["block","blocks"],"#/components":["component","components"],"#/users":["user","users"],"#/plugins":["plugin installed","plugins installed"],"#/system/notifications":["unread notification","unread notifications"]};function O(t,{fallbackLabel:n="",tone:i="info"}={}){const e=Number(typeof t=="object"&&t!==null?t.count:t);if(!Number.isFinite(e)||e<0)return null;const s=typeof t?.label=="string"&&t.label||(n?`${e} - ${n}`:String(e)),l={count:Math.round(e),label:s,tone:Y.includes(t?.tone)?t.tone:i};return t?.details&&typeof t.details=="object"&&(l.details=t.details),t?.inventory===!0&&(l.inventory=!0),l}function Q(t,n,i=null){if(t&&t.type==="separator")return'<hr class="sidebar-divider">';if(t&&t.type==="spacer"){const y=["xs","sm","md","lg","xl","flex"].includes(t.size)?t.size:"md";return`<div class="sidebar-spacer sidebar-spacer--${p(y)}" aria-hidden="true"></div>`}const e=t.icon?`<span data-icon="${p(t.icon)}"></span>`:"",s=p(t.text||""),l=t.url?p(t.url):"",r=Array.isArray(t.items)&&t.items.length>0,a=t.colour?K(t.colour):"",c=ie(t),u=[c.hover&&` data-menu-item-hover="${p(c.hover)}"`,c.active&&` data-menu-item-active="${p(c.active)}"`].filter(Boolean).join(""),m=[a&&`color:${p(a)}`,c.accent&&`--dm-menu-highlight:${p(c.accent)}`].filter(Boolean).join(";"),v=m?` style="${m}"`:"";let x="";if(t.badge&&t.badge.text!=null&&t.badge.text!==""){const y=t.badge.variant?K(t.badge.variant):"";x=`<span class="dm-menu-badge"${y?` style="background:${p(y)};color:var(--dm-text-inverse,#fff)"`:""}>${p(String(t.badge.text))}</span>`}if(r){const y=ue(t,i),L=S.get(y)!==!1,A=t.items.map(E=>Q(E,n,y)).join("");return`<details data-state-key="${p(y)}"${L?" open":""}>
2
+ <summary${v}>${e} <span class="sidebar-text">${s}</span>${x}</summary>
3
+ <div class="sidebar-children">${A}</div>
4
+ </details>`}return`<a href="${l}" class="sidebar-link" data-url="${l}"${v}${u}>${e} <span class="sidebar-text">${s}</span>${ve(t,n)}${x}</a>`}async function $e(t=[],n=[],i=null){const e=d=>d.then(h=>Array.isArray(h)?h.length:Array.isArray(h?.entries)?h.entries.length:0).catch(()=>0);w=we(t,i);const s=new Set(w.map(d=>d.url)),l={pages:"#/pages",media:"#/media",menus:"#/menus","context-menus":"#/context-menus",theme:"#/theme",collections:"#/collections",forms:"#/forms",views:"#/views",actions:"#/actions",blocks:"#/blocks",components:"#/components",users:"#/users",plugins:"#/plugins",notifications:"#/system/notifications"},r=(d,h)=>_(n,d)&&!s.has(l[d])?h():Promise.resolve(0),[a,c,u,m,v,x,y,L,A,E,z,q,T,I]=await Promise.all([r("pages",()=>e(g.pages.list())),r("media",()=>e(g.media.list())),r("menus",()=>e(g.menus.list())),r("context-menus",()=>e(g.contextMenus.list())),r("theme",()=>g.theme.get().then(d=>(d?.overrides||[]).length).catch(()=>0)),r("collections",()=>e(g.collections.list())),r("forms",()=>e(g.forms.list())),r("views",()=>e(g.views.list())),r("actions",()=>e(g.actions.list())),r("blocks",()=>e(g.blocks.list())),r("components",()=>e(g.components.list())),r("users",()=>e(g.users.list())),r("plugins",()=>e(g.plugins.list())),r("notifications",()=>g.system?.notifications?.unreadCount?.().then(d=>d?.count??0).catch(()=>0)??Promise.resolve(0))]),j={};await Promise.all(w.map(async d=>{const h=await Z(d);h&&(j[d.url]=h)}));const U={"#/pages":a,"#/media":c,"#/menus":u,"#/context-menus":m,"#/theme":v,"#/collections":x,"#/forms":y,"#/views":L,"#/actions":A,"#/blocks":E,"#/components":z,"#/users":q,"#/plugins":T,"#/system/notifications":I},C={};for(const[d,h]of Object.entries(U)){if(s.has(d))continue;const[N,B]=xe[d]??["item","items"],k=O(h);k&&(C[d]={...k,label:`${k.count} ${k.count===1?N:B}`})}return{...C,...j}}let w=[];const Se="dm:sidebar-count",Ce=6e4;function we(t=[],n=null){const i=[],e=s=>{if(s&&!(n&&typeof s.url=="string"&&s.url.startsWith("#/")&&!te(n,s.url.slice(1)))){s.url&&typeof s.countUrl=="string"&&s.countUrl&&i.push({url:s.url,countUrl:s.countUrl,text:s.text||"",countLabel:s.countLabel||"",inventory:s.inventory===!0});for(const l of[...s.children||[],...s.items||[]])e(l)}};for(const s of t??[])e(s?.item??s);return i}async function Z(t){try{const n=new Date,i=`${n.getFullYear()}-${String(n.getMonth()+1).padStart(2,"0")}-${String(n.getDate()).padStart(2,"0")}`,e=t.countUrl+(t.countUrl.includes("?")?"&":"?")+`today=${i}`;return O(await H.get(e),{fallbackLabel:t.countLabel||t.text})}catch{return null}}function ee(t,n,i){const e=[...t.querySelectorAll("a.sidebar-link")].find(l=>l.dataset.url===n);if(!e)return;const s=e.querySelector(".sidebar-badge[data-count-for]");if(!i||!(i.count>0))s?.remove();else{const l=document.createRange();l.selectNodeContents(e);const r=l.createContextualFragment(G(n,i)).firstElementChild;s?s.replaceWith(r):e.querySelector(".sidebar-text")?.after(r)}W.set(n,i),J(t)}const W=new Map;async function D(t,n=null){const i=n?w.filter(e=>e.url===n):w;await Promise.all(i.map(async e=>{const s=await Z(e),l=W.get(e.url);JSON.stringify(l??null)!==JSON.stringify(s)&&ee(t,e.url,s)}))}function Ae(t){t.dataset.liveCounts||(t.dataset.liveCounts="1",window.addEventListener(Se,n=>{const i=n.detail||{};if(i.url)if(i.count!==void 0){const e=w.find(s=>s.url===i.url);ee(t,i.url,O(i,{fallbackLabel:e?.countLabel||e?.text||""}))}else D(t,i.url)}),setInterval(()=>{!document.hidden&&document.body.contains(t)&&D(t)},Ce),document.addEventListener("visibilitychange",()=>{document.hidden||D(t)}),Le(t))}function ke(t,n,i){const e=(r,a,c)=>{const u=document.createElement(r);return a&&(u.className=a),c!=null&&(u.textContent=String(c)),u};if(!i){t.textContent=n;return}t.appendChild(e("strong","dm-badge-pop-title",i.title||n)),(i.rows?.length||!i.items?.length)&&t.appendChild(e("p","dm-badge-pop-sub",n));const s=Array.isArray(i.rows)?i.rows.slice(0,6):[];if(s.length){const r=e("dl","dm-badge-pop-rows");for(const a of s)r.appendChild(e("dt",null,a.label)),r.appendChild(e("dd",a.tone==="danger"?"is-danger":null,a.value));t.appendChild(r)}const l=Array.isArray(i.items)?i.items.slice(0,6):[];if(l.length){const r=e("ul","dm-badge-pop-items");for(const a of l){const c=e("li",a.tone==="danger"?"is-danger":null);c.appendChild(e("span","dm-badge-pop-text",a.text)),a.meta&&c.appendChild(e("span","dm-badge-pop-meta",a.meta)),r.appendChild(c)}t.appendChild(r)}else i.empty&&t.appendChild(e("p","dm-badge-pop-empty",i.empty))}function Le(t){let n=null,i=null;const e=()=>{clearTimeout(i),n?.remove(),n=null},s=l=>{e();const r=l?.dataset.badgeLabel;r&&(i=setTimeout(()=>{n=document.createElement("div"),n.className="dm-help-pop dm-badge-pop",n.setAttribute("role","tooltip"),ke(n,r,R.get(l.dataset.countFor)),document.body.appendChild(n);const a=l.getBoundingClientRect(),c=n.getBoundingClientRect(),u=Math.min(a.right+10,innerWidth-c.width-8);n.style.left=`${Math.max(8,u)}px`,n.style.top=`${Math.max(8,Math.min(a.top+a.height/2-c.height/2,innerHeight-c.height-8))}px`},150))};t.addEventListener("mouseover",l=>{const r=l.target.closest?.(".sidebar-badge[data-badge-label]");r&&s(r)}),t.addEventListener("mouseout",l=>{l.target.closest?.(".sidebar-badge[data-badge-label]")&&e()}),t.addEventListener("focusin",l=>{const r=l.target.closest?.("a, summary")?.querySelector(":scope > .sidebar-badge[data-badge-label]:not([hidden])");r?s(r):e()}),t.addEventListener("focusout",e),window.addEventListener("scroll",e,!0),window.addEventListener("hashchange",e)}async function Ee(t=[]){if(!_(t,"settings"))return"Admin";try{const n=await g.settings.get();return n?.adminBrand?.title||n?.title||"Admin"}catch{return"Admin"}}export async function renderAdminSidebar({mount:t,permissions:n,adminScope:i=null}){const e=$(t).get(0);if(!e)return;let s,l=null,r=null,a=null,c=null,u=null;try{const o=await g.get("/sidebar/menu");s=Array.isArray(o?.items)?o.items:null,l=o?.variant||null,r=o?.position||null,a=o?.style||null,c=o?.float||null,u=o?.highlight||null}catch{s=null}(!s||!s.some(o=>o&&(!o.hidden||o.restricted)))&&(console.warn("[admin-sidebar] No admin-sidebar menu found; using fallback tree"),s=he.slice());let m=[];try{m=await H.get("/api/sidebar/registered-items")||[]}catch{}s=le(s,V),s=oe(s,m.filter(o=>(o?.item??o)?.url!==V)),s=ae(s),s=ce(s,[re()]);const v=await be(n);v.length&&ye(s,v),s=me(s,n,i),s=de(s);const[x,y]=await Promise.all([$e(m.filter(o=>_(n,o?.item?.permission)),n,i).catch(()=>({})),Ee(n)]),L=l?` dm-admin-sidebar--${p(l)}`:"";function A(o,b="px"){if(o==null)return o;const f=String(o).trim();return/^\d+(\.\d+)?$/.test(f)?`${f}${b}`:f}let E="";if(a){const o=[];a.fontFamily&&o.push(`font-family: ${a.fontFamily}, sans-serif`),a.fontSize&&o.push(`font-size: ${A(a.fontSize)}`),a.fontWeight&&o.push(`font-weight: ${a.fontWeight}`),a.letterSpacing&&o.push(`letter-spacing: ${A(a.letterSpacing,"em")}`);const b=[];if(o.length&&b.push(`#admin-sidebar .dm-admin-sidebar, #admin-sidebar .dm-admin-sidebar .sidebar-link, #admin-sidebar .dm-admin-sidebar summary, #admin-sidebar .dm-admin-sidebar .sidebar-text { ${o.join("; ")} }`),a.iconSize){const f=A(a.iconSize);b.push(`#admin-sidebar .dm-admin-sidebar [data-icon], #admin-sidebar .dm-admin-sidebar [data-icon] svg { width: ${f} !important; height: ${f} !important; }`)}b.length&&(E=`<style data-admin-sidebar-style>${b.join(" ")}</style>`)}const z=ge(n)?fe():"",q=`<div class="dm-admin-sidebar-header"><span data-icon="layout"></span> ${p(y)}${z}</div>`,T=s.some(o=>o&&o.type==="spacer"&&o.size==="flex")?" dm-admin-sidebar--has-flex-spacer":"",I=`${E}<nav class="dm-admin-sidebar${L}${T}">${q}${s.map(o=>Q(o,x)).join("")}</nav>`,j=document.createRange();j.selectNodeContents(e);const U=j.createContextualFragment(I);e.replaceChildren(U),Domma.icons.scan(e),e.querySelector(".dm-admin-sidebar-arrange")?.addEventListener("click",()=>pe(e));for(const o of w)W.set(o.url,x[o.url]??null);J(e),Ae(e);const C=Number.parseInt(S.get("sidebar.width"),10);Number.isFinite(C)&&C>=180&&C<=480&&(e.style.width=C+"px"),e.removeAttribute("data-menu-hover"),e.removeAttribute("data-menu-active"),e.style.removeProperty("--dm-menu-highlight"),se(e,{highlight:u});const d=document.querySelector(".dashboard-wrapper");if(["position","top","bottom","left","right","zIndex","maxHeight","transform"].forEach(o=>{e.style[o]=""}),e.classList.remove("dm-menu-floating"),d&&(d.style.paddingLeft="",d.style.paddingRight=""),r==="floating"){ne(e,{position:"floating",float:c||{}});const b=c&&c.anchor||"TL",f=Number.isFinite(Number(c?.offsetX))?Number(c.offsetX):16,F=e.getBoundingClientRect().width||C||260;if(d){const P=Math.round(F+f*2)+"px";b==="R"||b==="TR"||b==="BR"?d.style.paddingRight=P:d.style.paddingLeft=P}}const h=document.createElement("div");h.className="dm-admin-sidebar-handle",h.setAttribute("aria-label","Resize sidebar"),e.appendChild(h),e.querySelectorAll("details").forEach(o=>{o.addEventListener("toggle",function(){const b=this.getAttribute("data-state-key");b&&S.set(b,this.open);const f=this.querySelector(":scope > .sidebar-children");if(f)if(this.open){const F=f.scrollHeight;f.style.maxHeight="0",requestAnimationFrame(()=>{f.style.maxHeight=F+"px",f.addEventListener("transitionend",function P(){f.style.maxHeight="none",f.removeEventListener("transitionend",P)})})}else{const F=f.scrollHeight;f.style.maxHeight=F+"px",requestAnimationFrame(()=>{f.style.maxHeight="0"})}})});let N=!1,B=0,k=0;h.addEventListener("mousedown",o=>{N=!0,B=o.clientX,k=e.getBoundingClientRect().width,document.body.style.cursor="col-resize",document.body.style.userSelect="none",o.preventDefault()}),e.dataset.resizeWired||(e.dataset.resizeWired="1",document.addEventListener("mousemove",o=>e.__dmResize?.move(o)),document.addEventListener("mouseup",()=>e.__dmResize?.up()),M.subscribe("router:afterChange",()=>e.__dmSetActive?.())),e.__dmResize={move(o){if(!N)return;const b=Math.max(180,Math.min(480,k+(o.clientX-B)));e.style.width=b+"px"},up(){N&&(N=!1,document.body.style.cursor="",document.body.style.userSelect="",S.set("sidebar.width",parseInt(e.style.width,10)))}};function X(){const o=location.hash||"#/";$(e).find(".sidebar-link").removeClass("active"),$(e).find(`.sidebar-link[data-url="${o}"]`).addClass("active")}X(),e.__dmSetActive=X}
@@ -46,8 +46,10 @@
46
46
  <h3>Editing a menu</h3>
47
47
  <ul>
48
48
  <li><strong>Items</strong> - click an item to edit its label, link, icon, badge, look and who
49
- sees it. Drag the grip to move an item, or drop it onto another to nest it (the navbar
50
- shows nested items as a dropdown). Right-click an item for add, move, indent, duplicate,
49
+ sees it. Drag the grip to move an item: a line shows where it will land, and an outline
50
+ round a row means it will go inside that row (the navbar shows nested items as a dropdown,
51
+ the admin sidebar as a folder inside a folder). Press Esc while dragging to cancel. On a
52
+ touch screen, drag by the grip too. Right-click an item for add, move, indent, duplicate,
51
53
  hide and remove. Separators and spacers are items too.</li>
52
54
  <li><strong>Behaviour</strong> - colour scheme, sticky, fixed, static or floating, horizontal
53
55
  or vertical, alignment, and the hover and current-page highlight. A single item can
@@ -78,6 +80,35 @@
78
80
  <p>The <code>admin-sidebar</code> menu is this sidebar. In the Menus editor you can move Tools
79
81
  between folders, rename them, hide them or add links of your own. Dashboard, Menus, Users and
80
82
  My Profile can be moved but never hidden, so you can always get back from a bad edit.</p>
83
+ <p>Folders can hold folders. The built-in Tools come in a <strong>Core</strong> group inside Tools;
84
+ move a Tool out of it, or move the whole group, and your arrangement is kept. A group that
85
+ nothing of yours has been saved into is not stored - it is made again when the sidebar draws,
86
+ and a user who may use none of its Tools does not see it. <strong>Back to its default
87
+ place</strong> on a Tool puts it back in its group. Each folder remembers whether you left it
88
+ open or closed on its own, so closing Tools &gt; Core does not close a project that is also
89
+ called Core.</p>
90
+
91
+ <h3>Arrange the sidebar in place</h3>
92
+ <p>You can also rearrange the sidebar without leaving the page you are on. Click the six-dot
93
+ button at the top of the sidebar, beside the site name, to turn on <strong>Arrange</strong>.
94
+ The sidebar then lists every item as a row, including hidden ones (dimmed and struck through),
95
+ and clicking a row no longer opens it.</p>
96
+ <ul>
97
+ <li><strong>Move</strong> - drag a row. A line shows where it will land.</li>
98
+ <li><strong>Put inside a folder</strong> - drop it on the middle of another row; an outline
99
+ shows it going in. Dropping on the line just under a folder puts it at the top of that
100
+ folder.</li>
101
+ <li><strong>Hide or show</strong> - the eye at the end of a row. A padlock means the item
102
+ can be moved but not hidden.</li>
103
+ <li><strong>Keyboard</strong> - with a row focused, Alt+Up and Alt+Down move it,
104
+ Alt+Right puts it inside the row above, Alt+Left takes it out of its folder.</li>
105
+ <li><strong>Done</strong> saves and redraws the sidebar. <strong>Cancel</strong> or Esc leaves
106
+ it as it was, asking first if you moved anything.</li>
107
+ </ul>
108
+ <p>Arrange changes the same <code>admin-sidebar</code> menu as the Menus editor, so it changes
109
+ the sidebar for everyone; each person still sees only what their role allows. Renaming items,
110
+ changing icons, badges or who can see an item, and adding links is done in the Menus editor.
111
+ The button is shown to users who may edit menus.</p>
81
112
 
82
113
  <p>Right-click menus on public pages are a separate feature: <strong>Content &gt; Context
83
114
  Menus</strong>.</p>
@@ -7,8 +7,8 @@
7
7
  <div class="col-12">
8
8
  <div class="docs-body">
9
9
 
10
- <p>Contacts, Notes, Todo, Analytics and SEO are part of the CMS. They sit in the sidebar's Tools folder
11
- and are on unless you switch them off at the top of the Marketplace (<strong>System &gt;
10
+ <p>Contacts, Notes, Todo, Analytics and SEO are part of the CMS. They sit together in a <strong>Core</strong>
11
+ group inside the sidebar's Tools folder (<strong>Tools &gt; Core &gt; Notes</strong>) and are on unless you switch them off at the top of the Marketplace (<strong>System &gt;
12
12
  Plugins</strong>). Switching a Tool off hides it and stops its screens and API; nothing is
13
13
  deleted. Who may use each is a permission under <strong>System &gt; Roles</strong> (Tools
14
14
  group): the level-0 role and Admin have them all to begin with (Admin is given them once -
@@ -65,8 +65,9 @@
65
65
  project.</p>
66
66
 
67
67
  <h3>Plugins</h3>
68
- <p>Tools from the Marketplace (Calendar, Blog, Feedback, Mail Reader and others) join the same
69
- folder when switched on. See <a href="#/docs/plugins">Plugin guides</a> for each one you have
68
+ <p>Tools from the Marketplace (Calendar, Blog, Feedback, Mail Reader and others) sit directly in
69
+ the Tools folder when switched on, beside the Core group, unless the plugin names a group of
70
+ its own. See <a href="#/docs/plugins">Plugin guides</a> for each one you have
70
71
  installed, and <a href="#/docs/usage/plugins">Plugins</a> for installing and switching.</p>
71
72
 
72
73
  </div>
@@ -313,8 +313,8 @@
313
313
  .mex-toolbar { display: flex; flex-wrap: wrap; align-items: center; gap: .4rem; }
314
314
  .mex-toolbar .btn { display: inline-flex; align-items: center; gap: .3rem; }
315
315
  /* Rows: grip, label, url, hide, edit, ⋮ - everything else is in the row's context menu. */
316
- .mex .menu-tree-row--slim { grid-template-columns: 16px minmax(0, 1fr) auto repeat(3, auto); padding: 3px 4px; border-radius: var(--dm-radius-sm); cursor: pointer; }
317
- .mex .menu-tree-row--separator, .mex .menu-tree-row--spacer { grid-template-columns: 16px minmax(80px, 1fr) auto; padding: 2px 4px; }
316
+ .mex .menu-tree-row--slim { grid-template-columns: 26px minmax(0, 1fr) auto repeat(3, auto); padding: 3px 4px; border-radius: var(--dm-radius-sm); cursor: pointer; }
317
+ .mex .menu-tree-row--separator, .mex .menu-tree-row--spacer { grid-template-columns: 26px minmax(80px, 1fr) auto; padding: 2px 4px; }
318
318
  .mex .menu-tree-row:hover { background: var(--dm-table-hover-bg, color-mix(in srgb, var(--dm-text) 5%, transparent)); }
319
319
  .mex .menu-tree-row:focus-visible { outline: 2px solid var(--dm-primary); outline-offset: 1px; }
320
320
  .mex .menu-tree-row .me-row-label, .mex .menu-tree-row .me-row-url { overflow: hidden; text-overflow: ellipsis; white-space: nowrap; min-width: 0; }
@@ -322,5 +322,5 @@
322
322
  .mex .mex-untitled { color: var(--dm-danger); font-style: italic; font-weight: 500; }
323
323
  .mex-kebab { font-size: var(--dm-text-lg); line-height: 1; color: var(--dm-text-muted); padding: 0 .4rem; }
324
324
  .mex-kebab:hover { color: var(--dm-primary); }
325
- @media (max-width: 640px) { .mex .menu-tree-row--slim .me-row-url { display: none; } .mex .menu-tree-row--slim { grid-template-columns: 16px minmax(0, 1fr) repeat(3, auto); } }
325
+ @media (max-width: 640px) { .mex .menu-tree-row--slim .me-row-url { display: none; } .mex .menu-tree-row--slim { grid-template-columns: 26px minmax(0, 1fr) repeat(3, auto); } }
326
326
  </style>
@@ -1,25 +1,25 @@
1
- import{api as T}from"../api.js";import{colourToCss as kt,HIGHLIGHT_HOVER as nt,HIGHLIGHT_ACTIVE as ot,HIGHLIGHT_HOVER_LABELS as at,HIGHLIGHT_ACTIVE_LABELS as it}from"/public/js/menu-decor.mjs?v=20260918-item-highlight";import{openIconPicker as St}from"../lib/card-builder.js";import{applyDrop as $t}from"../lib/menu-tree.js";import{placeTools as At,ensureLockedTools as xt,isLockedUrl as Et,TOOLS_FOLDER_KEY as Lt}from"../lib/sidebar-grouping.js";import{flatten as _t,nest as Ht,uid as xe}from"../lib/menu-rows.js";import{addBannerAction as Fe}from"../lib/plugin-chrome.js";import{helpPopovers as Ct}from"../lib/help-popover.js";import{onceClosed as It,openMenuAt as ze,sidebarCount as Tt}from"../lib/tool-kit.js";import{addChild as Dt,bindingFrom as Rt,duplicateRow as jt,indentRow as Nt,insertBelow as Ot,isStructural as oe,menuFromForm as Pt,menuProblems as st,moveRow as lt,outdentRow as Bt,siblingsOf as Ft,snapshot as Ee}from"../lib/menu-editor-arrange.js";import{fmtDateTime as zt}from"../lib/dates.js";const Mt=760,qt="admin-sidebar",Wt=/^\/menus\/(new|edit\/[^?#]+)(\?.*)?$/;function w(t){return String(t||"").replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;")}const Le=t=>String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");function Kt(t,r){let l=0,i=r.find(o=>o.id===t);for(;i&&i.parentId;)l++,i=r.find(o=>o.id===i.parentId);return l}function rt(t,r){const{top:l,height:i}=t.getBoundingClientRect(),o=i?(r-l)/i:.5;return o<.25?"above":o>.75?"below":"into"}const ct=["me-drop-above","me-drop-below","me-drop-into"];function Me(t){t.querySelectorAll(".menu-tree-row").forEach(r=>r.classList.remove(...ct))}function Ut(t,r,l){let i=null;t.querySelectorAll(".menu-tree-row").forEach(o=>{const f=o.querySelector(".menu-tree-grip");o.draggable=!1,f&&(f.addEventListener("mousedown",()=>{o.draggable=!0}),f.addEventListener("mouseup",()=>{o.draggable=!1})),o.addEventListener("dragstart",h=>{i=o.dataset.id,o.style.opacity="0.45",h.dataTransfer.effectAllowed="move";try{h.dataTransfer.setData("text/plain",i)}catch{}}),o.addEventListener("dragend",()=>{o.style.opacity="",o.draggable=!1,i=null,Me(t)}),o.addEventListener("dragover",h=>{if(!i||i===o.dataset.id)return;h.preventDefault(),h.dataTransfer.dropEffect="move";const d=rt(o,h.clientY);Me(t),o.classList.add(`me-drop-${d}`)}),o.addEventListener("dragleave",()=>o.classList.remove(...ct)),o.addEventListener("drop",h=>{h.preventDefault();const d=o.dataset.id,C=rt(o,h.clientY);if(Me(t),!i)return;const $=$t(r(),i,d,C);if($){const j=r().find(A=>A.id===i);j&&(j.touched=!0)}i=null,$&&l()})})}function dt(t){const r=new Set,l=new Set,i=o=>{for(const f of t.filter(h=>h.parentId===o))!f.type&&Et(f.url)&&!l.has(f.url)&&(l.add(f.url),r.add(f.id)),i(f.id)};return i(null),r}const qe='<button type="button" class="btn btn-sm btn-ghost mex-kebab" aria-label="Actions" title="Actions (right-click, or Shift+F10)">\u22EE</button>';function Gt(t,r,l=!1){const i=l?dt(r):new Set,o=[];function f(h){for(const d of r.filter(C=>C.parentId===h)){const $=`style="margin-left:${Kt(d.id,r)*28}px"`;if(d.type==="separator"){o.push(`
2
- <div class="menu-tree-row menu-tree-row--separator" data-id="${d.id}" tabindex="0" ${$}>
3
- <span class="menu-tree-grip" data-icon="move" title="Drag to move"></span>
1
+ import{api as C}from"../api.js";import{colourToCss as wt,HIGHLIGHT_HOVER as tt,HIGHLIGHT_ACTIVE as nt,HIGHLIGHT_HOVER_LABELS as ot,HIGHLIGHT_ACTIVE_LABELS as at}from"/public/js/menu-decor.mjs?v=20260918-item-highlight";import{openIconPicker as kt}from"../lib/card-builder.js";import{sortableMenuRows as St}from"../lib/menu-drag.js";import{placeTools as $t,ensureLockedTools as xt,isLockedUrl as Et,groupKeyFor as At,slugify as Lt,GROUP_ICON as _t,TOOLS_FOLDER_KEY as Ct}from"../lib/sidebar-grouping.js";import{flatten as it,nest as Ht,uid as Ee}from"../lib/menu-rows.js";import{addBannerAction as Be}from"../lib/plugin-chrome.js";import{helpPopovers as It}from"../lib/help-popover.js";import{onceClosed as Rt,openMenuAt as ze,sidebarCount as Tt}from"../lib/tool-kit.js";import{addChild as jt,bindingFrom as Dt,duplicateRow as Nt,indentRow as Ot,insertBelow as Pt,isStructural as oe,menuFromForm as Ft,menuProblems as st,moveRow as lt,outdentRow as Bt,siblingsOf as zt,snapshot as Ae}from"../lib/menu-editor-arrange.js";import{fmtDateTime as Mt}from"../lib/dates.js";const Kt=760,Wt="admin-sidebar",qt=/^\/menus\/(new|edit\/[^?#]+)(\?.*)?$/;function y(t){return String(t||"").replace(/&/g,"&amp;").replace(/"/g,"&quot;").replace(/</g,"&lt;")}const Le=t=>String(t??"").replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;").replace(/"/g,"&quot;");function Ut(t,d){let s=0,l=d.find(i=>i.id===t);for(;l&&l.parentId;)s++,l=d.find(i=>i.id===l.parentId);return s}function rt(t){const d=new Set,s=new Set,l=i=>{for(const g of t.filter(k=>k.parentId===i))!g.type&&Et(g.url)&&!s.has(g.url)&&(s.add(g.url),d.add(g.id)),l(g.id)};return l(null),d}const Me='<button type="button" class="btn btn-sm btn-ghost mex-kebab" aria-label="Actions" title="Actions (right-click, or Shift+F10)">\u22EE</button>';function Gt(t,d,s=!1){const l=s?rt(d):new Set,i=[];function g(k){for(const f of d.filter(N=>N.parentId===k)){const _=`style="margin-left:${Ut(f.id,d)*28}px"`;if(f.type==="separator"){i.push(`
2
+ <div class="menu-tree-row menu-tree-row--separator" data-id="${f.id}" tabindex="0" ${_}>
3
+ <span class="menu-tree-grip" data-icon="grip-vertical" data-icon-size="18" title="Drag to move"></span>
4
4
  <span class="me-sep-line"><span class="me-sep-label">Separator</span></span>
5
- ${qe}
6
- </div>`);continue}if(d.type==="spacer"){const ee=["xs","sm","md","lg","xl","flex"].map(P=>`<option value="${P}"${(d.size||"md")===P?" selected":""}>${P==="flex"?"flexible":P}</option>`).join("");o.push(`
7
- <div class="menu-tree-row menu-tree-row--spacer" data-id="${d.id}" tabindex="0" ${$}>
8
- <span class="menu-tree-grip" data-icon="move" title="Drag to move"></span>
5
+ ${Me}
6
+ </div>`);continue}if(f.type==="spacer"){const ee=["xs","sm","md","lg","xl","flex"].map(O=>`<option value="${O}"${(f.size||"md")===O?" selected":""}>${O==="flex"?"flexible":O}</option>`).join("");i.push(`
7
+ <div class="menu-tree-row menu-tree-row--spacer" data-id="${f.id}" tabindex="0" ${_}>
8
+ <span class="menu-tree-grip" data-icon="grip-vertical" data-icon-size="18" title="Drag to move"></span>
9
9
  <span class="me-spacer-line">
10
10
  <span class="me-spacer-label">Spacer</span>
11
11
  <select class="form-input me-spacer-size" title="Spacer size - flexible fills the leftover room" aria-label="Spacer size">${ee}</select>
12
12
  </span>
13
- ${qe}
14
- </div>`);continue}const j=d.badge&&(d.badge.text||d.badge.countFrom)?`<span class="dm-menu-badge">${w(String(d.badge.text||"#"))}</span>`:"",A=d.tool,g=A&&(A.persisted||d.touched),W=A?A.orphan?' <span class="badge badge-secondary me-tool-badge" title="A placeholder for a Tool that is not enabled - it returns here when it is">Not enabled</span>':` <span class="badge badge-secondary me-tool-badge" title="${g?"A Tool, placed here by this menu":"A Tool in its default place - move or edit it to place it here"}">${w(A.source||"Tool")}${g?"":" \xB7 default"}</span>`:"",ae=i.has(d.id),Q=kt(d.colour),K=Q?` style="color:${w(Q)}"`:"",ie=ae?'<button type="button" class="btn btn-sm btn-ghost" disabled title="Always shown - it can be moved, not hidden" aria-label="Always shown"><span data-icon="lock"></span></button>':`<button type="button" class="btn btn-sm btn-ghost me-hidden ${d.hidden?"active":""}" title="${d.hidden?"Hidden - click to show":"Hide"}" aria-label="${d.hidden?"Show":"Hide"}" aria-pressed="${d.hidden?"true":"false"}"><span data-icon="${d.hidden?"eye-off":"eye"}"></span></button>`;o.push(`
15
- <div class="menu-tree-row menu-tree-row--slim${d.hidden?" menu-tree-row--hidden":""}${A?" menu-tree-row--tool":""}${A&&!g?" menu-tree-row--default":""}" data-id="${d.id}" tabindex="0" ${$}>
16
- <span class="menu-tree-grip" data-icon="move" title="Drag to move"></span>
17
- <span class="me-row-label${!d.text&&!A?" mex-untitled":""}"${K}>${w(d.text||A?.label||"(no label - click to add one)")}${j}${W}</span>
18
- <span class="me-row-url">${w(d.url||"")}</span>
13
+ ${Me}
14
+ </div>`);continue}const V=f.badge&&(f.badge.text||f.badge.countFrom)?`<span class="dm-menu-badge">${y(String(f.badge.text||"#"))}</span>`:"",A=f.tool,h=A&&(A.persisted||f.touched),B=A?A.orphan?' <span class="badge badge-secondary me-tool-badge" title="A placeholder for a Tool that is not enabled - it returns here when it is">Not enabled</span>':` <span class="badge badge-secondary me-tool-badge" title="${h?"A Tool, placed here by this menu":"A Tool in its default place - move or edit it to place it here"}">${y(A.source||"Tool")}${h?"":" \xB7 default"}</span>`:"",ae=l.has(f.id),Z=wt(f.colour),z=Z?` style="color:${y(Z)}"`:"",ie=ae?'<button type="button" class="btn btn-sm btn-ghost" disabled title="Always shown - it can be moved, not hidden" aria-label="Always shown"><span data-icon="lock"></span></button>':`<button type="button" class="btn btn-sm btn-ghost me-hidden ${f.hidden?"active":""}" title="${f.hidden?"Hidden - click to show":"Hide"}" aria-label="${f.hidden?"Show":"Hide"}" aria-pressed="${f.hidden?"true":"false"}"><span data-icon="${f.hidden?"eye-off":"eye"}"></span></button>`;i.push(`
15
+ <div class="menu-tree-row menu-tree-row--slim${f.hidden?" menu-tree-row--hidden":""}${A?" menu-tree-row--tool":""}${A&&!h?" menu-tree-row--default":""}" data-id="${f.id}" tabindex="0" ${_}>
16
+ <span class="menu-tree-grip" data-icon="grip-vertical" data-icon-size="18" title="Drag to move"></span>
17
+ <span class="me-row-label${!f.text&&!A?" mex-untitled":""}"${z}>${y(f.text||A?.label||"(no label - click to add one)")}${V}${B}</span>
18
+ <span class="me-row-url">${y(f.url||"")}</span>
19
19
  ${ie}
20
20
  <button type="button" class="btn btn-sm btn-ghost me-edit" title="Edit" aria-label="Edit"><span data-icon="edit"></span></button>
21
- ${qe}
22
- </div>`),f(d.id)}}f(null),t.innerHTML=o.join("")||'<p class="mex-note">No items yet - Add item, or right-click an item for more.</p>',I.scan(t)}function k(t,r={},...l){const i=document.createElement(t);Object.assign(i,r);for(const o of l)o!=null&&i.append(o);return i}function D(t,r,l){const i=k("label",{className:"form-field"},k("span",{className:"form-label",textContent:t}),r);return l&&i.append(k("small",{className:"form-hint",textContent:l,style:"display:block;font-size:.78em;opacity:.7;margin-top:.25rem;line-height:1.35"})),i}function Vt(t,r){const l=[["","- Everyone -"],["public","Public - anyone, incl. logged-out"],...(r||[]).map(o=>[o.name,`${o.label||o.name} and above`]),...(r||[]).filter(o=>o.level!==0).map(o=>[`=${o.name}`,`${o.label||o.name} only`]),["private","Private - super-admin only"]];t&&!l.some(([o])=>o===t)&&l.push([t,`${t} (custom)`]);const i=Z(l,t||"");return i.name="visibility",i}function Z(t,r){const l=k("select",{className:"form-select"});return t.forEach(([i,o])=>l.add(new Option(o,i))),l.value=r??"",l}function _e(t,r){const l=typeof r=="string"&&r.startsWith("#"),i=Z([["","- none -"],["primary","primary"],["success","success"],["danger","danger"],["warning","warning"],["info","info"],["neutral","neutral"],["__custom__","Custom\u2026"]],l?"__custom__":r||""),o=k("input",{type:"color",className:"form-input me-colour-hex",value:l?r:"#000000"});o.style.display=l?"":"none",i.addEventListener("change",()=>{o.style.display=i.value==="__custom__"?"":"none"});const f=D(t,i);return f.append(o),f._read=()=>i.value==="__custom__"?o.value:i.value,f}function Yt(t,r){const l=k("input",{className:"form-input me-icon",name:"icon",value:r||""}),i=k("span",{className:"me-icon-preview"});r&&i.setAttribute("data-icon",r);const o=k("button",{type:"button",className:"btn btn-sm btn-ghost",textContent:"Browse\u2026"}),f=h=>{h?i.setAttribute("data-icon",h):i.removeAttribute("data-icon"),Domma.icons.scan(i.parentNode||i)};return o.addEventListener("click",()=>St(h=>{l.value=h,f(h)})),l.addEventListener("input",()=>f(l.value.trim())),D(t,k("div",{className:"me-icon-field"},l,o,i))}function He(...t){return k("div",{className:"me-field-grid"},...t)}async function Xt(t,r,l,i,o){const f=t.text||t.tool?.label||"",h=c=>k("h4",{className:"me-form-section",textContent:c}),d=D("Label",k("input",{className:"form-input",name:"text",value:t.text||""}),"The text shown for this item."),C=k("input",{className:"form-input",name:"url",value:t.url||""}),$=D("URL",C,t.tool||t.locked?"A Tool's address is its identity, so it cannot be changed here.":"Where it links. Must start with /, #, https://, or mailto: . Leave blank for a parent that only groups sub-items.");(t.tool||t.locked)&&(C.readOnly=!0);const j=Yt("Icon",t.icon||""),A=Vt(t.visibility||"",i),g=D("Visibility",A,t.locked?"Always in the sidebar for everyone who may use it, so it cannot be restricted here.":'Who can see this item. "Role and above" shows it to that role and anyone more senior; "Role only" shows it to holders of that role alone (and the super-admin). Blank = everyone.');t.locked&&(A.disabled=!0);const W=Z([["","- no permission gate -"],...(r||[]).map(c=>[c.key,c.label||c.key])],t.permission||"");W.name="permission";const ae=D("Permission",W,t.tool||t.locked?"A Tool is guarded by its own permission, which always applies.":"Hide unless the viewer holds this specific permission. Independent of Visibility - both must pass.");(t.tool||t.locked)&&(W.disabled=!0);const Q=D("Badge text",k("input",{className:"form-input",name:"badgeText",value:t.badge?.text||""})),K=Z([["","- none -"],...(l||[]).map(c=>[c.slug,c.title||c.slug])],t.badge?.countFrom||"");K.name="badgeCount";const ie=D("Badge count from",K,"Show a live count of this collection\u2019s entries as the badge."),ee=_e("Badge colour",t.badge?.variant||""),P=Z([["link","Link"],["pill","Pill"]],t.pill?"pill":"link");P.name="renderAs";const Ce=D("Render as",P,"Pill draws the item as a rounded chip. Pill styling applies to top-level navbar items."),U=D("Pill style",Z([["filled","Filled"],["outline","Outline"]],t.pill?.style||"filled"));U.querySelector("select").name="pillStyle";const me=_e("Pill colour",t.pill?.variant||""),se=k("div",{className:"me-pill-wrap"},He(U,me));se.style.display=t.pill?"":"none",P.addEventListener("change",()=>{se.style.display=P.value==="pill"?"":"none"});const p=_e("Text colour",t.colour||""),N=Z([["","- use the menu default -"],...nt.map(c=>[c,at[c]||c])],t.highlight?.hover||"");N.name="hlHover";const le=D("Hover effect",N,"Overrides the menu-wide hover effect for this item only."),pe=Z([["","- use the menu default -"],...ot.map(c=>[c,it[c]||c])],t.highlight?.active||"");pe.name="hlActive";const be=D("When selected",pe,"How this item is marked when it points at the page being viewed."),B=_e("Highlight colour",t.highlight?.accent||""),x=k("button",{className:"btn btn-primary",textContent:"Apply",title:"Apply to the item (Ctrl+Enter) - Save the menu to keep it"}),F=k("div",{className:"me-item-form"},h("Link"),d,$,j,h("Access"),He(g,ae),h("Badge"),He(Q,ee),ie,h("Appearance"),Ce,se,p,h("Highlighting"),He(le,be),B,x),y=E.slideover({title:f?`Edit ${Le(f)}`:"Edit menu item",size:"lg",position:"right"});y.element.appendChild(F);const Y=()=>JSON.stringify([...F.querySelectorAll("input, select, textarea")].map(c=>c.type==="checkbox"?c.checked:c.value)),te=Y();let G=!1,re=!1;It(y);const ye=y.close.bind(y);y.close=async c=>{if(!G&&c!==!0&&Y()!==te){if(re)return;re=!0;const V=await E.confirm("Discard the changes to this item?");if(re=!1,!V)return}return G=!0,ye()},F.addEventListener("keydown",c=>{(c.ctrlKey||c.metaKey)&&c.key==="Enter"&&(c.preventDefault(),x.click())}),y.open();const fe=y.element.closest(".dm-slideover")||y.element.querySelector(".dm-slideover")||y.element;fe.style.setProperty("width",Mt+"px","important"),fe.style.setProperty("max-width","95vw","important"),Domma.icons.scan(F);const L=c=>F.querySelector(`[name="${c}"]`)?.value||"";x.addEventListener("click",()=>{t.text=L("text"),t.icon=L("icon"),t.locked||(t.visibility=L("visibility")),!t.tool&&!t.locked?(t.url=L("url"),t.permission=L("permission")):t.touched=!0;const c=L("badgeText"),V=L("badgeCount"),ne=ee._read();if(t.badge=c||V?{...c&&{text:c},...V&&{countFrom:V},...ne&&{variant:ne}}:null,L("renderAs")==="pill"){const he=me._read();t.pill={style:L("pillStyle")||"filled",...he&&{variant:he}}}else t.pill=null;t.colour=p._read();const ce=L("hlHover"),de=L("hlActive"),ue=B._read();t.highlight=ce||de||ue?{...ce&&{hover:ce},...de&&{active:de},...ue&&{accent:ue}}:null,G=!0,y.close(!0),o()})}let q=null,ut=!1;function Jt(){ut||!window.R?.use||(ut=!0,R.use((t,r,l)=>{const i=r?.path||"";return!(Wt.test(i)&&(t?.path||"")!==i)||!q?.dirty()?l():E.confirm(`You have unsaved changes to the menu "${Le(q.name())}". Leave anyway? They are kept as a draft for your next visit.`).then(f=>{f?l():history.replaceState(null,"",`#${i}`)})}),M.subscribe("router:afterChange",({to:t}={})=>{if(q&&(t?.path||"")!==q.path){const r=q;q=null,r.dispose()}}))}function mt(t,r){const l=t.querySelector(".dm-plugin-banner-name"),i=l?.querySelector(".dm-plugin-banner-sep");if(!(!l||!i)){for(;i.nextSibling;)i.nextSibling.remove();l.appendChild(document.createTextNode(r))}}export const menuEditorView={templateUrl:"/admin/js/templates/menu-editor.html",async onMount(t){if(Jt(),q){const e=q;q=null,e.dispose()}const r=[],l=e=>(r.push(e),e);let i=!1;const o=t.get(0).querySelector(".mex")||t.get(0),f=()=>!i&&o.isConnected,h=location.hash.replace(/^#/,""),d=location.hash.match(/^#\/menus\/edit\/([^?#]+)/),C=d?decodeURIComponent(d[1]):null,$=!C,j=`menu-editor.draft.${C||"new"}`,A=E.loader(t.get(0),{type:"dots"});let g,W,ae,Q,K,ie,ee;try{if($)g={slug:"",name:"",description:"",items:[]};else try{g=await T.menus.get(C)}catch(e){E.toast(`Failed to load menu: ${e.message||e}`,{type:"error"}),location.hash="#/menus";return}[W,ae,Q,K,ie,ee]=await Promise.all([T.projects.list().catch(()=>[]),H.get("/api/auth/permissions-registry").catch(()=>({resources:[]})),T.collections.list().catch(()=>[]),T.get("/collections/roles/entries?limit=100").catch(()=>null),T.menuLocations.registry().catch(()=>[]),T.pages.list().catch(()=>[])])}finally{A.destroy()}if(!o.isConnected)return;const Ce=(Array.isArray(K)?K:K?.entries||[]).map(e=>({name:e.data?.name,label:e.data?.label,level:e.data?.level??99})).filter(e=>e.name).sort((e,n)=>n.level-e.level),U=!$&&C===qt;let me=[];if(U&&(me=await H.get("/api/sidebar/registered-items").catch(()=>(E.toast("Could not load the Tools - they are not shown, and saving keeps their places as they are.",{type:"warning",duration:8e3}),[])),!o.isConnected))return;const se=e=>_t(U?xt(At(e||[],me,{forEditor:!0}),{leaveInHiddenFolders:!0}):e);let p=se(g.items);const N=M.observable(!1),le=M.observable(!1),pe=M.observable(""),be=M.observable(0);let B="";const x=o.querySelector("#me-items-list");function F(){Gt(x,p,U),Ut(x,()=>p,()=>{F(),z()}),be.value=p.filter(e=>!oe(e)).length}const y=()=>{F(),z()},Y=()=>U?dt(p):new Set,te=e=>p.find(n=>n.id===e);function G(e){requestAnimationFrame(()=>x.querySelector(`.menu-tree-row[data-id="${CSS.escape(e)}"]`)?.focus())}function re(e){const n=u=>p.find(m=>!m.type&&!m.url&&!m.tool&&(m.key||"").toLowerCase()===u)||p.find(m=>!m.type&&!m.url&&!m.tool&&!m.key&&(m.text||"").toLowerCase()===u),s=n(String(e.tool.folder||"").toLowerCase())||n(Lt);e.parentId=s?s.id:null,p.splice(p.indexOf(e),1),p.push(e),Object.assign(e,{text:e.tool.defaults.text,icon:e.tool.defaults.icon,visibility:"",hidden:!1,badge:null,pill:null,colour:"",highlight:null,touched:!1}),e.tool={...e.tool,persisted:!1}}const ye=e=>!Y().has(e.id)&&!(e.tool&&!e.tool.orphan);async function fe(e){const n=te(e);if(!n||!ye(n))return;const s=b=>{let J=b;for(;J;){if(J.id===e)return!0;J=p.find(O=>O.id===J.parentId)}return!1},u=p.filter(b=>b.id!==e&&s(b));if(u.length&&!await E.confirm(`Remove "${Le(n.text||n.type||"this item")}" and the ${u.length} item${u.length===1?"":"s"} beneath it?`))return;const m=Y(),v=u.filter(b=>b.tool),_=u.filter(b=>!b.tool&&m.has(b.id));p=p.filter(b=>!s(b)||v.includes(b)||_.includes(b));for(const b of _)b.parentId=n.parentId??null;for(const b of v)b.tool.orphan?b.parentId=n.parentId??null:re(b);y()}function L(e){const n=te(e);!n||oe(n)||Y().has(e)||(n.hidden=!n.hidden,n.touched=!0,y())}function c(e){const n=te(e);!n||oe(n)||(n.locked=U&&Y().has(n.id),Xt(n,ae.resources||[],Q,Ce,()=>{y(),G(e)}))}function V(e){const n={id:xe(),parentId:null,...e==="separator"?{type:e}:e==="spacer"?{type:e,size:"md"}:{text:"",url:"/",icon:"",visibility:"",permission:"",hidden:!1,bundled:!1}};p.push(n),y(),oe(n)?G(n.id):c(n.id)}const ne=e=>n=>{e(n)&&(y(),G(n))},ce=ne(e=>lt(p,e,-1)),de=ne(e=>lt(p,e,1)),ue=ne(e=>Nt(p,e)),he=ne(e=>Bt(p,e));function pt(e){const n=te(e);if(!n)return[];const s=oe(n),u=Y().has(e),m=Ft(p,e),v=m.findIndex(O=>O.id===e),_=n.tool,b=_&&(_.persisted||n.touched),J=O=>()=>{const ge=Ot(p,e,O,xe());y(),ge&&!oe(ge)?c(ge.id):ge&&G(ge.id)};return[{header:s?n.type==="separator"?"Separator":"Spacer":n.text||_?.label||"(untitled)"},...s?[]:[{label:"Edit\u2026",icon:"edit",action:()=>c(e)}],{type:"divider"},{label:"Add item below",icon:"plus",action:J("item")},{label:"Add sub-item",icon:"corner-down-right",disabled:s,action:()=>{const O=Dt(p,e,xe());y(),O&&c(O.id)}},{label:"Add separator below",icon:"minus",action:J("separator")},{label:"Add spacer below",icon:"move",action:J("spacer")},{type:"divider"},{label:"Move up",icon:"arrow-up",shortcut:"Alt+\u2191",disabled:v<=0,action:()=>ce(e)},{label:"Move down",icon:"arrow-down",shortcut:"Alt+\u2193",disabled:v<0||v>=m.length-1,action:()=>de(e)},{label:"Indent",icon:"chevron-right",shortcut:"Alt+\u2192",disabled:v<=0||oe(m[v-1]),action:()=>ue(e)},{label:"Outdent",icon:"chevron-left",shortcut:"Alt+\u2190",disabled:n.parentId==null,action:()=>he(e)},{type:"divider"},...s?[]:[{label:n.hidden?"Show":"Hide",icon:n.hidden?"eye":"eye-off",disabled:u,action:()=>L(e)}],{label:"Duplicate",icon:"copy",disabled:!!_,action:()=>{const O=jt(p,e,xe);y(),O&&G(O.id)}},..._&&!_.orphan&&b?[{label:"Back to its default place",icon:"rotate-ccw",action:()=>{re(n),y()}}]:[],{label:u?"Remove - always in the sidebar":_&&!_.orphan?"Remove - a Tool is hidden, not removed":"Remove\u2026",icon:"trash",danger:!0,disabled:!ye(n),action:()=>fe(e)}]}const ft=E.contextMenu(x,{cursor:"glyph",match:".menu-tree-row",inherit:!1,density:"compact",items:e=>pt(e.dataset.id)});l(()=>ft?.destroy?.());const We=e=>{const n=e.target.closest(".menu-tree-row");if(!n)return;const s=n.dataset.id;if(e.target.closest(".mex-kebab")){ze(e.target.closest(".mex-kebab"));return}if(e.target.closest(".me-hidden")){L(s);return}if(e.target.closest(".me-edit")){c(s);return}e.target.closest("select, .menu-tree-grip, button")||c(s)},Ke=e=>{const n=e.target.closest(".menu-tree-row");if(!n||e.target!==n){n&&e.key==="F10"&&e.shiftKey&&(e.preventDefault(),ze(n));return}const s=n.dataset.id;if(e.key==="F10"&&e.shiftKey)e.preventDefault(),ze(n);else if(e.key==="Enter")e.preventDefault(),c(s);else if(e.key==="Delete")e.preventDefault(),fe(s);else if(e.altKey&&e.key==="ArrowUp")e.preventDefault(),ce(s);else if(e.altKey&&e.key==="ArrowDown")e.preventDefault(),de(s);else if(e.altKey&&e.key==="ArrowRight")e.preventDefault(),ue(s);else if(e.altKey&&e.key==="ArrowLeft")e.preventDefault(),he(s);else if(e.key==="ArrowDown"||e.key==="ArrowUp"){const u=[...x.querySelectorAll(".menu-tree-row")],m=u.indexOf(n)+(e.key==="ArrowDown"?1:-1);u[m]&&(e.preventDefault(),u[m].focus())}},Ue=e=>{if(!e.target.matches(".me-spacer-size"))return;const n=te(e.target.closest(".menu-tree-row")?.dataset.id);n&&(n.size=e.target.value,z())};x.addEventListener("click",We),x.addEventListener("keydown",Ke),x.addEventListener("change",Ue),l(()=>{x.removeEventListener("click",We),x.removeEventListener("keydown",Ke),x.removeEventListener("change",Ue)});const a=e=>t.find(e),we=a("#me-float-accent"),Ie=a("#me-float-accent-hex"),Te=()=>{Ie.get(0).style.display=we.val()==="__custom__"?"":"none"},ht=()=>we.val()==="__custom__"?Ie.val():we.val(),ke=a("#me-highlight-accent"),De=a("#me-highlight-accent-hex"),Ge=()=>{De.get(0).style.display=ke.val()==="__custom__"?"":"none"},vt=()=>ke.val()==="__custom__"?De.val():ke.val(),Ve=()=>{const e=a("#me-position").val()==="floating";a(".dm-float-field").each(function(){this.style.display=e?"":"none"}),e&&Te();const n=a("#me-orientation").val()==="vertical";a(".dm-vertical-field").each(function(){this.style.display=n?"":"none"});const s=!!(a("#me-float-collapsible").get(0)||{}).checked;a(".dm-float-collapsed-field").each(function(){this.style.display=e&&s?"":"none"})},Ye=(e,n,s,u)=>{const m=a(e).get(0);m&&(m.innerHTML="",m.add(new Option(u,"")),n.forEach(v=>m.add(new Option(s[v]||v,v))))};Ye("#me-highlight-hover",nt,at,"- theme default -"),Ye("#me-highlight-active",ot,it,"- theme default -");const Re=a("#me-bind-slot"),je=a("#me-bind-projects"),Se=a("#me-bind-pages");Re.html('<option value="">- not bound -</option>'+(ie||[]).map(e=>`<option value="${w(e.slot)}">${w(e.label||e.slot)} (${w(e.slot)})</option>`).join("")),je.html(W.map(e=>`<option value="${w(e.slug)}">${w(e.name||e.slug)}</option>`).join("")),a("#me-bind-page-pick").html('<option value="">- pick a page -</option>'+ee.map(e=>{const n=e.urlPath||e.url||"";return n?`<option value="${w(n)}">${w(e.title||n)} - ${w(n)}</option>`:""}).join(""));const Xe=()=>Rt({slot:Re.val(),projects:Array.from(je.get(0).selectedOptions).map(e=>e.value),pagesText:Se.val()});function Ne(){const e=Xe(),n=a("#me-bind-summary");if(!e){n.html('<span class="text-muted">Not bound - this menu renders only where it is mapped or placed by a shortcode.</span>');return}const s=[];e.projects.length&&s.push(`pages in ${e.projects.map(v=>`<code>${w(v)}</code>`).join(", ")}`),e.pages.length&&s.push(`pages matching ${e.pages.map(v=>`<code>${w(v)}</code>`).join(", ")}`);const u=e.pages.filter(v=>!/^\/[^\s?#*]*(\/\*)?$|^\/\*$/.test(v)),m=u.length?`<div class="text-danger" style="margin-top:.4rem">Not valid page patterns: ${u.map(v=>`<code>${w(v)}</code>`).join(", ")}</div>`:"";n.html(s.length?`Takes over the <code>${w(e.slot)}</code> slot on ${s.join(" and ")}.${m}`:`<span class="text-warning">Slot <code>${w(e.slot)}</code> selected but no project or page chosen - the binding will never match.</span>`)}const{getProjectFromHash:gt}=await import("../lib/project-context.js");if(!f())return;const bt=$?gt():null;a("#me-project").html('<option value="">- none -</option>'+W.map(e=>`<option value="${w(e.slug)}">${w(e.name||e.slug)}</option>`).join(""));function Oe(e){p=se(e.items),a("#me-variant").val(e.variant||""),a("#me-position").val(e.position||"");const n=a("#me-appearOnHover").get(0);n&&(n.checked=e.appearOnHover===!0),a("#me-float-anchor").val(e.float?.anchor||"TL"),a("#me-float-offsetX").val(e.float?.offsetX??""),a("#me-float-offsetY").val(e.float?.offsetY??""),a("#me-float-width").val(e.float?.width??""),a("#me-float-radius").val(e.float?.radius??""),a("#me-float-shadow").val(e.float?.shadow||""),a("#me-float-opacity").val(e.float?.opacity??""),a("#me-float-title").val(e.float?.title||"");for(const[v,_]of[["#me-float-collapsible",e.float?.collapsible],["#me-float-collapsed",e.float?.collapsed],["#me-float-movable",e.float?.movable],["#me-float-resizable",e.float?.resizable]]){const b=a(v).get(0);b&&(b.checked=_===!0)}const s=e.float?.accent||"";we.val(s.startsWith("#")?"__custom__":s),s.startsWith("#")&&Ie.val(s),Te(),a("#me-orientation").val(e.orientation||""),a("#me-align").val(e.align||""),a("#me-side").val(e.side||"left"),a("#me-highlight-hover").val(e.highlight?.hover||""),a("#me-highlight-active").val(e.highlight?.active||"");const u=e.highlight?.accent||"";ke.val(u.startsWith("#")?"__custom__":u),u.startsWith("#")&&De.val(u),Ge(),a("#me-fontFamily").val(e.style?.fontFamily||""),a("#me-fontSize").val(e.style?.fontSize||""),a("#me-fontWeight").val(e.style?.fontWeight||""),a("#me-letterSpacing").val(e.style?.letterSpacing||""),a("#me-iconSize").val(e.style?.iconSize||""),Re.val(e.binding?.slot||"");const m=new Set(e.binding?.projects||[]);Array.from(je.get(0).options).forEach(v=>{v.selected=m.has(v.value)}),Se.val((e.binding?.pages||[]).join(`
23
- `)),a("#me-slug").val(e.slug||""),a("#me-name").val(e.name||""),a("#me-description").val(e.description||""),a("#me-project").val(e.meta?.project||bt||""),Ve(),Ne(),F()}const ve=e=>!!(a(e).get(0)||{}).checked;function $e(){const e={variant:a("#me-variant").val(),position:a("#me-position").val(),appearOnHover:ve("#me-appearOnHover"),floatAnchor:a("#me-float-anchor").val(),floatOffsetX:a("#me-float-offsetX").val(),floatOffsetY:a("#me-float-offsetY").val(),floatWidth:a("#me-float-width").val(),floatRadius:a("#me-float-radius").val(),floatShadow:a("#me-float-shadow").val(),floatAccent:ht(),floatOpacity:a("#me-float-opacity").val(),floatTitle:a("#me-float-title").val(),floatCollapsible:ve("#me-float-collapsible"),floatCollapsed:ve("#me-float-collapsed"),floatMovable:ve("#me-float-movable"),floatResizable:ve("#me-float-resizable"),highlightHover:a("#me-highlight-hover").val(),highlightActive:a("#me-highlight-active").val(),highlightAccent:vt(),orientation:a("#me-orientation").val(),align:a("#me-align").val(),side:a("#me-side").val(),fontFamily:a("#me-fontFamily").val(),fontSize:a("#me-fontSize").val(),fontWeight:a("#me-fontWeight").val(),letterSpacing:a("#me-letterSpacing").val(),iconSize:a("#me-iconSize").val()},n={slug:a("#me-slug").val(),name:a("#me-name").val(),description:a("#me-description").val(),project:a("#me-project").val()};return Pt(e,n,Xe(),Ht(p),g.meta||{})}let Je=!1,Pe=null;function z(){if(!B)return;const e=$e();Pe=e,N.value=Ee(e)!==B,pe.value=N.peek()||Je?st(e).join(" "):""}const Ae=e=>{e.target.closest("#me-items-list")||(e.target.matches("#me-position, #me-orientation, #me-float-collapsible")&&Ve(),e.target.matches("#me-float-accent")&&Te(),e.target.matches("#me-highlight-accent")&&Ge(),e.target.closest("#me-binding")&&Ne(),z())};o.addEventListener("input",Ae),o.addEventListener("change",Ae),l(()=>{o.removeEventListener("input",Ae),o.removeEventListener("change",Ae)}),a("#me-bind-page-add").on("click",()=>{const e=a("#me-bind-page-pick").val();if(!e)return;const n=Se.val().split(`
24
- `).map(s=>s.trim()).filter(Boolean);n.includes(e)||n.push(e),Se.val(n.join(`
25
- `)),Ne(),z()}),Oe(g),B=Ee($e()),z();const Ze=()=>{try{S.remove?S.remove(j):S.set(j,null)}catch{}};async function Be(){if(le.peek())return;const e=$e(),n=st(e);if(n.length){Je=!0,z(),E.toast(n.join(" "),{type:"warning",duration:7e3});return}le.value=!0;try{if($)await T.menus.create(e);else if(e.slug!==g.slug){await T.menus.create(e);const s=await T.menuLocations.get();let u=!1;for(const[m,v]of Object.entries(s))v===g.slug&&(s[m]=e.slug,u=!0);u&&await T.menuLocations.save(s),await T.menus.remove(g.slug)}else await T.menus.update(g.slug,e);if(B=Ee(e),N.value=!1,Ze(),Tt("#/menus"),E.toast("Saved.",{type:"success"}),$||e.slug!==g.slug)location.hash="#/menus/edit/"+encodeURIComponent(e.slug);else{g={...g,...e};for(const s of p)s.tool&&s.touched&&(s.tool={...s.tool,persisted:!0});F(),B=Ee($e()),z(),mt(t.get(0),e.name||e.slug)}if(U)try{document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild"))}catch{}}catch(s){E.toast(`Save failed: ${s.message||s}`,{type:"error"})}finally{le.value=!1}}async function yt(){!N.peek()||!await E.confirm("Throw away the changes you have not saved?")||(Oe(g),z())}E.tabs(a("#me-tabs").get(0));const wt=M.applyBindings({dirty:N,saving:le,problems:pe,itemCount:be},o,{methods:{save:()=>Be(),discard:()=>yt(),addItem:()=>V("item"),addSeparator:()=>V("separator"),addSpacer:()=>V("spacer")}});l(()=>wt.dispose()),l(Ct(o,{position:"bottom"})),mt(t.get(0),$?"New menu":g.name||g.slug),Fe(t,{id:"menu-editor-back",icon:"arrow-left",title:"All menus",onClick:()=>{location.hash="#/menus"}}),Fe(t,{id:"menu-editor-locations",icon:"map-pin",title:"Menu locations",onClick:()=>{location.hash="#/menu-locations"}}),Fe(t,{id:"menu-editor-save",icon:"save",title:"Save (Ctrl+S)",onClick:()=>Be()});const Qe=e=>{if(!(!(e.ctrlKey||e.metaKey)||e.key!=="s")){if(e.preventDefault(),e.stopImmediatePropagation(),document.querySelector(".me-item-form")?.offsetParent){E.toast("Apply the item first (Ctrl+Enter), then Save.",{type:"info"});return}Be()}};document.addEventListener("keydown",Qe,!0),l(()=>document.removeEventListener("keydown",Qe,!0));const et=()=>{if(!(!N.peek()||!Pe))try{S.set(j,{menu:Pe,base:B,at:new Date().toISOString()})}catch{}},tt=e=>{N.peek()&&(et(),e.preventDefault(),e.returnValue="")};window.addEventListener("beforeunload",tt),l(()=>window.removeEventListener("beforeunload",tt)),q={path:h,dirty:()=>N.peek(),name:()=>a("#me-name").val()||g.name||g.slug||"new menu",dispose(){i=!0,et(),r.splice(0).reverse().forEach(e=>{try{e()}catch{}})}},I.scan(o);let X=null;try{X=S.get(j)}catch{}if(X?.menu){Ze();const e=X.base&&X.base!==B,n=X.at?` (${zt(X.at)})`:"",s=$?"the new menu you started":`the menu "${Le(g.name||g.slug)}"`,u=e?`You left unsaved changes to ${s}${n}, but the saved menu has changed since. Restore your version anyway?`:`You left unsaved changes to ${s}${n}. Restore them?`;await E.confirm(u)&&f()&&(Oe({...X.menu,meta:{...g.meta||{},...X.menu.meta||{}}}),z())}}};
21
+ ${Me}
22
+ </div>`),g(f.id)}}g(null),t.innerHTML=i.join("")||'<p class="mex-note">No items yet - Add item, or right-click an item for more.</p>',I.scan(t)}function $(t,d={},...s){const l=document.createElement(t);Object.assign(l,d);for(const i of s)i!=null&&l.append(i);return l}function T(t,d,s){const l=$("label",{className:"form-field"},$("span",{className:"form-label",textContent:t}),d);return s&&l.append($("small",{className:"form-hint",textContent:s,style:"display:block;font-size:.78em;opacity:.7;margin-top:.25rem;line-height:1.35"})),l}function Vt(t,d){const s=[["","- Everyone -"],["public","Public - anyone, incl. logged-out"],...(d||[]).map(i=>[i.name,`${i.label||i.name} and above`]),...(d||[]).filter(i=>i.level!==0).map(i=>[`=${i.name}`,`${i.label||i.name} only`]),["private","Private - super-admin only"]];t&&!s.some(([i])=>i===t)&&s.push([t,`${t} (custom)`]);const l=Q(s,t||"");return l.name="visibility",l}function Q(t,d){const s=$("select",{className:"form-select"});return t.forEach(([l,i])=>s.add(new Option(i,l))),s.value=d??"",s}function _e(t,d){const s=typeof d=="string"&&d.startsWith("#"),l=Q([["","- none -"],["primary","primary"],["success","success"],["danger","danger"],["warning","warning"],["info","info"],["neutral","neutral"],["__custom__","Custom\u2026"]],s?"__custom__":d||""),i=$("input",{type:"color",className:"form-input me-colour-hex",value:s?d:"#000000"});i.style.display=s?"":"none",l.addEventListener("change",()=>{i.style.display=l.value==="__custom__"?"":"none"});const g=T(t,l);return g.append(i),g._read=()=>l.value==="__custom__"?i.value:l.value,g}function Yt(t,d){const s=$("input",{className:"form-input me-icon",name:"icon",value:d||""}),l=$("span",{className:"me-icon-preview"});d&&l.setAttribute("data-icon",d);const i=$("button",{type:"button",className:"btn btn-sm btn-ghost",textContent:"Browse\u2026"}),g=k=>{k?l.setAttribute("data-icon",k):l.removeAttribute("data-icon"),Domma.icons.scan(l.parentNode||l)};return i.addEventListener("click",()=>kt(k=>{s.value=k,g(k)})),s.addEventListener("input",()=>g(s.value.trim())),T(t,$("div",{className:"me-icon-field"},s,i,l))}function Ce(...t){return $("div",{className:"me-field-grid"},...t)}async function Xt(t,d,s,l,i){const g=t.text||t.tool?.label||"",k=r=>$("h4",{className:"me-form-section",textContent:r}),f=T("Label",$("input",{className:"form-input",name:"text",value:t.text||""}),"The text shown for this item."),N=$("input",{className:"form-input",name:"url",value:t.url||""}),_=T("URL",N,t.tool||t.locked?"A Tool's address is its identity, so it cannot be changed here.":"Where it links. Must start with /, #, https://, or mailto: . Leave blank for a parent that only groups sub-items.");(t.tool||t.locked)&&(N.readOnly=!0);const V=Yt("Icon",t.icon||""),A=Vt(t.visibility||"",l),h=T("Visibility",A,t.locked?"Always in the sidebar for everyone who may use it, so it cannot be restricted here.":'Who can see this item. "Role and above" shows it to that role and anyone more senior; "Role only" shows it to holders of that role alone (and the super-admin). Blank = everyone.');t.locked&&(A.disabled=!0);const B=Q([["","- no permission gate -"],...(d||[]).map(r=>[r.key,r.label||r.key])],t.permission||"");B.name="permission";const ae=T("Permission",B,t.tool||t.locked?"A Tool is guarded by its own permission, which always applies.":"Hide unless the viewer holds this specific permission. Independent of Visibility - both must pass.");(t.tool||t.locked)&&(B.disabled=!0);const Z=T("Badge text",$("input",{className:"form-input",name:"badgeText",value:t.badge?.text||""})),z=Q([["","- none -"],...(s||[]).map(r=>[r.slug,r.title||r.slug])],t.badge?.countFrom||"");z.name="badgeCount";const ie=T("Badge count from",z,"Show a live count of this collection\u2019s entries as the badge."),ee=_e("Badge colour",t.badge?.variant||""),O=Q([["link","Link"],["pill","Pill"]],t.pill?"pill":"link");O.name="renderAs";const He=T("Render as",O,"Pill draws the item as a rounded chip. Pill styling applies to top-level navbar items."),K=T("Pill style",Q([["filled","Filled"],["outline","Outline"]],t.pill?.style||"filled"));K.querySelector("select").name="pillStyle";const me=_e("Pill colour",t.pill?.variant||""),se=$("div",{className:"me-pill-wrap"},Ce(K,me));se.style.display=t.pill?"":"none",O.addEventListener("change",()=>{se.style.display=O.value==="pill"?"":"none"});const m=_e("Text colour",t.colour||""),j=Q([["","- use the menu default -"],...tt.map(r=>[r,ot[r]||r])],t.highlight?.hover||"");j.name="hlHover";const le=T("Hover effect",j,"Overrides the menu-wide hover effect for this item only."),pe=Q([["","- use the menu default -"],...nt.map(r=>[r,at[r]||r])],t.highlight?.active||"");pe.name="hlActive";const be=T("When selected",pe,"How this item is marked when it points at the page being viewed."),P=_e("Highlight colour",t.highlight?.accent||""),x=$("button",{className:"btn btn-primary",textContent:"Apply",title:"Apply to the item (Ctrl+Enter) - Save the menu to keep it"}),W=$("div",{className:"me-item-form"},k("Link"),f,_,V,k("Access"),Ce(h,ae),k("Badge"),Ce(Z,ee),ie,k("Appearance"),He,se,m,k("Highlighting"),Ce(le,be),P,x),b=E.slideover({title:g?`Edit ${Le(g)}`:"Edit menu item",size:"lg",position:"right"});b.element.appendChild(W);const Y=()=>JSON.stringify([...W.querySelectorAll("input, select, textarea")].map(r=>r.type==="checkbox"?r.checked:r.value)),te=Y();let q=!1,re=!1;Rt(b);const ye=b.close.bind(b);b.close=async r=>{if(!q&&r!==!0&&Y()!==te){if(re)return;re=!0;const U=await E.confirm("Discard the changes to this item?");if(re=!1,!U)return}return q=!0,ye()},W.addEventListener("keydown",r=>{(r.ctrlKey||r.metaKey)&&r.key==="Enter"&&(r.preventDefault(),x.click())}),b.open();const fe=b.element.closest(".dm-slideover")||b.element.querySelector(".dm-slideover")||b.element;fe.style.setProperty("width",Kt+"px","important"),fe.style.setProperty("max-width","95vw","important"),Domma.icons.scan(W);const L=r=>W.querySelector(`[name="${r}"]`)?.value||"";x.addEventListener("click",()=>{t.text=L("text"),t.icon=L("icon"),t.locked||(t.visibility=L("visibility")),!t.tool&&!t.locked?(t.url=L("url"),t.permission=L("permission")):t.touched=!0;const r=L("badgeText"),U=L("badgeCount"),ne=ee._read();if(t.badge=r||U?{...r&&{text:r},...U&&{countFrom:U},...ne&&{variant:ne}}:null,L("renderAs")==="pill"){const he=me._read();t.pill={style:L("pillStyle")||"filled",...he&&{variant:he}}}else t.pill=null;t.colour=m._read();const ce=L("hlHover"),de=L("hlActive"),ue=P._read();t.highlight=ce||de||ue?{...ce&&{hover:ce},...de&&{active:de},...ue&&{accent:ue}}:null,q=!0,b.close(!0),i()})}let F=null,ct=!1;function Jt(){ct||!window.R?.use||(ct=!0,R.use((t,d,s)=>{const l=d?.path||"";return!(qt.test(l)&&(t?.path||"")!==l)||!F?.dirty()?s():E.confirm(`You have unsaved changes to the menu "${Le(F.name())}". Leave anyway? They are kept as a draft for your next visit.`).then(g=>{g?s():history.replaceState(null,"",`#${l}`)})}),M.subscribe("router:afterChange",({to:t}={})=>{if(F&&(t?.path||"")!==F.path){const d=F;F=null,d.dispose()}}))}function dt(t,d){const s=t.querySelector(".dm-plugin-banner-name"),l=s?.querySelector(".dm-plugin-banner-sep");if(!(!s||!l)){for(;l.nextSibling;)l.nextSibling.remove();s.appendChild(document.createTextNode(d))}}export const menuEditorView={templateUrl:"/admin/js/templates/menu-editor.html",async onMount(t){if(Jt(),F){const e=F;F=null,e.dispose()}const d=[],s=e=>(d.push(e),e);let l=!1;const i=t.get(0).querySelector(".mex")||t.get(0),g=()=>!l&&i.isConnected,k=location.hash.replace(/^#/,""),f=location.hash.match(/^#\/menus\/edit\/([^?#]+)/),N=f?decodeURIComponent(f[1]):null,_=!N,V=`menu-editor.draft.${N||"new"}`,A=E.loader(t.get(0),{type:"dots"});let h,B,ae,Z,z,ie,ee;try{if(_)h={slug:"",name:"",description:"",items:[]};else try{h=await C.menus.get(N)}catch(e){E.toast(`Failed to load menu: ${e.message||e}`,{type:"error"}),location.hash="#/menus";return}[B,ae,Z,z,ie,ee]=await Promise.all([C.projects.list().catch(()=>[]),H.get("/api/auth/permissions-registry").catch(()=>({resources:[]})),C.collections.list().catch(()=>[]),C.get("/collections/roles/entries?limit=100").catch(()=>null),C.menuLocations.registry().catch(()=>[]),C.pages.list().catch(()=>[])])}finally{A.destroy()}if(!i.isConnected)return;const He=(Array.isArray(z)?z:z?.entries||[]).map(e=>({name:e.data?.name,label:e.data?.label,level:e.data?.level??99})).filter(e=>e.name).sort((e,n)=>n.level-e.level),K=!_&&N===Wt;let me=[];if(K&&(me=await H.get("/api/sidebar/registered-items").catch(()=>(E.toast("Could not load the Tools - they are not shown, and saving keeps their places as they are.",{type:"warning",duration:8e3}),[])),!i.isConnected))return;const se=e=>it(K?xt($t(e||[],me,{forEditor:!0}),{leaveInHiddenFolders:!0}):e);let m=se(h.items);const j=M.observable(!1),le=M.observable(!1),pe=M.observable(""),be=M.observable(0);let P="";const x=i.querySelector("#me-items-list");function W(){Gt(x,m,K),be.value=m.filter(e=>!oe(e)).length}const b=()=>{W(),G()},Y=()=>K?rt(m):new Set,te=e=>m.find(n=>n.id===e);function q(e){requestAnimationFrame(()=>x.querySelector(`.menu-tree-row[data-id="${CSS.escape(e)}"]`)?.focus())}function re(e){const n=v=>m.find(c=>!c.type&&!c.url&&!c.tool&&(c.key||"").toLowerCase()===v)||m.find(c=>!c.type&&!c.url&&!c.tool&&!c.key&&(c.text||"").toLowerCase()===v);let a=n(String(e.tool.folder||"").toLowerCase())||n(Ct);const p=String(e.tool.group||"").trim();if(a&&p){const v=At(a.key||Lt(a.text),p),c=u=>u!==e&&!u.type&&!u.url&&!u.tool;let w=m.find(u=>c(u)&&(u.key||"").toLowerCase()===v)||m.find(u=>c(u)&&u.parentId===a.id&&(!u.key||u.key.toLowerCase()===v)&&(u.text||"").toLowerCase()===p.toLowerCase());w||([w]=it([{text:p,key:v,icon:_t,synthesised:!0}],a.id),m.push(w)),a=w}e.parentId=a?a.id:null,m.splice(m.indexOf(e),1),m.push(e),Object.assign(e,{text:e.tool.defaults.text,icon:e.tool.defaults.icon,visibility:"",hidden:!1,badge:null,pill:null,colour:"",highlight:null,touched:!1}),e.tool={...e.tool,persisted:!1}}const ye=e=>!Y().has(e.id)&&!(e.tool&&!e.tool.orphan);async function fe(e){const n=te(e);if(!n||!ye(n))return;const a=u=>{let J=u;for(;J;){if(J.id===e)return!0;J=m.find(D=>D.id===J.parentId)}return!1},p=m.filter(u=>u.id!==e&&a(u));if(p.length&&!await E.confirm(`Remove "${Le(n.text||n.type||"this item")}" and the ${p.length} item${p.length===1?"":"s"} beneath it?`))return;const v=Y(),c=p.filter(u=>u.tool),w=p.filter(u=>!u.tool&&v.has(u.id));m=m.filter(u=>!a(u)||c.includes(u)||w.includes(u));for(const u of w)u.parentId=n.parentId??null;for(const u of c)u.tool.orphan?u.parentId=n.parentId??null:re(u);b()}function L(e){const n=te(e);!n||oe(n)||Y().has(e)||(n.hidden=!n.hidden,n.touched=!0,b())}function r(e){const n=te(e);!n||oe(n)||(n.locked=K&&Y().has(n.id),Xt(n,ae.resources||[],Z,He,()=>{b(),q(e)}))}function U(e){const n={id:Ee(),parentId:null,...e==="separator"?{type:e}:e==="spacer"?{type:e,size:"md"}:{text:"",url:"/",icon:"",visibility:"",permission:"",hidden:!1,bundled:!1}};m.push(n),b(),oe(n)?q(n.id):r(n.id)}const ne=e=>n=>{e(n)&&(b(),q(n))},ce=ne(e=>lt(m,e,-1)),de=ne(e=>lt(m,e,1)),ue=ne(e=>Ot(m,e)),he=ne(e=>Bt(m,e));function ut(e){const n=te(e);if(!n)return[];const a=oe(n),p=Y().has(e),v=zt(m,e),c=v.findIndex(D=>D.id===e),w=n.tool,u=w&&(w.persisted||n.touched),J=D=>()=>{const ge=Pt(m,e,D,Ee());b(),ge&&!oe(ge)?r(ge.id):ge&&q(ge.id)};return[{header:a?n.type==="separator"?"Separator":"Spacer":n.text||w?.label||"(untitled)"},...a?[]:[{label:"Edit\u2026",icon:"edit",action:()=>r(e)}],{type:"divider"},{label:"Add item below",icon:"plus",action:J("item")},{label:"Add sub-item",icon:"corner-down-right",disabled:a,action:()=>{const D=jt(m,e,Ee());b(),D&&r(D.id)}},{label:"Add separator below",icon:"minus",action:J("separator")},{label:"Add spacer below",icon:"move",action:J("spacer")},{type:"divider"},{label:"Move up",icon:"arrow-up",shortcut:"Alt+\u2191",disabled:c<=0,action:()=>ce(e)},{label:"Move down",icon:"arrow-down",shortcut:"Alt+\u2193",disabled:c<0||c>=v.length-1,action:()=>de(e)},{label:"Indent",icon:"chevron-right",shortcut:"Alt+\u2192",disabled:c<=0||oe(v[c-1]),action:()=>ue(e)},{label:"Outdent",icon:"chevron-left",shortcut:"Alt+\u2190",disabled:n.parentId==null,action:()=>he(e)},{type:"divider"},...a?[]:[{label:n.hidden?"Show":"Hide",icon:n.hidden?"eye":"eye-off",disabled:p,action:()=>L(e)}],{label:"Duplicate",icon:"copy",disabled:!!w,action:()=>{const D=Nt(m,e,Ee);b(),D&&q(D.id)}},...w&&!w.orphan&&u?[{label:"Back to its default place",icon:"rotate-ccw",action:()=>{re(n),b()}}]:[],{label:p?"Remove - always in the sidebar":w&&!w.orphan?"Remove - a Tool is hidden, not removed":"Remove\u2026",icon:"trash",danger:!0,disabled:!ye(n),action:()=>fe(e)}]}const mt=E.contextMenu(x,{cursor:"glyph",match:".menu-tree-row",inherit:!1,density:"compact",items:e=>ut(e.dataset.id)});s(()=>mt?.destroy?.());const pt=St(x,()=>m,b,{items:".menu-tree-row",handle:".menu-tree-grip"});s(()=>pt?.destroy());const Ke=e=>{const n=e.target.closest(".menu-tree-row");if(!n)return;const a=n.dataset.id;if(e.target.closest(".mex-kebab")){ze(e.target.closest(".mex-kebab"));return}if(e.target.closest(".me-hidden")){L(a);return}if(e.target.closest(".me-edit")){r(a);return}e.target.closest("select, .menu-tree-grip, button")||r(a)},We=e=>{const n=e.target.closest(".menu-tree-row");if(!n||e.target!==n){n&&e.key==="F10"&&e.shiftKey&&(e.preventDefault(),ze(n));return}const a=n.dataset.id;if(e.key==="F10"&&e.shiftKey)e.preventDefault(),ze(n);else if(e.key==="Enter")e.preventDefault(),r(a);else if(e.key==="Delete")e.preventDefault(),fe(a);else if(e.altKey&&e.key==="ArrowUp")e.preventDefault(),ce(a);else if(e.altKey&&e.key==="ArrowDown")e.preventDefault(),de(a);else if(e.altKey&&e.key==="ArrowRight")e.preventDefault(),ue(a);else if(e.altKey&&e.key==="ArrowLeft")e.preventDefault(),he(a);else if(e.key==="ArrowDown"||e.key==="ArrowUp"){const p=[...x.querySelectorAll(".menu-tree-row")],v=p.indexOf(n)+(e.key==="ArrowDown"?1:-1);p[v]&&(e.preventDefault(),p[v].focus())}},qe=e=>{if(!e.target.matches(".me-spacer-size"))return;const n=te(e.target.closest(".menu-tree-row")?.dataset.id);n&&(n.size=e.target.value,G())};x.addEventListener("click",Ke),x.addEventListener("keydown",We),x.addEventListener("change",qe),s(()=>{x.removeEventListener("click",Ke),x.removeEventListener("keydown",We),x.removeEventListener("change",qe)});const o=e=>t.find(e),we=o("#me-float-accent"),Ie=o("#me-float-accent-hex"),Re=()=>{Ie.get(0).style.display=we.val()==="__custom__"?"":"none"},ft=()=>we.val()==="__custom__"?Ie.val():we.val(),ke=o("#me-highlight-accent"),Te=o("#me-highlight-accent-hex"),Ue=()=>{Te.get(0).style.display=ke.val()==="__custom__"?"":"none"},ht=()=>ke.val()==="__custom__"?Te.val():ke.val(),Ge=()=>{const e=o("#me-position").val()==="floating";o(".dm-float-field").each(function(){this.style.display=e?"":"none"}),e&&Re();const n=o("#me-orientation").val()==="vertical";o(".dm-vertical-field").each(function(){this.style.display=n?"":"none"});const a=!!(o("#me-float-collapsible").get(0)||{}).checked;o(".dm-float-collapsed-field").each(function(){this.style.display=e&&a?"":"none"})},Ve=(e,n,a,p)=>{const v=o(e).get(0);v&&(v.innerHTML="",v.add(new Option(p,"")),n.forEach(c=>v.add(new Option(a[c]||c,c))))};Ve("#me-highlight-hover",tt,ot,"- theme default -"),Ve("#me-highlight-active",nt,at,"- theme default -");const je=o("#me-bind-slot"),De=o("#me-bind-projects"),Se=o("#me-bind-pages");je.html('<option value="">- not bound -</option>'+(ie||[]).map(e=>`<option value="${y(e.slot)}">${y(e.label||e.slot)} (${y(e.slot)})</option>`).join("")),De.html(B.map(e=>`<option value="${y(e.slug)}">${y(e.name||e.slug)}</option>`).join("")),o("#me-bind-page-pick").html('<option value="">- pick a page -</option>'+ee.map(e=>{const n=e.urlPath||e.url||"";return n?`<option value="${y(n)}">${y(e.title||n)} - ${y(n)}</option>`:""}).join(""));const Ye=()=>Dt({slot:je.val(),projects:Array.from(De.get(0).selectedOptions).map(e=>e.value),pagesText:Se.val()});function Ne(){const e=Ye(),n=o("#me-bind-summary");if(!e){n.html('<span class="text-muted">Not bound - this menu renders only where it is mapped or placed by a shortcode.</span>');return}const a=[];e.projects.length&&a.push(`pages in ${e.projects.map(c=>`<code>${y(c)}</code>`).join(", ")}`),e.pages.length&&a.push(`pages matching ${e.pages.map(c=>`<code>${y(c)}</code>`).join(", ")}`);const p=e.pages.filter(c=>!/^\/[^\s?#*]*(\/\*)?$|^\/\*$/.test(c)),v=p.length?`<div class="text-danger" style="margin-top:.4rem">Not valid page patterns: ${p.map(c=>`<code>${y(c)}</code>`).join(", ")}</div>`:"";n.html(a.length?`Takes over the <code>${y(e.slot)}</code> slot on ${a.join(" and ")}.${v}`:`<span class="text-warning">Slot <code>${y(e.slot)}</code> selected but no project or page chosen - the binding will never match.</span>`)}const{getProjectFromHash:vt}=await import("../lib/project-context.js");if(!g())return;const gt=_?vt():null;o("#me-project").html('<option value="">- none -</option>'+B.map(e=>`<option value="${y(e.slug)}">${y(e.name||e.slug)}</option>`).join(""));function Oe(e){m=se(e.items),o("#me-variant").val(e.variant||""),o("#me-position").val(e.position||"");const n=o("#me-appearOnHover").get(0);n&&(n.checked=e.appearOnHover===!0),o("#me-float-anchor").val(e.float?.anchor||"TL"),o("#me-float-offsetX").val(e.float?.offsetX??""),o("#me-float-offsetY").val(e.float?.offsetY??""),o("#me-float-width").val(e.float?.width??""),o("#me-float-radius").val(e.float?.radius??""),o("#me-float-shadow").val(e.float?.shadow||""),o("#me-float-opacity").val(e.float?.opacity??""),o("#me-float-title").val(e.float?.title||"");for(const[c,w]of[["#me-float-collapsible",e.float?.collapsible],["#me-float-collapsed",e.float?.collapsed],["#me-float-movable",e.float?.movable],["#me-float-resizable",e.float?.resizable]]){const u=o(c).get(0);u&&(u.checked=w===!0)}const a=e.float?.accent||"";we.val(a.startsWith("#")?"__custom__":a),a.startsWith("#")&&Ie.val(a),Re(),o("#me-orientation").val(e.orientation||""),o("#me-align").val(e.align||""),o("#me-side").val(e.side||"left"),o("#me-highlight-hover").val(e.highlight?.hover||""),o("#me-highlight-active").val(e.highlight?.active||"");const p=e.highlight?.accent||"";ke.val(p.startsWith("#")?"__custom__":p),p.startsWith("#")&&Te.val(p),Ue(),o("#me-fontFamily").val(e.style?.fontFamily||""),o("#me-fontSize").val(e.style?.fontSize||""),o("#me-fontWeight").val(e.style?.fontWeight||""),o("#me-letterSpacing").val(e.style?.letterSpacing||""),o("#me-iconSize").val(e.style?.iconSize||""),je.val(e.binding?.slot||"");const v=new Set(e.binding?.projects||[]);Array.from(De.get(0).options).forEach(c=>{c.selected=v.has(c.value)}),Se.val((e.binding?.pages||[]).join(`
23
+ `)),o("#me-slug").val(e.slug||""),o("#me-name").val(e.name||""),o("#me-description").val(e.description||""),o("#me-project").val(e.meta?.project||gt||""),Ge(),Ne(),W()}const ve=e=>!!(o(e).get(0)||{}).checked;function $e(){const e={variant:o("#me-variant").val(),position:o("#me-position").val(),appearOnHover:ve("#me-appearOnHover"),floatAnchor:o("#me-float-anchor").val(),floatOffsetX:o("#me-float-offsetX").val(),floatOffsetY:o("#me-float-offsetY").val(),floatWidth:o("#me-float-width").val(),floatRadius:o("#me-float-radius").val(),floatShadow:o("#me-float-shadow").val(),floatAccent:ft(),floatOpacity:o("#me-float-opacity").val(),floatTitle:o("#me-float-title").val(),floatCollapsible:ve("#me-float-collapsible"),floatCollapsed:ve("#me-float-collapsed"),floatMovable:ve("#me-float-movable"),floatResizable:ve("#me-float-resizable"),highlightHover:o("#me-highlight-hover").val(),highlightActive:o("#me-highlight-active").val(),highlightAccent:ht(),orientation:o("#me-orientation").val(),align:o("#me-align").val(),side:o("#me-side").val(),fontFamily:o("#me-fontFamily").val(),fontSize:o("#me-fontSize").val(),fontWeight:o("#me-fontWeight").val(),letterSpacing:o("#me-letterSpacing").val(),iconSize:o("#me-iconSize").val()},n={slug:o("#me-slug").val(),name:o("#me-name").val(),description:o("#me-description").val(),project:o("#me-project").val()};return Ft(e,n,Ye(),Ht(m),h.meta||{})}let Xe=!1,Pe=null;function G(){if(!P)return;const e=$e();Pe=e,j.value=Ae(e)!==P,pe.value=j.peek()||Xe?st(e).join(" "):""}const xe=e=>{e.target.closest("#me-items-list")||(e.target.matches("#me-position, #me-orientation, #me-float-collapsible")&&Ge(),e.target.matches("#me-float-accent")&&Re(),e.target.matches("#me-highlight-accent")&&Ue(),e.target.closest("#me-binding")&&Ne(),G())};i.addEventListener("input",xe),i.addEventListener("change",xe),s(()=>{i.removeEventListener("input",xe),i.removeEventListener("change",xe)}),o("#me-bind-page-add").on("click",()=>{const e=o("#me-bind-page-pick").val();if(!e)return;const n=Se.val().split(`
24
+ `).map(a=>a.trim()).filter(Boolean);n.includes(e)||n.push(e),Se.val(n.join(`
25
+ `)),Ne(),G()}),Oe(h),P=Ae($e()),G();const Je=()=>{try{S.remove?S.remove(V):S.set(V,null)}catch{}};async function Fe(){if(le.peek())return;const e=$e(),n=st(e);if(n.length){Xe=!0,G(),E.toast(n.join(" "),{type:"warning",duration:7e3});return}le.value=!0;try{if(_)await C.menus.create(e);else if(e.slug!==h.slug){await C.menus.create(e);const a=await C.menuLocations.get();let p=!1;for(const[v,c]of Object.entries(a))c===h.slug&&(a[v]=e.slug,p=!0);p&&await C.menuLocations.save(a),await C.menus.remove(h.slug)}else await C.menus.update(h.slug,e);if(P=Ae(e),j.value=!1,Je(),Tt("#/menus"),E.toast("Saved.",{type:"success"}),_||e.slug!==h.slug)location.hash="#/menus/edit/"+encodeURIComponent(e.slug);else{h={...h,...e};for(const a of m)a.tool&&a.touched&&(a.tool={...a.tool,persisted:!0});W(),P=Ae($e()),G(),dt(t.get(0),e.name||e.slug)}if(K)try{document.dispatchEvent(new CustomEvent("dm:sidebar-rebuild"))}catch{}}catch(a){E.toast(`Save failed: ${a.message||a}`,{type:"error"})}finally{le.value=!1}}async function bt(){!j.peek()||!await E.confirm("Throw away the changes you have not saved?")||(Oe(h),G())}E.tabs(o("#me-tabs").get(0));const yt=M.applyBindings({dirty:j,saving:le,problems:pe,itemCount:be},i,{methods:{save:()=>Fe(),discard:()=>bt(),addItem:()=>U("item"),addSeparator:()=>U("separator"),addSpacer:()=>U("spacer")}});s(()=>yt.dispose()),s(It(i,{position:"bottom"})),dt(t.get(0),_?"New menu":h.name||h.slug),Be(t,{id:"menu-editor-back",icon:"arrow-left",title:"All menus",onClick:()=>{location.hash="#/menus"}}),Be(t,{id:"menu-editor-locations",icon:"map-pin",title:"Menu locations",onClick:()=>{location.hash="#/menu-locations"}}),Be(t,{id:"menu-editor-save",icon:"save",title:"Save (Ctrl+S)",onClick:()=>Fe()});const Qe=e=>{if(!(!(e.ctrlKey||e.metaKey)||e.key!=="s")){if(e.preventDefault(),e.stopImmediatePropagation(),document.querySelector(".me-item-form")?.offsetParent){E.toast("Apply the item first (Ctrl+Enter), then Save.",{type:"info"});return}Fe()}};document.addEventListener("keydown",Qe,!0),s(()=>document.removeEventListener("keydown",Qe,!0));const Ze=()=>{if(!(!j.peek()||!Pe))try{S.set(V,{menu:Pe,base:P,at:new Date().toISOString()})}catch{}},et=e=>{j.peek()&&(Ze(),e.preventDefault(),e.returnValue="")};window.addEventListener("beforeunload",et),s(()=>window.removeEventListener("beforeunload",et)),F={path:k,dirty:()=>j.peek(),name:()=>o("#me-name").val()||h.name||h.slug||"new menu",dispose(){l=!0,Ze(),d.splice(0).reverse().forEach(e=>{try{e()}catch{}})}},I.scan(i);let X=null;try{X=S.get(V)}catch{}if(X?.menu){Je();const e=X.base&&X.base!==P,n=X.at?` (${Mt(X.at)})`:"",a=_?"the new menu you started":`the menu "${Le(h.name||h.slug)}"`,p=e?`You left unsaved changes to ${a}${n}, but the saved menu has changed since. Restore your version anyway?`:`You left unsaved changes to ${a}${n}. Restore them?`;await E.confirm(p)&&g()&&(Oe({...X.menu,meta:{...h.meta||{},...X.menu.meta||{}}}),G())}}};
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "domma-cms",
3
- "version": "0.95.0",
3
+ "version": "0.97.0",
4
4
  "description": "File-based CMS powered by Domma and Fastify. Run npx domma-cms my-site to create a new project.",
5
5
  "type": "module",
6
6
  "main": "server/server.js",
@@ -83,7 +83,7 @@
83
83
  "@fastify/rate-limit": "^10.3.0",
84
84
  "@fastify/static": "9.1.1",
85
85
  "bcryptjs": "^3.0.3",
86
- "domma-js": "0.44.9",
86
+ "domma-js": "0.45.0",
87
87
  "dotenv": "^17.2.3",
88
88
  "fastify": "5.8.5",
89
89
  "gray-matter": "^4.0.3",
package/server/server.js CHANGED
@@ -583,6 +583,8 @@ await app.register(relatedRoutes, {prefix: '/api/related'});
583
583
  // site would simply never see Notes or Todo. Registered items are placed at
584
584
  // render time on every site (placeTools() in admin/js/lib/sidebar-grouping.js):
585
585
  // in the Tools folder by default, or wherever an admin has moved them.
586
+ // `group: 'Core'` gathers them in a Core sub-folder (Tools -> Core -> Notes),
587
+ // apart from the marketplace plugins' Tools, which sit directly in Tools.
586
588
  //
587
589
  // `permission` is what hides each one from a role that cannot use it; the
588
590
  // renderer filters on it.
@@ -598,7 +600,7 @@ const coreToolItems = [
598
600
  {text: 'SEO', url: '#/seo', icon: 'search', permission: 'seo', countUrl: '/api/seo/count'}
599
601
  ];
600
602
  for (const item of coreToolItems) {
601
- if (isToolEnabled(item.permission)) registerSidebarItem({item: {source: 'Built in', ...item}});
603
+ if (isToolEnabled(item.permission)) registerSidebarItem({group: 'Core', item: {source: 'Built in', ...item}});
602
604
  }
603
605
  // Todo's to-dos on the calendar (registered when routes/api/todo.js loads).
604
606
  if (!isToolEnabled('todo')) {
@@ -81,16 +81,23 @@ const _registeredSidebarItems = [];
81
81
  * places by `url` first (see placeTools in admin/js/lib/sidebar-grouping.js).
82
82
  * `parent` is the older form: any node matched by its text.
83
83
  *
84
- * @param {{folder?: string, parent?: string, item: {text: string, url: string, icon?: string, permission?: string, folder?: string, items?: object[]}}} opts
84
+ * `group` puts the Tool one level further down, in a sub-folder of that folder
85
+ * (`group: 'Core'` -> Tools -> Core -> the Tool). The sub-folder is keyed
86
+ * `<folder>.<slug of group>` and made at render time if the menu has none; an
87
+ * admin's own arrangement still wins.
88
+ *
89
+ * @param {{folder?: string, parent?: string, group?: string, item: {text: string, url: string, icon?: string, permission?: string, folder?: string, group?: string, items?: object[]}}} opts
85
90
  */
86
91
  export function registerSidebarItem(opts) {
87
92
  if (!opts || !opts.item || typeof opts.item.text !== 'string') {
88
93
  throw new Error('registerSidebarItem: opts.item.text is required');
89
94
  }
90
- const {folder: itemFolder, ...item} = opts.item;
95
+ const {folder: itemFolder, group: itemGroup, ...item} = opts.item;
96
+ const group = [opts.group, itemGroup].find(g => typeof g === 'string' && g.trim());
91
97
  _registeredSidebarItems.push({
92
98
  parent: opts.parent || null,
93
99
  folder: opts.folder || itemFolder || DEFAULT_TOOL_FOLDER,
100
+ ...(group && {group: group.trim()}),
94
101
  item
95
102
  });
96
103
  }
@@ -569,8 +569,9 @@ export async function registerPlugins(fastify) {
569
569
  // reads plugin nav from /api/sidebar/registered-items; plugins
570
570
  // declare their nav in the manifest rather than calling
571
571
  // registerSidebarItem, so register it here on their behalf. An
572
- // entry's `folder` is its default place (Tools when it names none);
573
- // an admin can move it anywhere in the menu.
572
+ // entry's `folder` is its default place (Tools when it names none),
573
+ // and an optional `group` a sub-folder inside it; an admin can move
574
+ // it anywhere in the menu.
574
575
  const isCore = CORE_PLUGINS.has(manifest.name);
575
576
  for (const item of manifest.admin?.sidebar || []) {
576
577
  try {
@@ -312,6 +312,9 @@ export function buildGitignore({sitePlugins = [], pluginContent = {}, sitePublic
312
312
  // SEO's runtime state; its redirects and overrides beside them are authored, and tracked.
313
313
  '/content/seo/audit.json',
314
314
  '/content/seo/hits.json',
315
+ // When each notification source last ran, and which one-off migrations have run - rewritten by the CMS itself.
316
+ '/content/.notification-sources.json',
317
+ '/content/.migrations.json',
315
318
  '/content/instances_log.json',
316
319
  '/content/preview-links.json',
317
320
  '/config/connections.json*',