@tekkare/romulus 0.1.13 → 0.1.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/module.json CHANGED
@@ -4,7 +4,7 @@
4
4
  "compatibility": {
5
5
  "nuxt": ">=3.16.0"
6
6
  },
7
- "version": "0.1.12",
7
+ "version": "0.1.14",
8
8
  "builder": {
9
9
  "@nuxt/module-builder": "0.8.4",
10
10
  "unbuild": "2.0.0"
package/dist/module.mjs CHANGED
@@ -22,6 +22,7 @@ const module = defineNuxtModule({
22
22
  nuxt.options.css.push(resolve(runtimeDir, "assets/styles/base.css"));
23
23
  nuxt.options.css.push(resolve(runtimeDir, "assets/styles/components.css"));
24
24
  nuxt.options.css.push(resolve(runtimeDir, "assets/styles/chrome.css"));
25
+ nuxt.options.css.push(resolve(runtimeDir, "assets/styles/shell.css"));
25
26
  if (options.utilities)
26
27
  nuxt.options.css.push(resolve(runtimeDir, "assets/styles/utilities.css"));
27
28
  await addComponentsDir({
@@ -1 +1 @@
1
- body.lcollapsed{padding-left:var(--sidebar-collapsed-w)}.nav-item .icn i,.rpanel-item .icn i{font-size:16px}.strip-icon i,.topbar-toggle i{font-size:18px}.chev i,.chev-r i{font-size:11px}.topbar-toggle{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:6px;color:var(--text-secondary);cursor:pointer;display:flex;font-size:16px;height:32px;justify-content:center;width:32px}.topbar-toggle:hover{background:var(--bg-hover);border-color:var(--color-violet-pale);color:var(--color-secondary)}.logo-mark{align-items:center;background:linear-gradient(135deg,var(--color-primary),var(--color-secondary));border-radius:6px;box-shadow:0 2px 6px rgba(107,63,255,.25);color:var(--color-text-inverse);display:flex;flex-shrink:0;font-size:14px;height:28px;justify-content:center;width:28px}.logo-mark,.logo-text{font-family:var(--font-serif);font-weight:700}.logo-text{font-size:16px;line-height:1}.logo-sub{color:var(--text-muted);font-size:10px;letter-spacing:.05em;margin-top:2px;text-transform:uppercase}.sidebar{background:var(--bg-surface);border-right:1px solid var(--border-default);bottom:0;display:flex;flex-direction:column;left:0;overflow-x:hidden;overflow-y:auto;position:fixed;top:0;transition:width .24s cubic-bezier(.2,0,0,1);width:var(--sidebar-w);z-index:70}.sidebar-top{border-bottom:1px solid var(--border-default);flex-shrink:0;height:var(--topbar-h);justify-content:space-between;padding:0 14px}.sidebar-top,.sidebar-top .logo-block{align-items:center;display:flex;gap:8px}.sidebar-top .logo-block{min-width:0}body.lcollapsed .sidebar-top{justify-content:center;padding:0}body.lcollapsed .sidebar-top .logo-block{display:none}body.lcollapsed .sidebar-top .logo-mark{display:flex}.sidebar-search{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:999px;display:flex;gap:10px;margin:10px 12px 4px;padding:7px 14px;transition:border-color .15s,background .15s}.sidebar-search:focus-within,.sidebar-search:hover{background:var(--bg-surface);border-color:var(--color-violet-pale)}.sidebar-search i{color:var(--text-muted);flex-shrink:0;font-size:14px}.sidebar-search input{background:transparent;border:none;color:var(--text-primary);flex:1;font-family:inherit;font-size:13px;min-width:0;outline:none}.sidebar-search input::-moz-placeholder{color:var(--text-muted)}.sidebar-search input::placeholder{color:var(--text-muted)}.sidebar-search kbd{background:var(--bg-surface);border:1px solid var(--border-default);border-radius:4px;color:var(--text-secondary);flex-shrink:0;font-family:inherit;font-size:10px;font-weight:600;padding:1px 5px}body.lcollapsed .sidebar-search{display:none}body.lcollapsed .sidebar{width:var(--sidebar-collapsed-w)}.nav-group{padding:4px 0}.nav-section-header{align-items:center;cursor:pointer;display:flex;justify-content:space-between;padding:14px 14px 6px;-webkit-user-select:none;-moz-user-select:none;user-select:none}.nav-section-header .label,.nav-section-header span{color:var(--text-muted);font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.nav-section-header .chev{color:var(--text-muted);font-size:10px;transition:transform .2s}.nav-section.collapsed .chev{transform:rotate(-90deg)}.nav-section.collapsed .nav-items{display:none}.nav-item{align-items:center;color:var(--text-secondary);cursor:pointer;display:flex;font-size:13px;font-weight:500;gap:10px;padding:7px 14px 7px 22px;transition:background .15s,color .15s;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.nav-item .icn{color:var(--text-muted);flex-shrink:0;text-align:center;width:16px}.nav-item .lbl{flex:1;overflow:hidden;text-overflow:ellipsis}.nav-item .chev-r{color:var(--text-muted);font-size:10px;transition:transform .2s}.nav-item.has-children.open .chev-r{transform:rotate(90deg)}.nav-item:hover{background:var(--bg-surface-3);color:var(--text-primary)}.nav-item:hover .icn{color:var(--text-secondary)}.nav-item.active{background:linear-gradient(90deg,var(--color-violet-pale) 0,var(--bg-hover) 100%);color:var(--color-primary);font-weight:700;position:relative}.nav-item.active:before{background:var(--color-secondary);border-radius:0 4px 4px 0;bottom:5px;content:"";left:0;position:absolute;top:5px;width:4px}.nav-item.active .icn{color:var(--color-secondary)}.nav-subitems{background:var(--bg-surface-2);border-bottom:1px solid var(--border-soft);border-top:1px solid var(--border-soft);display:none;padding:2px 0 4px}.nav-item.has-children.open+.nav-subitems{display:block}.nav-subitem{align-items:center;color:var(--text-secondary);cursor:pointer;display:flex;font-size:12px;gap:8px;padding:6px 14px 6px 44px}.nav-subitem:hover{background:var(--bg-surface-3);color:var(--text-primary)}.nav-subitem.active{background:linear-gradient(90deg,var(--color-violet-pale) 0,var(--bg-hover) 100%);color:var(--color-primary);font-weight:700;position:relative}.nav-subitem.active:before{background:var(--color-secondary);border-radius:0 4px 4px 0;bottom:4px;content:"";left:0;position:absolute;top:4px;width:4px}.sidebar-footer{border-top:1px solid var(--border-default);display:flex;flex-direction:column;gap:4px;margin-top:auto;padding:10px 8px}.sb-user{align-items:center;border-radius:8px;cursor:pointer;display:flex;gap:12px;padding:10px 12px;transition:background .15s;-webkit-user-select:none;-moz-user-select:none;user-select:none}.sb-user:hover{background:var(--bg-surface-3)}.sb-user-avatar{align-items:center;background:linear-gradient(135deg,var(--color-secondary),var(--color-accent-teal));border-radius:50%;box-shadow:0 2px 6px rgba(107,63,255,.22);color:var(--color-text-inverse);display:flex;flex-shrink:0;font-family:var(--font-serif);font-size:13px;font-weight:700;height:36px;justify-content:center;width:36px}.sb-user-info{flex:1;min-width:0}.sb-user-name{color:var(--text-primary);font-size:13px;font-weight:600;line-height:1.25}.sb-user-name,.sb-user-org{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sb-user-org{color:var(--text-muted);font-size:11px;line-height:1.2;margin-top:2px}.sb-user-chev{color:var(--text-muted);flex-shrink:0;font-size:13px}.sb-actions{display:flex;gap:4px}.sb-actions .sb-lang,.sb-actions a{align-items:center;border-radius:6px;color:var(--text-secondary);cursor:pointer;display:inline-flex;flex:1;font-family:inherit;font-size:12px;font-weight:600;gap:5px;justify-content:center;padding:8px 10px;text-decoration:none;transition:background .15s,color .15s}.sb-actions .sb-lang:hover,.sb-actions a:hover{background:var(--bg-surface-3);color:var(--text-primary)}.sb-actions a.primary{color:var(--color-primary)}.sb-actions a.primary:hover{background:var(--bg-hover);color:var(--color-secondary)}.sb-actions i{font-size:13px}body.lcollapsed .sidebar .chev-r,body.lcollapsed .sidebar .lbl,body.lcollapsed .sidebar .nav-section-header,body.lcollapsed .sidebar-footer{display:none}body.lcollapsed .sidebar .nav-item.has-children.open+.nav-subitems,body.lcollapsed .sidebar .nav-subitems{display:none!important}body.lcollapsed .sidebar .nav-item.has-children.open .chev-r{transform:none}body.lcollapsed .sidebar .nav-group{border-top:1px solid var(--border-soft);padding:4px 0}body.lcollapsed .sidebar .nav-group:first-of-type{border-top:none}.nav-subitems.flyout,body.lcollapsed .sidebar .nav-item.has-children.open+.nav-subitems.flyout,body.lcollapsed .sidebar .nav-subitems.flyout{animation:flyout-in .12s cubic-bezier(.2,0,0,1);background:var(--bg-surface);border:1px solid var(--border-default);border-left:none;border-radius:0 8px 8px 0;box-shadow:var(--shadow-lg);display:block!important;left:var(--sidebar-collapsed-w);min-width:220px;padding:8px 0;position:fixed;z-index:100}.nav-subitems.flyout:before{border-bottom:1px solid var(--border-soft);color:var(--text-muted);content:attr(data-parent-label);display:block;font-size:11px;font-weight:700;letter-spacing:.08em;margin-bottom:4px;padding:6px 16px 8px;text-transform:uppercase}.nav-subitems.flyout .nav-subitem{font-size:13px;padding:8px 16px}body.lcollapsed .sidebar .nav-item{position:relative}body.lcollapsed .sidebar .nav-item[data-tip]:hover:after{background:var(--text-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.2);color:var(--color-text-inverse);content:attr(data-tip);font-size:12px;font-weight:500;left:var(--sidebar-collapsed-w);margin-left:6px;padding:5px 10px;pointer-events:none;position:fixed;top:var(--tip-top,0);white-space:nowrap;z-index:110}.rsidebar .strip-icon{position:relative}.rsidebar .strip-icon[data-tip]:hover:before{background:var(--text-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.2);color:var(--color-text-inverse);content:attr(data-tip);font-size:12px;font-weight:500;margin-right:6px;padding:5px 10px;pointer-events:none;position:fixed;right:var(--rsidebar-collapsed-w);top:var(--tip-top,0);white-space:nowrap;z-index:110}body.ropen .rsidebar .strip-icon[data-tip]:hover:before{display:none}.rsidebar .strip-icon.has-flyout.show-flyout .rflyout{display:block}body.ropen .rsidebar .rflyout{display:none!important}body.lcollapsed .nav-item{justify-content:center;padding:10px 0}body.lcollapsed .nav-section-header{justify-content:center;padding:8px 0}.rsidebar{background:var(--bg-surface);border-left:1px solid var(--border-default);bottom:0;display:flex;flex-direction:column;overflow:hidden;position:fixed;right:0;top:0;width:var(--rsidebar-collapsed-w);z-index:70}.rstrip-top{align-items:center;border-bottom:1px solid var(--border-default);display:flex;flex-shrink:0;height:var(--topbar-h);justify-content:center}.rstrip-collapsed{align-items:stretch;gap:4px;padding:8px}.rstrip-collapsed,.strip-icon{display:flex;flex-direction:column}.strip-icon{align-items:center;border-radius:8px;color:var(--text-secondary);cursor:pointer;gap:5px;justify-content:center;padding:10px 4px;position:relative;transition:background .15s,color .15s}.strip-icon i{font-size:19px;transition:color .15s}.strip-icon .strip-label{color:inherit;font-size:10px;font-weight:600;letter-spacing:.01em;line-height:1;white-space:nowrap}.strip-icon:hover{background:var(--bg-surface-3);color:var(--text-primary)}.strip-icon.active,.strip-icon:hover i{color:var(--color-secondary)}.strip-icon.active{background:var(--bg-hover)}.strip-icon.active i{color:var(--color-secondary)}.strip-icon .dot{background:var(--color-notification);border-radius:50%;box-shadow:0 0 0 2px var(--color-text-inverse);height:8px;position:absolute;right:14px;top:6px;width:8px}.strip-icon.is-live .dot{background:var(--color-success);box-shadow:0 0 0 2px var(--bg-surface)}.strip-icon.is-live .dot:after{animation:stripLivePulse 1.8s ease-out infinite;background:var(--color-success);border-radius:50%;content:"";inset:-2px;position:absolute}.strip-icon.is-live .strip-label{background:var(--color-success);border-radius:var(--radius-pill);color:var(--color-text-inverse);display:inline-block;font-weight:var(--weight-bold);letter-spacing:.04em;line-height:1.2;margin-top:2px;padding:2px var(--space-6);text-transform:uppercase}@media (prefers-reduced-motion:reduce){.strip-icon.is-live .dot:after{animation:none}}.strip-badge{align-items:center;background:var(--color-primary);border-radius:999px;box-shadow:0 0 0 2px var(--color-text-inverse);color:var(--color-text-inverse);display:flex;font-size:9px;font-variant-numeric:tabular-nums;font-weight:700;height:16px;justify-content:center;line-height:1;min-width:18px;padding:0 5px;position:absolute;right:8px;top:4px}.strip-divider{background:var(--bg-surface-3);margin:6px auto;width:70%}body.ropen .rpanel-open{display:block}.ptabs.export-toptabs{align-items:stretch;border-bottom:1px solid var(--border-default);gap:0;height:auto;margin:0 0 var(--space-20);padding:0}.ptabs.export-toptabs .ptab{align-items:center;display:inline-flex;font-size:var(--font-14);font-weight:var(--weight-semibold);gap:var(--space-6);padding:var(--space-12) var(--space-16)}.ptabs.export-toptabs .ptab i{font-size:var(--font-16)}.ptabs.export-toptabs .lib-tab-count{background:var(--bg-surface-3);border-radius:var(--radius-pill);color:var(--text-muted);font-size:var(--font-11);font-variant-numeric:tabular-nums;font-weight:var(--weight-bold);min-width:18px;padding:0 var(--space-6);text-align:center}.ptabs.export-toptabs .ptab.active .lib-tab-count{background:var(--bg-hover);color:var(--color-secondary)}.ptabs.views-toptabs{align-items:stretch;border-bottom:1px solid var(--border-default);gap:0;height:auto;margin:0 0 var(--space-16);padding:0}.ptabs.views-toptabs .ptab{align-items:center;display:inline-flex;font-size:var(--font-14);font-weight:var(--weight-semibold);gap:var(--space-6);padding:var(--space-12) var(--space-16)}.ptabs.views-toptabs .ptab i{font-size:var(--font-16)}.ptabs.views-toptabs .lib-tab-count{background:var(--bg-surface-3);border-radius:var(--radius-pill);color:var(--text-muted);font-size:var(--font-11);font-variant-numeric:tabular-nums;font-weight:var(--weight-bold);min-width:18px;padding:0 var(--space-6);text-align:center}.ptabs.views-toptabs .ptab.active .lib-tab-count{background:var(--bg-hover);color:var(--color-secondary)}.ptabs.alerts-toptabs{gap:var(--space-4);margin:0 0 var(--space-16);padding:0}.ptabs.alerts-toptabs .ptab{font-size:var(--font-13);padding:var(--space-8) var(--space-12)}.ptabs.alerts-toptabs .ptab i{font-size:var(--font-16)}.topbar{background:var(--bg-surface);border-bottom:1px solid var(--border-default);padding-top:28px;position:sticky;top:var(--topbar-merged-h);transition:padding-top .2s ease;z-index:31}.topbar.compact{padding-top:10px}.topbar.compact .pane-title{font-size:19px;margin-bottom:8px}.ptabs{align-items:flex-end;display:flex;gap:4px;height:var(--tabs-h);padding:0 32px}.ptab{border-bottom:3px solid transparent;color:var(--text-secondary);cursor:pointer;font-size:14px;font-weight:500;padding:0 20px 12px;position:relative;transition:color .15s;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ptab:hover{color:var(--text-primary)}.ptab.active{background:linear-gradient(180deg,transparent 30%,rgba(var(--brand-rgb),.06) 100%);border-bottom-color:var(--color-primary);border-radius:6px 6px 0 0;color:var(--color-primary);font-weight:700}.strip-icon--hub{display:none}.strip-divider{background:var(--border-default);height:1px;margin:var(--space-8) auto var(--space-4);width:60%}.topbar>*{margin-left:auto;margin-right:auto;max-width:var(--content-max-w);width:100%}body.lcollapsed .hint{left:calc(var(--sidebar-collapsed-w) + 16px)}body.ropen .hint{right:calc(var(--rsidebar-w) + 16px)}.mobile-hamburger{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:999px;box-shadow:0 2px 8px rgba(0,0,0,.08);cursor:pointer;display:none;height:40px;justify-content:center;left:10px;position:fixed;top:10px;width:40px;z-index:260}.mobile-hamburger i{color:var(--text-primary);font-size:18px}.mobile-backdrop{background:rgba(0,0,0,.4);display:none;inset:0;position:fixed;z-index:240}body.lopen .mobile-backdrop{display:block}@media (max-width:767px){.mobile-hamburger{display:inline-flex}body.lopen .mobile-hamburger{display:none}.sidebar{box-shadow:4px 0 16px rgba(0,0,0,.15);transform:translateX(-100%);transition:transform .24s cubic-bezier(.2,0,0,1);width:280px;z-index:250}body.lopen .sidebar{transform:translateX(0)}body.lcollapsed .sidebar{width:280px}#rDrawer,.rsidebar{display:none!important}.ptabs{flex-wrap:nowrap;overflow-x:auto;padding:0 14px;scrollbar-width:thin}.ptabs::-webkit-scrollbar{height:4px}.ptab{flex-shrink:0;white-space:nowrap}}body.rm-shell{background:var(--bg-app);color:var(--text-primary);font-family:var(--font-sans);margin:0;padding-left:var(--sidebar-w);padding-right:var(--rsidebar-collapsed-w);padding-top:var(--topbar-merged-h);transition:padding .24s cubic-bezier(.2,0,0,1)}body.rm-shell.lcollapsed{padding-left:var(--sidebar-collapsed-w)}body.rm-switching.rm-shell,body.theme-switching.rm-shell{transition:none!important}@media (max-width:767px){body.rm-shell,body.rm-shell.lcollapsed{padding-left:0;padding-right:0}}
1
+ body.lcollapsed{padding-left:var(--sidebar-collapsed-w)}.nav-item .icn i,.rpanel-item .icn i{font-size:16px}.strip-icon i,.topbar-toggle i{font-size:18px}.chev i,.chev-r i{font-size:11px}.topbar-toggle{align-items:center;border-radius:6px;color:var(--text-secondary);cursor:pointer;display:flex;font-size:16px;height:32px;justify-content:center;width:32px}.topbar-toggle:hover{background:var(--bg-hover);border-color:var(--color-violet-pale);color:var(--color-secondary)}.logo-mark{align-items:center;background:linear-gradient(135deg,var(--color-primary),var(--color-secondary));border-radius:6px;box-shadow:0 2px 6px rgba(107,63,255,.25);color:var(--color-text-inverse);display:flex;flex-shrink:0;font-size:14px;height:28px;justify-content:center;width:28px}.logo-mark,.logo-text{font-family:var(--font-serif);font-weight:700}.logo-text{font-size:16px;line-height:1}.logo-sub{color:var(--text-muted);font-size:10px;letter-spacing:.05em;margin-top:2px;text-transform:uppercase}.sidebar{background:var(--bg-surface);border-right:1px solid var(--border-default);bottom:0;display:flex;flex-direction:column;left:0;overflow-x:hidden;overflow-y:auto;position:fixed;top:0;transition:width .24s cubic-bezier(.2,0,0,1);width:var(--sidebar-w);z-index:70}.sidebar-top{border-bottom:1px solid var(--border-default);flex-shrink:0;height:var(--topbar-h);justify-content:space-between;padding:0 14px}.sidebar-top,.sidebar-top .logo-block{align-items:center;display:flex;gap:8px}.sidebar-top .logo-block{min-width:0}body.lcollapsed .sidebar-top{justify-content:center;padding:0}body.lcollapsed .sidebar-top .logo-block{display:none}body.lcollapsed .sidebar-top .logo-mark{display:flex}.sidebar-search{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:999px;display:flex;gap:10px;margin:10px 12px 4px;padding:7px 14px;transition:border-color .15s,background .15s}.sidebar-search:focus-within,.sidebar-search:hover{background:var(--bg-surface);border-color:var(--color-violet-pale)}.sidebar-search i{color:var(--text-muted);flex-shrink:0;font-size:14px}.sidebar-search input{background:transparent;border:none;color:var(--text-primary);flex:1;font-family:inherit;font-size:13px;min-width:0;outline:none}.sidebar-search input::-moz-placeholder{color:var(--text-muted)}.sidebar-search input::placeholder{color:var(--text-muted)}.sidebar-search kbd{background:var(--bg-surface);border:1px solid var(--border-default);border-radius:4px;color:var(--text-secondary);flex-shrink:0;font-family:inherit;font-size:10px;font-weight:600;padding:1px 5px}body.lcollapsed .sidebar-search{display:none}body.lcollapsed .sidebar{width:var(--sidebar-collapsed-w)}.nav-group{padding:4px 0}.nav-section-header{padding:14px 14px 6px;-webkit-user-select:none;-moz-user-select:none;user-select:none}.nav-section-header .label,.nav-section-header span{color:var(--text-muted);font-size:11px;font-weight:700;letter-spacing:.08em;text-transform:uppercase}.nav-section-header .chev{color:var(--text-muted);font-size:10px;transition:transform .2s}.nav-section.collapsed .chev{transform:rotate(-90deg)}.nav-section.collapsed .nav-items{display:none}.nav-item{align-items:center;color:var(--text-secondary);cursor:pointer;display:flex;font-size:13px;font-weight:500;gap:10px;padding:7px 14px 7px 22px;transition:background .15s,color .15s;-webkit-user-select:none;-moz-user-select:none;user-select:none;white-space:nowrap}.nav-item .icn{color:var(--text-muted);flex-shrink:0;text-align:center;width:16px}.nav-item .lbl{flex:1;overflow:hidden;text-overflow:ellipsis}.nav-item .chev-r{color:var(--text-muted);font-size:10px;transition:transform .2s}.nav-item.has-children.open .chev-r{transform:rotate(90deg)}.nav-item:hover{background:var(--bg-surface-3);color:var(--text-primary)}.nav-item:hover .icn{color:var(--text-secondary)}.nav-item.active{background:linear-gradient(90deg,var(--color-violet-pale) 0,var(--bg-hover) 100%);color:var(--color-primary);font-weight:700;position:relative}.nav-item.active:before{background:var(--color-secondary);border-radius:0 4px 4px 0;bottom:5px;content:"";left:0;position:absolute;top:5px;width:4px}.nav-item.active .icn{color:var(--color-secondary)}.nav-subitems{background:var(--bg-surface-2);border-bottom:1px solid var(--border-soft);border-top:1px solid var(--border-soft);display:none;padding:2px 0 4px}.nav-item.has-children.open+.nav-subitems{display:block}.nav-subitem{align-items:center;color:var(--text-secondary);cursor:pointer;display:flex;font-size:12px;gap:8px;padding:6px 14px 6px 44px}.nav-subitem:hover{background:var(--bg-surface-3);color:var(--text-primary)}.nav-subitem.active{background:linear-gradient(90deg,var(--color-violet-pale) 0,var(--bg-hover) 100%);color:var(--color-primary);font-weight:700;position:relative}.nav-subitem.active:before{background:var(--color-secondary);border-radius:0 4px 4px 0;bottom:4px;content:"";left:0;position:absolute;top:4px;width:4px}.sidebar-footer{border-top:1px solid var(--border-default);display:flex;flex-direction:column;gap:4px;margin-top:auto;padding:10px 8px}.sb-user{align-items:center;border-radius:8px;cursor:pointer;display:flex;gap:12px;padding:10px 12px;transition:background .15s;-webkit-user-select:none;-moz-user-select:none;user-select:none}.sb-user:hover{background:var(--bg-surface-3)}.sb-user-avatar{align-items:center;background:linear-gradient(135deg,var(--color-secondary),var(--color-accent-teal));border-radius:50%;box-shadow:0 2px 6px rgba(107,63,255,.22);color:var(--color-text-inverse);display:flex;flex-shrink:0;font-family:var(--font-serif);font-size:13px;font-weight:700;height:36px;justify-content:center;width:36px}.sb-user-info{flex:1;min-width:0}.sb-user-name{color:var(--text-primary);font-size:13px;font-weight:600;line-height:1.25}.sb-user-name,.sb-user-org{overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.sb-user-org{color:var(--text-muted);font-size:11px;line-height:1.2;margin-top:2px}.sb-user-chev{color:var(--text-muted);flex-shrink:0;font-size:13px}.sb-actions{display:flex;gap:4px}.sb-actions .sb-lang,.sb-actions a{align-items:center;border-radius:6px;color:var(--text-secondary);cursor:pointer;display:inline-flex;flex:1;font-family:inherit;font-size:12px;font-weight:600;gap:5px;justify-content:center;padding:8px 10px;text-decoration:none;transition:background .15s,color .15s}.sb-actions .sb-lang:hover,.sb-actions a:hover{background:var(--bg-surface-3);color:var(--text-primary)}.sb-actions a.primary{color:var(--color-primary)}.sb-actions a.primary:hover{background:var(--bg-hover);color:var(--color-secondary)}.sb-actions i{font-size:13px}body.lcollapsed .sidebar .chev-r,body.lcollapsed .sidebar .lbl,body.lcollapsed .sidebar .nav-section-header,body.lcollapsed .sidebar-footer{display:none}body.lcollapsed .sidebar .nav-item.has-children.open+.nav-subitems,body.lcollapsed .sidebar .nav-subitems{display:none!important}body.lcollapsed .sidebar .nav-item.has-children.open .chev-r{transform:none}body.lcollapsed .sidebar .nav-group{border-top:1px solid var(--border-soft);padding:4px 0}body.lcollapsed .sidebar .nav-group:first-of-type{border-top:none}.nav-subitems.flyout,body.lcollapsed .sidebar .nav-item.has-children.open+.nav-subitems.flyout,body.lcollapsed .sidebar .nav-subitems.flyout{animation:flyout-in .12s cubic-bezier(.2,0,0,1);background:var(--bg-surface);border:1px solid var(--border-default);border-left:none;border-radius:0 8px 8px 0;box-shadow:var(--shadow-lg);display:block!important;left:var(--sidebar-collapsed-w);min-width:220px;padding:8px 0;position:fixed;z-index:100}.nav-subitems.flyout:before{border-bottom:1px solid var(--border-soft);color:var(--text-muted);content:attr(data-parent-label);display:block;font-size:11px;font-weight:700;letter-spacing:.08em;margin-bottom:4px;padding:6px 16px 8px;text-transform:uppercase}.nav-subitems.flyout .nav-subitem{font-size:13px;padding:8px 16px}body.lcollapsed .sidebar .nav-item{position:relative}body.lcollapsed .sidebar .nav-item[data-tip]:hover:after{background:var(--text-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.2);color:var(--color-text-inverse);content:attr(data-tip);font-size:12px;font-weight:500;left:var(--sidebar-collapsed-w);margin-left:6px;padding:5px 10px;pointer-events:none;position:fixed;top:var(--tip-top,0);white-space:nowrap;z-index:110}.rsidebar .strip-icon{position:relative}.rsidebar .strip-icon[data-tip]:hover:before{background:var(--text-primary);border-radius:6px;box-shadow:0 4px 12px rgba(0,0,0,.2);color:var(--color-text-inverse);content:attr(data-tip);font-size:12px;font-weight:500;margin-right:6px;padding:5px 10px;pointer-events:none;position:fixed;right:var(--rsidebar-collapsed-w);top:var(--tip-top,0);white-space:nowrap;z-index:110}body.ropen .rsidebar .strip-icon[data-tip]:hover:before{display:none}.rsidebar .strip-icon.has-flyout.show-flyout .rflyout{display:block}body.ropen .rsidebar .rflyout{display:none!important}body.lcollapsed .nav-item{justify-content:center;padding:10px 0}body.lcollapsed .nav-section-header{justify-content:center;padding:8px 0}.rsidebar{background:var(--bg-surface);border-left:1px solid var(--border-default);bottom:0;display:flex;flex-direction:column;overflow:hidden;position:fixed;right:0;top:0;width:var(--rsidebar-collapsed-w);z-index:70}.rstrip-top{align-items:center;border-bottom:1px solid var(--border-default);display:flex;flex-shrink:0;height:var(--topbar-h);justify-content:center}.rstrip-collapsed{align-items:stretch;gap:4px;padding:8px}.rstrip-collapsed,.strip-icon{display:flex;flex-direction:column}.strip-icon{align-items:center;border-radius:8px;color:var(--text-secondary);cursor:pointer;gap:5px;justify-content:center;padding:10px 4px;position:relative;transition:background .15s,color .15s}.strip-icon i{font-size:19px;transition:color .15s}.strip-icon .strip-label{color:inherit;font-size:10px;font-weight:600;letter-spacing:.01em;line-height:1;white-space:nowrap}.strip-icon:hover{background:var(--bg-surface-3);color:var(--text-primary)}.strip-icon.active,.strip-icon:hover i{color:var(--color-secondary)}.strip-icon.active{background:var(--bg-hover)}.strip-icon.active i{color:var(--color-secondary)}.strip-icon .dot{background:var(--color-notification);border-radius:50%;box-shadow:0 0 0 2px var(--color-text-inverse);height:8px;position:absolute;right:14px;top:6px;width:8px}.strip-icon.is-live .dot{background:var(--color-success);box-shadow:0 0 0 2px var(--bg-surface)}.strip-icon.is-live .dot:after{animation:stripLivePulse 1.8s ease-out infinite;background:var(--color-success);border-radius:50%;content:"";inset:-2px;position:absolute}.strip-icon.is-live .strip-label{background:var(--color-success);border-radius:var(--radius-pill);color:var(--color-text-inverse);display:inline-block;font-weight:var(--weight-bold);letter-spacing:.04em;line-height:1.2;margin-top:2px;padding:2px var(--space-6);text-transform:uppercase}@media (prefers-reduced-motion:reduce){.strip-icon.is-live .dot:after{animation:none}}.strip-badge{align-items:center;background:var(--color-primary);border-radius:999px;box-shadow:0 0 0 2px var(--color-text-inverse);color:var(--color-text-inverse);display:flex;font-size:9px;font-variant-numeric:tabular-nums;font-weight:700;height:16px;justify-content:center;line-height:1;min-width:18px;padding:0 5px;position:absolute;right:8px;top:4px}.strip-divider{background:var(--bg-surface-3);margin:6px auto;width:70%}body.ropen .rpanel-open{display:block}.ptabs.export-toptabs{align-items:stretch;border-bottom:1px solid var(--border-default);gap:0;height:auto;margin:0 0 var(--space-20);padding:0}.ptabs.export-toptabs .ptab{align-items:center;display:inline-flex;font-size:var(--font-14);font-weight:var(--weight-semibold);gap:var(--space-6);padding:var(--space-12) var(--space-16)}.ptabs.export-toptabs .ptab i{font-size:var(--font-16)}.ptabs.export-toptabs .lib-tab-count{background:var(--bg-surface-3);border-radius:var(--radius-pill);color:var(--text-muted);font-size:var(--font-11);font-variant-numeric:tabular-nums;font-weight:var(--weight-bold);min-width:18px;padding:0 var(--space-6);text-align:center}.ptabs.export-toptabs .ptab.active .lib-tab-count{background:var(--bg-hover);color:var(--color-secondary)}.ptabs.views-toptabs{align-items:stretch;border-bottom:1px solid var(--border-default);gap:0;height:auto;margin:0 0 var(--space-16);padding:0}.ptabs.views-toptabs .ptab{align-items:center;display:inline-flex;font-size:var(--font-14);font-weight:var(--weight-semibold);gap:var(--space-6);padding:var(--space-12) var(--space-16)}.ptabs.views-toptabs .ptab i{font-size:var(--font-16)}.ptabs.views-toptabs .lib-tab-count{background:var(--bg-surface-3);border-radius:var(--radius-pill);color:var(--text-muted);font-size:var(--font-11);font-variant-numeric:tabular-nums;font-weight:var(--weight-bold);min-width:18px;padding:0 var(--space-6);text-align:center}.ptabs.views-toptabs .ptab.active .lib-tab-count{background:var(--bg-hover);color:var(--color-secondary)}.ptabs.alerts-toptabs{gap:var(--space-4);margin:0 0 var(--space-16);padding:0}.ptabs.alerts-toptabs .ptab{font-size:var(--font-13);padding:var(--space-8) var(--space-12)}.ptabs.alerts-toptabs .ptab i{font-size:var(--font-16)}.topbar{background:var(--bg-surface);border-bottom:1px solid var(--border-default);padding-top:28px;position:sticky;top:var(--topbar-merged-h);transition:padding-top .2s ease;z-index:31}.topbar.compact{padding-top:10px}.topbar.compact .pane-title{font-size:19px;margin-bottom:8px}.ptabs{align-items:flex-end;display:flex;gap:4px;height:var(--tabs-h);padding:0 32px}.ptab{border-bottom:3px solid transparent;color:var(--text-secondary);cursor:pointer;font-size:14px;font-weight:500;padding:0 20px 12px;position:relative;transition:color .15s;-webkit-user-select:none;-moz-user-select:none;user-select:none}.ptab:hover{color:var(--text-primary)}.ptab.active{background:linear-gradient(180deg,transparent 30%,rgba(var(--brand-rgb),.06) 100%);border-bottom-color:var(--color-primary);border-radius:6px 6px 0 0;color:var(--color-primary);font-weight:700}.strip-icon--hub{display:none}.strip-divider{background:var(--border-default);height:1px;margin:var(--space-8) auto var(--space-4);width:60%}.topbar>*{margin-left:auto;margin-right:auto;max-width:var(--content-max-w);width:100%}body.lcollapsed .hint{left:calc(var(--sidebar-collapsed-w) + 16px)}body.ropen .hint{right:calc(var(--rsidebar-w) + 16px)}.mobile-hamburger{align-items:center;background:var(--bg-surface);border:1px solid var(--border-default);border-radius:999px;box-shadow:0 2px 8px rgba(0,0,0,.08);cursor:pointer;display:none;height:40px;justify-content:center;left:10px;position:fixed;top:10px;width:40px;z-index:260}.mobile-hamburger i{color:var(--text-primary);font-size:18px}.mobile-backdrop{background:rgba(0,0,0,.4);display:none;inset:0;position:fixed;z-index:240}body.lopen .mobile-backdrop{display:block}@media (max-width:767px){.mobile-hamburger{display:inline-flex}body.lopen .mobile-hamburger{display:none}.sidebar{box-shadow:4px 0 16px rgba(0,0,0,.15);transform:translateX(-100%);transition:transform .24s cubic-bezier(.2,0,0,1);width:280px;z-index:250}body.lopen .sidebar{transform:translateX(0)}body.lcollapsed .sidebar{width:280px}#rDrawer,.rsidebar{display:none!important}.ptabs{flex-wrap:nowrap;overflow-x:auto;padding:0 14px;scrollbar-width:thin}.ptabs::-webkit-scrollbar{height:4px}.ptab{flex-shrink:0;white-space:nowrap}}body.rm-shell{background:var(--bg-app);color:var(--text-primary);font-family:var(--font-sans);margin:0;padding-left:var(--sidebar-w);padding-right:var(--rsidebar-collapsed-w);padding-top:var(--topbar-merged-h);transition:padding .24s cubic-bezier(.2,0,0,1)}body.rm-shell.lcollapsed{padding-left:var(--sidebar-collapsed-w)}body.rm-switching.rm-shell,body.theme-switching.rm-shell{transition:none!important}@media (max-width:767px){body.rm-shell,body.rm-shell.lcollapsed{padding-left:0;padding-right:0}}.nav-item,.nav-section-header,.ptab,.sb-actions a,.strip-icon,.topbar-toggle{-webkit-appearance:none;-moz-appearance:none;appearance:none;background:none;border:0;box-shadow:none;color:inherit;font:inherit;margin:0;text-align:inherit;text-decoration:none}.topbar-toggle{background:var(--bg-surface);border:1px solid var(--border-default)}.nav-section-header{align-items:center;cursor:pointer;display:flex;justify-content:space-between;width:100%}.strip-label{display:block;max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}
@@ -0,0 +1 @@
1
+ :root{--rm-shell-bg:#f9f9fa;--rm-shell-surface:#fff;--rm-shell-border:#dbdef0;--rm-shell-subtle:#f5f5f9;--rm-shell-text:#1e293b;--rm-shell-text-dark:#475569;--rm-shell-text-muted:#878ca6;--rm-shell-accent:#2017ad;--rm-shell-inset:8px;--rm-shell-radius:12px;--rm-bar-h:56px;--rm-nav-w:240px;--rm-nav-collapsed-w:64px;--rm-rail-w:56px;--rm-dots-image:url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAACgAAAAoCAYAAACM/rhtAAAAcUlEQVR42u3TwQmAMAxAUdfQfUoSZ3OBTNMFHEqLVBEtCB6M8B8EevwktOsAAACAl0SkNzNXtaw6zut7SikNYeJq2Hksh4gs27rG7ZH+eWA7bttigMC78x4TIdBbceX8fJKnkSL1s5RY8zBxAAAA+LUF0ula10BxVDoAAAAASUVORK5CYII=");--rm-dots-size:12px;--rm-dots-opacity:0.1}body.night{--rm-shell-bg:var(--bg-app);--rm-shell-surface:var(--bg-surface,#1a1a24);--rm-shell-border:var(--border-default);--rm-shell-subtle:var(--bg-subtle,#22222e);--rm-shell-text:var(--text-primary);--rm-shell-text-dark:var(--text-secondary);--rm-shell-text-muted:var(--text-muted);--rm-shell-accent:var(--color-primary);--rm-dots-opacity:0.06}.rm-shell{background:var(--rm-shell-bg);color:var(--rm-shell-text);font-family:var(--font-sans,"Figtree",sans-serif);height:100vh;overflow:hidden;position:relative;width:100%}.rm-shell__dots{background-image:var(--rm-dots-image);background-repeat:repeat;background-size:var(--rm-dots-size) var(--rm-dots-size);inset:0;opacity:var(--rm-dots-opacity);pointer-events:none;position:absolute}.rm-shell__frame{border:1px solid var(--rm-shell-border);border-radius:var(--rm-shell-radius);display:flex;inset:var(--rm-shell-inset);overflow:hidden;position:absolute}.rm-shell__body{display:flex;flex:1;flex-direction:column;min-width:0}.rm-shell__main{flex:1;min-width:0;overflow-y:auto}.rm-sb{background:var(--rm-shell-surface);display:flex;flex-direction:column;flex-shrink:0;height:100%}.rm-sb--left{border-right:1px solid var(--rm-shell-border);transition:width .2s;width:var(--rm-nav-w)}.rm-sb--left.rm-sb--collapsed{width:var(--rm-nav-collapsed-w)}.rm-sb--right{border-left:1px solid var(--rm-shell-border);width:var(--rm-rail-w)}.rm-sb__header{align-items:center;border-bottom:1px solid var(--rm-shell-border);display:flex;flex-shrink:0;gap:8px;height:var(--rm-bar-h);padding:0 16px}.rm-sb--collapsed .rm-sb__header{justify-content:center;padding:0}.rm-sb__logo{color:var(--rm-shell-text);flex:1;font-size:20px;font-weight:700;line-height:1.4;min-width:0;overflow:hidden;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.rm-sb__toggle{-moz-appearance:none;appearance:none;-webkit-appearance:none;background:none;border:none;border-radius:0;box-shadow:none;color:var(--rm-shell-text-muted);cursor:pointer;display:block;flex-shrink:0;height:20px;margin:0;padding:0;transition:color .15s;width:20px}.rm-sb__toggle:hover{color:var(--rm-shell-text)}.rm-sb__toggle svg{display:block;height:100%;width:100%}.rm-sb__nav{display:flex;flex:1;flex-direction:column;gap:16px;overflow-y:auto;padding:16px}.rm-sb--collapsed .rm-sb__nav{padding-left:8px;padding-right:8px}.rm-sb__group{display:flex;flex-direction:column;gap:4px}.rm-sb__label{align-items:center;-moz-appearance:none;appearance:none;-webkit-appearance:none;background:none;border:none;border-radius:0;box-shadow:none;color:var(--rm-shell-text-muted);display:flex;font-family:inherit;font-size:10px;font-weight:500;gap:4px;letter-spacing:.025em;line-height:1.6;margin:0;padding:0 2px;text-align:left;text-transform:uppercase;width:100%}button.rm-sb__label{cursor:pointer}button.rm-sb__label:hover{color:var(--rm-shell-text)}.rm-sb__label-text{flex:1;min-width:0}.rm-sb__chev{display:block;flex-shrink:0;height:12px;transition:transform .2s;width:12px}.rm-sb__label[aria-expanded=true] .rm-sb__chev{transform:rotate(90deg)}.rm-sb__rule{background:var(--rm-shell-border);height:1px;margin:4px}.rm-mi{align-items:center;-moz-appearance:none;appearance:none;-webkit-appearance:none;background:none;border:none;border-radius:4px;box-shadow:none;color:var(--rm-shell-text);cursor:pointer;display:flex;font-family:inherit;gap:8px;height:26px;margin:0;padding:2px;text-align:left;text-decoration:none;transition:background-color .15s;width:100%}.rm-mi:hover{background:color-mix(in srgb,var(--rm-shell-subtle) 50%,transparent)}.rm-mi.rm-mi--active{background:var(--rm-shell-subtle)}.rm-mi.rm-mi--current{background:color-mix(in srgb,var(--rm-shell-accent) 5%,transparent)}.rm-mi.rm-mi--current .rm-mi__icon{background:var(--rm-shell-accent);color:#fff}.rm-mi.rm-mi--current .rm-mi__icon svg{stroke:#fff}.rm-mi__icon{align-items:center;background:var(--rm-shell-subtle);border-radius:4px;color:var(--rm-shell-text-dark);display:flex;flex-shrink:0;height:22px;justify-content:center;line-height:1;width:22px}.rm-mi__icon svg{display:block;height:14px;width:14px}.rm-mi__icon i{font-size:14px;line-height:1}.rm-mi__label{color:var(--rm-shell-text);flex:1;font-size:14px;line-height:1.625;min-width:0;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rm-mi__badge{background:var(--rm-shell-subtle);border-radius:4px;color:var(--rm-shell-text-muted);flex-shrink:0;font-size:9px;font-weight:700;letter-spacing:.025em;padding:2px 4px;text-transform:uppercase}.rm-sb--collapsed .rm-mi{justify-content:center}.rm-sb--collapsed .rm-mi>:not(.rm-mi__icon),.rm-sb--collapsed .rm-sb__sub{display:none}.rm-sb__sub{display:flex;flex-direction:column;gap:2px;padding:2px 0 2px 28px}.rm-sb__sub-item{border-radius:4px;color:var(--rm-shell-text);display:block;font-size:14px;line-height:1.625;overflow:hidden;padding:2px 4px;text-decoration:none;text-overflow:ellipsis;white-space:nowrap}.rm-sb__sub-item:hover{background:color-mix(in srgb,var(--rm-shell-subtle) 50%,transparent)}.rm-rail__item{align-items:center;-moz-appearance:none;appearance:none;-webkit-appearance:none;background:none;border:none;border-radius:0;box-shadow:none;cursor:pointer;display:flex;flex-direction:column;font-family:inherit;gap:4px;margin:0;padding:12px 0 8px;text-decoration:none;width:100%}.rm-rail__avatar{align-items:center;border:2px solid var(--rm-shell-surface);border-radius:9999px;color:#fff;display:flex;font-size:14px;height:32px;justify-content:center;transition:opacity .15s;width:32px}.rm-rail__item:hover .rm-rail__avatar{opacity:.8}.rm-rail__tile{align-items:center;background:var(--rm-shell-subtle);border-radius:8px;color:var(--rm-shell-text-dark);display:flex;font-size:16px;height:32px;justify-content:center;transition:background-color .15s,color .15s;width:32px}.rm-rail__item:hover .rm-rail__tile{background:var(--rm-shell-border)}.rm-rail__item.rm-rail__item--active .rm-rail__tile{background:var(--rm-shell-accent);color:#fff}.rm-rail__caption{color:var(--rm-shell-text-muted);font-size:10px;line-height:1;max-width:100%;overflow:hidden;padding:0 2px;text-overflow:ellipsis;transition:color .15s;white-space:nowrap}.rm-rail__item--active .rm-rail__caption,.rm-rail__item:hover .rm-rail__caption{color:var(--rm-shell-text)}.rm-rail__bottom{display:flex;justify-content:center;margin-top:auto;padding-bottom:16px}.rm-lang{background:var(--rm-shell-subtle);border:1px solid var(--rm-shell-accent);border-radius:9999px;display:grid;gap:2px;grid-template-rows:1fr 1fr;padding:3px;position:relative}.rm-lang__thumb{background:var(--rm-shell-surface);border-radius:9999px;box-shadow:0 1px 4px rgba(30,41,59,.16);height:32px;left:3px;position:absolute;top:3px;transition:transform .26s cubic-bezier(.34,1.56,.64,1);width:32px}.rm-lang--second .rm-lang__thumb{transform:translateY(34px)}.rm-lang__option{align-items:center;-moz-appearance:none;appearance:none;-webkit-appearance:none;background:none;border:none;border-radius:9999px;box-shadow:none;cursor:pointer;display:flex;filter:grayscale(1);font-size:17px;height:32px;justify-content:center;line-height:1;margin:0;opacity:.5;padding:0;position:relative;transition:filter .18s ease,opacity .18s ease,transform .18s ease;width:32px}.rm-lang__option:hover{filter:grayscale(0);opacity:.85}.rm-lang__option.rm-lang__option--active{filter:grayscale(0);opacity:1}.rm-lang__option:focus-visible{outline:2px solid var(--rm-shell-accent);outline-offset:2px}@media (prefers-reduced-motion:reduce){.rm-lang__option,.rm-lang__thumb{transition:none}}.rm-hd{background:var(--rm-shell-surface);border-bottom:1px solid var(--rm-shell-border);display:flex;flex-direction:column;flex-shrink:0}.rm-hd__row{gap:16px;height:var(--rm-bar-h);padding:0 16px}.rm-hd__crumbs,.rm-hd__row{align-items:center;display:flex}.rm-hd__crumbs{flex:1;font-size:14px;gap:4px;min-width:0}.rm-hd__crumb{color:var(--rm-shell-text-muted);text-decoration:none;transition:color .15s;white-space:nowrap}a.rm-hd__crumb:hover{color:var(--rm-shell-text)}.rm-hd__sep{color:var(--rm-shell-text-muted)}.rm-hd__crumb--last{color:var(--rm-shell-text);font-weight:500;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.rm-hd__search{align-items:center;background:var(--rm-shell-surface);border:1px solid var(--rm-shell-border);border-radius:9999px;display:flex;flex-shrink:0;gap:4px;padding:4px 12px;width:300px}.rm-hd__search input{background:transparent;border:none;color:var(--rm-shell-text);flex:1;font-family:inherit;font-size:14px;min-width:0;outline:none}.rm-hd__search input::-moz-placeholder{color:var(--rm-shell-text-muted)}.rm-hd__search input::placeholder{color:var(--rm-shell-text-muted)}.rm-hd__search i{color:var(--rm-shell-text-muted);font-size:16px}.rm-hd__tabs{display:flex;gap:16px;padding:0 16px}.rm-hd__tab{align-items:flex-start;-moz-appearance:none;appearance:none;-webkit-appearance:none;background:none;border:none;border-bottom:2px solid transparent;border-radius:0;box-shadow:none;color:var(--rm-shell-text-dark);cursor:pointer;display:flex;flex-direction:column;font-family:inherit;font-size:14px;font-weight:700;line-height:1.6;margin:0;padding:4px 4px 8px;white-space:nowrap}.rm-hd__tab--active{border-bottom-color:var(--rm-shell-accent);color:var(--rm-shell-text)}@media (max-width:767px){.rm-sb--left{inset:0 auto 0 0;position:absolute;transform:translateX(-100%);transition:transform .2s;z-index:40}.rm-sb--left.rm-sb--open{transform:translateX(0)}.rm-sb--right{display:none}.rm-hd__search{flex:1;width:auto}}
@@ -0,0 +1,81 @@
1
+ <!--
2
+ RmAppHeader - le bandeau du portail OIP 7.
3
+
4
+ Provenance : oip7/app/components/AppHeader.vue. Rangee de 56px : le fil
5
+ d'Ariane a gauche, la recherche a droite ; une deuxieme rangee d'onglets
6
+ apparait quand la page en declare.
7
+
8
+ Le fil est fourni entier par l'appelant, racine comprise. Dans oip7 la racine
9
+ est ecrite en dur dans le composant, parce qu'il n'y a qu'un portail ; ici la
10
+ racine change d'une app a l'autre (« OIP Healthcare » puis le nom de l'app),
11
+ et c'est le layout qui la connait. Le dernier maillon n'est jamais un lien :
12
+ il designe la page courante.
13
+ -->
14
+ <script setup lang="ts">
15
+ export interface RmCrumb {
16
+ label: string
17
+ /** Route interne. */
18
+ to?: string
19
+ /** Lien externe : la plateforme vit sur un autre domaine. */
20
+ href?: string
21
+ }
22
+
23
+ export interface RmHeaderTab {
24
+ key: string
25
+ label: string
26
+ active?: boolean
27
+ }
28
+
29
+ withDefaults(defineProps<{
30
+ crumbs: RmCrumb[]
31
+ tabs?: RmHeaderTab[]
32
+ ariaLabel?: string
33
+ }>(), {
34
+ tabs: () => [],
35
+ ariaLabel: 'Fil d\'Ariane',
36
+ })
37
+
38
+ const emit = defineEmits<{ tab: [key: string] }>()
39
+ </script>
40
+
41
+ <template>
42
+ <header class="rm-hd">
43
+ <div class="rm-hd__row">
44
+ <nav class="rm-hd__crumbs" :aria-label="ariaLabel">
45
+ <template v-for="(crumb, i) in crumbs" :key="crumb.label">
46
+ <span v-if="i > 0" class="rm-hd__sep" aria-hidden="true">/</span>
47
+ <a
48
+ v-if="crumb.href && i < crumbs.length - 1"
49
+ class="rm-hd__crumb"
50
+ :href="crumb.href"
51
+ >{{ crumb.label }}</a>
52
+ <NuxtLink
53
+ v-else-if="crumb.to && i < crumbs.length - 1"
54
+ class="rm-hd__crumb"
55
+ :to="crumb.to"
56
+ >{{ crumb.label }}</NuxtLink>
57
+ <span
58
+ v-else
59
+ class="rm-hd__crumb rm-hd__crumb--last"
60
+ :aria-current="i === crumbs.length - 1 ? 'page' : undefined"
61
+ >{{ crumb.label }}</span>
62
+ </template>
63
+ </nav>
64
+
65
+ <slot name="search" />
66
+ <slot name="actions" />
67
+ </div>
68
+
69
+ <div v-if="tabs.length" class="rm-hd__tabs">
70
+ <button
71
+ v-for="tab in tabs"
72
+ :key="tab.key"
73
+ class="rm-hd__tab"
74
+ :class="{ 'rm-hd__tab--active': tab.active }"
75
+ type="button"
76
+ :aria-current="tab.active ? 'page' : undefined"
77
+ @click="emit('tab', tab.key)"
78
+ >{{ tab.label }}</button>
79
+ </div>
80
+ </header>
81
+ </template>
@@ -1,68 +1,55 @@
1
1
  <!--
2
- RmAppShell - le chrome d'application du design system : barre laterale fixe
3
- a gauche, strip d'actions fixe a droite, contenu decale entre les deux.
4
-
5
- Structure et classes reprises de `app-shell.html`. La regle n°0 du skill est
6
- de ne jamais reconstruire ce chrome de memoire : ce composant ne fait que
7
- poser le markup attendu et gerer l'etat de repli.
8
-
9
- Le decalage vit sur `body.rm-shell`, pose au montage et retire au demontage.
10
- Sans ce retrait, une app multi-layout garderait le decalage sur ses autres
11
- ecrans apres avoir quitte celui-ci.
2
+ RmAppShell - le cadre du portail OIP 7, porte a l'identique.
3
+
4
+ Provenance : oip7/app/layouts/default.vue. La structure est celle-la, dans
5
+ cet ordre : un plan pleine fenetre qui porte le fond pointille, puis un cadre
6
+ `inset-2` borde et arrondi qui contient trois colonnes (barre gauche, corps,
7
+ rail droit). Le cadre n'a pas de fond : le pointille se voit au travers du
8
+ contenu, c'est ce qui donne le fond du portail.
9
+
10
+ Rien ici ne touche a `body`. La version precedente de ce composant portait le
11
+ decalage du contenu sur `body.rm-shell`, parce que le chrome du design system
12
+ data est en position fixe. Ce cadre-la est un flex : les colonnes prennent
13
+ leur place elles-memes, et quitter l'ecran ne laisse rien derriere.
12
14
  -->
13
15
  <script setup lang="ts">
14
- import { onBeforeUnmount, onMounted, ref } from 'vue'
15
- import { rmWithoutTransitions } from '../utils/transitionGuard'
16
+ import { ref } from 'vue'
16
17
 
17
18
  const props = withDefaults(defineProps<{
18
19
  /** Barre laterale repliee au chargement. */
19
20
  navCollapsed?: boolean
20
21
  }>(), { navCollapsed: false })
21
22
 
23
+ /** Repli desktop : la barre passe de 240 a 64px, icones seules. */
22
24
  const collapsed = ref(props.navCollapsed)
23
- const stripOpen = ref(false)
25
+ /** Ouverture mobile : sous 768px la barre est un tiroir hors-champ. */
26
+ const navOpen = ref(false)
24
27
 
25
- function sync() {
26
- if (typeof document === 'undefined') return
27
- const { body } = document
28
- body.classList.add('rm-shell')
29
- body.classList.toggle('lcollapsed', collapsed.value)
30
- body.classList.toggle('ropen', stripOpen.value)
31
- }
28
+ const toggleNav = () => { collapsed.value = !collapsed.value }
29
+ const openNav = (open: boolean) => { navOpen.value = open }
30
+
31
+ defineExpose({ collapsed, navOpen, toggleNav, openNav })
32
+ </script>
32
33
 
33
- onMounted(sync)
34
+ <template>
35
+ <div class="rm-shell">
36
+ <!-- Le motif ne porte aucune information : hors du flux, hors des clics,
37
+ hors de l'arbre d'accessibilite. -->
38
+ <div class="rm-shell__dots" aria-hidden="true" />
34
39
 
35
- onBeforeUnmount(() => {
36
- if (typeof document === 'undefined') return
37
- document.body.classList.remove('rm-shell', 'lcollapsed', 'ropen')
38
- })
40
+ <div class="rm-shell__frame">
41
+ <slot name="nav" :collapsed="collapsed" :open="navOpen" :toggle="toggleNav" :set-open="openNav" />
39
42
 
40
- // Sans la garde, replier la barre laterale ne fait rien : sa largeur vient
41
- // d'un `var()` et la propriete est sous transition (cf. utils/transitionGuard).
42
- function toggleNav() {
43
- rmWithoutTransitions(() => {
44
- collapsed.value = !collapsed.value
45
- sync()
46
- })
47
- }
48
- function setStrip(open: boolean) {
49
- rmWithoutTransitions(() => {
50
- stripOpen.value = open
51
- sync()
52
- })
53
- }
43
+ <div class="rm-shell__body">
44
+ <slot name="header" :open-nav="openNav" />
45
+ <main class="rm-shell__main">
46
+ <slot />
47
+ </main>
48
+ </div>
54
49
 
55
- defineExpose({ collapsed, stripOpen, toggleNav, setStrip })
56
- </script>
50
+ <slot name="rail" />
51
+ </div>
57
52
 
58
- <template>
59
- <div class="rm-app-shell">
60
- <slot name="nav" :collapsed="collapsed" :toggle="toggleNav" />
61
- <slot name="strip" :open="stripOpen" :set-open="setStrip" />
62
- <slot />
53
+ <slot name="overlay" />
63
54
  </div>
64
55
  </template>
65
-
66
- <style scoped>
67
- .rm-app-shell{display:contents}
68
- </style>
@@ -0,0 +1,175 @@
1
+ <!--
2
+ RmSidebarLeft - la barre laterale gauche du portail OIP 7.
3
+
4
+ Provenance : oip7/app/components/SidebarLeft.vue et SidebarMenuItem.vue.
5
+ L'anatomie est reprise telle quelle : un en-tete de 56px avec l'identite et
6
+ le bouton de repli, puis des groupes separes de 16px, chacun coiffe d'un
7
+ libelle de section en 10px capitales, chaque entree etant une ligne de 26px
8
+ avec une boite d'icone de 22px.
9
+
10
+ Un ecart assume avec oip7 : le libelle de section est un bouton, et les
11
+ groupes forment un accordeon exclusif. La barre du portail liste dix entrees,
12
+ celle d'une app metier en liste vingt et plus ; toutes deployees, la
13
+ navigation devient un long defilement. Le style du libelle, lui, ne change
14
+ pas. Un groupe sans `label` reste toujours ouvert, comme le premier groupe
15
+ d'oip7.
16
+ -->
17
+ <script setup lang="ts">
18
+ import { computed, ref, watch } from 'vue'
19
+
20
+ export interface RmNavItem {
21
+ label: string
22
+ /** Icone Phosphor, nom en kebab-case sans le prefixe `ph-`. */
23
+ icon?: string
24
+ /** Route interne. */
25
+ to?: string
26
+ /** Lien externe : ouvert dans un nouvel onglet. */
27
+ href?: string
28
+ /** Etiquette courte a droite (« bientot », un compteur...). */
29
+ badge?: string
30
+ /** Force l'etat actif quand le chemin ne suffit pas a le deduire. */
31
+ active?: boolean
32
+ }
33
+
34
+ export interface RmNavSection {
35
+ key: string
36
+ /** Absent : groupe sans libelle, toujours ouvert. */
37
+ label?: string
38
+ items: RmNavItem[]
39
+ /** false : groupe toujours ouvert malgre son libelle. */
40
+ collapsible?: boolean
41
+ }
42
+
43
+ const props = withDefaults(defineProps<{
44
+ /** Identite affichee dans l'en-tete. Un emoji au debut est dans l'esprit du portail. */
45
+ title: string
46
+ /** Cible du titre. Absent : le titre n'est pas un lien. */
47
+ titleTo?: string
48
+ sections: RmNavSection[]
49
+ /** Chemin courant, pour marquer l'entree active. */
50
+ activePath?: string
51
+ collapsed?: boolean
52
+ /** Tiroir ouvert en mobile. */
53
+ open?: boolean
54
+ collapseLabel?: string
55
+ expandLabel?: string
56
+ }>(), {
57
+ titleTo: undefined,
58
+ activePath: undefined,
59
+ collapsed: false,
60
+ open: false,
61
+ collapseLabel: 'Replier la barre latérale',
62
+ expandLabel: 'Déplier la barre latérale',
63
+ })
64
+
65
+ const emit = defineEmits<{
66
+ toggle: []
67
+ navigate: [to: string]
68
+ }>()
69
+
70
+ const collapsibles = computed(() =>
71
+ props.sections.filter(s => s.label && s.collapsible !== false),
72
+ )
73
+
74
+ /** Section ouverte : celle qui contient le chemin courant, sinon la premiere. */
75
+ const sectionOf = (path?: string) =>
76
+ collapsibles.value.find(s => s.items.some(i => i.to === path))?.key
77
+ ?? collapsibles.value[0]?.key
78
+ ?? null
79
+
80
+ const openSection = ref<string | null>(sectionOf(props.activePath))
81
+ watch(() => props.activePath, (path) => {
82
+ const key = sectionOf(path)
83
+ if (key && key !== openSection.value) openSection.value = key
84
+ })
85
+
86
+ const isCollapsible = (s: RmNavSection) => !!s.label && s.collapsible !== false
87
+ const isOpen = (s: RmNavSection) => !isCollapsible(s) || openSection.value === s.key
88
+ const isActive = (item: RmNavItem) => item.active ?? (!!item.to && item.to === props.activePath)
89
+ </script>
90
+
91
+ <template>
92
+ <aside
93
+ class="rm-sb rm-sb--left"
94
+ :class="{ 'rm-sb--collapsed': collapsed, 'rm-sb--open': open }"
95
+ >
96
+ <div class="rm-sb__header">
97
+ <component
98
+ :is="titleTo ? 'NuxtLink' : 'span'"
99
+ v-if="!collapsed"
100
+ :to="titleTo"
101
+ class="rm-sb__logo"
102
+ >{{ title }}</component>
103
+
104
+ <!-- Le pictogramme est celui d'oip7, repris trait pour trait : un cadre
105
+ arrondi barre d'un trait vertical. -->
106
+ <button
107
+ class="rm-sb__toggle"
108
+ type="button"
109
+ :title="collapsed ? expandLabel : collapseLabel"
110
+ :aria-label="collapsed ? expandLabel : collapseLabel"
111
+ :aria-expanded="!collapsed"
112
+ @click="emit('toggle')"
113
+ >
114
+ <svg viewBox="0 0 20 20" fill="none" stroke="currentColor" stroke-width="1.5">
115
+ <rect x="3" y="3" width="14" height="14" rx="2" />
116
+ <line x1="8" y1="3" x2="8" y2="17" />
117
+ </svg>
118
+ </button>
119
+ </div>
120
+
121
+ <nav class="rm-sb__nav">
122
+ <div v-for="section in sections" :key="section.key" class="rm-sb__group">
123
+ <template v-if="section.label">
124
+ <!-- Replie, le libelle cede la place au filet d'oip7 : trois lettres
125
+ capitales dans un rail de 64px seraient illisibles. -->
126
+ <div v-if="collapsed" class="rm-sb__rule" aria-hidden="true" />
127
+ <button
128
+ v-else-if="isCollapsible(section)"
129
+ class="rm-sb__label"
130
+ type="button"
131
+ :aria-expanded="isOpen(section)"
132
+ @click="openSection = openSection === section.key ? null : section.key"
133
+ >
134
+ <span class="rm-sb__label-text">{{ section.label }}</span>
135
+ <svg class="rm-sb__chev" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5">
136
+ <path d="M4 2.5L7.5 6L4 9.5" />
137
+ </svg>
138
+ </button>
139
+ <span v-else class="rm-sb__label">
140
+ <span class="rm-sb__label-text">{{ section.label }}</span>
141
+ </span>
142
+ </template>
143
+
144
+ <template v-if="isOpen(section)">
145
+ <component
146
+ v-for="item in section.items"
147
+ :key="item.to ?? item.href ?? item.label"
148
+ :is="item.href ? 'a' : 'NuxtLink'"
149
+ :to="item.href ? undefined : item.to"
150
+ :href="item.href"
151
+ :target="item.href ? '_blank' : undefined"
152
+ :rel="item.href ? 'noopener noreferrer' : undefined"
153
+ class="rm-mi"
154
+ :class="{ 'rm-mi--active': isActive(item) }"
155
+ :title="item.label"
156
+ :aria-current="isActive(item) ? 'page' : undefined"
157
+ @click="item.to && !item.href ? emit('navigate', item.to) : undefined"
158
+ >
159
+ <span class="rm-mi__icon"><i v-if="item.icon" :class="`ph ph-${item.icon}`" /></span>
160
+ <span class="rm-mi__label">{{ item.label }}</span>
161
+ <span v-if="item.badge" class="rm-mi__badge">{{ item.badge }}</span>
162
+ <!-- Fleche de sortie : elle previent qu'on quitte l'app, comme dans oip7. -->
163
+ <svg v-else-if="item.href" class="rm-sb__chev" viewBox="0 0 12 12" fill="none" stroke="currentColor" stroke-width="1.5">
164
+ <path d="M9 3L3 9M9 3H5M9 3V7" />
165
+ </svg>
166
+ </component>
167
+ </template>
168
+ </div>
169
+
170
+ <slot name="nav-footer" />
171
+ </nav>
172
+
173
+ <slot name="footer" />
174
+ </aside>
175
+ </template>
@@ -0,0 +1,112 @@
1
+ <!--
2
+ RmSidebarRight - le rail droit du portail OIP 7.
3
+
4
+ Provenance : oip7/app/components/SidebarRight.vue. Rail de 56px : le bloc
5
+ utilisateur en haut, la bascule de langue collee en bas. La bascule est
6
+ reprise a l'identique, y compris la course du pouce (34px) et sa courbe
7
+ d'amortissement.
8
+
9
+ Les tuiles d'action sont un ajout : le rail du portail n'en a pas, mais une
10
+ app metier a besoin d'appeler ses panneaux (sources, export, acces) et ce
11
+ rail est le seul endroit du cadre qui n'appartient pas au contenu. Elles
12
+ reprennent l'anatomie du bloc utilisateur - pastille de 32px, libelle de
13
+ 10px en dessous - pour ne pas introduire une deuxieme forme.
14
+ -->
15
+ <script setup lang="ts">
16
+ import { computed } from 'vue'
17
+
18
+ export interface RmRailTile {
19
+ key: string
20
+ label: string
21
+ /** Icone Phosphor, nom en kebab-case sans le prefixe `ph-`. */
22
+ icon: string
23
+ }
24
+
25
+ export interface RmRailLocale {
26
+ code: string
27
+ /** Drapeau : dans un rail de 56px il n'y a pas la place d'un nom. */
28
+ flag: string
29
+ label: string
30
+ }
31
+
32
+ const props = withDefaults(defineProps<{
33
+ user?: { initials: string, name?: string, color?: string }
34
+ profileTo?: string
35
+ profileLabel?: string
36
+ tiles?: RmRailTile[]
37
+ /** Cle de la tuile active. */
38
+ active?: string | null
39
+ locales?: RmRailLocale[]
40
+ locale?: string
41
+ }>(), {
42
+ user: undefined,
43
+ profileTo: '/profile',
44
+ profileLabel: 'Profil',
45
+ tiles: () => [],
46
+ active: null,
47
+ locales: () => [],
48
+ locale: undefined,
49
+ })
50
+
51
+ const emit = defineEmits<{
52
+ select: [key: string]
53
+ 'update:locale': [code: string]
54
+ }>()
55
+
56
+ /** Couleur par defaut de la pastille : l'accent du portail. */
57
+ const avatarColor = computed(() => props.user?.color ?? 'var(--rm-shell-accent)')
58
+
59
+ /** Le pouce descend quand la langue active n'est pas la premiere. */
60
+ const second = computed(() =>
61
+ props.locales.length > 1 && props.locale === props.locales[1]?.code,
62
+ )
63
+ </script>
64
+
65
+ <template>
66
+ <aside class="rm-sb rm-sb--right">
67
+ <NuxtLink
68
+ v-if="user"
69
+ :to="profileTo"
70
+ class="rm-rail__item"
71
+ :title="user.name || profileLabel"
72
+ >
73
+ <span class="rm-rail__avatar" :style="{ backgroundColor: avatarColor }">{{ user.initials }}</span>
74
+ <span class="rm-rail__caption">{{ profileLabel }}</span>
75
+ </NuxtLink>
76
+
77
+ <button
78
+ v-for="tile in tiles"
79
+ :key="tile.key"
80
+ class="rm-rail__item"
81
+ :class="{ 'rm-rail__item--active': active === tile.key }"
82
+ type="button"
83
+ :title="tile.label"
84
+ :aria-pressed="active === tile.key"
85
+ @click="emit('select', tile.key)"
86
+ >
87
+ <span class="rm-rail__tile"><i :class="`ph ph-${tile.icon}`" /></span>
88
+ <span class="rm-rail__caption">{{ tile.label }}</span>
89
+ </button>
90
+
91
+ <slot />
92
+
93
+ <div v-if="locales.length > 1" class="rm-rail__bottom">
94
+ <div class="rm-lang" :class="{ 'rm-lang--second': second }" role="group" aria-label="Langue">
95
+ <span class="rm-lang__thumb" aria-hidden="true" />
96
+ <button
97
+ v-for="option in locales"
98
+ :key="option.code"
99
+ class="rm-lang__option"
100
+ :class="{ 'rm-lang__option--active': locale === option.code }"
101
+ type="button"
102
+ :title="option.label"
103
+ :aria-label="option.label"
104
+ :aria-pressed="locale === option.code"
105
+ @click="emit('update:locale', option.code)"
106
+ >
107
+ <span aria-hidden="true">{{ option.flag }}</span>
108
+ </button>
109
+ </div>
110
+ </div>
111
+ </aside>
112
+ </template>
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@tekkare/romulus",
3
- "version": "0.1.13",
3
+ "version": "0.1.15",
4
4
  "description": "Romulus Design System - Nuxt module by Tekkare",
5
5
  "license": "MIT",
6
6
  "type": "module",