@jungherz-de/notionkit-elements 1.5.3 → 1.7.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.
Files changed (115) hide show
  1. package/README.md +27 -18
  2. package/dist/components/base.js +346 -0
  3. package/dist/components/nk-ai-input-row.js +2 -1
  4. package/dist/components/nk-ai-msg.js +10 -3
  5. package/dist/components/nk-ai-thread.js +2 -1
  6. package/dist/components/nk-app.js +2 -1
  7. package/dist/components/nk-avatar-group.js +2 -1
  8. package/dist/components/nk-avatar.js +57 -0
  9. package/dist/components/nk-banner.js +2 -1
  10. package/dist/components/nk-block-host.js +2 -1
  11. package/dist/components/nk-board-view.js +4 -2
  12. package/dist/components/nk-breadcrumb.js +2 -1
  13. package/dist/components/nk-btn.js +31 -4
  14. package/dist/components/nk-callout.js +2 -1
  15. package/dist/components/nk-check.js +2 -1
  16. package/dist/components/nk-cmdk.js +3 -2
  17. package/dist/components/nk-code.js +2 -1
  18. package/dist/components/nk-comment.js +9 -6
  19. package/dist/components/nk-comments.js +2 -1
  20. package/dist/components/nk-danger-zone.js +2 -1
  21. package/dist/components/nk-database.js +16 -6
  22. package/dist/components/nk-divider.js +2 -1
  23. package/dist/components/nk-emoji-picker.js +2 -1
  24. package/dist/components/nk-empty.js +2 -1
  25. package/dist/components/nk-field.js +2 -1
  26. package/dist/components/nk-fields.js +2 -1
  27. package/dist/components/nk-filter-bar.js +59 -37
  28. package/dist/components/nk-heading.js +2 -1
  29. package/dist/components/nk-input.js +2 -1
  30. package/dist/components/nk-kbd.js +2 -1
  31. package/dist/components/nk-list-view.js +96 -0
  32. package/dist/components/nk-member-list.js +2 -1
  33. package/dist/components/nk-member-row.js +10 -6
  34. package/dist/components/nk-mention.js +2 -1
  35. package/dist/components/nk-menu-item.js +27 -3
  36. package/dist/components/nk-menu.js +88 -2
  37. package/dist/components/nk-modal.js +3 -2
  38. package/dist/components/nk-model-card.js +2 -1
  39. package/dist/components/nk-page-actions.js +2 -1
  40. package/dist/components/nk-page-cover.js +12 -11
  41. package/dist/components/nk-page-title.js +2 -1
  42. package/dist/components/nk-page.js +12 -4
  43. package/dist/components/nk-panel.js +61 -0
  44. package/dist/components/nk-panels.js +18 -0
  45. package/dist/components/nk-pop.js +2 -1
  46. package/dist/components/nk-profile-row.js +2 -1
  47. package/dist/components/nk-progress.js +5 -2
  48. package/dist/components/nk-prop.js +54 -0
  49. package/dist/components/nk-props.js +21 -0
  50. package/dist/components/nk-quote.js +2 -1
  51. package/dist/components/nk-radio.js +2 -1
  52. package/dist/components/nk-section-label.js +2 -1
  53. package/dist/components/nk-segmented.js +21 -1
  54. package/dist/components/nk-select.js +2 -1
  55. package/dist/components/nk-settings-pane.js +2 -1
  56. package/dist/components/nk-settings-user.js +2 -1
  57. package/dist/components/nk-sheet.js +97 -0
  58. package/dist/components/nk-sidebar.js +17 -37
  59. package/dist/components/nk-skeleton.js +2 -1
  60. package/dist/components/nk-slider.js +2 -1
  61. package/dist/components/nk-stat.js +2 -1
  62. package/dist/components/nk-stats.js +2 -1
  63. package/dist/components/nk-steps.js +61 -0
  64. package/dist/components/nk-switch.js +2 -1
  65. package/dist/components/nk-synced.js +2 -1
  66. package/dist/components/nk-tab-bar-item.js +2 -1
  67. package/dist/components/nk-tab-bar.js +2 -1
  68. package/dist/components/nk-tab.js +2 -1
  69. package/dist/components/nk-table-view.js +6 -2
  70. package/dist/components/nk-tabs.js +2 -1
  71. package/dist/components/nk-tag.js +2 -1
  72. package/dist/components/nk-template-btn.js +2 -1
  73. package/dist/components/nk-textarea.js +2 -1
  74. package/dist/components/nk-theme-toggle.js +2 -1
  75. package/dist/components/nk-toast.js +2 -1
  76. package/dist/components/nk-todo.js +2 -1
  77. package/dist/components/nk-toggle.js +2 -1
  78. package/dist/components/nk-topbar.js +2 -1
  79. package/dist/components/nk-tree-item.js +2 -1
  80. package/dist/components/nk-tree.js +2 -1
  81. package/dist/components/nk-workspace-switcher.js +2 -1
  82. package/dist/components/shared/avatar-BiqCaHOt.js +19 -0
  83. package/dist/components/shared/{focus-DXrK9oLe.js → focus-BNAChOXO.js} +12 -4
  84. package/dist/components/shared/{property-cell-CtXQpUjQ.js → property-cell-o7N30kAQ.js} +8 -3
  85. package/dist/notionkit-elements.esm.js +759 -120
  86. package/dist/notionkit-elements.js +767 -119
  87. package/dist/notionkit-elements.min.js +1 -1
  88. package/package.json +7 -6
  89. package/src/components/content/nk-progress.js +3 -1
  90. package/src/components/data/nk-ai-msg.js +8 -2
  91. package/src/components/data/nk-comment.js +7 -5
  92. package/src/components/data/nk-database.js +14 -5
  93. package/src/components/data/nk-filter-bar.js +57 -36
  94. package/src/components/data/nk-list-view.js +93 -0
  95. package/src/components/data/nk-table-view.js +2 -0
  96. package/src/components/forms/nk-btn.js +29 -3
  97. package/src/components/overlays/nk-menu-item.js +25 -2
  98. package/src/components/overlays/nk-menu.js +86 -1
  99. package/src/components/overlays/nk-sheet.js +95 -0
  100. package/src/components/page/nk-avatar.js +55 -0
  101. package/src/components/page/nk-member-row.js +8 -5
  102. package/src/components/page/nk-page-cover.js +10 -10
  103. package/src/components/page/nk-page.js +10 -3
  104. package/src/components/page/nk-panel.js +59 -0
  105. package/src/components/page/nk-panels.js +16 -0
  106. package/src/components/page/nk-prop.js +52 -0
  107. package/src/components/page/nk-props.js +19 -0
  108. package/src/components/page/nk-segmented.js +19 -0
  109. package/src/components/page/nk-steps.js +59 -0
  110. package/src/components/shell/nk-sidebar.js +15 -36
  111. package/src/index.js +18 -0
  112. package/src/util/avatar.js +17 -0
  113. package/src/util/focus.js +11 -3
  114. package/src/util/property-cell.js +7 -3
  115. package/dist/components/shared/base-C3eJwHKA.js +0 -366
@@ -1,12 +1,12 @@
1
- // NotionKit v1.5.3 – Constructable Stylesheet
1
+ // NotionKit v1.7.1 – Constructable Stylesheet
2
2
  // Auto-generated by build-styles-js.mjs – do not edit manually.
3
3
 
4
4
  // The :root and [data-theme="dark"] blocks that declare --nk-* …
5
- const tokensCss = ":root{color-scheme:light;--nk-bg:#ffffff;--nk-bg-sidebar:#f9f8f7;--nk-bg-hover:rgba(55,53,47,0.06);--nk-bg-active:rgba(55,53,47,0.08);--nk-bg-callout:#f0efed;--nk-bg-code:#f7f6f3;--nk-bg-card:#ffffff;--nk-bg-input:rgba(242,241,238,0.6);--nk-text:#2c2c2b;--nk-text-secondary:#7d7a75;--nk-text-tertiary:#91918e;--nk-text-sidebar:#5f5e5b;--nk-border:rgba(28,19,1,0.11);--nk-border-strong:rgba(27,21,0,0.19);--nk-accent:#2383e2;--nk-on-accent:#ffffff;--nk-danger:#cd3c3a;--nk-tag-gray-bg:#e3e2e0;--nk-tag-gray-text:#32302c;--nk-tag-brown-bg:#eee0da;--nk-tag-brown-text:#442a1e;--nk-tag-orange-bg:#fadec9;--nk-tag-orange-text:#49290e;--nk-tag-yellow-bg:#fdecc8;--nk-tag-yellow-text:#402c1b;--nk-tag-green-bg:#dbeddb;--nk-tag-green-text:#1c3829;--nk-tag-blue-bg:#d3e5ef;--nk-tag-blue-text:#183347;--nk-tag-purple-bg:#e8deee;--nk-tag-purple-text:#412454;--nk-tag-pink-bg:#f5e0e9;--nk-tag-pink-text:#4c2337;--nk-tag-red-bg:#ffe2dd;--nk-tag-red-text:#5d1715;--nk-tint-gray:#f1f1ef;--nk-color-gray:#787774;--nk-tint-brown:#f4eeee;--nk-color-brown:#9f6b53;--nk-tint-orange:#fbecdd;--nk-color-orange:#d9730d;--nk-tint-yellow:#fbf3db;--nk-color-yellow:#cb912f;--nk-tint-green:#edf3ec;--nk-color-green:#448361;--nk-tint-blue:#e7f3f8;--nk-color-blue:#337ea9;--nk-tint-purple:#f8f3fc;--nk-color-purple:#9065b0;--nk-tint-pink:#fcf1f6;--nk-color-pink:#c14c8a;--nk-tint-red:#fdebec;--nk-color-red:#cd3c3a;--nk-decor-purple:#9065b0;--nk-decor-blue:#529cca;--nk-decor-orange:#d9730d;--nk-scrim:rgba(15,15,15,0.6);--nk-scrim-soft:rgba(15,15,15,0.5);--nk-sidebar-width:260px;--nk-tab-bar-height:58px;--nk-radius:6px;--nk-font:ui-sans-serif,-apple-system,\"Segoe UI\",Inter,Helvetica,Arial,sans-serif;--nk-font-mono:ui-monospace,\"SF Mono\",Menlo,Consolas,monospace;--nk-shadow-menu:rgba(15,15,15,0.05) 0px 0px 0px 1px,rgba(15,15,15,0.1) 0px 3px 6px,rgba(15,15,15,0.2) 0px 9px 24px;--nk-shadow-card:0 1px 2px rgba(0,0,0,0.04);--nk-shadow-btn:inset 0 0 0 1px rgba(15,15,15,0.1),0 1px 2px rgba(15,15,15,0.1);--nk-shadow-knob:0 1px 2px rgba(0,0,0,0.2);--nk-shadow-segment:0 1px 2px rgba(0,0,0,0.08)}[data-theme=dark]{color-scheme:dark;--nk-bg:#191919;--nk-bg-sidebar:#202020;--nk-bg-hover:rgba(255,255,255,0.055);--nk-bg-active:rgba(255,255,255,0.08);--nk-bg-callout:#252525;--nk-bg-code:#202020;--nk-bg-card:#202020;--nk-bg-input:rgba(255,255,255,0.055);--nk-text:rgba(255,255,255,0.81);--nk-text-secondary:rgba(255,255,255,0.46);--nk-text-tertiary:rgba(255,255,255,0.32);--nk-text-sidebar:rgba(255,255,255,0.62);--nk-border:rgba(255,255,255,0.094);--nk-border-strong:rgba(255,255,255,0.16);--nk-accent:#529CCA;--nk-danger:#df5452;--nk-tag-gray-bg:#373737;--nk-tag-gray-text:rgba(255,255,255,0.85);--nk-tag-brown-bg:#603b2c;--nk-tag-brown-text:rgba(255,255,255,0.85);--nk-tag-orange-bg:#854c1d;--nk-tag-orange-text:rgba(255,255,255,0.85);--nk-tag-yellow-bg:#89632a;--nk-tag-yellow-text:rgba(255,255,255,0.85);--nk-tag-green-bg:#2b593f;--nk-tag-green-text:rgba(255,255,255,0.85);--nk-tag-blue-bg:#28456c;--nk-tag-blue-text:rgba(255,255,255,0.85);--nk-tag-purple-bg:#492f64;--nk-tag-purple-text:rgba(255,255,255,0.85);--nk-tag-pink-bg:#69314c;--nk-tag-pink-text:rgba(255,255,255,0.85);--nk-tag-red-bg:#6e3630;--nk-tag-red-text:rgba(255,255,255,0.85);--nk-tint-gray:#252525;--nk-color-gray:#9b9b9b;--nk-tint-brown:#2e2724;--nk-color-brown:#ba856f;--nk-tint-orange:#36291f;--nk-color-orange:#c77d48;--nk-tint-yellow:#372e20;--nk-color-yellow:#ca8f3d;--nk-tint-green:#242b26;--nk-color-green:#529e72;--nk-tint-blue:#1f282d;--nk-color-blue:#5e87c9;--nk-tint-purple:#2a2430;--nk-color-purple:#9d68d3;--nk-tint-pink:#2e2328;--nk-color-pink:#d15796;--nk-tint-red:#332523;--nk-color-red:#df5452;--nk-shadow-menu:rgba(15,15,15,0.2) 0px 0px 0px 1px,rgba(15,15,15,0.4) 0px 3px 6px,rgba(15,15,15,0.6) 0px 9px 24px;--nk-shadow-card:none;--nk-shadow-btn:inset 0 0 0 1px rgba(255,255,255,0.1),0 1px 2px rgba(0,0,0,0.3)}";
5
+ const tokensCss = ":root{color-scheme:light;--nk-bg: #ffffff;--nk-bg-sidebar: #f9f8f7;--nk-bg-hover: rgba(55,53,47,.06);--nk-bg-active: rgba(55,53,47,.08);--nk-bg-callout: #f0efed;--nk-bg-code: #f7f6f3;--nk-bg-card: #ffffff;--nk-bg-input: rgba(242,241,238,.6);--nk-text: #2c2c2b;--nk-text-secondary: #7d7a75;--nk-text-tertiary: #91918e;--nk-text-sidebar: #5f5e5b;--nk-border: rgba(28,19,1,.11);--nk-border-strong: rgba(27,21,0,.19);--nk-accent: #2383e2;--nk-on-accent: #ffffff;--nk-danger: #cd3c3a;--nk-tag-gray-bg: #e3e2e0;--nk-tag-gray-text: #32302c;--nk-tag-brown-bg: #eee0da;--nk-tag-brown-text: #442a1e;--nk-tag-orange-bg: #fadec9;--nk-tag-orange-text: #49290e;--nk-tag-yellow-bg: #fdecc8;--nk-tag-yellow-text: #402c1b;--nk-tag-green-bg: #dbeddb;--nk-tag-green-text: #1c3829;--nk-tag-blue-bg: #d3e5ef;--nk-tag-blue-text: #183347;--nk-tag-purple-bg: #e8deee;--nk-tag-purple-text: #412454;--nk-tag-pink-bg: #f5e0e9;--nk-tag-pink-text: #4c2337;--nk-tag-red-bg: #ffe2dd;--nk-tag-red-text: #5d1715;--nk-tint-gray: #f1f1ef;--nk-color-gray: #787774;--nk-tint-brown: #f4eeee;--nk-color-brown: #9f6b53;--nk-tint-orange: #fbecdd;--nk-color-orange: #d9730d;--nk-tint-yellow: #fbf3db;--nk-color-yellow: #cb912f;--nk-tint-green: #edf3ec;--nk-color-green: #448361;--nk-tint-blue: #e7f3f8;--nk-color-blue: #337ea9;--nk-tint-purple: #f8f3fc;--nk-color-purple: #9065b0;--nk-tint-pink: #fcf1f6;--nk-color-pink: #c14c8a;--nk-tint-red: #fdebec;--nk-color-red: #cd3c3a;--nk-decor-purple: #9065b0;--nk-decor-blue: #529cca;--nk-decor-orange: #d9730d;--nk-scrim: rgba(15,15,15,.6);--nk-scrim-soft: rgba(15,15,15,.5);--nk-sidebar-width: 260px;--nk-tab-bar-height: 58px;--nk-radius: 6px;--nk-font: ui-sans-serif, -apple-system, \"Segoe UI\", Inter, Helvetica, Arial, sans-serif;--nk-font-mono: ui-monospace, \"SF Mono\", Menlo, Consolas, monospace;--nk-shadow-menu: rgba(15,15,15,.05) 0px 0px 0px 1px, rgba(15,15,15,.1) 0px 3px 6px, rgba(15,15,15,.2) 0px 9px 24px;--nk-shadow-card: 0 1px 2px rgba(0,0,0,.04);--nk-shadow-btn: inset 0 0 0 1px rgba(15,15,15,.1), 0 1px 2px rgba(15,15,15,.1);--nk-shadow-knob: 0 1px 2px rgba(0,0,0,.2);--nk-shadow-segment: 0 1px 2px rgba(0,0,0,.08)}[data-theme=dark]{color-scheme:dark;--nk-bg: #191919;--nk-bg-sidebar: #202020;--nk-bg-hover: rgba(255,255,255,.055);--nk-bg-active: rgba(255,255,255,.08);--nk-bg-callout: #252525;--nk-bg-code: #202020;--nk-bg-card: #202020;--nk-bg-input: rgba(255,255,255,.055);--nk-text: rgba(255,255,255,.81);--nk-text-secondary: rgba(255,255,255,.46);--nk-text-tertiary: rgba(255,255,255,.32);--nk-text-sidebar: rgba(255,255,255,.62);--nk-border: rgba(255,255,255,.094);--nk-border-strong: rgba(255,255,255,.16);--nk-accent: #529CCA;--nk-danger: #df5452;--nk-tag-gray-bg: #373737;--nk-tag-gray-text: rgba(255,255,255,.85);--nk-tag-brown-bg: #603b2c;--nk-tag-brown-text: rgba(255,255,255,.85);--nk-tag-orange-bg: #854c1d;--nk-tag-orange-text: rgba(255,255,255,.85);--nk-tag-yellow-bg: #89632a;--nk-tag-yellow-text: rgba(255,255,255,.85);--nk-tag-green-bg: #2b593f;--nk-tag-green-text: rgba(255,255,255,.85);--nk-tag-blue-bg: #28456c;--nk-tag-blue-text: rgba(255,255,255,.85);--nk-tag-purple-bg: #492f64;--nk-tag-purple-text: rgba(255,255,255,.85);--nk-tag-pink-bg: #69314c;--nk-tag-pink-text: rgba(255,255,255,.85);--nk-tag-red-bg: #6e3630;--nk-tag-red-text: rgba(255,255,255,.85);--nk-tint-gray: #252525;--nk-color-gray: #9b9b9b;--nk-tint-brown: #2e2724;--nk-color-brown: #ba856f;--nk-tint-orange: #36291f;--nk-color-orange: #c77d48;--nk-tint-yellow: #372e20;--nk-color-yellow: #ca8f3d;--nk-tint-green: #242b26;--nk-color-green: #529e72;--nk-tint-blue: #1f282d;--nk-color-blue: #5e87c9;--nk-tint-purple: #2a2430;--nk-color-purple: #9d68d3;--nk-tint-pink: #2e2328;--nk-color-pink: #d15796;--nk-tint-red: #332523;--nk-color-red: #df5452;--nk-shadow-menu: rgba(15,15,15,.2) 0px 0px 0px 1px, rgba(15,15,15,.4) 0px 3px 6px, rgba(15,15,15,.6) 0px 9px 24px;--nk-shadow-card: none;--nk-shadow-btn: inset 0 0 0 1px rgba(255,255,255,.1), 0 1px 2px rgba(0,0,0,.3)}";
6
6
 
7
7
  // … and everything else, in two pieces around where they were.
8
- const componentsHead = "[class*=nk-],[class*=nk-] *,[class*=nk-] ::after,[class*=nk-] ::before,[class*=nk-]::after,[class*=nk-]::before{box-sizing:border-box}[class*=nk-] :where(h1,h2,h3,h4,h5,h6,p,figure,blockquote,dl,dd,pre,ul,ol,li){margin:0;padding:0}[class*=nk-] :where(ul,ol){list-style:none}:where(button,input,select,textarea)[class*=nk-],[class*=nk-] :where(button,input,select,textarea,option,optgroup,fieldset,legend){margin:0;padding:0}[class*=nk-][hidden]:not([hidden=until-found i]){display:none!important}::slotted([hidden]:not([hidden=until-found i])){display:none!important}";
9
- const componentsTail = ".nk-body{margin:0;min-height:100vh;min-height:100dvh;font-family:var(--nk-font);font-size:14px;background:var(--nk-bg);color:var(--nk-text);-webkit-font-smoothing:auto;transition:background .25s,color .25s}.nk-app{display:flex;height:100vh;height:100dvh;overflow:hidden}.nk-sidebar{width:calc(var(--nk-sidebar-width) + env(safe-area-inset-left,0px));min-width:calc(var(--nk-sidebar-width) + env(safe-area-inset-left,0px));padding-left:env(safe-area-inset-left,0);background:var(--nk-bg-sidebar);display:flex;flex-direction:column;border-right:1px solid var(--nk-border);transition:background .25s}.nk-workspace{display:flex;align-items:center;gap:8px;padding:10px 12px;margin:6px 8px 2px;border-radius:var(--nk-radius);cursor:pointer;font-weight:500;user-select:none}.nk-workspace:hover{background:var(--nk-bg-hover)}.nk-workspace .avatar,.nk-workspace ::slotted(.avatar),.nk-workspace ::slotted([slot=avatar]){width:22px;height:22px;border-radius:4px;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:11px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-workspace .chev{margin-left:auto;color:var(--nk-text-tertiary);font-size:11px}.nk-sidebar-scroll{flex:1;overflow-y:auto;padding:4px 8px 16px}.nk-sidebar-scroll::-webkit-scrollbar{width:8px}.nk-sidebar-scroll::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:4px}.nk-section-label{font-size:12px;font-weight:500;letter-spacing:.01em;color:var(--nk-text-tertiary);padding:14px 10px 4px;display:flex;justify-content:space-between;align-items:center}.nk-section-label .plus{cursor:pointer;border-radius:4px;padding:0 4px;font-size:13px;opacity:0;transition:opacity .15s}.nk-section-label:hover .plus{opacity:1}.nk-section-label .plus:hover{background:var(--nk-bg-hover)}.nk-sidebar-footer{padding:8px;border-top:1px solid var(--nk-border);color:var(--nk-text-sidebar);font-size:14px}.nk-sidebar-footer .nk-tree-item{min-height:26px}.nk-main{flex:1;display:flex;flex-direction:column;min-width:0}.nk-topbar{height:44px;display:flex;align-items:center;padding:0 max(12px,env(safe-area-inset-right,0px)) 0 max(12px,env(safe-area-inset-left,0px));gap:8px;flex-shrink:0}.nk-breadcrumb{display:flex;align-items:center;gap:4px;font-size:14px}.nk-breadcrumb .crumb,.nk-breadcrumb ::slotted(.crumb){padding:2px 6px;border-radius:4px;cursor:pointer;color:var(--nk-text-sidebar);display:flex;align-items:center;gap:5px}.nk-breadcrumb .crumb:hover{background:var(--nk-bg-hover)}a.crumb{text-decoration:none}.nk-breadcrumb .crumb.current,.nk-breadcrumb ::slotted(.crumb.current){color:var(--nk-text)}.nk-breadcrumb .sep{color:var(--nk-text-tertiary);font-size:12px}.nk-topbar-actions{margin-left:auto;display:flex;align-items:center;gap:4px}.nk-topbar-btn{padding:4px 8px;border-radius:var(--nk-radius);cursor:pointer;color:var(--nk-text-sidebar);font-size:14px;user-select:none;border:none;background:0 0;font-family:inherit}.nk-topbar-btn:hover{background:var(--nk-bg-hover)}.nk-topbar-btn ::slotted(svg),.nk-topbar-btn svg{width:16px;height:16px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.nk-share-btn{font-size:14px;padding:4px 8px}.nk-topbar-actions ::slotted(.nk-topbar-meta),.nk-topbar-meta{padding:4px 8px;font-size:12px;color:var(--nk-text-tertiary);white-space:nowrap}.nk-theme-toggle{font-size:15px;width:30px;height:28px;padding:0}.nk-tab-bar{display:none;flex:none;align-items:stretch;gap:2px;position:sticky;bottom:0;z-index:30;box-sizing:border-box;height:calc(var(--nk-tab-bar-height) - 6px + max(6px,env(safe-area-inset-bottom,0px)));padding:6px max(4px,env(safe-area-inset-right,0px)) max(6px,env(safe-area-inset-bottom,0px)) max(4px,env(safe-area-inset-left,0px));background:var(--nk-bg-sidebar);border-top:1px solid var(--nk-border)}.nk-tab-bar.always{display:flex}.nk-tab-bar.fixed{position:fixed;left:0;right:0;bottom:0}.nk-tab-bar-spacer{display:none;flex:none;height:calc(var(--nk-tab-bar-height) - 6px + max(6px,env(safe-area-inset-bottom,0px)))}.nk-tab-bar.always.fixed+.nk-tab-bar-spacer{display:block}.nk-tab-bar.floating{position:fixed;left:max(12px,env(safe-area-inset-left,0px));right:max(12px,env(safe-area-inset-right,0px));bottom:calc(12px + env(safe-area-inset-bottom,0px));height:var(--nk-tab-bar-height);padding:6px;border:1px solid var(--nk-border);border-radius:16px;box-shadow:var(--nk-shadow-menu)}.nk-tab-bar-item{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;padding:4px 2px;border:none;border-radius:var(--nk-radius);background:0 0;font-family:inherit;font-size:10.5px;line-height:1.2;color:var(--nk-text-secondary);text-decoration:none;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent}.nk-tab-bar-item:hover{color:var(--nk-text);background:var(--nk-bg-hover)}.nk-tab-bar-item.active{color:var(--nk-accent)}.nk-tab-bar-item:disabled{opacity:.5;cursor:not-allowed}.nk-tab-bar-item .icon,.nk-tab-bar-item ::slotted([slot=icon]){font-size:20px;line-height:1}.nk-tab-bar-item .label,.nk-tab-bar-item ::slotted(.label){max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nk-tree-item{display:flex;align-items:center;gap:6px;padding:3px 8px 3px 10px;border-radius:var(--nk-radius);cursor:pointer;user-select:none;color:var(--nk-text-sidebar);position:relative;min-height:28px}.nk-tree-item:hover{background:var(--nk-bg-hover)}.nk-tree-item.active{background:var(--nk-bg-active);color:var(--nk-text);font-weight:500}.nk-tree-item.compact{min-height:26px}.nk-tree-item .icon,.nk-tree-item ::slotted(.icon),.nk-tree-item ::slotted([slot=icon]){font-size:15px;width:20px;text-align:center;flex-shrink:0}.nk-tree-item .label,.nk-tree-item ::slotted(.label){white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nk-tree-item .actions{margin-left:auto;display:none;gap:2px;color:var(--nk-text-tertiary)}.nk-tree-item:hover .actions{display:flex}.nk-tree-item .actions span{padding:0 3px;border-radius:3px;font-size:12px}.nk-tree-item .actions span:hover{background:var(--nk-bg-active)}.nk-tree-children{margin-left:14px;border-left:1px solid var(--nk-border);padding-left:4px;overflow:hidden}.nk-tree-children.collapsed{display:none}.nk-toggle-arrow{width:16px;height:16px;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;font-size:9px;color:var(--nk-text-tertiary);border-radius:3px;transition:transform .15s}.nk-toggle-arrow.open{transform:rotate(90deg)}.nk-kbd-hint{margin-left:auto;display:flex;gap:3px;align-items:center}.nk-kbd{font-family:inherit;font-size:10.5px;background:var(--nk-bg-callout);border:1px solid var(--nk-border-strong);border-bottom-width:2px;border-radius:4px;padding:0 4px}.nk-page-scroll{flex:1;overflow-y:auto}.nk-page-scroll::-webkit-scrollbar{width:10px}.nk-page-scroll::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:5px;border:2px solid var(--nk-bg)}.nk-cover{height:200px;background:radial-gradient(ellipse at 20% 40%,color-mix(in srgb,var(--nk-decor-purple) 35%,transparent),transparent 55%),radial-gradient(ellipse at 80% 20%,color-mix(in srgb,var(--nk-decor-blue) 35%,transparent),transparent 55%),radial-gradient(ellipse at 60% 90%,color-mix(in srgb,var(--nk-decor-orange) 25%,transparent),transparent 55%),var(--nk-bg-callout)}.nk-page{max-width:760px;margin:0 auto;padding:24px max(64px,env(safe-area-inset-right,0px)) 120px max(64px,env(safe-area-inset-left,0px));font-size:16px;line-height:1.5}.nk-cover+.nk-page,.nk-page.covered{padding-top:0}.nk-page ::slotted(.nk-page-icon),.nk-page ::slotted([slot=icon]),.nk-page-icon{font-size:64px;line-height:1;margin-top:0;cursor:pointer;user-select:none;display:inline-block}.nk-cover+.nk-page .nk-page-icon,.nk-cover+.nk-page ::slotted(.nk-page-icon),.nk-cover+.nk-page ::slotted([slot=icon]),.nk-page.covered .nk-page-icon,.nk-page.covered ::slotted(.nk-page-icon),.nk-page.covered ::slotted([slot=icon]){margin-top:-42px}.nk-page-title{font-size:40px;font-weight:700;line-height:1.2;margin:8px 0 4px;outline:0;letter-spacing:0}.nk-page-meta{color:var(--nk-text-tertiary);font-size:13px;margin-bottom:24px;display:flex;gap:16px}.nk-page p.lead{font-size:16px;line-height:1.6;color:var(--nk-text-secondary);margin-bottom:20px}.nk-page ::slotted(p.lead){font-size:16px;line-height:1.6;color:var(--nk-text-secondary);margin-bottom:20px!important}.nk-heading{font-size:24px;font-weight:600;line-height:1.3;margin:32px 0 10px;display:flex;align-items:center;gap:8px}.nk-callout{display:flex;gap:10px;align-items:flex-start;background:var(--nk-bg-callout);border-radius:var(--nk-radius);padding:16px 16px 16px 12px;margin:16px 0;line-height:1.5}.nk-callout .c-icon,.nk-callout ::slotted(.c-icon),.nk-callout ::slotted([slot=icon]){font-size:17px}.nk-todo{display:flex;align-items:flex-start;gap:8px;padding:4px 0}.nk-todo input[type=checkbox]{appearance:none;width:16px;height:16px;margin-top:3px;border:1.4px solid var(--nk-border-strong);border-radius:2px;cursor:pointer;flex-shrink:0;position:relative;background:var(--nk-bg)}.nk-todo input[type=checkbox]:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-todo input[type=checkbox]:checked::after{content:\"✓\";color:var(--nk-on-accent);font-size:11px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-todo input:checked+span{text-decoration:line-through;color:var(--nk-text-tertiary)}.nk-todo input:disabled{opacity:.5;cursor:not-allowed}.nk-toggle{margin:6px 0}.nk-toggle summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:6px;padding:4px 6px;border-radius:var(--nk-radius);font-weight:500;user-select:none}.nk-toggle summary::-webkit-details-marker{display:none}.nk-toggle summary:hover{background:var(--nk-bg-hover)}.nk-toggle summary::before{content:\"▸\";color:var(--nk-text-tertiary);font-size:11px;transition:transform .15s;display:inline-block}.nk-toggle[open] summary::before{transform:rotate(90deg)}.nk-toggle .toggle-body,.nk-toggle ::slotted(.toggle-body){padding:4px 0 8px 26px;color:var(--nk-text-secondary);line-height:1.55}.nk-divider{border:none;border-top:1px solid var(--nk-border);margin:24px 0}.nk-quote{border-left:3px solid var(--nk-text);padding:2px 0 2px 14px;margin:16px 0;color:var(--nk-text-secondary);line-height:1.5}.nk-quote .q-cite{display:block;margin-top:6px;font-size:12.5px;color:var(--nk-text-tertiary)}.nk-mention{display:inline-flex;align-items:center;gap:4px;padding:0 4px;border-radius:4px;font-weight:500;cursor:pointer;white-space:nowrap}.nk-mention:hover{background:var(--nk-bg-hover)}.nk-mention.person{color:var(--nk-text)}.nk-mention.person .mini-avatar,.nk-mention.person ::slotted(.mini-avatar),.nk-mention.person ::slotted([slot=avatar]){width:16px;height:16px;border-radius:50%;color:var(--nk-on-accent);font-size:8.5px;font-weight:600;display:inline-flex;align-items:center;justify-content:center}.nk-mention.page{color:var(--nk-text-secondary);text-decoration:underline;text-decoration-color:var(--nk-border-strong);text-underline-offset:2px}.nk-mention.date{color:var(--nk-color-orange)}.nk-inline-code{font-family:var(--nk-font-mono);font-size:85%;color:var(--nk-danger);background:color-mix(in srgb,var(--nk-danger) 8%,transparent);border-radius:4px;padding:1px 5px}.nk-code{background:var(--nk-bg-code);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:20px 24px;font-family:var(--nk-font-mono);font-size:13px;line-height:1.6;margin:14px 0;overflow-x:auto;color:var(--nk-text-secondary);white-space:pre;position:relative}.nk-code .lang{position:absolute;top:6px;right:10px;font-size:11px;color:var(--nk-text-tertiary);font-family:var(--nk-font)}.nk-code .tag,.nk-code ::slotted(.tag){color:var(--nk-accent)}.nk-code .attr,.nk-code ::slotted(.attr){color:var(--nk-color-orange)}.nk-database{margin:12px 0 8px}.nk-db-tabs{display:flex;gap:2px;align-items:center;padding:0 0 6px;margin-bottom:0;font-size:14px}.nk-db-tab{padding:4px 8px;cursor:pointer;color:var(--nk-text-secondary);border-radius:var(--nk-radius);user-select:none;line-height:20px;display:flex;align-items:center;gap:6px}.nk-db-tab:hover{color:var(--nk-text);background:var(--nk-bg-hover)}.nk-db-tab.active{color:var(--nk-text);background:var(--nk-bg-active);font-weight:500}.nk-db-tab .badge,.nk-db-tab ::slotted(.badge){background:var(--nk-bg-callout);border-radius:8px;font-size:11px;padding:0 6px;color:var(--nk-text-tertiary)}.nk-table-wrap{overflow-x:auto}.nk-table{width:100%;border-collapse:collapse;font-size:14px}.nk-table th{text-align:left;font-weight:400;color:var(--nk-text-secondary);height:36px;padding:0 8px;border-bottom:1px solid var(--nk-border);border-right:1px solid var(--nk-border);font-size:14px;white-space:nowrap;user-select:none;cursor:pointer}.nk-table th:hover{background:var(--nk-bg-hover)}.nk-table th .th-icon,.nk-table th ::slotted(.th-icon){margin-right:6px;font-size:13px;color:var(--nk-text-tertiary)}.nk-table td{height:36px;padding:6px 8px;line-height:1.5;border-bottom:1px solid var(--nk-border);border-right:1px solid var(--nk-border);white-space:nowrap;vertical-align:middle}.nk-table td:last-child,.nk-table th:last-child{border-right:none}.nk-table td.wrap,.nk-table.wrap td{white-space:normal;vertical-align:top}.nk-table tbody tr:hover{background:var(--nk-bg-hover)}.nk-table .row-title{display:flex;align-items:center;gap:7px;font-weight:500;cursor:pointer}.nk-table .row-title:hover{text-decoration:underline;text-decoration-color:var(--nk-text-tertiary)}.nk-table .date-cell{color:var(--nk-text-secondary)}.nk-table .person-cell{display:flex;align-items:center;gap:6px;color:var(--nk-text-secondary)}.nk-table .person-cell .mini-avatar,.nk-table .person-cell ::slotted(.mini-avatar){width:20px;height:20px;border-radius:50%;font-size:10px;color:var(--nk-on-accent);display:inline-flex;align-items:center;justify-content:center;font-weight:600}.nk-new-row,.nk-table .new-row{color:var(--nk-text-tertiary);cursor:pointer;padding:8px;display:flex;align-items:center;gap:7px;font-size:14px}.nk-new-row:hover,.nk-table .new-row:hover{background:var(--nk-bg-hover)}.nk-tag{display:inline-flex;align-items:center;max-width:100%;height:20px;padding:0 6px;border-radius:3px;font-size:14px;font-weight:400;line-height:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;background:var(--nk-tag-gray-bg);color:var(--nk-tag-gray-text)}.nk-tag.gray{background:var(--nk-tag-gray-bg);color:var(--nk-tag-gray-text)}.nk-tag.brown{background:var(--nk-tag-brown-bg);color:var(--nk-tag-brown-text)}.nk-tag.orange{background:var(--nk-tag-orange-bg);color:var(--nk-tag-orange-text)}.nk-tag.yellow{background:var(--nk-tag-yellow-bg);color:var(--nk-tag-yellow-text)}.nk-tag.green{background:var(--nk-tag-green-bg);color:var(--nk-tag-green-text)}.nk-tag.blue{background:var(--nk-tag-blue-bg);color:var(--nk-tag-blue-text)}.nk-tag.purple{background:var(--nk-tag-purple-bg);color:var(--nk-tag-purple-text)}.nk-tag.pink{background:var(--nk-tag-pink-bg);color:var(--nk-tag-pink-text)}.nk-tag.red{background:var(--nk-tag-red-bg);color:var(--nk-tag-red-text)}.nk-progress{width:110px;height:6px;border-radius:3px;background:var(--nk-tint-blue);overflow:hidden;display:inline-block}.nk-progress>i{display:block;height:100%;background:var(--nk-color-blue);border-radius:3px}.nk-progress-label{font-size:12px;color:var(--nk-text-tertiary);margin-left:7px}.nk-board{display:none;gap:12px;padding:14px 2px;overflow-x:auto}.nk-board.active{display:flex}.nk-board-col{min-width:220px;width:220px;flex-shrink:0}.nk-board-col-header{display:flex;align-items:center;gap:7px;margin-bottom:8px;font-size:13.5px;font-weight:500}.nk-board-col-header .count{color:var(--nk-text-tertiary);font-weight:400}.nk-card{background:var(--nk-bg-card);border:1px solid var(--nk-border);border-radius:8px;padding:10px 12px;margin-bottom:8px;cursor:grab;box-shadow:var(--nk-shadow-card);transition:border-color .15s}.nk-card:hover{border-color:var(--nk-border-strong)}.nk-card .card-title,.nk-card ::slotted(.card-title){font-weight:500;margin-bottom:7px;display:flex;gap:6px;align-items:center}.nk-card .card-meta,.nk-card ::slotted(.card-meta){display:flex;gap:6px;flex-wrap:wrap;align-items:center;font-size:12px;color:var(--nk-text-secondary)}.nk-field{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:9px 0}.nk-field .f-label,.nk-field ::slotted(.f-label),.nk-field ::slotted([slot=label]){font-size:14px}.nk-field .f-desc,.nk-field ::slotted(.f-desc),.nk-field ::slotted([slot=desc]){font-size:12px;color:var(--nk-text-secondary);margin-top:2px;line-height:1.45}.nk-field .f-control,.nk-field ::slotted(.f-control){flex-shrink:0}.nk-field.stacked,.nk-fields>.nk-field{flex-direction:column;align-items:stretch;gap:6px;min-width:0}.nk-field.stacked .f-control,.nk-field.stacked .nk-input,.nk-field.stacked .nk-select,.nk-field.stacked .nk-textarea,.nk-fields>.nk-field .f-control,.nk-fields>.nk-field .nk-input,.nk-fields>.nk-field .nk-select,.nk-fields>.nk-field .nk-textarea{width:100%;min-width:0}.nk-field.compact,.nk-fields>.nk-field{padding:0;gap:4px;min-width:0}.nk-field.compact .f-label,.nk-field.compact ::slotted([slot=label]),.nk-fields>.nk-field .f-label,.nk-fields>.nk-field ::slotted([slot=label]){font-size:12px;color:var(--nk-text-tertiary)}.nk-fields{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px 12px;padding:9px 0}.nk-fields>.nk-field{min-width:0}.nk-input,.nk-select,.nk-textarea{font-family:inherit;font-size:14px;line-height:20px;color:var(--nk-text);background:var(--nk-bg-input);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:5px 10px;outline:0;transition:border-color .15s,box-shadow .15s;min-width:210px}.nk-input:hover,.nk-select:hover,.nk-textarea:hover{border-color:var(--nk-border-strong)}.nk-input:focus,.nk-select:focus,.nk-textarea:focus{border-color:color-mix(in srgb,var(--nk-accent) 60%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 30%,transparent)}.nk-input::placeholder,.nk-textarea::placeholder{color:var(--nk-text-tertiary)}.nk-input.wide,.nk-select.wide,.nk-textarea.wide{width:100%;min-width:0}.nk-input[type=date],.nk-input[type=datetime-local],.nk-input[type=month],.nk-input[type=time]{appearance:none}.nk-input::-webkit-date-and-time-value{text-align:start;min-height:1lh}.nk-select.compact{min-width:120px}.nk-textarea{resize:vertical;min-height:70px;line-height:1.5}.nk-select{appearance:none;cursor:pointer;padding-right:26px;background-image:linear-gradient(45deg,transparent 50%,var(--nk-text-tertiary) 50%),linear-gradient(135deg,var(--nk-text-tertiary) 50%,transparent 50%);background-position:calc(100% - 14px) 55%,calc(100% - 10px) 55%;background-size:4px 4px;background-repeat:no-repeat}.nk-btn{font-family:inherit;font-size:14px;line-height:20px;font-weight:500;border-radius:var(--nk-radius);cursor:pointer;padding:3px 12px;border:1px solid transparent;transition:background .15s,border-color .15s,box-shadow .15s,opacity .15s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap}.nk-btn ::slotted(svg),.nk-btn svg{width:15px;height:15px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.nk-btn.primary{background:var(--nk-accent);color:var(--nk-on-accent)}.nk-btn.primary:hover{opacity:.88}.nk-btn.secondary{background:var(--nk-bg-card);color:var(--nk-text);box-shadow:var(--nk-shadow-btn)}.nk-btn.secondary:hover{background:color-mix(in srgb,var(--nk-bg-card),var(--nk-text) 6%)}.nk-btn.danger{background:var(--nk-bg-card);color:var(--nk-danger);box-shadow:var(--nk-shadow-btn)}.nk-btn.danger:hover{background:color-mix(in srgb,var(--nk-danger) 8%,var(--nk-bg-card))}.nk-btn.danger-solid{background:var(--nk-danger);color:var(--nk-on-accent)}.nk-btn.danger-solid:hover{opacity:.88}.nk-btn.small{padding:1px 8px;font-size:13px;line-height:20px}a.nk-btn{text-decoration:none}.nk-btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.nk-switch{position:relative;width:34px;height:20px;flex-shrink:0;appearance:none;border:none;cursor:pointer;border-radius:20px;background:var(--nk-border-strong);transition:background .2s}.nk-switch::after{content:\"\";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--nk-on-accent);transition:transform .2s;box-shadow:var(--nk-shadow-knob)}.nk-switch:checked,.nk-switch[aria-checked=true]{background:var(--nk-accent)}.nk-switch:checked::after,.nk-switch[aria-checked=true]::after{transform:translateX(14px)}.nk-switch:disabled{opacity:.5;cursor:not-allowed}.nk-switch-label{display:inline-flex;align-items:flex-start;gap:8px;font-size:14px;cursor:pointer}.nk-switch-label>.nk-switch{font-size:inherit;line-height:inherit;margin-top:max(0px,calc((1lh - 20px)/ 2))}.nk-switch-label>span{padding-top:max(0px,calc((20px - 1lh)/ 2))}.nk-switch-label:has(.nk-switch:disabled){cursor:not-allowed;color:var(--nk-text-tertiary)}.nk-check{display:flex;align-items:flex-start;gap:8px;padding:4px 0;font-size:14px;cursor:pointer}.nk-check input{appearance:none;width:16px;height:16px;flex-shrink:0;border:1.4px solid var(--nk-border-strong);border-radius:3px;cursor:pointer;position:relative;background:var(--nk-bg);font-size:inherit;line-height:inherit;margin-top:max(0px,calc((1lh - 16px)/ 2))}.nk-check input[type=radio]{border-radius:50%}.nk-check input:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-check input:checked::after{content:\"✓\";color:var(--nk-on-accent);font-size:10.5px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-check input[type=radio]:checked::after{content:\"●\";font-size:7px}.nk-check input:disabled{opacity:.5;cursor:not-allowed}.nk-check input:disabled+*{opacity:.6}.nk-slider{width:210px;accent-color:var(--nk-accent);cursor:pointer}.nk-slider-value{font-size:12.5px;color:var(--nk-text-tertiary);margin-top:3px}.nk-profile-row{display:flex;align-items:center;gap:14px;padding:8px 0}.nk-profile-row .big-avatar,.nk-profile-row ::slotted(.big-avatar),.nk-profile-row ::slotted([slot=avatar]){width:56px;height:56px;border-radius:50%;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:20px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-model-card{border:1px solid var(--nk-border-strong);border-radius:8px;padding:12px 14px;margin-bottom:10px;cursor:pointer;display:flex;align-items:flex-start;gap:11px;transition:border-color .15s,background .15s}.nk-model-card:hover{background:var(--nk-bg-hover)}.nk-model-card.selected{border-color:var(--nk-accent);background:color-mix(in srgb,var(--nk-accent) 6%,transparent)}.nk-model-card .m-radio{width:15px;height:15px;border-radius:50%;flex-shrink:0;margin-top:2px;border:1.4px solid var(--nk-border-strong);position:relative}.nk-model-card.selected .m-radio{border-color:var(--nk-accent)}.nk-model-card.selected .m-radio::after{content:\"\";position:absolute;inset:3px;border-radius:50%;background:var(--nk-accent)}.nk-model-card .m-name,.nk-model-card ::slotted(.m-name),.nk-model-card ::slotted([slot=title]){font-weight:500;font-size:14px;display:flex;align-items:center;gap:7px}.nk-model-card .m-desc,.nk-model-card ::slotted(.m-desc),.nk-model-card ::slotted([slot=desc]){font-size:12px;color:var(--nk-text-secondary);margin-top:2px;line-height:1.45}.nk-danger-zone{border:1px solid color-mix(in srgb,var(--nk-danger) 40%,transparent);border-radius:8px;padding:14px 16px;margin-top:26px}.nk-danger-zone .dz-title{color:var(--nk-danger);font-weight:600;font-size:13px;margin-bottom:8px}.nk-member-row{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--nk-border)}.nk-member-list ::slotted(.nk-member-row:last-child),.nk-member-list>.nk-member-row:last-child,.nk-member-row.last{border-bottom:none}.nk-member-row .mini-avatar,.nk-member-row ::slotted(.mini-avatar),.nk-member-row ::slotted([slot=avatar]){width:28px;height:28px;border-radius:50%;color:var(--nk-on-accent);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;flex-shrink:0}.nk-member-row>:has(> .m-mail){min-width:0}.nk-member-row .m-mail{font-size:12px;color:var(--nk-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nk-member-row .nk-select{min-width:120px;margin-left:auto}.nk-member-row ::slotted([slot=role]){margin-left:auto}.nk-modal-backdrop{position:fixed;inset:0;background:var(--nk-scrim);padding:env(safe-area-inset-top,0) env(safe-area-inset-right,0) env(safe-area-inset-bottom,0) env(safe-area-inset-left,0);display:flex;align-items:center;justify-content:center;z-index:100;opacity:0;pointer-events:none;transition:opacity .2s}.nk-modal-backdrop.open{opacity:1;pointer-events:auto}.nk-modal{width:min(1150px,92vw);height:min(715px,86vh);max-width:100%;max-height:100%;background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);display:flex;overflow:hidden;transform:scale(.98) translateY(6px);transition:transform .2s}.nk-modal-backdrop.open .nk-modal{transform:scale(1) translateY(0)}.nk-settings-nav{width:240px;min-width:240px;background:var(--nk-bg-sidebar);border-right:1px solid var(--nk-border);padding:10px 8px;overflow-y:auto;flex-shrink:0}.nk-settings-user{display:flex;align-items:center;gap:9px;padding:6px 10px 12px;margin-bottom:4px}.nk-settings-user .avatar,.nk-settings-user ::slotted(.avatar),.nk-settings-user ::slotted([slot=avatar]){width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-weight:600;font-size:13px;display:flex;align-items:center;justify-content:center}.nk-settings-user .name{font-weight:500;font-size:14px}.nk-settings-user .mail{font-size:12px;color:var(--nk-text-secondary)}.nk-settings-nav .nk-tree-item{min-height:28px}.nk-settings-nav .nk-tree-item.active{background:var(--nk-bg-active);color:var(--nk-text);font-weight:500}.nk-settings-content{flex:1;overflow-y:auto;padding:36px 60px 80px;min-width:0}.nk-settings-content::-webkit-scrollbar{width:10px}.nk-settings-content::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:5px;border:2px solid var(--nk-bg)}.nk-settings-pane{display:none;max-width:800px}.nk-settings-pane.active{display:block}.nk-settings-pane>h2{font-size:22px;font-weight:600;line-height:1.3;margin-bottom:20px}.nk-settings-pane>h3{font-size:16px;font-weight:500;padding-bottom:8px;border-bottom:1px solid var(--nk-border);margin:30px 0 12px}.nk-settings-pane ::slotted(h2){font-size:22px;font-weight:600;line-height:1.3;padding:0!important;margin:0 0 20px!important}.nk-settings-pane ::slotted(h3){font-size:16px;font-weight:500;border:0;border-bottom:1px solid var(--nk-border);padding:0 0 8px!important;margin:30px 0 12px!important}.nk-pop{background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);padding:10px;width:296px}.nk-emoji-search{width:100%;font-family:inherit;font-size:14px;color:var(--nk-text);background:var(--nk-bg-input);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:6px 10px;outline:0;margin-bottom:8px}.nk-emoji-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:2px}.nk-emoji-grid ::slotted(span),.nk-emoji-grid span{font-size:18px;text-align:center;padding:4px 0;border-radius:5px;cursor:pointer;user-select:none}.nk-emoji-grid span:hover{background:var(--nk-bg-hover)}.nk-emoji-cats{display:flex;gap:2px;margin-top:8px;padding-top:8px;border-top:1px solid var(--nk-border)}.nk-emoji-cats span{font-size:14px;padding:3px 7px;border-radius:5px;cursor:pointer;color:var(--nk-text-tertiary);filter:grayscale(1);opacity:.6}.nk-emoji-cats span.active,.nk-emoji-cats span:hover{filter:none;opacity:1;background:var(--nk-bg-hover)}.nk-menu{padding:5px;width:230px}.nk-menu-item{display:flex;align-items:center;gap:9px;padding:4px 8px;min-height:28px;border-radius:5px;cursor:pointer;font-size:14px;user-select:none}.nk-menu-item:hover{background:var(--nk-bg-hover)}.nk-menu-item .m-icon,.nk-menu-item ::slotted(.m-icon),.nk-menu-item ::slotted([slot=icon]){width:17px;text-align:center;font-size:14px}.nk-menu-item .m-shortcut,.nk-menu-item ::slotted(.m-shortcut){margin-left:auto;font-size:12px;color:var(--nk-text-tertiary)}.nk-menu-item.danger{color:var(--nk-danger)}.nk-menu-sep{border-top:1px solid var(--nk-border);margin:5px 4px}.nk-menu-label{font-size:12px;color:var(--nk-text-tertiary);padding:5px 8px 2px}.nk-cmdk-backdrop{position:fixed;inset:0;background:var(--nk-scrim-soft);display:flex;justify-content:center;align-items:flex-start;padding:max(14vh,env(safe-area-inset-top,0px)) env(safe-area-inset-right,0) env(safe-area-inset-bottom,0) env(safe-area-inset-left,0);z-index:110;opacity:0;pointer-events:none;transition:opacity .18s}.nk-cmdk-backdrop.open{opacity:1;pointer-events:auto}.nk-cmdk{max-width:100%;width:min(560px,92vw);background:var(--nk-bg);border-radius:12px;box-shadow:var(--nk-shadow-menu);overflow:hidden;transform:scale(.98);transition:transform .18s}.nk-cmdk-backdrop.open .nk-cmdk{transform:scale(1)}.nk-cmdk-input-row{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--nk-border)}.nk-cmdk-input-row input{flex:1;border:none;outline:0;background:0 0;font-family:inherit;font-size:16px;color:var(--nk-text)}.nk-cmdk-input-row input::placeholder{color:var(--nk-text-tertiary)}.nk-cmdk-list{max-height:320px;overflow-y:auto;padding:6px}.nk-cmdk-group{font-size:12px;color:var(--nk-text-tertiary);padding:8px 10px 3px}.nk-cmdk-item{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer;font-size:14px;user-select:none}.nk-cmdk-item.selected{background:var(--nk-bg-active)}.nk-cmdk-item .m-icon,.nk-cmdk-item ::slotted(.m-icon),.nk-cmdk-item ::slotted([slot=icon]){width:17px;text-align:center;font-size:14px}.nk-cmdk-item .m-shortcut,.nk-cmdk-item ::slotted(.m-shortcut){margin-left:auto;font-size:12px;color:var(--nk-text-tertiary)}.nk-cmdk-empty{padding:30px;text-align:center;color:var(--nk-text-tertiary);font-size:13.5px}.nk-cmdk-footer{display:flex;gap:14px;padding:8px 16px;border-top:1px solid var(--nk-border);font-size:11.5px;color:var(--nk-text-tertiary)}.nk-toast{position:fixed;bottom:max(20px,calc(env(safe-area-inset-bottom,0px) + 12px));left:50%;transform:translateX(-50%) translateY(80px);z-index:120;width:max-content;max-width:calc(100% - 32px);background:var(--nk-text);color:var(--nk-bg);padding:8px 16px;border-radius:8px;font-size:14px;opacity:0;transition:.3s;pointer-events:none;box-shadow:var(--nk-shadow-menu);display:flex;gap:8px;align-items:center}.nk-toast.show{opacity:1;transform:translateX(-50%) translateY(0)}.nk-gallery-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr));gap:20px 32px;margin:12px 0}.nk-g-item>h4{font-size:12px;font-weight:500;color:var(--nk-text-tertiary);text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px}.nk-g-item ::slotted(h4){font-size:12px;font-weight:500;color:var(--nk-text-tertiary);text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px!important}.nk-tabs{display:flex;gap:2px;border-bottom:1px solid var(--nk-border);font-size:14px}.nk-tab{padding:7px 11px;cursor:pointer;color:var(--nk-text-secondary);border-bottom:2px solid transparent;margin-bottom:-1px;user-select:none}.nk-tab:hover{color:var(--nk-text)}.nk-tab.active{color:var(--nk-text);border-bottom-color:var(--nk-text);font-weight:500}.nk-tab-panel{padding:12px 2px;color:var(--nk-text-secondary);line-height:1.55;font-size:14px}.nk-template-btn{display:flex;align-items:center;gap:8px;width:100%;font-family:inherit;font-size:14px;color:var(--nk-text-secondary);background:var(--nk-bg-callout);border:none;border-radius:var(--nk-radius);padding:8px 12px;cursor:pointer;margin-bottom:6px;text-align:left}.nk-template-btn:hover{background:var(--nk-bg-hover)}.nk-stats{display:flex;gap:10px}.nk-stat{flex:1;border:1px solid var(--nk-border);border-radius:8px;padding:12px 14px}.nk-stat .s-label,.nk-stat ::slotted(.s-label),.nk-stat ::slotted([slot=label]){font-size:12px;color:var(--nk-text-secondary);margin-bottom:4px}.nk-stat .s-value,.nk-stat ::slotted(.s-value),.nk-stat ::slotted([slot=value]){font-size:22px;font-weight:600;letter-spacing:-.01em}.nk-stat .s-delta,.nk-stat ::slotted(.s-delta),.nk-stat ::slotted([slot=delta]){font-size:12px;margin-top:3px}.nk-stat .s-delta.up,.nk-stat ::slotted(.s-delta.up),.nk-stat ::slotted([slot=delta].up){color:var(--nk-color-green)}.nk-stat .s-delta.down,.nk-stat ::slotted(.s-delta.down),.nk-stat ::slotted([slot=delta].down){color:var(--nk-danger)}.nk-synced{border:1.5px solid color-mix(in srgb,var(--nk-danger) 55%,transparent);border-radius:8px;padding:12px 14px;position:relative;margin:8px 0}.nk-synced .synced-badge{position:absolute;top:-9px;right:10px;font-size:11px;background:var(--nk-danger);color:var(--nk-on-accent);border-radius:8px;padding:1px 8px}.nk-segmented{display:inline-flex;background:var(--nk-bg-callout);border-radius:7px;padding:2px}.nk-segmented button{font-family:inherit;font-size:14px;border:none;background:0 0;color:var(--nk-text-secondary);padding:4px 12px;border-radius:5px;cursor:pointer}.nk-segmented ::slotted(button){font-family:inherit;font-size:14px;border:none;background:0 0;color:var(--nk-text-secondary);padding:4px 12px!important;border-radius:5px;cursor:pointer}.nk-segmented ::slotted(button.active),.nk-segmented button.active{background:var(--nk-bg);color:var(--nk-text);font-weight:500;box-shadow:var(--nk-shadow-segment)}.nk-segmented.wrap{flex-wrap:wrap}.nk-segmented.scroll{max-width:100%;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}.nk-segmented.scroll::-webkit-scrollbar{display:none}.nk-segmented.scroll ::slotted(button),.nk-segmented.scroll button{flex-shrink:0;white-space:nowrap}.nk-banner{display:flex;align-items:center;gap:10px;font-size:14px;border-radius:8px;padding:10px 14px;margin-bottom:8px;color:var(--nk-text)}.nk-banner.info{background:var(--nk-tint-blue)}.nk-banner.success{background:var(--nk-tint-green)}.nk-banner.warning{background:var(--nk-tint-yellow)}.nk-banner.danger{background:var(--nk-tint-red)}.nk-banner .b-action,.nk-banner ::slotted(.b-action),.nk-banner ::slotted([slot=action]){margin-left:auto;font-weight:500;cursor:pointer;text-decoration:underline;text-underline-offset:2px}.nk-avatar-group{display:flex}.nk-avatar-group .mini-avatar,.nk-avatar-group ::slotted(.mini-avatar){width:26px;height:26px;border-radius:50%;color:var(--nk-on-accent);font-size:10.5px;font-weight:600;border:2px solid var(--nk-bg);display:flex;align-items:center;justify-content:center;margin-left:-7px}.nk-avatar-group .mini-avatar:first-child,.nk-avatar-group ::slotted(.mini-avatar:first-child){margin-left:0}.nk-avatar-group .more,.nk-avatar-group ::slotted(.more){background:var(--nk-bg-callout);color:var(--nk-text-secondary)}.nk-skeleton{border-radius:5px;margin-bottom:10px;background:linear-gradient(90deg,var(--nk-bg-callout) 25%,var(--nk-bg-hover) 50%,var(--nk-bg-callout) 75%);background-size:200% 100%;animation:1.6s infinite nk-shimmer}@keyframes nk-shimmer{to{background-position:-200% 0}}.nk-empty{text-align:center;padding:36px 20px;border:1.5px dashed var(--nk-border-strong);border-radius:10px;color:var(--nk-text-tertiary)}.nk-empty .e-icon,.nk-empty ::slotted(.e-icon),.nk-empty ::slotted([slot=icon]){font-size:30px;margin-bottom:8px}.nk-empty .e-title,.nk-empty ::slotted(.e-title),.nk-empty ::slotted([slot=title]){font-weight:500;color:var(--nk-text-secondary);margin-bottom:3px;font-size:14px}.nk-empty .e-desc,.nk-empty ::slotted(.e-desc),.nk-empty ::slotted([slot=desc]){font-size:13px;margin-bottom:12px}.nk-empty .e-actions,.nk-empty ::slotted(.e-actions){display:flex;flex-wrap:wrap;justify-content:center;gap:8px}.nk-comments{border-left:1px solid var(--nk-border);padding:4px 0 4px 18px;margin:8px 0 8px 8px}.nk-comment{display:flex;gap:9px;margin-bottom:14px}.nk-comment .mini-avatar,.nk-comment ::slotted(.mini-avatar),.nk-comment ::slotted([slot=avatar]){width:24px;height:24px;border-radius:50%;color:var(--nk-on-accent);flex-shrink:0;font-size:10px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-comment .c-head,.nk-comment ::slotted(.c-head){font-size:12px;color:var(--nk-text-tertiary);margin-bottom:2px}.nk-comment .c-head b{color:var(--nk-text);font-weight:600}.nk-comment .c-body,.nk-comment ::slotted(.c-body){font-size:14px;line-height:1.5}.nk-comment-input{display:flex;gap:8px;align-items:center;margin-top:4px}.nk-comment-input input{min-width:0;flex:1}.nk-ai-thread{display:flex;flex-direction:column;gap:14px}.nk-ai-msg{display:flex;gap:9px}.nk-ai-msg .mini-avatar,.nk-ai-msg ::slotted(.mini-avatar),.nk-ai-msg ::slotted([slot=avatar]){width:24px;height:24px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:12px;background:var(--nk-bg-callout)}.nk-ai-msg.user .mini-avatar,.nk-ai-msg.user ::slotted(.mini-avatar),.nk-ai-msg.user ::slotted([slot=avatar]){background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:9.5px;font-weight:600}.nk-ai-msg .a-body,.nk-ai-msg ::slotted(.a-body){font-size:14px;line-height:1.55;padding-top:2px}.nk-ai-msg .a-name,.nk-ai-msg ::slotted(.a-name){font-size:12px;font-weight:600;margin-bottom:2px}.nk-ai-msg .a-name span{color:var(--nk-text-tertiary);font-weight:400}.nk-ai-actions{display:flex;gap:4px;margin-top:6px}.nk-ai-actions button{font-family:inherit;font-size:12px;color:var(--nk-text-secondary);background:0 0;border:1px solid var(--nk-border);border-radius:5px;padding:2px 8px;cursor:pointer}.nk-ai-actions ::slotted(button){font-family:inherit;font-size:12px;color:var(--nk-text-secondary);background:0 0;border:1px solid var(--nk-border);border-radius:5px;padding:2px 8px!important;cursor:pointer}.nk-ai-actions ::slotted(button:hover),.nk-ai-actions button:hover{background:var(--nk-bg-hover);color:var(--nk-text)}.nk-ai-input-row{display:flex;align-items:center;gap:8px;margin-top:14px;border:1px solid var(--nk-border-strong);border-radius:10px;padding:8px 12px}.nk-ai-input-row:focus-within{border-color:var(--nk-accent)}.nk-ai-input-row input{flex:1;border:none;outline:0;background:0 0;font-family:inherit;font-size:14px;color:var(--nk-text);min-width:0}.nk-ai-input-row input::placeholder{color:var(--nk-text-tertiary)}.nk-ai-send{border:none;background:var(--nk-accent);color:var(--nk-on-accent);border-radius:6px;width:26px;height:26px;cursor:pointer;font-size:13px;flex-shrink:0}.nk-block-host{position:relative;border-radius:var(--nk-radius);margin:8px 0;padding:2px 0 2px 2px;transition:background .15s,box-shadow .15s}.nk-block-host:hover{background:var(--nk-bg-hover)}.nk-block-host:focus-within{background:0 0;box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 25%,transparent)}.nk-block-host.nk-drop-target{box-shadow:0 -2px 0 0 var(--nk-accent);background:0 0}.nk-block-host .nk-block-handle,.nk-block-host ::slotted(.nk-block-handle){position:absolute;left:-26px;top:4px;width:18px;height:20px;border-radius:4px;display:flex;align-items:center;justify-content:center;color:var(--nk-text-tertiary);font-size:13px;cursor:grab;opacity:0;transition:opacity .15s;user-select:none}.nk-block-host:hover .nk-block-handle{opacity:1}.nk-block-host .nk-block-actions{position:absolute;display:flex;gap:1px;z-index:2;opacity:0;transition:opacity .15s;pointer-events:none}.nk-block-host .nk-block-actions.show{opacity:1;pointer-events:auto}.nk-block-host .nk-block-actions ::slotted(button),.nk-block-host .nk-block-actions button{width:20px;height:22px;padding:0;border:none;border-radius:4px;background:0 0;color:var(--nk-text-tertiary);font-family:inherit;font-size:14px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}.nk-block-host .nk-block-actions button:hover{background:var(--nk-bg-hover);color:var(--nk-text)}.nk-block-host .nk-block-actions .drag{cursor:grab}.nk-block-host .nk-block-actions .drag:active{cursor:grabbing}.nk-block-host .ProseMirror{outline:0;font-family:var(--nk-font);font-size:14px;line-height:1.6;color:var(--nk-text);min-height:60px;padding:4px 2px}.nk-block-host .ProseMirror>*+*{margin-top:6px}.nk-block-host .ProseMirror h1{font-size:30px;font-weight:600;letter-spacing:-.01em;margin:24px 0 6px}.nk-block-host .ProseMirror h2{font-size:22px;font-weight:600;margin:20px 0 6px}.nk-block-host .ProseMirror h3{font-size:17px;font-weight:600;margin:16px 0 4px}.nk-block-host .ProseMirror p{margin:0}.nk-block-host .ProseMirror ol,.nk-block-host .ProseMirror ul{padding-left:24px;margin:4px 0}.nk-block-host .ProseMirror ul{list-style:disc}.nk-block-host .ProseMirror ol{list-style:decimal}.nk-block-host .ProseMirror li{margin:2px 0}.nk-block-host .ProseMirror li::marker{color:var(--nk-text-tertiary)}.nk-block-host .ProseMirror ul[data-type=taskList]{list-style:none;padding-left:2px}.nk-block-host .ProseMirror ul[data-type=taskList] li{display:flex;gap:8px;align-items:flex-start}.nk-block-host .ProseMirror ul[data-type=taskList] li>label{flex-shrink:0;margin-top:3px;user-select:none}.nk-block-host .ProseMirror ul[data-type=taskList] li>div{flex:1;min-width:0}.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]{appearance:none;width:16px;height:16px;margin:0;border:1.4px solid var(--nk-border-strong);border-radius:2px;cursor:pointer;position:relative;background:var(--nk-bg);display:block}.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]:checked::after{content:\"✓\";color:var(--nk-on-accent);font-size:11px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-block-host .ProseMirror li[data-checked=true]>div{text-decoration:line-through;color:var(--nk-text-tertiary)}.nk-block-host .ProseMirror-gapcursor::after{border-top-color:var(--nk-text)}.nk-block-host .ProseMirror .ProseMirror-selectednode{background:color-mix(in srgb,var(--nk-accent) 8%,transparent)}.nk-block-host .ProseMirror blockquote{border-left:3px solid var(--nk-text);padding:2px 0 2px 14px;margin:12px 0;color:var(--nk-text-secondary)}.nk-block-host .ProseMirror code{font-family:var(--nk-font-mono);font-size:85%;color:var(--nk-danger);background:color-mix(in srgb,var(--nk-danger) 8%,transparent);border-radius:4px;padding:1px 5px}.nk-block-host .ProseMirror pre{background:var(--nk-bg-code);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:16px 20px;margin:12px 0;font-family:var(--nk-font-mono);font-size:13px;line-height:1.6;color:var(--nk-text-secondary);overflow-x:auto}.nk-block-host .ProseMirror pre code{background:0 0;color:inherit;padding:0;font-size:inherit}.nk-block-host .ProseMirror hr{border:none;border-top:1px solid var(--nk-border);margin:20px 0}.nk-block-host .ProseMirror a{color:var(--nk-accent);text-decoration:underline;text-underline-offset:2px}.nk-block-host .ProseMirror-selectednode{box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 35%,transparent);border-radius:3px}.nk-block-host .ProseMirror ::selection{background:color-mix(in srgb,var(--nk-accent) 25%,transparent)}.nk-block-host .ProseMirror .is-empty::before,.nk-block-host .ProseMirror p.is-editor-empty:first-child::before{content:attr(data-placeholder);color:var(--nk-text-tertiary);float:left;height:0;pointer-events:none}.nk-block-host .bn-container{font-family:var(--nk-font);color:var(--nk-text);background:0 0}.nk-block-host .bn-editor{padding:4px 2px}.nk-block-host .bn-block-content{font-size:14px;line-height:1.6}.nk-block-host .bn-side-menu{color:var(--nk-text-tertiary)}.nk-block-host .bn-drag-handle{border-radius:4px}.nk-block-host .bn-drag-handle:hover{background:var(--nk-bg-hover)}.nk-block-host .novel-editor{font-family:var(--nk-font);color:var(--nk-text)}.nk-block-host .novel-prose{max-width:none}.nk-block-host .bn-suggestion-menu,.nk-block-host .tippy-box,.nk-slash-menu{background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);padding:6px;width:280px;max-height:320px;overflow-y:auto;font-family:var(--nk-font);font-size:14px;color:var(--nk-text)}.nk-slash-menu-label{font-size:12px;color:var(--nk-text-tertiary);padding:6px 9px 2px}.nk-slash-item{display:flex;align-items:center;gap:10px;padding:6px 9px;border-radius:5px;cursor:pointer;user-select:none}.nk-slash-item.selected,.nk-slash-item:hover{background:var(--nk-bg-hover)}.nk-slash-item .m-icon,.nk-slash-item ::slotted(.m-icon){width:28px;height:28px;flex-shrink:0;border-radius:4px;background:var(--nk-bg-callout);border:1px solid var(--nk-border);display:flex;align-items:center;justify-content:center;font-size:15px}.nk-slash-item .m-desc{font-size:12px;color:var(--nk-text-tertiary)}.nk-bubble-menu{display:flex;align-items:center;gap:2px;background:var(--nk-bg);border-radius:8px;box-shadow:var(--nk-shadow-menu);padding:4px}.nk-bubble-menu button{font-family:inherit;font-size:13px;border:none;background:0 0;color:var(--nk-text-secondary);padding:4px 8px;border-radius:5px;cursor:pointer}.nk-bubble-menu ::slotted(button){font-family:inherit;font-size:13px;border:none;background:0 0;color:var(--nk-text-secondary);padding:4px 8px!important;border-radius:5px;cursor:pointer}.nk-bubble-menu ::slotted(button:hover),.nk-bubble-menu button:hover{background:var(--nk-bg-hover);color:var(--nk-text)}.nk-bubble-menu ::slotted(button.active),.nk-bubble-menu button.active{color:var(--nk-accent)}@media (max-width:860px){.nk-sidebar{display:none}.nk-tab-bar{display:flex}.nk-tab-bar.fixed+.nk-tab-bar-spacer{display:block}.nk-page{padding-left:max(24px,env(safe-area-inset-left,0px));padding-right:max(24px,env(safe-area-inset-right,0px));padding-bottom:80px}.nk-settings-nav{width:60px;min-width:60px}.nk-settings-nav .label,.nk-settings-nav .nk-section-label,.nk-settings-user .u-text{display:none}.nk-settings-content{padding:24px}.nk-cmdk-backdrop{padding-top:max(6vh,env(safe-area-inset-top,0px))}.nk-cmdk{width:min(560px,96vw)}.nk-stats{flex-wrap:wrap}.nk-breadcrumb{min-width:0}.nk-breadcrumb ::slotted(.crumb:not(:last-child)),.nk-breadcrumb ::slotted(.sep),.nk-breadcrumb>.crumb:not(:last-child),.nk-breadcrumb>.sep,.nk-topbar-actions ::slotted(.nk-topbar-meta),.nk-topbar-meta{display:none}.nk-breadcrumb ::slotted(.crumb:last-child),.nk-breadcrumb>.crumb:last-child{display:block;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nk-topbar-actions{flex-shrink:0}.nk-field{flex-wrap:wrap;row-gap:6px}.nk-field .f-control,.nk-field ::slotted(.f-control){max-width:100%;min-width:0}.nk-input,.nk-select,.nk-slider,.nk-textarea{max-width:100%}:root:has(.nk-tab-bar:not([hidden])) .nk-toast{bottom:calc(var(--nk-tab-bar-height) + max(6px,env(safe-area-inset-bottom,0px)) + 6px)}:root:has(.nk-tab-bar.floating:not([hidden])) .nk-toast{bottom:calc(var(--nk-tab-bar-height) + 24px + env(safe-area-inset-bottom,0px))}}@media (prefers-reduced-motion:reduce){.nk-skeleton{animation:none;background:var(--nk-bg-callout)}[class*=nk-],[class*=nk-]::after,[class*=nk-]::before{animation-duration:NaNs!important;animation-iteration-count:1!important;transition-duration:NaNs!important;scroll-behavior:auto!important}}\n/*# sourceMappingURL=notionkit.min.css.map */";
8
+ const componentsHead = "[class*=nk-],[class*=nk-] *,[class*=nk-]:before,[class*=nk-]:after,[class*=nk-] *:before,[class*=nk-] *:after{box-sizing:border-box}[class*=nk-] :where(h1,h2,h3,h4,h5,h6,p,figure,blockquote,dl,dd,pre,ul,ol,li){margin:0;padding:0}[class*=nk-] :where(ul,ol){list-style:none}[class*=nk-] :where(button,input,select,textarea,option,optgroup,fieldset,legend),:where(button,input,select,textarea)[class*=nk-]{margin:0;padding:0}[class*=nk-][hidden]:not([hidden=until-found i]){display:none!important}::slotted([hidden]:not([hidden=\"until-found\" i])){display:none!important}";
9
+ const componentsTail = ".nk-body{margin:0;min-height:100vh;min-height:100dvh;font-family:var(--nk-font);font-size:14px;background:var(--nk-bg);color:var(--nk-text);-webkit-font-smoothing:auto;transition:background .25s ease,color .25s ease}.nk-app{display:flex;height:100vh;height:100dvh;overflow:hidden}.nk-sidebar{width:calc(var(--nk-sidebar-width) + env(safe-area-inset-left,0px));min-width:calc(var(--nk-sidebar-width) + env(safe-area-inset-left,0px));padding-left:env(safe-area-inset-left,0px);background:var(--nk-bg-sidebar);display:flex;flex-direction:column;border-right:1px solid var(--nk-border);transition:background .25s ease}.nk-workspace{display:flex;align-items:center;gap:8px;padding:10px 12px;margin:6px 8px 2px;border-radius:var(--nk-radius);cursor:pointer;font-weight:500;user-select:none}.nk-workspace:hover{background:var(--nk-bg-hover)}.nk-workspace .avatar,.nk-workspace ::slotted(.avatar),.nk-workspace ::slotted([slot=\"avatar\"]){width:22px;height:22px;border-radius:4px;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:11px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-workspace .chev{margin-left:auto;color:var(--nk-text-tertiary);font-size:11px}.nk-sidebar-scroll{flex:1;overflow-y:auto;padding:4px 8px 16px}.nk-sidebar-scroll::-webkit-scrollbar{width:8px}.nk-sidebar-scroll::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:4px}.nk-section-label{font-size:12px;font-weight:500;letter-spacing:.01em;color:var(--nk-text-tertiary);padding:14px 10px 4px;display:flex;justify-content:space-between;align-items:center}.nk-section-label .plus{cursor:pointer;border-radius:4px;padding:0 4px;font-size:13px;opacity:0;transition:opacity .15s}.nk-section-label:hover .plus{opacity:1}.nk-section-label .plus:hover{background:var(--nk-bg-hover)}.nk-sidebar-footer{padding:8px;border-top:1px solid var(--nk-border);color:var(--nk-text-sidebar);font-size:14px}.nk-sidebar-footer .nk-tree-item{min-height:26px}.nk-sidebar-backdrop{display:none;position:fixed;inset:0;z-index:59;background:var(--nk-scrim-soft)}.nk-sidebar-toggle{display:none}.nk-main{flex:1;display:flex;flex-direction:column;min-width:0}.nk-topbar{height:44px;display:flex;align-items:center;padding:0 max(12px,env(safe-area-inset-right,0px)) 0 max(12px,env(safe-area-inset-left,0px));gap:8px;flex-shrink:0}.nk-breadcrumb{display:flex;align-items:center;gap:4px;font-size:14px}.nk-breadcrumb .crumb,.nk-breadcrumb ::slotted(.crumb){padding:2px 6px;border-radius:4px;cursor:pointer;color:var(--nk-text-sidebar);display:flex;align-items:center;gap:5px}.nk-breadcrumb .crumb:hover{background:var(--nk-bg-hover)}a.crumb{text-decoration:none}.nk-breadcrumb .crumb.current,.nk-breadcrumb ::slotted(.crumb.current){color:var(--nk-text)}.nk-breadcrumb .sep{color:var(--nk-text-tertiary);font-size:12px}.nk-topbar-actions{margin-left:auto;display:flex;align-items:center;gap:4px}.nk-topbar-btn{padding:4px 8px;border-radius:var(--nk-radius);cursor:pointer;color:var(--nk-text-sidebar);font-size:14px;user-select:none;border:none;background:transparent;font-family:inherit}.nk-topbar-btn:hover{background:var(--nk-bg-hover)}.nk-topbar-btn svg,.nk-topbar-btn ::slotted(svg){width:16px;height:16px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.nk-share-btn{font-size:14px;padding:4px 8px}.nk-topbar-meta,.nk-topbar-actions ::slotted(.nk-topbar-meta){padding:4px 8px;font-size:12px;color:var(--nk-text-tertiary);white-space:nowrap}.nk-theme-toggle{font-size:15px;width:30px;height:28px;padding:0}.nk-tab-bar{display:none;flex:none;align-items:stretch;gap:2px;position:sticky;bottom:0;z-index:30;box-sizing:border-box;height:calc(var(--nk-tab-bar-height) - 6px + max(6px,env(safe-area-inset-bottom,0px)));padding:6px max(4px,env(safe-area-inset-right,0px)) max(6px,env(safe-area-inset-bottom,0px)) max(4px,env(safe-area-inset-left,0px));background:var(--nk-bg-sidebar);border-top:1px solid var(--nk-border)}.nk-tab-bar.always{display:flex}.nk-tab-bar.fixed{position:fixed;left:0;right:0;bottom:0}.nk-tab-bar-spacer{display:none;flex:none;height:calc(var(--nk-tab-bar-height) - 6px + max(6px,env(safe-area-inset-bottom,0px)))}.nk-tab-bar.always.fixed+.nk-tab-bar-spacer{display:block}.nk-tab-bar.floating{position:fixed;left:max(12px,env(safe-area-inset-left,0px));right:max(12px,env(safe-area-inset-right,0px));bottom:calc(12px + env(safe-area-inset-bottom,0px));height:var(--nk-tab-bar-height);padding:6px;border:1px solid var(--nk-border);border-radius:16px;box-shadow:var(--nk-shadow-menu)}.nk-tab-bar-item{flex:1 1 0;min-width:0;display:flex;flex-direction:column;align-items:center;justify-content:center;gap:2px;padding:4px 2px;border:none;border-radius:var(--nk-radius);background:transparent;font-family:inherit;font-size:10.5px;line-height:1.2;color:var(--nk-text-secondary);text-decoration:none;cursor:pointer;user-select:none;-webkit-tap-highlight-color:transparent}.nk-tab-bar-item:hover{color:var(--nk-text);background:var(--nk-bg-hover)}.nk-tab-bar-item.active{color:var(--nk-accent)}.nk-tab-bar-item:disabled{opacity:.5;cursor:not-allowed}.nk-tab-bar-item .icon,.nk-tab-bar-item ::slotted([slot=\"icon\"]){font-size:20px;line-height:1}.nk-tab-bar-item .label,.nk-tab-bar-item ::slotted(.label){max-width:100%;overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nk-tree-item{display:flex;align-items:center;gap:6px;padding:3px 8px 3px 10px;border-radius:var(--nk-radius);cursor:pointer;user-select:none;color:var(--nk-text-sidebar);position:relative;min-height:var(--_nk-row, 28px)}.nk-tree-item:hover{background:var(--nk-bg-hover)}.nk-tree-item.active{background:var(--nk-bg-active);color:var(--nk-text);font-weight:500}.nk-tree-item.compact{min-height:26px}.nk-tree-item .icon,.nk-tree-item ::slotted(.icon),.nk-tree-item ::slotted([slot=\"icon\"]){font-size:15px;width:20px;text-align:center;flex-shrink:0}.nk-tree-item .label,.nk-tree-item ::slotted(.label){white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nk-tree-item .actions{margin-left:auto;display:none;gap:2px;color:var(--nk-text-tertiary)}.nk-tree-item:hover .actions{display:flex}.nk-tree-item .actions span{padding:0 3px;border-radius:3px;font-size:12px}.nk-tree-item .actions span:hover{background:var(--nk-bg-active)}.nk-tree-children{margin-left:14px;border-left:1px solid var(--nk-border);padding-left:4px;overflow:hidden}.nk-tree-children.collapsed{display:none}.nk-toggle-arrow{width:16px;height:16px;flex-shrink:0;display:inline-flex;align-items:center;justify-content:center;font-size:9px;color:var(--nk-text-tertiary);border-radius:3px;transition:transform .15s}.nk-toggle-arrow.open{transform:rotate(90deg)}.nk-kbd-hint{margin-left:auto;display:flex;gap:3px;align-items:center}.nk-kbd{font-family:inherit;font-size:10.5px;background:var(--nk-bg-callout);border:1px solid var(--nk-border-strong);border-bottom-width:2px;border-radius:4px;padding:0 4px}.nk-page-scroll{flex:1;overflow-y:auto}.nk-page-scroll::-webkit-scrollbar{width:10px}.nk-page-scroll::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:5px;border:2px solid var(--nk-bg)}.nk-cover{height:200px;background:radial-gradient(ellipse at 20% 40%,color-mix(in srgb,var(--nk-decor-purple) 35%,transparent),transparent 55%),radial-gradient(ellipse at 80% 20%,color-mix(in srgb,var(--nk-decor-blue) 35%,transparent),transparent 55%),radial-gradient(ellipse at 60% 90%,color-mix(in srgb,var(--nk-decor-orange) 25%,transparent),transparent 55%),var(--nk-bg-callout)}.nk-cover>img,.nk-cover ::slotted(img){display:block;width:100%;height:100%;object-fit:cover}.nk-page{max-width:760px;margin:0 auto;padding:24px max(64px,env(safe-area-inset-right,0px)) 120px max(64px,env(safe-area-inset-left,0px));font-size:16px;line-height:1.5}.nk-page.full{max-width:none}.nk-page.small{font-size:14px}.nk-cover+.nk-page,.nk-page.covered{padding-top:0}.nk-page-icon,.nk-page ::slotted(.nk-page-icon),.nk-page ::slotted([slot=\"icon\"]){font-size:64px;line-height:1;margin-top:0;cursor:pointer;user-select:none;display:inline-block}.nk-cover+.nk-page .nk-page-icon,.nk-cover+.nk-page ::slotted(.nk-page-icon),.nk-cover+.nk-page ::slotted([slot=\"icon\"]),.nk-page.covered .nk-page-icon,.nk-page.covered ::slotted(.nk-page-icon),.nk-page.covered ::slotted([slot=\"icon\"]){margin-top:-42px}.nk-page-title{font-size:40px;font-weight:700;line-height:1.2;margin:8px 0 4px;outline:none;letter-spacing:0}.nk-page-meta{color:var(--nk-text-tertiary);font-size:13px;margin-bottom:24px;display:flex;gap:16px}.nk-props{display:flex;flex-direction:column;margin:0 0 20px;font-size:14px;line-height:1.5}.nk-prop{display:flex;align-items:flex-start;min-width:0}.nk-prop .p-name{flex:0 0 160px;min-width:0;min-height:34px;padding:0 6px;display:flex;align-items:center;gap:6px;overflow:hidden;border-radius:var(--nk-radius);color:var(--nk-text-secondary);white-space:nowrap;user-select:none}.nk-prop .p-icon,.nk-prop ::slotted([slot=\"icon\"]){width:16px;flex-shrink:0;text-align:center;font-size:13px}.nk-prop .p-value{flex:1 1 auto;min-width:0;min-height:34px;padding:5px 8px;display:flex;align-items:center;flex-wrap:wrap;gap:4px 6px;border-radius:var(--nk-radius);overflow-wrap:anywhere}.nk-prop .p-name:hover,.nk-prop .p-value:hover{background:var(--nk-bg-hover)}.nk-page p.lead{font-size:1em;line-height:1.6;color:var(--nk-text-secondary);margin-bottom:20px}.nk-page ::slotted(p.lead){font-size:1em;line-height:1.6;color:var(--nk-text-secondary);margin-bottom:20px!important}.nk-heading{font-size:1.5em;font-weight:600;line-height:1.3;margin:32px 0 10px;display:flex;align-items:center;gap:8px}.nk-callout{display:flex;gap:10px;align-items:flex-start;background:var(--nk-bg-callout);border-radius:var(--nk-radius);padding:16px 16px 16px 12px;margin:16px 0;line-height:1.5}.nk-callout .c-icon,.nk-callout ::slotted(.c-icon),.nk-callout ::slotted([slot=\"icon\"]){font-size:17px}.nk-todo{display:flex;align-items:flex-start;gap:8px;padding:4px 0}.nk-todo input[type=checkbox]{appearance:none;width:16px;height:16px;margin-top:3px;border:1.4px solid var(--nk-border-strong);border-radius:2px;cursor:pointer;flex-shrink:0;position:relative;background:var(--nk-bg)}.nk-todo input[type=checkbox]:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-todo input[type=checkbox]:checked:after{content:\"\\2713\";color:var(--nk-on-accent);font-size:11px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-todo input:checked+span{text-decoration:line-through;color:var(--nk-text-tertiary)}.nk-todo input:disabled{opacity:.5;cursor:not-allowed}.nk-toggle{margin:6px 0}.nk-toggle summary{cursor:pointer;list-style:none;display:flex;align-items:center;gap:6px;padding:4px 6px;border-radius:var(--nk-radius);font-weight:500;user-select:none}.nk-toggle summary::-webkit-details-marker{display:none}.nk-toggle summary:hover{background:var(--nk-bg-hover)}.nk-toggle summary:before{content:\"\\25b8\";color:var(--nk-text-tertiary);font-size:11px;transition:transform .15s;display:inline-block}.nk-toggle[open] summary:before{transform:rotate(90deg)}.nk-toggle .toggle-body,.nk-toggle ::slotted(.toggle-body){padding:4px 0 8px 26px;color:var(--nk-text-secondary);line-height:1.55}.nk-divider{border:none;border-top:1px solid var(--nk-border);margin:24px 0}.nk-quote{border-left:3px solid var(--nk-text);padding:2px 0 2px 14px;margin:16px 0;color:var(--nk-text-secondary);line-height:1.5}.nk-quote .q-cite{display:block;margin-top:6px;font-size:12.5px;color:var(--nk-text-tertiary)}.nk-mention{display:inline-flex;align-items:center;gap:4px;padding:0 4px;border-radius:4px;font-weight:500;cursor:pointer;white-space:nowrap}.nk-mention:hover{background:var(--nk-bg-hover)}.nk-mention.person{color:var(--nk-text)}.nk-mention.person .mini-avatar,.nk-mention.person .nk-avatar,.nk-mention.person ::slotted(.mini-avatar),.nk-mention.person ::slotted([slot=\"avatar\"]){width:16px;height:16px;border-radius:50%;color:var(--nk-on-accent);font-size:8.5px;font-weight:600;display:inline-flex;align-items:center;justify-content:center}.nk-mention.page{color:var(--nk-text-secondary);text-decoration:underline;text-decoration-color:var(--nk-border-strong);text-underline-offset:2px}.nk-mention.date{color:var(--nk-color-orange)}.nk-inline-code{font-family:var(--nk-font-mono);font-size:85%;color:var(--nk-danger);background:color-mix(in srgb,var(--nk-danger) 8%,transparent);border-radius:4px;padding:1px 5px}.nk-code{background:var(--nk-bg-code);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:20px 24px;font-family:var(--nk-font-mono);font-size:13px;line-height:1.6;margin:14px 0;overflow-x:auto;color:var(--nk-text-secondary);white-space:pre;position:relative}.nk-code .lang{position:absolute;top:6px;right:10px;font-size:11px;color:var(--nk-text-tertiary);font-family:var(--nk-font)}.nk-code .tag,.nk-code ::slotted(.tag){color:var(--nk-accent)}.nk-code .attr,.nk-code ::slotted(.attr){color:var(--nk-color-orange)}.nk-database{margin:12px 0 8px}.nk-db-tabs{display:flex;gap:2px;align-items:center;padding:0 0 6px;margin-bottom:0;font-size:14px}.nk-db-tab{padding:4px 8px;cursor:pointer;color:var(--nk-text-secondary);border-radius:var(--nk-radius);user-select:none;line-height:20px;display:flex;align-items:center;gap:6px;flex-shrink:0;white-space:nowrap}.nk-db-tab:hover{color:var(--nk-text);background:var(--nk-bg-hover)}.nk-db-tab.active{color:var(--nk-text);background:var(--nk-bg-active);font-weight:500}.nk-db-tab.add{color:var(--nk-text-tertiary)}.nk-db-tab .badge,.nk-db-tab ::slotted(.badge){background:var(--nk-bg-callout);border-radius:8px;font-size:11px;padding:0 6px;color:var(--nk-text-tertiary)}.nk-db-toolbar{display:flex;align-items:center;gap:8px;min-width:0;padding-bottom:6px}.nk-db-toolbar>.nk-db-tabs{flex:1 1 auto;min-width:0;padding-bottom:0;overflow-x:auto;scrollbar-width:none}.nk-db-toolbar>.nk-db-tabs::-webkit-scrollbar{display:none}.nk-db-toolbar .tools{flex:none;display:flex;align-items:center;gap:4px;margin-left:auto}.nk-db-tool{display:inline-flex;align-items:center;gap:4px;height:28px;padding:0 8px;border:none;border-radius:var(--nk-radius);background:transparent;font-family:inherit;font-size:14px;color:var(--nk-text-secondary);white-space:nowrap;cursor:pointer;user-select:none}.nk-db-tool:hover{background:var(--nk-bg-hover);color:var(--nk-text)}.nk-db-tool.active{color:var(--nk-accent)}.nk-filter-row{display:flex;align-items:center;flex-wrap:wrap;gap:6px;padding:2px 0 8px}.nk-filter-pill{display:inline-flex;align-items:center;gap:4px;height:24px;padding:0 8px;border:1px solid var(--nk-border-strong);border-radius:12px;background:transparent;font-family:inherit;font-size:13px;line-height:1;color:var(--nk-text-secondary);white-space:nowrap;cursor:pointer;user-select:none}.nk-filter-pill:hover{background:var(--nk-bg-hover)}.nk-filter-pill.active{color:var(--nk-accent);border-color:color-mix(in srgb,var(--nk-accent) 35%,transparent);background:color-mix(in srgb,var(--nk-accent) 6%,transparent)}.nk-filter-pill.add{border-color:transparent;color:var(--nk-text-tertiary)}.nk-filter-pill.add:hover{color:var(--nk-text-secondary)}.nk-filter-pill button{padding:0;border:none;background:none;font:inherit;color:inherit;cursor:pointer}.nk-filter-pill .fp-remove{display:inline-flex;align-items:center;justify-content:center;width:16px;height:16px;margin-right:-4px;border-radius:50%;font-size:13px}.nk-filter-pill .fp-remove:hover{background:color-mix(in srgb,currentColor 15%,transparent)}.nk-table-wrap{overflow-x:auto}.nk-table{width:100%;border-collapse:collapse;font-size:14px}.nk-table th{text-align:left;font-weight:400;color:var(--nk-text-secondary);height:36px;padding:0 8px;border-bottom:1px solid var(--nk-border);border-right:1px solid var(--nk-border);font-size:14px;white-space:nowrap;user-select:none;cursor:pointer}.nk-table th:hover{background:var(--nk-bg-hover)}.nk-table th .th-icon,.nk-table th ::slotted(.th-icon){margin-right:6px;font-size:13px;color:var(--nk-text-tertiary)}.nk-table td{height:36px;padding:6px 8px;line-height:1.5;border-bottom:1px solid var(--nk-border);border-right:1px solid var(--nk-border);white-space:nowrap;vertical-align:middle}.nk-table th:last-child,.nk-table td:last-child{border-right:none}.nk-table.wrap td,.nk-table td.wrap{white-space:normal;vertical-align:top}.nk-table tbody tr:hover{background:var(--nk-bg-hover)}.nk-table .row-title{display:flex;align-items:center;gap:7px;font-weight:500;cursor:pointer}.nk-table .row-title:hover{text-decoration:underline;text-decoration-color:var(--nk-text-tertiary)}.nk-table .date-cell{color:var(--nk-text-secondary)}.nk-table .num{text-align:right;font-variant-numeric:tabular-nums}.nk-table .person-cell{display:flex;align-items:center;gap:6px;color:var(--nk-text-secondary)}.nk-table .person-cell .mini-avatar,.nk-table .person-cell ::slotted(.mini-avatar){width:20px;height:20px;border-radius:50%;font-size:10px;color:var(--nk-on-accent);display:inline-flex;align-items:center;justify-content:center;font-weight:600}.nk-new-row,.nk-table .new-row{color:var(--nk-text-tertiary);cursor:pointer;padding:8px;display:flex;align-items:center;gap:7px;font-size:14px}.nk-new-row:hover,.nk-table .new-row:hover{background:var(--nk-bg-hover)}.nk-tag{display:inline-flex;align-items:center;max-width:100%;height:20px;padding:0 6px;border-radius:3px;font-size:14px;font-weight:400;line-height:20px;white-space:nowrap;overflow:hidden;text-overflow:ellipsis;vertical-align:middle;background:var(--nk-tag-gray-bg);color:var(--nk-tag-gray-text)}.nk-tag.gray{background:var(--nk-tag-gray-bg);color:var(--nk-tag-gray-text)}.nk-tag.brown{background:var(--nk-tag-brown-bg);color:var(--nk-tag-brown-text)}.nk-tag.orange{background:var(--nk-tag-orange-bg);color:var(--nk-tag-orange-text)}.nk-tag.yellow{background:var(--nk-tag-yellow-bg);color:var(--nk-tag-yellow-text)}.nk-tag.green{background:var(--nk-tag-green-bg);color:var(--nk-tag-green-text)}.nk-tag.blue{background:var(--nk-tag-blue-bg);color:var(--nk-tag-blue-text)}.nk-tag.purple{background:var(--nk-tag-purple-bg);color:var(--nk-tag-purple-text)}.nk-tag.pink{background:var(--nk-tag-pink-bg);color:var(--nk-tag-pink-text)}.nk-tag.red{background:var(--nk-tag-red-bg);color:var(--nk-tag-red-text)}.nk-progress{width:110px;height:6px;border-radius:3px;background:var(--nk-tint-blue);overflow:hidden;display:inline-block}.nk-progress>i{display:block;height:100%;background:var(--nk-color-blue);border-radius:3px}.nk-progress.wide{width:100%;flex:1 1 60px}.nk-progress-label{font-size:12px;color:var(--nk-text-tertiary);margin-left:7px;white-space:nowrap}.nk-list{display:flex;flex-direction:column;font-size:14px}.nk-list-item{display:flex;align-items:center;gap:8px;min-width:0;overflow:hidden;min-height:36px;padding:4px 6px;border-bottom:1px solid var(--nk-border);color:inherit;text-decoration:none;cursor:pointer}.nk-list-item:hover{background:var(--nk-bg-hover)}.nk-list>.nk-list-item:last-child,.nk-list ::slotted(.nk-list-item:last-child),.nk-list-item.last{border-bottom:none}.nk-list-item .l-icon,.nk-list-item ::slotted([slot=\"icon\"]){width:20px;flex-shrink:0;text-align:center;font-size:15px}.nk-list-item .l-title,.nk-list-item ::slotted(.l-title){flex:1 1 auto;min-width:0;font-weight:500;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nk-list-item .l-meta,.nk-list-item ::slotted(.l-meta){flex:none;display:flex;align-items:center;gap:8px;margin-left:auto;font-size:12px;color:var(--nk-text-secondary);white-space:nowrap}.nk-board{display:none;gap:12px;padding:14px 2px;overflow-x:auto}.nk-board.active{display:flex}.nk-board-col{min-width:220px;width:220px;flex-shrink:0}.nk-board-col-header{display:flex;align-items:center;gap:7px;margin-bottom:8px;font-size:13.5px;font-weight:500}.nk-board-col-header .count{color:var(--nk-text-tertiary);font-weight:400}.nk-card{background:var(--nk-bg-card);border:1px solid var(--nk-border);border-radius:8px;padding:10px 12px;margin-bottom:8px;cursor:grab;box-shadow:var(--nk-shadow-card);transition:border-color .15s}.nk-card:hover{border-color:var(--nk-border-strong)}.nk-card .card-title,.nk-card ::slotted(.card-title){font-weight:500;margin-bottom:7px;display:flex;gap:6px;align-items:center}.nk-card .card-meta,.nk-card ::slotted(.card-meta){display:flex;gap:6px;flex-wrap:wrap;align-items:center;font-size:12px;color:var(--nk-text-secondary)}.nk-field{display:flex;align-items:center;justify-content:space-between;gap:24px;padding:9px 0}.nk-field .f-label,.nk-field ::slotted(.f-label),.nk-field ::slotted([slot=\"label\"]){font-size:14px}.nk-field .f-desc,.nk-field ::slotted(.f-desc),.nk-field ::slotted([slot=\"desc\"]){font-size:12px;color:var(--nk-text-secondary);margin-top:2px;line-height:1.45}.nk-field .f-control,.nk-field ::slotted(.f-control){flex-shrink:0}.nk-field.stacked,.nk-fields>.nk-field{flex-direction:column;align-items:stretch;gap:6px;min-width:0}.nk-field.stacked .f-control,.nk-fields>.nk-field .f-control{width:100%;min-width:0}.nk-field.stacked .nk-input,.nk-field.stacked .nk-textarea,.nk-field.stacked .nk-select,.nk-fields>.nk-field .nk-input,.nk-fields>.nk-field .nk-textarea,.nk-fields>.nk-field .nk-select{width:100%;min-width:0}.nk-field.compact,.nk-fields>.nk-field{padding:0;gap:4px;min-width:0}.nk-field.compact .f-label,.nk-field.compact ::slotted([slot=\"label\"]),.nk-fields>.nk-field .f-label,.nk-fields>.nk-field ::slotted([slot=\"label\"]){font-size:12px;color:var(--nk-text-tertiary)}.nk-fields{display:grid;grid-template-columns:repeat(auto-fill,minmax(150px,1fr));gap:10px 12px;padding:9px 0}.nk-fields>.nk-field{min-width:0}.nk-input,.nk-select,.nk-textarea{font-family:inherit;font-size:14px;line-height:20px;color:var(--nk-text);background:var(--nk-bg-input);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:5px 10px;outline:none;transition:border-color .15s,box-shadow .15s;min-width:210px}.nk-input:hover,.nk-select:hover,.nk-textarea:hover{border-color:var(--nk-border-strong)}.nk-input:focus,.nk-select:focus,.nk-textarea:focus{border-color:color-mix(in srgb,var(--nk-accent) 60%,transparent);box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 30%,transparent)}.nk-input::placeholder,.nk-textarea::placeholder{color:var(--nk-text-tertiary)}.nk-input.wide,.nk-textarea.wide,.nk-select.wide{width:100%;min-width:0}.nk-input[type=date],.nk-input[type=time],.nk-input[type=datetime-local],.nk-input[type=month]{appearance:none}.nk-input::-webkit-date-and-time-value{text-align:start;min-height:1lh}.nk-select.compact{min-width:120px}.nk-textarea{resize:vertical;min-height:70px;line-height:1.5}.nk-select{appearance:none;cursor:pointer;padding-right:26px;background-image:linear-gradient(45deg,transparent 50%,var(--nk-text-tertiary) 50%),linear-gradient(135deg,var(--nk-text-tertiary) 50%,transparent 50%);background-position:calc(100% - 14px) 55%,calc(100% - 10px) 55%;background-size:4px 4px;background-repeat:no-repeat}.nk-btn{font-family:inherit;font-size:14px;line-height:20px;font-weight:500;border-radius:var(--nk-radius);cursor:pointer;padding:3px 12px;border:1px solid transparent;transition:background .15s,border-color .15s,box-shadow .15s,opacity .15s;display:inline-flex;align-items:center;gap:6px;white-space:nowrap}.nk-btn svg,.nk-btn ::slotted(svg){width:15px;height:15px;flex-shrink:0;fill:none;stroke:currentColor;stroke-width:2;stroke-linecap:round;stroke-linejoin:round}.nk-btn.primary{background:var(--nk-accent);color:var(--nk-on-accent)}.nk-btn.primary:hover{opacity:.88}.nk-btn.secondary{background:var(--nk-bg-card);color:var(--nk-text);box-shadow:var(--nk-shadow-btn)}.nk-btn.secondary:hover{background:color-mix(in srgb,var(--nk-bg-card),var(--nk-text) 6%)}.nk-btn.danger{background:var(--nk-bg-card);color:var(--nk-danger);box-shadow:var(--nk-shadow-btn)}.nk-btn.danger:hover{background:color-mix(in srgb,var(--nk-danger) 8%,var(--nk-bg-card))}.nk-btn.danger-solid{background:var(--nk-danger);color:var(--nk-on-accent)}.nk-btn.danger-solid:hover{opacity:.88}.nk-btn.small{padding:1px 8px;font-size:13px;line-height:20px}a.nk-btn{text-decoration:none}.nk-btn:disabled{opacity:.5;cursor:not-allowed;pointer-events:none}.nk-switch{position:relative;width:34px;height:20px;flex-shrink:0;appearance:none;border:none;cursor:pointer;border-radius:20px;background:var(--nk-border-strong);transition:background .2s}.nk-switch:after{content:\"\";position:absolute;top:2px;left:2px;width:16px;height:16px;border-radius:50%;background:var(--nk-on-accent);transition:transform .2s;box-shadow:var(--nk-shadow-knob)}.nk-switch:checked,.nk-switch[aria-checked=true]{background:var(--nk-accent)}.nk-switch:checked:after,.nk-switch[aria-checked=true]:after{transform:translate(14px)}.nk-switch:disabled{opacity:.5;cursor:not-allowed}.nk-switch-label{display:inline-flex;align-items:flex-start;gap:8px;font-size:14px;cursor:pointer}.nk-switch-label>.nk-switch{font-size:inherit;line-height:inherit;margin-top:max(0px,calc((1lh - 20px)/2))}.nk-switch-label>span{padding-top:max(0px,calc((20px - 1lh)/2))}.nk-switch-label:has(.nk-switch:disabled){cursor:not-allowed;color:var(--nk-text-tertiary)}.nk-check{display:flex;align-items:flex-start;gap:8px;padding:4px 0;font-size:14px;cursor:pointer}.nk-check input{appearance:none;width:16px;height:16px;flex-shrink:0;border:1.4px solid var(--nk-border-strong);border-radius:3px;cursor:pointer;position:relative;background:var(--nk-bg);font-size:inherit;line-height:inherit;margin-top:max(0px,calc((1lh - 16px)/2))}.nk-check input[type=radio]{border-radius:50%}.nk-check input:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-check input:checked:after{content:\"\\2713\";color:var(--nk-on-accent);font-size:10.5px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-check input[type=radio]:checked:after{content:\"\\25cf\";font-size:7px}.nk-check input:disabled{opacity:.5;cursor:not-allowed}.nk-check input:disabled+*{opacity:.6}.nk-slider{width:210px;accent-color:var(--nk-accent);cursor:pointer}.nk-slider-value{font-size:12.5px;color:var(--nk-text-tertiary);margin-top:3px}.nk-profile-row{display:flex;align-items:center;gap:14px;padding:8px 0}.nk-profile-row .big-avatar,.nk-profile-row ::slotted(.big-avatar),.nk-profile-row ::slotted([slot=\"avatar\"]){width:56px;height:56px;border-radius:50%;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:20px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-model-card{border:1px solid var(--nk-border-strong);border-radius:8px;padding:12px 14px;margin-bottom:10px;cursor:pointer;display:flex;align-items:flex-start;gap:11px;transition:border-color .15s,background .15s}.nk-model-card:hover{background:var(--nk-bg-hover)}.nk-model-card.selected{border-color:var(--nk-accent);background:color-mix(in srgb,var(--nk-accent) 6%,transparent)}.nk-model-card .m-radio{width:15px;height:15px;border-radius:50%;flex-shrink:0;margin-top:2px;border:1.4px solid var(--nk-border-strong);position:relative}.nk-model-card.selected .m-radio{border-color:var(--nk-accent)}.nk-model-card.selected .m-radio:after{content:\"\";position:absolute;inset:3px;border-radius:50%;background:var(--nk-accent)}.nk-model-card .m-name,.nk-model-card ::slotted(.m-name),.nk-model-card ::slotted([slot=\"title\"]){font-weight:500;font-size:14px;display:flex;align-items:center;gap:7px}.nk-model-card .m-desc,.nk-model-card ::slotted(.m-desc),.nk-model-card ::slotted([slot=\"desc\"]){font-size:12px;color:var(--nk-text-secondary);margin-top:2px;line-height:1.45}.nk-danger-zone{border:1px solid color-mix(in srgb,var(--nk-danger) 40%,transparent);border-radius:8px;padding:14px 16px;margin-top:26px}.nk-danger-zone .dz-title{color:var(--nk-danger);font-weight:600;font-size:13px;margin-bottom:8px}.nk-member-row{display:flex;align-items:center;gap:10px;padding:8px 0;border-bottom:1px solid var(--nk-border)}.nk-member-list>.nk-member-row:last-child,.nk-member-list ::slotted(.nk-member-row:last-child),.nk-member-row.last{border-bottom:none}.nk-member-row .mini-avatar,.nk-member-row .nk-avatar,.nk-member-row ::slotted(.mini-avatar),.nk-member-row ::slotted([slot=\"avatar\"]){width:28px;height:28px;border-radius:50%;color:var(--nk-on-accent);display:flex;align-items:center;justify-content:center;font-size:11px;font-weight:600;flex-shrink:0}.nk-member-row>:has(>.m-mail){min-width:0}.nk-member-row .m-mail{font-size:12px;color:var(--nk-text-secondary);overflow:hidden;text-overflow:ellipsis;white-space:nowrap}.nk-member-row .nk-select{min-width:120px;margin-left:auto}.nk-member-row ::slotted([slot=\"role\"]){margin-left:auto}.nk-modal-backdrop{position:fixed;inset:0;background:var(--nk-scrim);padding:env(safe-area-inset-top,0px) env(safe-area-inset-right,0px) env(safe-area-inset-bottom,0px) env(safe-area-inset-left,0px);display:flex;align-items:center;justify-content:center;z-index:100;opacity:0;pointer-events:none;transition:opacity .2s ease}.nk-modal-backdrop.open{opacity:1;pointer-events:auto}.nk-modal{width:min(1150px,92vw);height:min(715px,86vh);max-width:100%;max-height:100%;background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);display:flex;overflow:hidden;transform:scale(.98) translateY(6px);transition:transform .2s ease}.nk-modal-backdrop.open .nk-modal{transform:scale(1) translateY(0)}.nk-settings-nav{width:240px;min-width:240px;background:var(--nk-bg-sidebar);border-right:1px solid var(--nk-border);padding:10px 8px;overflow-y:auto;flex-shrink:0}.nk-settings-user{display:flex;align-items:center;gap:9px;padding:6px 10px 12px;margin-bottom:4px}.nk-settings-user .avatar,.nk-settings-user ::slotted(.avatar),.nk-settings-user ::slotted([slot=\"avatar\"]){width:34px;height:34px;border-radius:50%;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-weight:600;font-size:13px;display:flex;align-items:center;justify-content:center}.nk-settings-user .name{font-weight:500;font-size:14px}.nk-settings-user .mail{font-size:12px;color:var(--nk-text-secondary)}.nk-settings-nav .nk-tree-item{min-height:28px}.nk-settings-nav .nk-tree-item.active{background:var(--nk-bg-active);color:var(--nk-text);font-weight:500}.nk-settings-content{flex:1;overflow-y:auto;padding:36px 60px 80px;min-width:0}.nk-settings-content::-webkit-scrollbar{width:10px}.nk-settings-content::-webkit-scrollbar-thumb{background:var(--nk-border-strong);border-radius:5px;border:2px solid var(--nk-bg)}.nk-settings-pane{display:none;max-width:800px}.nk-settings-pane.active{display:block}.nk-settings-pane>h2{font-size:22px;font-weight:600;line-height:1.3;margin-bottom:20px}.nk-settings-pane>h3{font-size:16px;font-weight:500;padding-bottom:8px;border-bottom:1px solid var(--nk-border);margin:30px 0 12px}.nk-settings-pane ::slotted(h2){font-size:22px;font-weight:600;line-height:1.3;padding:0!important;margin:0 0 20px!important}.nk-settings-pane ::slotted(h3){font-size:16px;font-weight:500;border:0;border-bottom:1px solid var(--nk-border);padding:0 0 8px!important;margin:30px 0 12px!important}.nk-pop{background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);padding:10px;width:296px}.nk-emoji-search{width:100%;font-family:inherit;font-size:14px;color:var(--nk-text);background:var(--nk-bg-input);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:6px 10px;outline:none;margin-bottom:8px}.nk-emoji-grid{display:grid;grid-template-columns:repeat(8,1fr);gap:2px}.nk-emoji-grid span,.nk-emoji-grid ::slotted(span){font-size:18px;text-align:center;padding:4px 0;border-radius:5px;cursor:pointer;user-select:none}.nk-emoji-grid span:hover{background:var(--nk-bg-hover)}.nk-emoji-cats{display:flex;gap:2px;margin-top:8px;padding-top:8px;border-top:1px solid var(--nk-border)}.nk-emoji-cats span{font-size:14px;padding:3px 7px;border-radius:5px;cursor:pointer;color:var(--nk-text-tertiary);filter:grayscale(1);opacity:.6}.nk-emoji-cats span.active,.nk-emoji-cats span:hover{filter:none;opacity:1;background:var(--nk-bg-hover)}.nk-menu{padding:5px;width:230px}.nk-menu-item{display:flex;align-items:center;gap:9px;padding:4px 8px;min-height:var(--_nk-row, 28px);border-radius:5px;cursor:pointer;font-size:14px;user-select:none}.nk-menu-item:hover{background:var(--nk-bg-hover)}.nk-menu-item .m-icon,.nk-menu-item ::slotted(.m-icon),.nk-menu-item ::slotted([slot=\"icon\"]){width:17px;text-align:center;font-size:14px}.nk-menu-item .m-shortcut,.nk-menu-item ::slotted(.m-shortcut){margin-left:auto;font-size:12px;color:var(--nk-text-tertiary)}.nk-menu-item.danger{color:var(--nk-danger)}.nk-menu-item>.nk-switch{margin-left:auto}.nk-menu-sep{border-top:1px solid var(--nk-border);margin:5px 4px}.nk-menu-label{font-size:12px;color:var(--nk-text-tertiary);padding:5px 8px 2px}.nk-pop.floating{z-index:60;opacity:0;visibility:hidden;pointer-events:none;transform:translateY(-4px) scale(.98);transform-origin:top;transition:opacity .15s ease,transform .15s ease,visibility 0s linear .15s}.nk-pop.floating.open{opacity:1;visibility:visible;pointer-events:auto;transform:none;transition:opacity .15s ease,transform .15s ease,visibility 0s}.nk-cmdk-backdrop{position:fixed;inset:0;background:var(--nk-scrim-soft);display:flex;justify-content:center;align-items:flex-start;padding:max(14vh,env(safe-area-inset-top,0px)) env(safe-area-inset-right,0px) env(safe-area-inset-bottom,0px) env(safe-area-inset-left,0px);z-index:110;opacity:0;pointer-events:none;transition:opacity .18s ease}.nk-cmdk-backdrop.open{opacity:1;pointer-events:auto}.nk-cmdk{max-width:100%;width:min(560px,92vw);background:var(--nk-bg);border-radius:12px;box-shadow:var(--nk-shadow-menu);overflow:hidden;transform:scale(.98);transition:transform .18s ease}.nk-cmdk-backdrop.open .nk-cmdk{transform:scale(1)}.nk-cmdk-input-row{display:flex;align-items:center;gap:10px;padding:14px 16px;border-bottom:1px solid var(--nk-border)}.nk-cmdk-input-row input{flex:1;border:none;outline:none;background:transparent;font-family:inherit;font-size:16px;color:var(--nk-text)}.nk-cmdk-input-row input::placeholder{color:var(--nk-text-tertiary)}.nk-cmdk-list{max-height:320px;overflow-y:auto;padding:6px}.nk-cmdk-group{font-size:12px;color:var(--nk-text-tertiary);padding:8px 10px 3px}.nk-cmdk-item{display:flex;align-items:center;gap:10px;padding:8px 10px;border-radius:6px;cursor:pointer;font-size:14px;user-select:none}.nk-cmdk-item.selected{background:var(--nk-bg-active)}.nk-cmdk-item .m-icon,.nk-cmdk-item ::slotted(.m-icon),.nk-cmdk-item ::slotted([slot=\"icon\"]){width:17px;text-align:center;font-size:14px}.nk-cmdk-item .m-shortcut,.nk-cmdk-item ::slotted(.m-shortcut){margin-left:auto;font-size:12px;color:var(--nk-text-tertiary)}.nk-cmdk-empty{padding:30px;text-align:center;color:var(--nk-text-tertiary);font-size:13.5px}.nk-cmdk-footer{display:flex;gap:14px;padding:8px 16px;border-top:1px solid var(--nk-border);font-size:11.5px;color:var(--nk-text-tertiary)}.nk-sheet-backdrop{position:fixed;inset:0;z-index:100;display:none;flex-direction:column;align-items:center;justify-content:flex-end;padding-top:max(24px,env(safe-area-inset-top,0px));background:var(--nk-scrim-soft);opacity:0;transition:opacity .2s ease,display .25s allow-discrete}.nk-sheet-backdrop.open{display:flex;opacity:1}@starting-style{.nk-sheet-backdrop.open{opacity:0}}.nk-sheet{--_nk-row: 40px;width:100%;max-width:640px;max-height:100%;overflow-y:auto;overscroll-behavior:contain;padding:6px max(10px,env(safe-area-inset-right,0px)) max(16px,env(safe-area-inset-bottom,0px)) max(10px,env(safe-area-inset-left,0px));background:var(--nk-bg);color:var(--nk-text);border-radius:14px 14px 0 0;box-shadow:var(--nk-shadow-menu);translate:0 100%;transition:translate .25s cubic-bezier(.2,.8,.2,1)}.nk-sheet-backdrop.open .nk-sheet{translate:0 0}@starting-style{.nk-sheet-backdrop.open .nk-sheet{translate:0 100%}}.nk-sheet .sh-grabber,.nk-sheet ::slotted(.sh-grabber){width:36px;height:4px;margin:4px auto 10px;border-radius:2px;background:var(--nk-border-strong)}.nk-sheet .sh-title,.nk-sheet ::slotted(.sh-title){font-size:14px;font-weight:600;text-align:center;padding:0 8px 10px}.nk-toast{position:fixed;bottom:max(20px,calc(env(safe-area-inset-bottom,0px) + 12px));left:50%;transform:translate(-50%) translateY(80px);z-index:120;width:max-content;max-width:calc(100% - 32px);background:var(--nk-text);color:var(--nk-bg);padding:8px 16px;border-radius:8px;font-size:14px;opacity:0;transition:all .3s ease;pointer-events:none;box-shadow:var(--nk-shadow-menu);display:flex;gap:8px;align-items:center}.nk-toast.show{opacity:1;transform:translate(-50%) translateY(0)}.nk-gallery-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(280px,100%),1fr));gap:20px 32px;margin:12px 0}.nk-g-item>h4{font-size:12px;font-weight:500;color:var(--nk-text-tertiary);text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px}.nk-g-item ::slotted(h4){font-size:12px;font-weight:500;color:var(--nk-text-tertiary);text-transform:uppercase;letter-spacing:.04em;margin-bottom:8px!important}.nk-tabs{display:flex;gap:2px;border-bottom:1px solid var(--nk-border);font-size:14px}.nk-tab{padding:7px 11px;cursor:pointer;color:var(--nk-text-secondary);border-bottom:2px solid transparent;margin-bottom:-1px;user-select:none}.nk-tab:hover{color:var(--nk-text)}.nk-tab.active{color:var(--nk-text);border-bottom-color:var(--nk-text);font-weight:500}.nk-tab-panel{padding:12px 2px;color:var(--nk-text-secondary);line-height:1.55;font-size:14px}.nk-template-btn{display:flex;align-items:center;gap:8px;width:100%;font-family:inherit;font-size:14px;color:var(--nk-text-secondary);background:var(--nk-bg-callout);border:none;border-radius:var(--nk-radius);padding:8px 12px;cursor:pointer;margin-bottom:6px;text-align:left}.nk-template-btn:hover{background:var(--nk-bg-hover)}.nk-stats{display:flex;gap:10px}.nk-stat{flex:1;border:1px solid var(--nk-border);border-radius:8px;padding:12px 14px}.nk-stat .s-label,.nk-stat ::slotted(.s-label),.nk-stat ::slotted([slot=\"label\"]){font-size:12px;color:var(--nk-text-secondary);margin-bottom:4px}.nk-stat .s-value,.nk-stat ::slotted(.s-value),.nk-stat ::slotted([slot=\"value\"]){font-size:22px;font-weight:600;letter-spacing:-.01em}.nk-stat .s-delta,.nk-stat ::slotted(.s-delta),.nk-stat ::slotted([slot=\"delta\"]){font-size:12px;margin-top:3px}.nk-stat .s-delta.up,.nk-stat ::slotted(.s-delta.up),.nk-stat ::slotted([slot=\"delta\"].up){color:var(--nk-color-green)}.nk-stat .s-delta.down,.nk-stat ::slotted(.s-delta.down),.nk-stat ::slotted([slot=\"delta\"].down){color:var(--nk-danger)}.nk-synced{border:1.5px solid color-mix(in srgb,var(--nk-danger) 55%,transparent);border-radius:8px;padding:12px 14px;position:relative;margin:8px 0}.nk-synced .synced-badge{position:absolute;top:-9px;right:10px;font-size:11px;background:var(--nk-danger);color:var(--nk-on-accent);border-radius:8px;padding:1px 8px}.nk-segmented{display:inline-flex;background:var(--nk-bg-callout);border-radius:7px;padding:2px}.nk-segmented button{font-family:inherit;font-size:14px;border:none;background:transparent;color:var(--nk-text-secondary);padding:4px 12px;border-radius:5px;cursor:pointer}.nk-segmented ::slotted(button){font-family:inherit;font-size:14px;border:none;background:transparent;color:var(--nk-text-secondary);padding:4px 12px!important;border-radius:5px;cursor:pointer}.nk-segmented button.active,.nk-segmented ::slotted(button.active){background:var(--nk-bg);color:var(--nk-text);font-weight:500;box-shadow:var(--nk-shadow-segment)}.nk-segmented.wrap{flex-wrap:wrap}.nk-segmented.scroll{max-width:100%;overflow-x:auto;scrollbar-width:none;-webkit-overflow-scrolling:touch}.nk-segmented.scroll::-webkit-scrollbar{display:none}.nk-segmented.scroll button,.nk-segmented.scroll ::slotted(button){flex-shrink:0;white-space:nowrap}.nk-banner{display:flex;align-items:center;gap:10px;font-size:14px;border-radius:8px;padding:10px 14px;margin-bottom:8px;color:var(--nk-text)}.nk-banner.info{background:var(--nk-tint-blue)}.nk-banner.success{background:var(--nk-tint-green)}.nk-banner.warning{background:var(--nk-tint-yellow)}.nk-banner.danger{background:var(--nk-tint-red)}.nk-banner .b-action,.nk-banner ::slotted(.b-action),.nk-banner ::slotted([slot=\"action\"]){margin-left:auto;font-weight:500;cursor:pointer;text-decoration:underline;text-underline-offset:2px}.nk-avatar-group{display:flex}.nk-avatar-group .mini-avatar,.nk-avatar-group .nk-avatar,.nk-avatar-group ::slotted(.mini-avatar),.nk-avatar-group ::slotted(.nk-avatar){width:26px;height:26px;border-radius:50%;color:var(--nk-on-accent);font-size:10.5px;font-weight:600;border:2px solid var(--nk-bg);display:flex;align-items:center;justify-content:center;margin-left:-7px}.nk-avatar-group .mini-avatar:first-child,.nk-avatar-group .nk-avatar:first-child,.nk-avatar-group ::slotted(.mini-avatar:first-child),.nk-avatar-group ::slotted(.nk-avatar:first-child){margin-left:0}.nk-avatar-group .more,.nk-avatar-group ::slotted(.more){background:var(--nk-bg-callout);color:var(--nk-text-secondary)}.nk-avatar{display:inline-flex;align-items:center;justify-content:center;flex-shrink:0;width:24px;height:24px;border-radius:50%;overflow:hidden;vertical-align:middle;font-size:10px;font-weight:600;line-height:1;color:var(--nk-on-accent);user-select:none;background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));object-fit:cover}.nk-avatar.small{width:20px;height:20px;font-size:9px}.nk-avatar.large{width:32px;height:32px;font-size:12px}.nk-avatar.xlarge{width:56px;height:56px;font-size:20px}.nk-avatar.square{border-radius:4px}.nk-avatar>img,.nk-avatar ::slotted(img){display:block;width:100%;height:100%;object-fit:cover}.nk-avatar.gray{background:var(--nk-color-gray)}.nk-avatar.brown{background:var(--nk-color-brown)}.nk-avatar.orange{background:var(--nk-color-orange)}.nk-avatar.yellow{background:var(--nk-color-yellow)}.nk-avatar.green{background:var(--nk-color-green)}.nk-avatar.blue{background:var(--nk-color-blue)}.nk-avatar.purple{background:var(--nk-color-purple)}.nk-avatar.pink{background:var(--nk-color-pink)}.nk-avatar.red{background:var(--nk-color-red)}.nk-panels{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(200px,100%),1fr));gap:12px;margin:12px 0}.nk-panel{display:flex;flex-direction:column;gap:6px;min-width:0;padding:14px 16px;border:1px solid var(--nk-border);border-radius:10px;background:var(--nk-bg-card);box-shadow:var(--nk-shadow-card);font-size:14px;line-height:1.5;color:inherit;text-decoration:none;text-align:left}:is(a,button).nk-panel{cursor:pointer;font-family:inherit;transition:border-color .15s,background .15s}:is(a,button).nk-panel:hover{border-color:var(--nk-border-strong)}.nk-panel>h3{font-size:14px;font-weight:600;line-height:1.4}.nk-panel ::slotted(h3){font-size:14px;font-weight:600;line-height:1.4;margin:0!important}.nk-panel>p{font-size:13px;color:var(--nk-text-secondary)}.nk-panel ::slotted(p){font-size:13px;color:var(--nk-text-secondary);margin:0!important}.nk-panel>.nk-cover{flex:none;height:64px;margin:-14px -16px 2px;border-radius:9px 9px 0 0}.nk-panel>.nk-page-icon{font-size:28px}.nk-panel>.nk-cover+.nk-page-icon{margin-top:-24px}.nk-skeleton{border-radius:5px;margin-bottom:10px;background:linear-gradient(90deg,var(--nk-bg-callout) 25%,var(--nk-bg-hover) 50%,var(--nk-bg-callout) 75%);background-size:200% 100%;animation:nk-shimmer 1.6s infinite}@keyframes nk-shimmer{to{background-position:-200% 0}}.nk-empty{text-align:center;padding:36px 20px;border:1.5px dashed var(--nk-border-strong);border-radius:10px;color:var(--nk-text-tertiary)}.nk-empty .e-icon,.nk-empty ::slotted(.e-icon),.nk-empty ::slotted([slot=\"icon\"]){font-size:30px;margin-bottom:8px}.nk-empty .e-title,.nk-empty ::slotted(.e-title),.nk-empty ::slotted([slot=\"title\"]){font-weight:500;color:var(--nk-text-secondary);margin-bottom:3px;font-size:14px}.nk-empty .e-desc,.nk-empty ::slotted(.e-desc),.nk-empty ::slotted([slot=\"desc\"]){font-size:13px;margin-bottom:12px}.nk-empty .e-actions,.nk-empty ::slotted(.e-actions){display:flex;flex-wrap:wrap;justify-content:center;gap:8px}.nk-steps{display:flex;flex-direction:column;margin:8px 0;padding:0;list-style:none;font-size:14px}.nk-step{position:relative;display:flex;align-items:flex-start;gap:10px;padding-bottom:14px;line-height:20px;color:var(--nk-text-tertiary)}.nk-step:last-child{padding-bottom:0}.nk-step:not(:last-child):after{content:\"\";position:absolute;left:10px;top:24px;bottom:4px;width:1px;background:var(--nk-border)}.nk-step .st-mark{flex:none;width:20px;height:20px;border-radius:50%;display:inline-flex;align-items:center;justify-content:center;border:1px solid var(--nk-border-strong);background:var(--nk-bg);font-size:11px;font-weight:600;line-height:1}.nk-step .st-desc{display:block;font-size:12px;line-height:18px;color:var(--nk-text-tertiary);font-weight:400}.nk-step.done{color:var(--nk-text-secondary)}.nk-step.done .st-mark{background:var(--nk-tag-green-bg);color:var(--nk-tag-green-text);border-color:transparent}.nk-step.current{color:var(--nk-text);font-weight:500}.nk-step.current .st-mark{border-color:var(--nk-accent);color:var(--nk-accent)}.nk-comments{border-left:1px solid var(--nk-border);padding:4px 0 4px 18px;margin:8px 0 8px 8px}.nk-comment{display:flex;gap:9px;margin-bottom:14px}.nk-comment .mini-avatar,.nk-comment ::slotted(.mini-avatar),.nk-comment ::slotted([slot=\"avatar\"]){width:24px;height:24px;border-radius:50%;color:var(--nk-on-accent);flex-shrink:0;font-size:10px;font-weight:600;display:flex;align-items:center;justify-content:center}.nk-comment .c-head,.nk-comment ::slotted(.c-head){font-size:12px;color:var(--nk-text-tertiary);margin-bottom:2px}.nk-comment .c-head b{color:var(--nk-text);font-weight:600}.nk-comment .c-body,.nk-comment ::slotted(.c-body){font-size:14px;line-height:1.5}.nk-comment-input{display:flex;gap:8px;align-items:center;margin-top:4px}.nk-comment-input input{min-width:0;flex:1}.nk-ai-thread{display:flex;flex-direction:column;gap:14px}.nk-ai-msg{display:flex;gap:9px}.nk-ai-msg .mini-avatar,.nk-ai-msg ::slotted(.mini-avatar),.nk-ai-msg ::slotted([slot=\"avatar\"]){width:24px;height:24px;border-radius:50%;flex-shrink:0;display:flex;align-items:center;justify-content:center;font-size:12px;background:var(--nk-bg-callout)}.nk-ai-msg.user .mini-avatar,.nk-ai-msg.user ::slotted(.mini-avatar),.nk-ai-msg.user ::slotted([slot=\"avatar\"]){background:linear-gradient(135deg,var(--nk-decor-purple),var(--nk-decor-blue));color:var(--nk-on-accent);font-size:9.5px;font-weight:600}.nk-ai-msg .a-body,.nk-ai-msg ::slotted(.a-body){font-size:14px;line-height:1.55;padding-top:2px}.nk-ai-msg .a-name,.nk-ai-msg ::slotted(.a-name){font-size:12px;font-weight:600;margin-bottom:2px}.nk-ai-msg .a-name span{color:var(--nk-text-tertiary);font-weight:400}.nk-ai-msg.user.bubble{justify-content:flex-end}.nk-ai-msg.bubble .a-body,.nk-ai-msg.bubble ::slotted(.a-body){max-width:85%;padding:6px 12px;border-radius:16px;background:var(--nk-bg-callout)}.nk-ai-actions{display:flex;gap:4px;margin-top:6px}.nk-ai-actions button{font-family:inherit;font-size:12px;color:var(--nk-text-secondary);background:transparent;border:1px solid var(--nk-border);border-radius:5px;padding:2px 8px;cursor:pointer}.nk-ai-actions ::slotted(button){font-family:inherit;font-size:12px;color:var(--nk-text-secondary);background:transparent;border:1px solid var(--nk-border);border-radius:5px;padding:2px 8px!important;cursor:pointer}.nk-ai-actions button:hover,.nk-ai-actions ::slotted(button:hover){background:var(--nk-bg-hover);color:var(--nk-text)}.nk-ai-input-row{display:flex;align-items:center;gap:8px;margin-top:14px;border:1px solid var(--nk-border-strong);border-radius:10px;padding:8px 12px}.nk-ai-input-row:focus-within{border-color:var(--nk-accent)}.nk-ai-input-row input{flex:1;border:none;outline:none;background:transparent;font-family:inherit;font-size:14px;color:var(--nk-text);min-width:0}.nk-ai-input-row input::placeholder{color:var(--nk-text-tertiary)}.nk-ai-send{border:none;background:var(--nk-accent);color:var(--nk-on-accent);border-radius:6px;width:26px;height:26px;cursor:pointer;font-size:13px;flex-shrink:0}.nk-block-host{position:relative;border-radius:var(--nk-radius);margin:8px 0;padding:2px 0 2px 2px;transition:background .15s,box-shadow .15s}.nk-block-host:hover{background:var(--nk-bg-hover)}.nk-block-host:focus-within{background:transparent;box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 25%,transparent)}.nk-block-host.nk-drop-target{box-shadow:0 -2px 0 0 var(--nk-accent);background:transparent}.nk-block-host .nk-block-handle,.nk-block-host ::slotted(.nk-block-handle){position:absolute;left:-26px;top:4px;width:18px;height:20px;border-radius:4px;display:flex;align-items:center;justify-content:center;color:var(--nk-text-tertiary);font-size:13px;cursor:grab;opacity:0;transition:opacity .15s;user-select:none}.nk-block-host:hover .nk-block-handle{opacity:1}.nk-block-host .nk-block-actions{position:absolute;display:flex;gap:1px;z-index:2;opacity:0;transition:opacity .15s;pointer-events:none}.nk-block-host .nk-block-actions.show{opacity:1;pointer-events:auto}.nk-block-host .nk-block-actions button,.nk-block-host .nk-block-actions ::slotted(button){width:20px;height:22px;padding:0;border:none;border-radius:4px;background:transparent;color:var(--nk-text-tertiary);font-family:inherit;font-size:14px;line-height:1;cursor:pointer;display:flex;align-items:center;justify-content:center}.nk-block-host .nk-block-actions button:hover{background:var(--nk-bg-hover);color:var(--nk-text)}.nk-block-host .nk-block-actions .drag{cursor:grab}.nk-block-host .nk-block-actions .drag:active{cursor:grabbing}.nk-prose,.nk-block-host .ProseMirror{font-family:var(--nk-font);line-height:1.5;color:var(--nk-text);overflow-wrap:break-word}.nk-block-host .ProseMirror{outline:none;min-height:60px;padding:4px 2px}.nk-prose>*+*,.nk-block-host .ProseMirror>*+*{margin-top:6px}.nk-prose h1,.nk-block-host .ProseMirror h1{font-size:1.875em;font-weight:600;line-height:1.3;letter-spacing:-.01em;margin:32px 0 4px}.nk-prose h2,.nk-block-host .ProseMirror h2{font-size:1.5em;font-weight:600;line-height:1.3;margin:24px 0 4px}.nk-prose h3,.nk-block-host .ProseMirror h3{font-size:1.25em;font-weight:600;line-height:1.3;margin:16px 0 2px}.nk-prose :is(h4,h5,h6),.nk-block-host .ProseMirror :is(h4,h5,h6){font-size:1em;font-weight:600;margin:12px 0 0}.nk-prose>:first-child,.nk-block-host .ProseMirror>:first-child{margin-top:0}.nk-prose>:last-child,.nk-block-host .ProseMirror>:last-child{margin-bottom:0}.nk-prose p:empty:before{content:\"\";display:inline-block}.nk-prose :is(strong,b),.nk-block-host .ProseMirror :is(strong,b){font-weight:600}.nk-prose :is(ul,ol),.nk-block-host .ProseMirror :is(ul,ol){padding-left:24px;margin:4px 0}.nk-prose ul,.nk-block-host .ProseMirror ul{list-style:disc}.nk-prose ol,.nk-block-host .ProseMirror ol{list-style:decimal}.nk-prose li,.nk-block-host .ProseMirror li{margin:2px 0}.nk-prose li::marker,.nk-block-host .ProseMirror li::marker{color:var(--nk-text-tertiary)}.nk-prose ul[data-type=taskList],.nk-block-host .ProseMirror ul[data-type=taskList]{list-style:none;padding-left:2px}.nk-prose ul[data-type=taskList] li,.nk-block-host .ProseMirror ul[data-type=taskList] li{display:flex;gap:8px;align-items:flex-start}.nk-prose ul[data-type=taskList] li>label,.nk-block-host .ProseMirror ul[data-type=taskList] li>label{flex-shrink:0;margin-top:max(0px,calc((1lh - 16px)/2));user-select:none}.nk-prose ul[data-type=taskList] li>div,.nk-block-host .ProseMirror ul[data-type=taskList] li>div{flex:1;min-width:0}.nk-prose ul[data-type=taskList] input[type=checkbox],.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]{appearance:none;width:16px;height:16px;margin:0;border:1.4px solid var(--nk-border-strong);border-radius:2px;cursor:pointer;position:relative;background:var(--nk-bg);display:block}.nk-prose ul[data-type=taskList] input[type=checkbox]:checked,.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]:checked{background:var(--nk-accent);border-color:var(--nk-accent)}.nk-prose ul[data-type=taskList] input[type=checkbox]:checked:after,.nk-block-host .ProseMirror ul[data-type=taskList] input[type=checkbox]:checked:after{content:\"\\2713\";color:var(--nk-on-accent);font-size:11px;position:absolute;inset:0;display:flex;align-items:center;justify-content:center}.nk-prose li[data-checked=true]>div,.nk-block-host .ProseMirror li[data-checked=true]>div{text-decoration:line-through;color:var(--nk-text-tertiary)}.nk-prose blockquote,.nk-block-host .ProseMirror blockquote{border-left:3px solid var(--nk-text);padding:2px 0 2px 14px;margin:12px 0;color:var(--nk-text-secondary)}.nk-prose code,.nk-block-host .ProseMirror code{font-family:var(--nk-font-mono);font-size:85%;color:var(--nk-danger);background:color-mix(in srgb,var(--nk-danger) 8%,transparent);border-radius:4px;padding:1px 5px}.nk-prose pre,.nk-block-host .ProseMirror pre{background:var(--nk-bg-code);border:1px solid var(--nk-border);border-radius:var(--nk-radius);padding:16px 20px;margin:12px 0;font-family:var(--nk-font-mono);font-size:13px;line-height:1.6;color:var(--nk-text-secondary);overflow-x:auto}.nk-prose pre code,.nk-block-host .ProseMirror pre code{background:none;color:inherit;padding:0;font-size:inherit}.nk-prose hr,.nk-block-host .ProseMirror hr{border:none;border-top:1px solid var(--nk-border);margin:20px 0}.nk-prose a,.nk-block-host .ProseMirror a{color:var(--nk-accent);text-decoration:underline;text-underline-offset:2px}.nk-prose img{max-width:100%;height:auto}.nk-prose table{display:block;width:max-content;max-width:100%;overflow-x:auto;border-collapse:collapse;font-size:14px;margin:12px 0}.nk-prose :is(th,td){padding:6px 10px;border:1px solid var(--nk-border);text-align:left;vertical-align:top}.nk-prose th{font-weight:600}.nk-block-host .ProseMirror-gapcursor:after{border-top-color:var(--nk-text)}.nk-block-host .ProseMirror .ProseMirror-selectednode{background:color-mix(in srgb,var(--nk-accent) 8%,transparent)}.nk-block-host .ProseMirror-selectednode{box-shadow:0 0 0 2px color-mix(in srgb,var(--nk-accent) 35%,transparent);border-radius:3px}.nk-block-host .ProseMirror ::selection{background:color-mix(in srgb,var(--nk-accent) 25%,transparent)}.nk-block-host .ProseMirror p.is-editor-empty:first-child:before,.nk-block-host .ProseMirror .is-empty:before{content:attr(data-placeholder);color:var(--nk-text-tertiary);float:left;height:0;pointer-events:none}.nk-block-host .bn-container{font-family:var(--nk-font);color:var(--nk-text);background:transparent}.nk-block-host .bn-editor{padding:4px 2px}.nk-block-host .bn-block-content{font-size:14px;line-height:1.6}.nk-block-host .bn-side-menu{color:var(--nk-text-tertiary)}.nk-block-host .bn-drag-handle{border-radius:4px}.nk-block-host .bn-drag-handle:hover{background:var(--nk-bg-hover)}.nk-block-host .novel-editor{font-family:var(--nk-font);color:var(--nk-text)}.nk-block-host .novel-prose{max-width:none}.nk-slash-menu,.nk-block-host .bn-suggestion-menu,.nk-block-host .tippy-box{background:var(--nk-bg);border-radius:10px;box-shadow:var(--nk-shadow-menu);padding:6px;width:280px;max-height:320px;overflow-y:auto;font-family:var(--nk-font);font-size:14px;color:var(--nk-text)}.nk-slash-menu-label{font-size:12px;color:var(--nk-text-tertiary);padding:6px 9px 2px}.nk-slash-item{display:flex;align-items:center;gap:10px;padding:6px 9px;border-radius:5px;cursor:pointer;user-select:none}.nk-slash-item:hover,.nk-slash-item.selected{background:var(--nk-bg-hover)}.nk-slash-item .m-icon,.nk-slash-item ::slotted(.m-icon){width:28px;height:28px;flex-shrink:0;border-radius:4px;background:var(--nk-bg-callout);border:1px solid var(--nk-border);display:flex;align-items:center;justify-content:center;font-size:15px}.nk-slash-item .m-desc{font-size:12px;color:var(--nk-text-tertiary)}.nk-bubble-menu{display:flex;align-items:center;gap:2px;background:var(--nk-bg);border-radius:8px;box-shadow:var(--nk-shadow-menu);padding:4px}.nk-bubble-menu button{font-family:inherit;font-size:13px;border:none;background:transparent;color:var(--nk-text-secondary);padding:4px 8px;border-radius:5px;cursor:pointer}.nk-bubble-menu ::slotted(button){font-family:inherit;font-size:13px;border:none;background:transparent;color:var(--nk-text-secondary);padding:4px 8px!important;border-radius:5px;cursor:pointer}.nk-bubble-menu button:hover,.nk-bubble-menu ::slotted(button:hover){background:var(--nk-bg-hover);color:var(--nk-text)}.nk-bubble-menu button.active,.nk-bubble-menu ::slotted(button.active){color:var(--nk-accent)}@media(max-width:860px){.nk-sidebar{display:none;position:fixed;inset:0 auto 0 0;z-index:60;transform:translate(-100%);transition:background .25s ease,transform .24s cubic-bezier(.2,.8,.25,1),display .24s allow-discrete}.nk-sidebar.open{display:flex;transform:none}@starting-style{.nk-sidebar.open{transform:translate(-100%)}}.nk-sidebar-backdrop{opacity:0;transition:opacity .24s ease,display .24s allow-discrete}.nk-sidebar-backdrop.open{display:block;opacity:1}@starting-style{.nk-sidebar-backdrop.open{opacity:0}}.nk-sidebar-toggle{display:inline-flex}.nk-tab-bar{display:flex}.nk-tab-bar.fixed+.nk-tab-bar-spacer{display:block}.nk-page{padding-left:max(24px,env(safe-area-inset-left,0px));padding-right:max(24px,env(safe-area-inset-right,0px));padding-bottom:80px}.nk-settings-nav{width:60px;min-width:60px}.nk-settings-nav .label,.nk-settings-nav .nk-section-label,.nk-settings-user .u-text{display:none}.nk-settings-content{padding:24px}.nk-cmdk-backdrop{padding-top:max(6vh,env(safe-area-inset-top,0px))}.nk-cmdk{width:min(560px,96vw)}.nk-stats{flex-wrap:wrap}.nk-breadcrumb{min-width:0}.nk-breadcrumb>.crumb:not(:last-child),.nk-breadcrumb ::slotted(.crumb:not(:last-child)),.nk-breadcrumb>.sep,.nk-breadcrumb ::slotted(.sep),.nk-topbar-meta,.nk-topbar-actions ::slotted(.nk-topbar-meta){display:none}.nk-breadcrumb>.crumb:last-child,.nk-breadcrumb ::slotted(.crumb:last-child){display:block;min-width:0;white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.nk-topbar-actions{flex-shrink:0}.nk-field{flex-wrap:wrap;row-gap:6px}.nk-field .f-control,.nk-field ::slotted(.f-control){max-width:100%;min-width:0}.nk-input,.nk-select,.nk-textarea,.nk-slider{max-width:100%}.nk-prop{flex-direction:column;align-items:stretch}.nk-prop .p-name{flex:none;min-height:26px}.nk-prop .p-value{min-height:30px;padding:3px 6px 7px}.nk-pop.sheet{position:fixed!important;inset:auto 0 0!important;width:auto!important;transform:none!important;z-index:100;--_nk-row: 40px;max-height:85dvh;overflow-y:auto;overscroll-behavior:contain;border-radius:14px 14px 0 0;padding:6px max(8px,env(safe-area-inset-right,0px)) max(12px,env(safe-area-inset-bottom,0px)) max(8px,env(safe-area-inset-left,0px));box-shadow:0 0 0 100vmax var(--nk-scrim-soft),var(--nk-shadow-menu)}.nk-pop.sheet:before{content:\"\";display:block;width:36px;height:4px;margin:4px auto 8px;border-radius:2px;background:var(--nk-border-strong)}.nk-pop.sheet.floating{translate:0 100%;transition:opacity .2s ease,translate .25s cubic-bezier(.2,.8,.2,1),visibility 0s linear .25s}.nk-pop.sheet.floating.open{translate:0 0;transition:opacity .2s ease,translate .25s cubic-bezier(.2,.8,.2,1),visibility 0s}:root:has(.nk-tab-bar:not([hidden])) .nk-toast{bottom:calc(var(--nk-tab-bar-height) + max(6px,env(safe-area-inset-bottom,0px)) + 6px)}:root:has(.nk-tab-bar.floating:not([hidden])) .nk-toast{bottom:calc(var(--nk-tab-bar-height) + 24px + env(safe-area-inset-bottom,0px))}}@media(prefers-reduced-motion:reduce){.nk-skeleton{animation:none;background:var(--nk-bg-callout)}[class*=nk-],[class*=nk-]:before,[class*=nk-]:after{animation-duration:.01ms!important;animation-iteration-count:1!important;transition-duration:.01ms!important;scroll-behavior:auto!important}}\n/*# sourceMappingURL=notionkit.min.css.map */\n";
10
10
 
11
11
  const componentsCss = componentsHead + componentsTail;
12
12
  const css = componentsHead + tokensCss + componentsTail;
@@ -366,13 +366,16 @@ class NkFormElement extends NkElement {
366
366
  // <nk-btn variant="primary" small>Save</nk-btn> → <button class="nk-btn primary small">
367
367
  // <nk-btn href="/docs" variant="secondary">Docs</nk-btn> → <a class="nk-btn secondary">
368
368
  // <nk-btn variant="topbar">⭐</nk-btn> → <button class="nk-topbar-btn">
369
+ // <nk-btn variant="tool" active>Filter</nk-btn> → <button class="nk-db-tool active"> (slot="tools" of nk-database)
370
+ // <nk-btn variant="sidebar" aria-label="Menu">☰</nk-btn> → <button class="nk-topbar-btn nk-sidebar-toggle">:
371
+ // shown on phones only, it opens the page's <nk-sidebar> as a drawer.
369
372
  //
370
373
  // Modifier classes become attributes. A slotted <svg> is sized by the
371
374
  // `.nk-btn ::slotted(svg)` twin; pass the icon itself, never wrapped.
372
375
  const VARIANTS$1 = ['primary', 'secondary', 'danger', 'danger-solid', 'topbar', 'share'];
373
376
 
374
377
  class NkBtn extends NkElement {
375
- static get observedAttributes() { return ['variant', 'small', 'disabled', 'type', 'href', 'title', 'aria-label']; }
378
+ static get observedAttributes() { return ['variant', 'small', 'disabled', 'type', 'href', 'title', 'aria-label', 'aria-haspopup', 'active']; }
376
379
 
377
380
  render() {
378
381
  this._build();
@@ -400,13 +403,22 @@ class NkBtn extends NkElement {
400
403
  else el.setAttribute('aria-disabled', disabled ? 'true' : 'false');
401
404
  const title = this.getAttribute('title');
402
405
  title ? el.setAttribute('title', title) : el.removeAttribute('title');
403
- const label = this.getAttribute('aria-label');
404
- label ? el.setAttribute('aria-label', label) : el.removeAttribute('aria-label');
406
+ // The accessible name and the popup hint belong on the button itself.
407
+ for (const name of ['aria-label', 'aria-haspopup']) {
408
+ const v = this.getAttribute(name);
409
+ v ? el.setAttribute(name, v) : el.removeAttribute(name);
410
+ }
411
+ if (this.getAttribute('variant') === 'sidebar') el.setAttribute('aria-expanded', this._sidebar()?.open ? 'true' : 'false');
412
+ else el.removeAttribute('aria-expanded');
405
413
  }
406
414
 
415
+ /** The sidebar the ☰ opens: the one in its own app, else the page's. */
416
+ _sidebar() { return this.closest('nk-app')?.querySelector('nk-sidebar') ?? document.querySelector('nk-sidebar'); }
417
+
407
418
  setupEvents() {
408
419
  this._onClick = (e) => {
409
420
  if (this.getBoolAttr('disabled')) { e.preventDefault(); e.stopPropagation(); return; }
421
+ if (this.getAttribute('variant') === 'sidebar') { this._sidebar()?.toggle?.(); return; }
410
422
  // A button inside a shadow root is not a submit button of the outer
411
423
  // form; forward the intent to the form the host sits in.
412
424
  const type = this.getAttribute('type');
@@ -415,11 +427,17 @@ class NkBtn extends NkElement {
415
427
  if (form) type === 'submit' ? form.requestSubmit() : form.reset();
416
428
  }
417
429
  };
430
+ // The ☰ says whether its drawer is open, however the drawer closed.
431
+ this._onToggle = (e) => {
432
+ if (this.getAttribute('variant') === 'sidebar' && e.target === this._sidebar()) this._btn.setAttribute('aria-expanded', e.detail.open ? 'true' : 'false');
433
+ };
418
434
  this._btn.addEventListener('click', this._onClick);
435
+ document.addEventListener('nk-toggle', this._onToggle);
419
436
  }
420
437
 
421
438
  teardownEvents() {
422
439
  this._btn?.removeEventListener('click', this._onClick);
440
+ document.removeEventListener('nk-toggle', this._onToggle);
423
441
  }
424
442
 
425
443
  onAttributeChanged(name) {
@@ -429,7 +447,11 @@ class NkBtn extends NkElement {
429
447
  this._build();
430
448
  break;
431
449
  case 'variant':
450
+ this._btn.className = this._computeClasses().join(' ');
451
+ this._applyState(this._btn);
452
+ break;
432
453
  case 'small':
454
+ case 'active':
433
455
  this._btn.className = this._computeClasses().join(' ');
434
456
  break;
435
457
  case 'type':
@@ -444,6 +466,8 @@ class NkBtn extends NkElement {
444
466
  const variant = this.getAttribute('variant');
445
467
  if (variant === 'topbar') return ['nk-topbar-btn'];
446
468
  if (variant === 'share') return ['nk-topbar-btn', 'nk-share-btn'];
469
+ if (variant === 'sidebar') return ['nk-topbar-btn', 'nk-sidebar-toggle'];
470
+ if (variant === 'tool') return this.getBoolAttr('active') ? ['nk-db-tool', 'active'] : ['nk-db-tool'];
447
471
  const classes = ['nk-btn'];
448
472
  if (VARIANTS$1.includes(variant)) classes.push(variant);
449
473
  if (this.getBoolAttr('small')) classes.push('small');
@@ -455,6 +479,8 @@ class NkBtn extends NkElement {
455
479
 
456
480
  get variant() { return this.getAttribute('variant'); }
457
481
  set variant(v) { v ? this.setAttribute('variant', v) : this.removeAttribute('variant'); }
482
+ get active() { return this.getBoolAttr('active'); }
483
+ set active(v) { this.setBoolAttr('active', v); }
458
484
  get small() { return this.getBoolAttr('small'); }
459
485
  set small(v) { this.setBoolAttr('small', v); }
460
486
  get disabled() { return this.getBoolAttr('disabled'); }
@@ -1345,9 +1371,10 @@ class NkTag extends NkElement {
1345
1371
  customElements.define('nk-tag', NkTag);
1346
1372
 
1347
1373
  // <nk-progress value="72" label="72%"></nk-progress>
1374
+ // <nk-progress value="72" label="72 %" wide></nk-progress> → fills its row, the label stays beside it
1348
1375
  // The bar is `.nk-progress > i` — a child combinator, so both nodes live here.
1349
1376
  class NkProgress extends NkElement {
1350
- static get observedAttributes() { return ['value', 'max', 'label']; }
1377
+ static get observedAttributes() { return ['value', 'max', 'label', 'wide']; }
1351
1378
 
1352
1379
  render() {
1353
1380
  this._bar = this.createElement('span', ['nk-progress'], { role: 'progressbar' });
@@ -1366,6 +1393,7 @@ class NkProgress extends NkElement {
1366
1393
  const max = Number(this.getAttribute('max')) || 100;
1367
1394
  const value = Math.min(max, Math.max(0, Number(this.getAttribute('value')) || 0));
1368
1395
  this._fill.style.width = `${(value / max) * 100}%`;
1396
+ this._bar.classList.toggle('wide', this.getBoolAttr('wide'));
1369
1397
  this._bar.setAttribute('aria-valuenow', value);
1370
1398
  this._bar.setAttribute('aria-valuemin', 0);
1371
1399
  this._bar.setAttribute('aria-valuemax', max);
@@ -1709,42 +1737,12 @@ customElements.define('nk-app', NkApp);
1709
1737
  //
1710
1738
  // The host is display:contents so the <aside> is a direct flex child of
1711
1739
  // .nk-app, exactly like the class markup. Below 860px notionkit.css hides the
1712
- // aside; `open` brings it back as an off-canvas drawer (position only – the
1713
- // look is still the stylesheet's).
1714
- //
1715
- // The drawer slides and the scrim fades without a line of JavaScript:
1716
- // `display` transitions with transition-behavior: allow-discrete (the old
1717
- // value is held for the whole duration, so closing animates too) and
1718
- // @starting-style gives the first frame after display: none its start
1719
- // values. `position: fixed` lives on the plain .nk-sidebar, not on the open
1720
- // state – while closing, the aside is still displayed and must not fall
1721
- // back into the flow. Browsers without either feature switch hard, as
1722
- // before; prefers-reduced-motion switches hard on purpose.
1723
- const drawerSheet = new CSSStyleSheet();
1724
- drawerSheet.replaceSync(`
1725
- .nk-sidebar-backdrop { display: none; position: fixed; inset: 0; z-index: 59; background: var(--nk-scrim-soft); }
1726
- @media (max-width: 860px) {
1727
- .nk-sidebar {
1728
- position: fixed; inset: 0 auto 0 0; z-index: 60;
1729
- transform: translateX(-100%);
1730
- transition: background .25s ease, transform .24s cubic-bezier(.2, .8, .25, 1), display .24s;
1731
- transition-behavior: allow-discrete;
1732
- }
1733
- :host([open]) .nk-sidebar { display: flex; transform: none; }
1734
- @starting-style { :host([open]) .nk-sidebar { transform: translateX(-100%); } }
1735
- .nk-sidebar-backdrop {
1736
- opacity: 0;
1737
- transition: opacity .24s ease, display .24s;
1738
- transition-behavior: allow-discrete;
1739
- }
1740
- :host([open]) .nk-sidebar-backdrop { display: block; opacity: 1; }
1741
- @starting-style { :host([open]) .nk-sidebar-backdrop { opacity: 0; } }
1742
- }
1743
- @media (prefers-reduced-motion: reduce) { .nk-sidebar, .nk-sidebar-backdrop { transition: none; } }
1744
- `);
1745
-
1740
+ // aside; `open` brings it back as a drawer over the page. The drawer is the
1741
+ // stylesheet's since NotionKit 1.7.0 (.nk-sidebar.open, .nk-sidebar-backdrop
1742
+ // .open) – the sidebar slides and the scrim fades by the same rules as the
1743
+ // class markup; the element toggles the two classes. <nk-btn variant="sidebar">
1744
+ // in the topbar is the ☰ that opens it.
1746
1745
  class NkSidebar extends NkElement {
1747
- static get hostStyles() { return drawerSheet; }
1748
1746
  static get observedAttributes() { return ['open']; }
1749
1747
 
1750
1748
  render() {
@@ -1761,6 +1759,13 @@ class NkSidebar extends NkElement {
1761
1759
  this._wrapper.appendChild(this._backdrop);
1762
1760
  this._wrapper.appendChild(this._aside);
1763
1761
  this._syncFooter();
1762
+ this._syncOpen();
1763
+ }
1764
+
1765
+ _syncOpen() {
1766
+ const open = this.getBoolAttr('open');
1767
+ this._aside.classList.toggle('open', open);
1768
+ this._backdrop.classList.toggle('open', open);
1764
1769
  }
1765
1770
 
1766
1771
  _syncFooter() {
@@ -1787,7 +1792,9 @@ class NkSidebar extends NkElement {
1787
1792
  }
1788
1793
 
1789
1794
  onAttributeChanged(name) {
1790
- if (name === 'open') this.emit('nk-toggle', { open: this.getBoolAttr('open') });
1795
+ if (name !== 'open') return;
1796
+ this._syncOpen();
1797
+ this.emit('nk-toggle', { open: this.getBoolAttr('open') });
1791
1798
  }
1792
1799
 
1793
1800
  show() { this.setBoolAttr('open', true); }
@@ -2517,7 +2524,7 @@ class NkTabBarItem extends NkElement {
2517
2524
 
2518
2525
  customElements.define('nk-tab-bar-item', NkTabBarItem);
2519
2526
 
2520
- // <nk-page icon="🚀" cover>
2527
+ // <nk-page icon="🚀" cover full small>
2521
2528
  // <nk-page-title>NotionKit MVP</nk-page-title>
2522
2529
  // <nk-page-actions>…</nk-page-actions>
2523
2530
  // <p class="lead">…</p>
@@ -2529,9 +2536,10 @@ customElements.define('nk-tab-bar-item', NkTabBarItem);
2529
2536
  // The host is display:contents, so .nk-page-scroll is the flex child of
2530
2537
  // .nk-main that scrolls. `narrow` drops the scroll wrapper for pages that are
2531
2538
  // the document itself (landing / docs skeleton). The page icon is rendered
2532
- // here because its ::slotted twin is keyed on the parent (.nk-page).
2539
+ // here because its ::slotted twin is keyed on the parent (.nk-page). `full` and
2540
+ // `small` are Notion's page options – full width, 14px text – set on the page.
2533
2541
  class NkPage extends NkElement {
2534
- static get observedAttributes() { return ['icon', 'cover', 'narrow']; }
2542
+ static get observedAttributes() { return ['icon', 'cover', 'narrow', 'full', 'small']; }
2535
2543
 
2536
2544
  render() {
2537
2545
  this._page = this.createElement('div', ['nk-page']);
@@ -2568,6 +2576,8 @@ class NkPage extends NkElement {
2568
2576
  // (attribute or a slotted nk-page-cover) the icon sits in the padding.
2569
2577
  const slotted = this._coverSlot.assignedNodes().some(n => n.nodeType === Node.ELEMENT_NODE || n.data.trim());
2570
2578
  this._page.classList.toggle('covered', this.getBoolAttr('cover') || slotted);
2579
+ this._page.classList.toggle('full', this.getBoolAttr('full'));
2580
+ this._page.classList.toggle('small', this.getBoolAttr('small'));
2571
2581
  }
2572
2582
 
2573
2583
  setupEvents() {
@@ -2589,17 +2599,25 @@ class NkPage extends NkElement {
2589
2599
  set icon(v) { v == null ? this.removeAttribute('icon') : this.setAttribute('icon', v); }
2590
2600
  get cover() { return this.getBoolAttr('cover'); }
2591
2601
  set cover(v) { this.setBoolAttr('cover', v); }
2602
+ get full() { return this.getBoolAttr('full'); }
2603
+ set full(v) { this.setBoolAttr('full', v); }
2604
+ get small() { return this.getBoolAttr('small'); }
2605
+ set small(v) { this.setBoolAttr('small', v); }
2592
2606
  }
2593
2607
 
2594
2608
  customElements.define('nk-page', NkPage);
2595
2609
 
2596
2610
  // <nk-page-cover slot="cover"></nk-page-cover> → the token gradient
2597
- // <nk-page-cover slot="cover" src="cover.jpg"></nk-page-cover> → an image
2611
+ // <nk-page-cover slot="cover" src="cover.jpg" position="center 30%"></nk-page-cover> → a picture
2612
+ // → <div class="nk-cover"><img src="cover.jpg" alt=""></div>: the picture fills
2613
+ // the band, cropped rather than stretched; `position` moves the crop, as
2614
+ // Notion's "Reposition" does. The gradient stays underneath while it loads.
2598
2615
  class NkPageCover extends NkElement {
2599
- static get observedAttributes() { return ['src']; }
2616
+ static get observedAttributes() { return ['src', 'position']; }
2600
2617
 
2601
2618
  render() {
2602
2619
  this._cover = this.createElement('div', ['nk-cover']);
2620
+ this._img = this.createElement('img', [], { alt: '' });
2603
2621
  this._wrapper.appendChild(this._cover);
2604
2622
  this._sync();
2605
2623
  }
@@ -2607,14 +2625,10 @@ class NkPageCover extends NkElement {
2607
2625
  _sync() {
2608
2626
  const src = this.getAttribute('src');
2609
2627
  if (src) {
2610
- this._cover.style.backgroundImage = `url("${src}")`;
2611
- this._cover.style.backgroundSize = 'cover';
2612
- this._cover.style.backgroundPosition = 'center';
2613
- } else {
2614
- this._cover.style.backgroundImage = '';
2615
- this._cover.style.backgroundSize = '';
2616
- this._cover.style.backgroundPosition = '';
2617
- }
2628
+ this._img.src = src;
2629
+ this._img.style.objectPosition = this.getAttribute('position') || '';
2630
+ if (!this._img.isConnected) this._cover.appendChild(this._img);
2631
+ } else this._img.remove();
2618
2632
  }
2619
2633
 
2620
2634
  onAttributeChanged() { this._sync(); }
@@ -2995,6 +3009,9 @@ customElements.define('nk-tab', NkTab);
2995
3009
  // → <div class="nk-segmented">…</div> with .active on the chosen button.
2996
3010
  // The buttons stay in the light DOM (their look comes from the ::slotted
2997
3011
  // twins); the element sets type/role, moves .active and submits the value.
3012
+ // With `scroll` the chosen option is kept in view – after the first layout,
3013
+ // on every change and when the row's width changes – by scrolling the row
3014
+ // alone, never the page, by a relative distance, so right-to-left works too.
2998
3015
  const KEYS = { ArrowRight: 1, ArrowDown: 1, ArrowLeft: -1, ArrowUp: -1 };
2999
3016
 
3000
3017
  class NkSegmented extends NkFormElement {
@@ -3038,6 +3055,19 @@ class NkSegmented extends NkFormElement {
3038
3055
  }
3039
3056
  this._value = value;
3040
3057
  this.setFormValue(value);
3058
+ this._reveal(this._revealed ? 'smooth' : 'instant');
3059
+ }
3060
+
3061
+ /** Scrolls the row the least distance that shows the chosen button whole. */
3062
+ _reveal(behavior) {
3063
+ if (!this.getBoolAttr('scroll') || !this._box?.clientWidth) return;
3064
+ const btn = this.buttons.find(b => b.classList.contains('active'));
3065
+ if (!btn) return;
3066
+ const row = this._box.getBoundingClientRect(), r = btn.getBoundingClientRect(), pad = 8;
3067
+ const delta = r.left < row.left ? r.left - row.left - pad : r.right > row.right ? r.right - row.right + pad : 0;
3068
+ const smooth = behavior === 'smooth' && !matchMedia('(prefers-reduced-motion: reduce)').matches;
3069
+ if (delta) this._box.scrollBy({ left: delta, behavior: smooth ? 'smooth' : 'instant' });
3070
+ this._revealed = true;
3041
3071
  }
3042
3072
 
3043
3073
  setupEvents() {
@@ -3061,6 +3091,8 @@ class NkSegmented extends NkFormElement {
3061
3091
  this._slot.addEventListener('slotchange', this._onSlot);
3062
3092
  this.addEventListener('click', this._onClick);
3063
3093
  this.addEventListener('keydown', this._onKey);
3094
+ this._resize = new ResizeObserver(() => this._reveal('instant'));
3095
+ this._resize.observe(this._box);
3064
3096
  this._sync();
3065
3097
  }
3066
3098
 
@@ -3068,6 +3100,7 @@ class NkSegmented extends NkFormElement {
3068
3100
  this._slot?.removeEventListener('slotchange', this._onSlot);
3069
3101
  this.removeEventListener('click', this._onClick);
3070
3102
  this.removeEventListener('keydown', this._onKey);
3103
+ this._resize?.disconnect();
3071
3104
  }
3072
3105
 
3073
3106
  _choose(value) {
@@ -3179,6 +3212,76 @@ class NkAvatarGroup extends NkElement {
3179
3212
 
3180
3213
  customElements.define('nk-avatar-group', NkAvatarGroup);
3181
3214
 
3215
+ // Shared by every element that draws an avatar: nk-avatar itself, member
3216
+ // rows, comments and the person cells of a database view.
3217
+ const AVATAR_COLORS = ['gray', 'brown', 'orange', 'yellow', 'green', 'blue', 'purple', 'pink', 'red'];
3218
+
3219
+ /**
3220
+ * Paints an .nk-avatar. One of Notion's nine colour names becomes its class,
3221
+ * so the tokens decide the shade in each theme; any other value – a hex, a
3222
+ * gradient, a var() – is taken as an inline background, as before 1.6.0.
3223
+ * Without a colour the avatar keeps the stylesheet's gradient.
3224
+ */
3225
+ function paintAvatar(el, color) {
3226
+ for (const c of AVATAR_COLORS) el.classList.toggle(c, c === color);
3227
+ el.style.background = color && !AVATAR_COLORS.includes(color) ? color : '';
3228
+ }
3229
+
3230
+ /** "Sara Lindt" → "SL". */
3231
+ const initialsOf = name => String(name || '').split(/\s+/).map(w => w[0]).filter(Boolean).join('').slice(0, 2).toUpperCase();
3232
+
3233
+ // <nk-avatar>MK</nk-avatar> → <span class="nk-avatar">MK</span>
3234
+ // <nk-avatar size="small" color="green">SL</nk-avatar>
3235
+ // <nk-avatar name="Ada Lovelace" size="large"></nk-avatar> → initials "AL"
3236
+ // <nk-avatar src="ada.jpg" name="Ada Lovelace" size="xlarge"></nk-avatar>
3237
+ // <nk-avatar square>A</nk-avatar> → a workspace icon
3238
+ // size: small (20px) · default 24px · large (32px) · xlarge (56px). color: one
3239
+ // of Notion's nine names, or any CSS background. Without content the initials
3240
+ // come from `name`; with `src` a photo fills the circle and `name` is its alt.
3241
+ class NkAvatar extends NkElement {
3242
+ static get observedAttributes() { return ['size', 'color', 'square', 'src', 'name']; }
3243
+
3244
+ render() {
3245
+ this._box = this.createElement('span', ['nk-avatar']);
3246
+ this._slot = document.createElement('slot');
3247
+ this._initials = document.createTextNode('');
3248
+ this._slot.appendChild(this._initials);
3249
+ this._img = this.createElement('img', [], { alt: '' });
3250
+ this._box.appendChild(this._slot);
3251
+ this._wrapper.appendChild(this._box);
3252
+ this._sync();
3253
+ }
3254
+
3255
+ _sync() {
3256
+ const size = this.getAttribute('size');
3257
+ for (const s of ['small', 'large', 'xlarge']) this._box.classList.toggle(s, s === size);
3258
+ this._box.classList.toggle('square', this.getBoolAttr('square'));
3259
+ paintAvatar(this._box, this.getAttribute('color'));
3260
+ const name = this.getAttribute('name');
3261
+ this._initials.data = initialsOf(name);
3262
+ const src = this.getAttribute('src');
3263
+ if (src) {
3264
+ this._img.src = src;
3265
+ this._img.alt = name || '';
3266
+ if (this._slot.isConnected) this._slot.replaceWith(this._img);
3267
+ } else if (this._img.isConnected) this._img.replaceWith(this._slot);
3268
+ // A picture or initials with a name speak for themselves; a bare glyph is decoration.
3269
+ if (name && !src) { this._box.setAttribute('role', 'img'); this._box.setAttribute('aria-label', name); }
3270
+ else { this._box.removeAttribute('role'); this._box.removeAttribute('aria-label'); }
3271
+ }
3272
+
3273
+ onAttributeChanged() { this._sync(); }
3274
+
3275
+ get size() { return this.getAttribute('size'); }
3276
+ set size(v) { v == null ? this.removeAttribute('size') : this.setAttribute('size', v); }
3277
+ get color() { return this.getAttribute('color'); }
3278
+ set color(v) { v == null ? this.removeAttribute('color') : this.setAttribute('color', v); }
3279
+ get src() { return this.getAttribute('src'); }
3280
+ set src(v) { v == null ? this.removeAttribute('src') : this.setAttribute('src', v); }
3281
+ }
3282
+
3283
+ customElements.define('nk-avatar', NkAvatar);
3284
+
3182
3285
  // <nk-mention type="person"><span slot="avatar" class="mini-avatar" style="background:#448361">SL</span>Sara Lindt</nk-mention>
3183
3286
  // <nk-mention type="page">📄 Onboarding</nk-mention> <nk-mention type="date">📅 May 20</nk-mention>
3184
3287
  // → <span class="nk-mention person">…</span>
@@ -3420,16 +3523,18 @@ class NkMemberList extends NkElement {
3420
3523
 
3421
3524
  customElements.define('nk-member-list', NkMemberList);
3422
3525
 
3423
- // <nk-member-row name="Sara Lindt" mail="sara@…" avatar="SL" color="#448361">
3526
+ // <nk-member-row name="Sara Lindt" mail="sara@…" avatar="SL" color="green">
3424
3527
  // <nk-select slot="role" compact>…</nk-select>
3425
3528
  // </nk-member-row>
3426
- // → <div class="nk-member-row"><span class="mini-avatar">SL</span><div>Sara Lindt<div class="m-mail">…</div></div><select …></div>
3529
+ // → <div class="nk-member-row"><span class="nk-avatar green">SL</span><div>Sara Lindt<div class="m-mail">…</div></div><select …></div>
3530
+ // color: one of Notion's nine names, or any CSS background; without it the
3531
+ // avatar gradient. The row sizes the avatar to 28px.
3427
3532
  class NkMemberRow extends NkElement {
3428
3533
  static get observedAttributes() { return ['name', 'mail', 'avatar', 'color', 'last']; }
3429
3534
 
3430
3535
  render() {
3431
3536
  this._row = this.createElement('div', ['nk-member-row']);
3432
- this._avatar = this.createElement('span', ['mini-avatar']);
3537
+ this._avatar = this.createElement('span', ['nk-avatar']);
3433
3538
  const avatarSlot = this.createElement('slot', [], { name: 'avatar' });
3434
3539
  avatarSlot.appendChild(this._avatar);
3435
3540
  const text = document.createElement('div');
@@ -3453,8 +3558,8 @@ class NkMemberRow extends NkElement {
3453
3558
  this._mail.textContent = mail || '';
3454
3559
  this._mail.style.display = mail ? '' : 'none';
3455
3560
  const avatar = this.getAttribute('avatar');
3456
- this._avatar.textContent = avatar || (this.getAttribute('name') || '').split(/\s+/).map(w => w[0]).join('').slice(0, 2).toUpperCase();
3457
- this._avatar.style.background = this.getAttribute('color') || 'var(--nk-text-tertiary)';
3561
+ this._avatar.textContent = avatar || initialsOf(this.getAttribute('name'));
3562
+ paintAvatar(this._avatar, this.getAttribute('color'));
3458
3563
  this._row.classList.toggle('last', this.getBoolAttr('last'));
3459
3564
  }
3460
3565
 
@@ -3463,9 +3568,148 @@ class NkMemberRow extends NkElement {
3463
3568
 
3464
3569
  customElements.define('nk-member-row', NkMemberRow);
3465
3570
 
3466
- // Overlay plumbing shared by nk-modal and nk-cmdk: body scroll lock with a
3467
- // refcount, and `inert` on everything outside the overlay so focus and
3468
- // assistive technology stay inside – nested shadow roots included.
3571
+ // <nk-props>
3572
+ // <nk-prop label="Status" icon="◉"><nk-tag color="blue">In progress</nk-tag></nk-prop>
3573
+ // <nk-prop label="Owner" icon="👤"><nk-avatar size="small">MK</nk-avatar>Marcel Karas</nk-prop>
3574
+ // </nk-props>
3575
+ // → <dl class="nk-props">…</dl> – the properties under a page title. The rows
3576
+ // are <nk-prop> hosts with display: contents, so each .nk-prop is a row of
3577
+ // this list.
3578
+ class NkProps extends NkElement {
3579
+ render() {
3580
+ const list = this.createElement('dl', ['nk-props']);
3581
+ list.appendChild(document.createElement('slot'));
3582
+ this._wrapper.appendChild(list);
3583
+ }
3584
+ }
3585
+
3586
+ customElements.define('nk-props', NkProps);
3587
+
3588
+ // <nk-prop label="Due" icon="📅">2 June 2026</nk-prop>
3589
+ // → <div class="nk-prop"><dt class="p-name"><span class="p-icon">📅</span>Due</dt><dd class="p-value">2 June 2026</dd></div>
3590
+ // The value is the element's content – tags, an avatar and a name, a date, a
3591
+ // <nk-progress wide>. slot="icon" replaces the icon glyph. A click on the
3592
+ // name or the value fires nk-action { action: 'name' | 'value', label }, the
3593
+ // moment Notion opens the property's editor.
3594
+ class NkProp extends NkElement {
3595
+ static get observedAttributes() { return ['label', 'icon']; }
3596
+
3597
+ render() {
3598
+ this._row = this.createElement('div', ['nk-prop']);
3599
+ this._name = this.createElement('dt', ['p-name']);
3600
+ this._icon = this.createElement('span', ['p-icon']);
3601
+ const iconSlot = this.createElement('slot', [], { name: 'icon' });
3602
+ iconSlot.appendChild(this._icon);
3603
+ this._label = document.createTextNode('');
3604
+ this._name.append(iconSlot, this._label);
3605
+ this._value = this.createElement('dd', ['p-value']);
3606
+ this._value.appendChild(document.createElement('slot'));
3607
+ this._row.append(this._name, this._value);
3608
+ this._wrapper.appendChild(this._row);
3609
+ this._sync();
3610
+ }
3611
+
3612
+ _sync() {
3613
+ const icon = this.getAttribute('icon');
3614
+ this._icon.textContent = icon || '';
3615
+ this._icon.style.display = icon ? '' : 'none';
3616
+ this._label.data = this.getAttribute('label') || '';
3617
+ }
3618
+
3619
+ setupEvents() {
3620
+ this._onClick = (e) => {
3621
+ const part = e.composedPath().includes(this._name) ? 'name' : 'value';
3622
+ this.emit('nk-action', { action: part, label: this.label });
3623
+ };
3624
+ this._row.addEventListener('click', this._onClick);
3625
+ }
3626
+
3627
+ teardownEvents() { this._row?.removeEventListener('click', this._onClick); }
3628
+ onAttributeChanged() { this._sync(); }
3629
+
3630
+ get label() { return this.getAttribute('label') || ''; }
3631
+ set label(v) { this.setAttribute('label', v); }
3632
+ get icon() { return this.getAttribute('icon'); }
3633
+ set icon(v) { v == null ? this.removeAttribute('icon') : this.setAttribute('icon', v); }
3634
+ }
3635
+
3636
+ customElements.define('nk-prop', NkProp);
3637
+
3638
+ // <nk-panels><nk-panel …></nk-panel><nk-panel …></nk-panel></nk-panels>
3639
+ // → <div class="nk-panels">…</div>: columns of at least 200px that share the
3640
+ // row and fall to one on a phone. The <nk-panel> hosts are display: contents,
3641
+ // so each .nk-panel is a cell of this grid.
3642
+ class NkPanels extends NkElement {
3643
+ render() {
3644
+ const grid = this.createElement('div', ['nk-panels']);
3645
+ grid.appendChild(document.createElement('slot'));
3646
+ this._wrapper.appendChild(grid);
3647
+ }
3648
+ }
3649
+
3650
+ customElements.define('nk-panels', NkPanels);
3651
+
3652
+ // <nk-panel title="Weekly review"><p>Three pages changed.</p></nk-panel>
3653
+ // <nk-panel href="/roadmap" cover="covers/aurora.svg" icon="🚀" title="Roadmap"><p>2 min ago</p></nk-panel>
3654
+ // → <a class="nk-panel" href="/roadmap"><div class="nk-cover"><img src="…" alt=""></div>
3655
+ // <div class="nk-page-icon">🚀</div><h3>Roadmap</h3>…</a>
3656
+ // `cover` without a value draws the token gradient, with one a picture; `icon`
3657
+ // overlaps the cover as on a page – a page tile, as on Notion's Home. With
3658
+ // `href` the panel is a link. `title` is the heading, never a tooltip.
3659
+ class NkPanel extends NkElement {
3660
+ static get observedAttributes() { return ['title', 'icon', 'cover', 'href', 'target']; }
3661
+
3662
+ render() {
3663
+ this._cover = this.createElement('div', ['nk-cover']);
3664
+ this._img = this.createElement('img', [], { alt: '' });
3665
+ this._icon = this.createElement('div', ['nk-page-icon']);
3666
+ this._heading = document.createElement('h3');
3667
+ this._slot = document.createElement('slot');
3668
+ this.takeTitle();
3669
+ this._build();
3670
+ }
3671
+
3672
+ _build() {
3673
+ const href = this.getAttribute('href');
3674
+ const box = this.createElement(href ? 'a' : 'div', ['nk-panel']);
3675
+ box.append(this._cover, this._icon, this._heading, this._slot);
3676
+ this._wrapper.replaceChildren(box);
3677
+ this._box = box;
3678
+ this._sync();
3679
+ }
3680
+
3681
+ _sync() {
3682
+ const href = this.getAttribute('href');
3683
+ if (href) { this._box.setAttribute('href', href); this._box.target = this.getAttribute('target') || ''; }
3684
+ const cover = this.getAttribute('cover');
3685
+ this._cover.style.display = cover === null ? 'none' : '';
3686
+ if (cover) { this._img.src = cover; if (!this._img.isConnected) this._cover.appendChild(this._img); }
3687
+ else this._img.remove();
3688
+ const icon = this.getAttribute('icon');
3689
+ this._icon.textContent = icon || '';
3690
+ this._icon.style.display = icon ? '' : 'none';
3691
+ this._heading.textContent = this._titleText || '';
3692
+ this._heading.style.display = this._titleText ? '' : 'none';
3693
+ }
3694
+
3695
+ onAttributeChanged(name, _old, value) {
3696
+ if (name === 'title' && !this.takeTitle(value)) return;
3697
+ if (name === 'href' && (value === null) !== (this._box.localName === 'div')) { this._build(); return; }
3698
+ this._sync();
3699
+ }
3700
+
3701
+ get title() { return this._titleText ?? ''; }
3702
+ set title(v) { this._titleText = v == null ? '' : String(v); if (this._initialized) this._sync(); }
3703
+ get href() { return this.getAttribute('href'); }
3704
+ set href(v) { v == null ? this.removeAttribute('href') : this.setAttribute('href', v); }
3705
+ }
3706
+
3707
+ customElements.define('nk-panel', NkPanel);
3708
+
3709
+ // Overlay plumbing shared by nk-modal, nk-sheet, nk-cmdk and nk-menu: body
3710
+ // scroll lock with a refcount, `inert` on everything outside the overlay so
3711
+ // focus and assistive technology stay inside – nested shadow roots included –
3712
+ // and the focused element behind shadow hosts, to return focus to.
3469
3713
  let locks = 0, previousOverflow = '';
3470
3714
 
3471
3715
  function lockScroll() {
@@ -3496,6 +3740,13 @@ function inertOutside(el) {
3496
3740
  return () => { for (const c of made) c.inert = false; };
3497
3741
  }
3498
3742
 
3743
+ /** The focused element itself, looking into shadow roots (document.activeElement stops at the host). */
3744
+ function deepActiveElement() {
3745
+ let el = document.activeElement;
3746
+ while (el?.shadowRoot?.activeElement) el = el.shadowRoot.activeElement;
3747
+ return el;
3748
+ }
3749
+
3499
3750
  /** The first tabbable element inside a light-DOM subtree, looking into shadow roots. */
3500
3751
  function firstFocusable(root) {
3501
3752
  const SEL = 'a[href], button:not([disabled]), input:not([disabled]):not([type=hidden]), select:not([disabled]), textarea:not([disabled]), [tabindex]:not([tabindex="-1"]), [contenteditable="true"], [contenteditable="plaintext-only"]';
@@ -3509,6 +3760,155 @@ function firstFocusable(root) {
3509
3760
  return walk(root);
3510
3761
  }
3511
3762
 
3763
+ // <nk-sheet id="more" title="More">
3764
+ // <nk-tree manual>
3765
+ // <nk-section-label>Favourites</nk-section-label>
3766
+ // <nk-tree-item icon="🚀">NotionKit MVP</nk-tree-item>
3767
+ // </nk-tree>
3768
+ // </nk-sheet>
3769
+ // → <div class="nk-sheet-backdrop open"><div class="nk-sheet" role="dialog">
3770
+ // <div class="sh-grabber"></div><div class="sh-title">More</div>…</div></div>
3771
+ //
3772
+ // A bottom sheet (NotionKit 1.7.0) with nk-modal's contract: show(), close()
3773
+ // and toggle(), Escape and the backdrop close it, focus moves in and back
3774
+ // out, the page behind is scroll-locked and inert. It lies above the tab
3775
+ // bar; rows inside are 40px high. `title` is the heading shown under the
3776
+ // grabber and the dialog's name, never a tooltip – see NkElement.takeTitle().
3777
+ // Choosing a row does not close the sheet – the app decides (nk-select
3778
+ // bubbles out). Put the element directly under <body>: a transformed
3779
+ // ancestor would trap the fixed backdrop.
3780
+ class NkSheet extends NkElement {
3781
+ static get observedAttributes() { return ['open', 'title']; }
3782
+
3783
+ render() {
3784
+ this.takeTitle();
3785
+ this._backdrop = this.createElement('div', ['nk-sheet-backdrop']);
3786
+ this._backdrop.inert = true;
3787
+ this._box = this.createElement('div', ['nk-sheet'], { role: 'dialog', 'aria-modal': 'true', tabindex: '-1' });
3788
+ this._heading = this.createElement('div', ['sh-title'], { id: 'title' });
3789
+ this._box.append(this.createElement('div', ['sh-grabber']), this._heading, document.createElement('slot'));
3790
+ this._backdrop.appendChild(this._box);
3791
+ this._wrapper.appendChild(this._backdrop);
3792
+ this._syncTitle();
3793
+ this._syncOpen();
3794
+ }
3795
+
3796
+ _syncTitle() {
3797
+ const text = this._titleText || '';
3798
+ this._heading.textContent = text;
3799
+ this._heading.hidden = !text;
3800
+ if (text) this._box.setAttribute('aria-labelledby', 'title');
3801
+ else this._box.removeAttribute('aria-labelledby');
3802
+ }
3803
+
3804
+ _syncOpen() {
3805
+ const open = this.getBoolAttr('open');
3806
+ this._backdrop.classList.toggle('open', open);
3807
+ this._backdrop.inert = !open;
3808
+ if (open === this._wasOpen) return;
3809
+ this._wasOpen = open;
3810
+ if (open) {
3811
+ this._returnFocus = deepActiveElement();
3812
+ lockScroll();
3813
+ this._undoInert = inertOutside(this);
3814
+ requestAnimationFrame(() => (firstFocusable(this) || this._box).focus({ preventScroll: true }));
3815
+ } else {
3816
+ unlockScroll();
3817
+ this._undoInert?.(); this._undoInert = null;
3818
+ const back = this._returnFocus;
3819
+ if (back && typeof back.focus === 'function' && back.isConnected) back.focus({ preventScroll: true });
3820
+ this._returnFocus = null;
3821
+ }
3822
+ }
3823
+
3824
+ setupEvents() {
3825
+ this._onBackdrop = (e) => { if (e.target === this._backdrop) this.close(); };
3826
+ this._onKey = (e) => { if (e.key === 'Escape' && this.getBoolAttr('open')) { e.stopPropagation(); this.close(); } };
3827
+ this._backdrop.addEventListener('click', this._onBackdrop);
3828
+ document.addEventListener('keydown', this._onKey);
3829
+ }
3830
+
3831
+ teardownEvents() {
3832
+ this._backdrop?.removeEventListener('click', this._onBackdrop);
3833
+ document.removeEventListener('keydown', this._onKey);
3834
+ if (this._wasOpen) { unlockScroll(); this._undoInert?.(); this._undoInert = null; this._wasOpen = false; }
3835
+ }
3836
+
3837
+ onAttributeChanged(name, oldValue, value) {
3838
+ if (name === 'title') { if (this.takeTitle(value)) this._syncTitle(); return; }
3839
+ this._syncOpen();
3840
+ this.emit('nk-toggle', { open: this.getBoolAttr('open') });
3841
+ }
3842
+
3843
+ show() { this.setBoolAttr('open', true); }
3844
+ close() { this.setBoolAttr('open', false); }
3845
+ toggle() { this.setBoolAttr('open', !this.getBoolAttr('open')); }
3846
+
3847
+ get open() { return this.getBoolAttr('open'); }
3848
+ set open(v) { this.setBoolAttr('open', v); }
3849
+ get title() { return this._titleText ?? ''; }
3850
+ set title(v) { this._titleText = v == null ? '' : String(v); if (this._initialized) this._syncTitle(); }
3851
+ }
3852
+
3853
+ customElements.define('nk-sheet', NkSheet);
3854
+
3855
+ // <nk-steps label="Connect your own model" current="2"
3856
+ // steps="Choose a provider, Enter the API key, Test the connection"></nk-steps>
3857
+ // steps.steps = [{ label: 'Choose a provider', desc: 'Anthropic' }, 'Enter the API key', …];
3858
+ // → <ol class="nk-steps" aria-label="…">
3859
+ // <li class="nk-step done"><span class="st-mark">✓</span><span>Choose a provider<span class="st-desc">Anthropic</span></span></li>
3860
+ // <li class="nk-step current" aria-current="step"><span class="st-mark">2</span><span>Enter the API key</span></li>
3861
+ // <li class="nk-step"><span class="st-mark">3</span><span>Test the connection</span></li></ol>
3862
+ // A setup in a few steps (NotionKit 1.7.0). `current` counts from 1; the
3863
+ // steps before it are done, one past the last marks all of them done. The
3864
+ // `steps` attribute is a comma-separated list; the property also takes
3865
+ // { label, desc } objects for a line under the label.
3866
+ class NkSteps extends NkElement {
3867
+ static get observedAttributes() { return ['steps', 'current', 'label']; }
3868
+
3869
+ render() {
3870
+ this._list = this.createElement('ol', ['nk-steps']);
3871
+ this._wrapper.appendChild(this._list);
3872
+ this._sync();
3873
+ }
3874
+
3875
+ _items() {
3876
+ if (this._steps) return this._steps;
3877
+ return (this.getAttribute('steps') || '').split(',').map(s => s.trim()).filter(Boolean);
3878
+ }
3879
+
3880
+ _sync() {
3881
+ const label = this.getAttribute('label');
3882
+ if (label) this._list.setAttribute('aria-label', label); else this._list.removeAttribute('aria-label');
3883
+ const current = this.current;
3884
+ this._list.replaceChildren(...this._items().map((step, i) => {
3885
+ const n = i + 1, { label: text, desc } = typeof step === 'object' && step ? step : { label: String(step) };
3886
+ const li = this.createElement('li', ['nk-step']);
3887
+ li.classList.toggle('done', n < current);
3888
+ li.classList.toggle('current', n === current);
3889
+ if (n === current) li.setAttribute('aria-current', 'step');
3890
+ const mark = this.createElement('span', ['st-mark'], { 'aria-hidden': 'true' });
3891
+ mark.textContent = n < current ? '✓' : String(n);
3892
+ const body = document.createElement('span');
3893
+ body.textContent = text ?? '';
3894
+ if (desc) { const d = this.createElement('span', ['st-desc']); d.textContent = desc; body.appendChild(d); }
3895
+ li.append(mark, body);
3896
+ return li;
3897
+ }));
3898
+ }
3899
+
3900
+ onAttributeChanged() { this._sync(); }
3901
+
3902
+ get steps() { return this._items(); }
3903
+ set steps(v) { this._steps = Array.isArray(v) ? v : null; if (this._list) this._sync(); }
3904
+ get current() { const n = parseInt(this.getAttribute('current'), 10); return Number.isFinite(n) ? n : 1; }
3905
+ set current(v) { this.setAttribute('current', String(v)); }
3906
+ /** Moves on to the next step; returns the new current step. */
3907
+ next() { this.current = Math.min(this.current + 1, this._items().length + 1); return this.current; }
3908
+ }
3909
+
3910
+ customElements.define('nk-steps', NkSteps);
3911
+
3512
3912
  // <nk-modal id="settings">
3513
3913
  // <nk-settings-user slot="user" name="…" mail="…"></nk-settings-user>
3514
3914
  // <nk-settings-pane name="profile" group="Account" icon="👤" label="My profile" title="My profile" active>…</nk-settings-pane>
@@ -3971,12 +4371,78 @@ customElements.define('nk-cmdk', NkCmdk);
3971
4371
  // </nk-menu>
3972
4372
  // → <div class="nk-pop nk-menu" role="menu">…</div>
3973
4373
  // ↑↓ move between items, Enter selects, nk-select bubbles from the item.
4374
+ //
4375
+ // <nk-menu floating sheet> is a menu over the page (NotionKit 1.7.0): it
4376
+ // fades in like the palette when `open` is set and is a bottom sheet on a
4377
+ // phone. The host becomes the fixed box you position – show(anchor) puts it
4378
+ // under the anchor, right edges aligned (align="start": left edges). A tap
4379
+ // outside closes it and reaches nothing else; Escape and a chosen item
4380
+ // close it too, a switch row does not. Opened from the keyboard, focus moves
4381
+ // to the first item; closing returns it to where it was.
4382
+ const floatSheet = new CSSStyleSheet();
4383
+ floatSheet.replaceSync(`:host([floating]) { display: block; position: fixed; z-index: 60; pointer-events: none; }`);
4384
+
4385
+ /** The border box of an element, or of the first descendant with one (display: contents hosts). */
4386
+ function boxOf(el) {
4387
+ if (el.getClientRects().length) return el.getBoundingClientRect();
4388
+ for (const child of [...(el.shadowRoot?.children ?? []), ...el.children]) {
4389
+ const r = boxOf(child);
4390
+ if (r.width || r.height) return r;
4391
+ }
4392
+ return el.getBoundingClientRect();
4393
+ }
4394
+
3974
4395
  class NkMenu extends NkElement {
4396
+ static get hostStyles() { return floatSheet; }
4397
+ static get observedAttributes() { return ['floating', 'sheet', 'open', 'align']; }
4398
+
3975
4399
  render() {
3976
4400
  this._box = this.createElement('div', ['nk-pop', 'nk-menu'], { role: 'menu' });
3977
4401
  this._box.appendChild(document.createElement('slot'));
3978
4402
  this._wrapper.appendChild(this._box);
4403
+ this._syncMode();
4404
+ }
4405
+
4406
+ _syncMode() {
4407
+ this._box.classList.toggle('floating', this.getBoolAttr('floating'));
4408
+ this._box.classList.toggle('sheet', this.getBoolAttr('sheet'));
4409
+ this._box.classList.toggle('open', this.getBoolAttr('open'));
4410
+ }
4411
+
4412
+ onAttributeChanged(name) {
4413
+ this._syncMode();
4414
+ if (name !== 'open') return;
4415
+ const open = this.getBoolAttr('open');
4416
+ // aria-expanded belongs on the control itself, inside a host such as <nk-btn>.
4417
+ if (this._anchor) (this._anchor.shadowRoot?.querySelector('button, a[href]') ?? this._anchor).setAttribute('aria-expanded', String(open));
4418
+ if (open) {
4419
+ this._returnFocus = deepActiveElement();
4420
+ if (this._returnFocus?.matches(':focus-visible')) requestAnimationFrame(() => this.focusFirst());
4421
+ document.addEventListener('click', this._onOutside, true);
4422
+ } else {
4423
+ document.removeEventListener('click', this._onOutside, true);
4424
+ const back = this._returnFocus;
4425
+ this._returnFocus = null;
4426
+ if (back?.isConnected && this.contains(document.activeElement)) back.focus({ preventScroll: true });
4427
+ }
4428
+ this.emit('nk-toggle', { open });
4429
+ }
4430
+
4431
+ /** Opens under `anchor` (any element, display: contents hosts included). */
4432
+ show(anchor) {
4433
+ if (anchor) {
4434
+ this._anchor = anchor;
4435
+ const r = boxOf(anchor);
4436
+ this.style.top = `${r.bottom + 6}px`;
4437
+ if (this.getAttribute('align') === 'start') { this.style.left = `${r.left}px`; this.style.right = ''; }
4438
+ else { this.style.right = `${Math.max(8, innerWidth - r.right)}px`; this.style.left = ''; }
4439
+ }
4440
+ this.setBoolAttr('open', true);
3979
4441
  }
4442
+ close() { this.setBoolAttr('open', false); }
4443
+ toggle(anchor) { this.getBoolAttr('open') ? this.close() : this.show(anchor); }
4444
+ get open() { return this.getBoolAttr('open'); }
4445
+ set open(v) { this.setBoolAttr('open', v); }
3980
4446
 
3981
4447
  get items() { return [...this.querySelectorAll(':scope > nk-menu-item')].filter(i => i.selectable); }
3982
4448
 
@@ -3995,9 +4461,27 @@ class NkMenu extends NkElement {
3995
4461
  }
3996
4462
  };
3997
4463
  this.addEventListener('keydown', this._onKey);
4464
+ // Floating: outside taps close and go nowhere else; Escape and a chosen item close.
4465
+ this._onOutside = (e) => {
4466
+ const path = e.composedPath();
4467
+ if (path.includes(this) || (this._anchor && path.includes(this._anchor))) return;
4468
+ e.preventDefault(); e.stopPropagation();
4469
+ this.close();
4470
+ };
4471
+ // Captured, so a menu inside a modal or sheet closes before they do.
4472
+ this._onEscape = (e) => { if (e.key === 'Escape' && this.getBoolAttr('floating') && this.getBoolAttr('open')) { e.stopPropagation(); this.close(); } };
4473
+ this._onSelect = () => { if (this.getBoolAttr('floating')) this.close(); };
4474
+ document.addEventListener('keydown', this._onEscape, true);
4475
+ this.addEventListener('nk-select', this._onSelect);
4476
+ if (this.getBoolAttr('open')) document.addEventListener('click', this._onOutside, true);
3998
4477
  }
3999
4478
 
4000
- teardownEvents() { this.removeEventListener('keydown', this._onKey); }
4479
+ teardownEvents() {
4480
+ this.removeEventListener('keydown', this._onKey);
4481
+ document.removeEventListener('keydown', this._onEscape, true);
4482
+ this.removeEventListener('nk-select', this._onSelect);
4483
+ document.removeEventListener('click', this._onOutside, true);
4484
+ }
4001
4485
 
4002
4486
  /** Focuses the first item (called by a popover when it opens). */
4003
4487
  focusFirst() { this.items[0]?.focus(); }
@@ -4008,9 +4492,15 @@ customElements.define('nk-menu', NkMenu);
4008
4492
  // <nk-menu-item icon="✏️" shortcut="⌘E" value="rename">Rename</nk-menu-item>
4009
4493
  // <nk-menu-item type="separator"></nk-menu-item> <nk-menu-item type="label">Danger</nk-menu-item>
4010
4494
  // <nk-menu-item icon="🗑️" danger value="delete">Delete</nk-menu-item>
4495
+ // <nk-menu-item type="switch" icon="🔡" value="small" checked>Small text</nk-menu-item>
4496
+ // <nk-menu-item type="check" icon="◉" value="open" checked>Status: Open</nk-menu-item>
4011
4497
  // → <div class="nk-menu-item danger"><span class="m-icon">🗑️</span>Delete<span class="m-shortcut">…</span></div>
4498
+ // A switch item carries a .nk-switch on the right, as "Small text" does in
4499
+ // Notion's page menu; a check item a ✓ where the shortcut stands, as in a
4500
+ // filter menu. A click on either flips `checked` and fires nk-change
4501
+ // { value, checked } instead of nk-select, so the menu around it stays open.
4012
4502
  class NkMenuItem extends NkElement {
4013
- static get observedAttributes() { return ['icon', 'shortcut', 'danger', 'value', 'type', 'disabled']; }
4503
+ static get observedAttributes() { return ['icon', 'shortcut', 'danger', 'value', 'type', 'disabled', 'checked']; }
4014
4504
 
4015
4505
  render() { this._build(); }
4016
4506
 
@@ -4023,12 +4513,16 @@ class NkMenuItem extends NkElement {
4023
4513
  el = this.createElement('div', ['nk-menu-label']);
4024
4514
  el.appendChild(document.createElement('slot'));
4025
4515
  } else {
4026
- el = this.createElement('div', ['nk-menu-item'], { role: 'menuitem', tabindex: '-1' });
4516
+ const isSwitch = type === 'switch';
4517
+ this._check = type === 'check';
4518
+ el = this.createElement('div', ['nk-menu-item'], { role: isSwitch || this._check ? 'menuitemcheckbox' : 'menuitem', tabindex: '-1' });
4027
4519
  this._icon = this.createElement('span', ['m-icon']);
4028
4520
  const iconSlot = this.createElement('slot', [], { name: 'icon' });
4029
4521
  iconSlot.appendChild(this._icon);
4030
4522
  this._shortcut = this.createElement('span', ['m-shortcut']);
4031
4523
  el.append(iconSlot, document.createElement('slot'), this._shortcut);
4524
+ this._switch = isSwitch ? this.createElement('span', ['nk-switch'], { 'aria-hidden': 'true' }) : null;
4525
+ if (this._switch) el.appendChild(this._switch);
4032
4526
  }
4033
4527
  if (this._el) { this._el.removeEventListener('click', this._onClick); this._el.replaceWith(el); } else this._wrapper.appendChild(el);
4034
4528
  this._el = el;
@@ -4046,6 +4540,12 @@ class NkMenuItem extends NkElement {
4046
4540
  this._shortcut.style.display = sc ? '' : 'none';
4047
4541
  this._el.classList.toggle('danger', this.getBoolAttr('danger'));
4048
4542
  this._el.setAttribute('aria-disabled', this.getBoolAttr('disabled') ? 'true' : 'false');
4543
+ if (this._switch || this._check) {
4544
+ const on = this.getBoolAttr('checked') ? 'true' : 'false';
4545
+ this._el.setAttribute('aria-checked', on);
4546
+ if (this._switch) this._switch.setAttribute('aria-checked', on);
4547
+ if (this._check) { this._shortcut.textContent = on === 'true' ? '✓' : ''; this._shortcut.style.display = ''; }
4548
+ }
4049
4549
  }
4050
4550
 
4051
4551
  setupEvents() {
@@ -4057,6 +4557,11 @@ class NkMenuItem extends NkElement {
4057
4557
 
4058
4558
  select() {
4059
4559
  if (!this._el.classList.contains('nk-menu-item') || this.getBoolAttr('disabled')) return;
4560
+ if (this._switch || this._check) {
4561
+ this.checked = !this.checked;
4562
+ this.emit('nk-change', { value: this.value, checked: this.checked, item: this });
4563
+ return;
4564
+ }
4060
4565
  this.emit('nk-select', { value: this.value, label: this.textContent.trim(), item: this });
4061
4566
  }
4062
4567
 
@@ -4064,6 +4569,8 @@ class NkMenuItem extends NkElement {
4064
4569
  focus(o) { this._el?.focus(o); }
4065
4570
  get selectable() { return this._el?.classList.contains('nk-menu-item') && !this.getBoolAttr('disabled'); }
4066
4571
 
4572
+ get checked() { return this.getBoolAttr('checked'); }
4573
+ set checked(v) { this.setBoolAttr('checked', v); }
4067
4574
  get value() { return this.getAttribute('value') ?? this.textContent.trim(); }
4068
4575
  set value(v) { this.setAttribute('value', v); }
4069
4576
  }
@@ -4338,16 +4845,24 @@ customElements.define('nk-toast', NkToast);
4338
4845
  // </nk-database>
4339
4846
  // db.columns = [{ key: 'name', label: 'Name', type: 'text', icon: '📄', title: true }, { key: 'status', type: 'select', options: [...] }, …];
4340
4847
  // db.rows = [{ id: 1, icon: '🧭', name: '…', status: 'done', … }];
4341
- // → <div class="nk-database"><div class="nk-db-tabs">…</div>…active view…</div>
4848
+ // <nk-btn slot="tools" variant="tool">Filter</nk-btn> … sit right of the tabs,
4849
+ // <nk-filter-bar slot="filters"> under them (NotionKit 1.7.0's toolbar).
4850
+ // → <div class="nk-database"><div class="nk-db-toolbar"><div class="nk-db-tabs">…</div>
4851
+ // <div class="tools">…</div></div>…filters…active view…</div>
4342
4852
  // The tabs come from the child views; data is pushed into every view.
4343
4853
  class NkDatabase extends NkElement {
4344
4854
  static get observedAttributes() { return ['view', 'add-view']; }
4345
4855
 
4346
4856
  render() {
4347
4857
  this._box = this.createElement('div', ['nk-database']);
4858
+ this._toolbar = this.createElement('div', ['nk-db-toolbar']);
4348
4859
  this._tabs = this.createElement('div', ['nk-db-tabs'], { role: 'tablist' });
4860
+ const tools = this.createElement('div', ['tools']);
4861
+ this._toolsSlot = this.createElement('slot', [], { name: 'tools' });
4862
+ tools.appendChild(this._toolsSlot);
4863
+ this._toolbar.append(this._tabs, tools);
4349
4864
  this._slot = document.createElement('slot');
4350
- this._box.append(this._tabs, this._slot);
4865
+ this._box.append(this._toolbar, this.createElement('slot', [], { name: 'filters' }), this._slot);
4351
4866
  this._wrapper.appendChild(this._box);
4352
4867
  this._columns = []; this._rows = [];
4353
4868
  this._sync();
@@ -4375,12 +4890,11 @@ class NkDatabase extends NkElement {
4375
4890
  v.setData?.(this._columns, this._rows);
4376
4891
  }
4377
4892
  if (this.getBoolAttr('add-view')) {
4378
- const add = this.createElement('span', ['nk-db-tab'], { role: 'button', 'data-add': '', tabindex: '0' });
4379
- add.style.color = 'var(--nk-text-tertiary)';
4893
+ const add = this.createElement('span', ['nk-db-tab', 'add'], { role: 'button', 'data-add': '', tabindex: '0' });
4380
4894
  add.textContent = '+';
4381
4895
  this._tabs.appendChild(add);
4382
4896
  }
4383
- this._tabs.style.display = views.length ? '' : 'none';
4897
+ this._toolbar.hidden = !views.length && !this._toolsSlot.assignedElements().length;
4384
4898
  this._current = current;
4385
4899
  }
4386
4900
 
@@ -4402,6 +4916,7 @@ class NkDatabase extends NkElement {
4402
4916
  this._tabs.addEventListener('click', this._onClick);
4403
4917
  this._tabs.addEventListener('keydown', this._onKey);
4404
4918
  this._slot.addEventListener('slotchange', this._onSlot);
4919
+ this._toolsSlot.addEventListener('slotchange', this._onSlot);
4405
4920
  this._sync();
4406
4921
  }
4407
4922
 
@@ -4409,6 +4924,7 @@ class NkDatabase extends NkElement {
4409
4924
  this._tabs?.removeEventListener('click', this._onClick);
4410
4925
  this._tabs?.removeEventListener('keydown', this._onKey);
4411
4926
  this._slot?.removeEventListener('slotchange', this._onSlot);
4927
+ this._toolsSlot?.removeEventListener('slotchange', this._onSlot);
4412
4928
  }
4413
4929
 
4414
4930
  onAttributeChanged(name) {
@@ -4436,6 +4952,7 @@ customElements.define('nk-database', NkDatabase);
4436
4952
  //
4437
4953
  // column: { key, label, type, icon, options: [{ value, label, color }], title }
4438
4954
  // types: text | select | multi-select | date | person | checkbox | url | number | progress
4955
+
4439
4956
  const el = (tag, cls, text) => { const n = document.createElement(tag); if (cls) n.className = cls; if (text != null) n.textContent = text; return n; };
4440
4957
  const COLORS = ['gray', 'brown', 'orange', 'yellow', 'green', 'blue', 'purple', 'pink', 'red'];
4441
4958
 
@@ -4469,14 +4986,16 @@ function renderPropertyCell(column, value, row = {}) {
4469
4986
  case 'person': {
4470
4987
  const cell = el('span', 'person-cell');
4471
4988
  const p = typeof value === 'string' ? { name: value } : value;
4472
- const avatar = el('span', 'mini-avatar', p.initials || p.avatar || (p.name || '').split(/\s+/).map(w => w[0]).join('').slice(0, 2).toUpperCase());
4473
- avatar.style.background = p.color || 'var(--nk-text-tertiary)';
4989
+ // color: one of Notion's nine names, or any CSS background; none – the avatar gradient.
4990
+ const avatar = el('span', 'nk-avatar small', p.initials || p.avatar || initialsOf(p.name));
4991
+ paintAvatar(avatar, p.color);
4474
4992
  cell.append(avatar, document.createTextNode(' ' + (p.name || '')));
4475
4993
  return cell;
4476
4994
  }
4477
4995
  case 'checkbox': return checkbox(column, !!value, row);
4478
4996
  case 'url': { const a = el('a', null, String(value).replace(/^https?:\/\//, '')); a.href = String(value); a.target = '_blank'; a.rel = 'noopener'; return a; }
4479
- case 'number': return el('span', null, typeof value === 'number' ? value.toLocaleString() : String(value));
4997
+ // column.locale / column.format: Intl.NumberFormat locale and options, e.g. { minimumFractionDigits: 1 }.
4998
+ case 'number': return el('span', null, typeof value === 'number' ? value.toLocaleString(column.locale, column.format) : String(value));
4480
4999
  case 'progress': return progress(Number(value) || 0);
4481
5000
  default: {
4482
5001
  if (column.title) {
@@ -4569,6 +5088,8 @@ class NkTableView extends NkElement {
4569
5088
  const r = this.createElement('tr', [], { 'data-id': row.id ?? '' });
4570
5089
  for (const col of this._columns) {
4571
5090
  const td = document.createElement('td');
5091
+ // Numbers right-aligned in figures of equal width, as Notion sets them.
5092
+ if (col.type === 'number') td.className = 'num';
4572
5093
  td.appendChild(renderPropertyCell(col, row[col.key], row));
4573
5094
  r.appendChild(td);
4574
5095
  }
@@ -4752,61 +5273,167 @@ class NkBoardView extends NkElement {
4752
5273
 
4753
5274
  customElements.define('nk-board-view', NkBoardView);
4754
5275
 
4755
- // <nk-filter-bar search placeholder="Search rows …"></nk-filter-bar>
4756
- // bar.filters = [{ key: 'status', label: 'Status: Done', value: 'done' }];
4757
- // Composed from existing classes (nk-btn secondary small, nk-input, nk-tag):
4758
- // filter / sort buttons fire nk-action, chips remove on ×, search and chip
4759
- // changes fire nk-change { filters, search }. The wrapper is layout only.
5276
+ // <nk-list-view name="list" label="☰ List" meta-keys="due,status" new-row></nk-list-view>
5277
+ // The third database view: one line per row – icon and title, the `meta-keys`
5278
+ // on the right (default: the select and date columns, in column order). Dates
5279
+ // and text stand as text, selects as tags, a person as avatar and name.
5280
+ // Standalone: view.columns = […]; view.rows = […]. Inside <nk-database> the
5281
+ // database pushes the data. Rows fire nk-select, the add row nk-action
5282
+ // { action: 'new-row' }.
5283
+ // → <div class="nk-list"><div class="nk-list-item"><span class="l-icon">…</span><span class="l-title">…</span><span class="l-meta">…</span></div>…</div>
5284
+ class NkListView extends NkElement {
5285
+ static get observedAttributes() { return ['name', 'label', 'badge', 'count', 'title-key', 'meta-keys', 'new-row', 'new-row-label']; }
5286
+
5287
+ render() {
5288
+ this._box = document.createElement('div');
5289
+ this._list = this.createElement('div', ['nk-list'], { role: 'list' });
5290
+ this._newRow = this.createElement('div', ['nk-new-row'], { role: 'button', tabindex: '0' });
5291
+ this._box.append(this._list, this._newRow);
5292
+ this._wrapper.appendChild(this._box);
5293
+ this._columns ??= []; this._rows ??= [];
5294
+ this._render();
5295
+ this.closest('nk-database')?.requestSync?.();
5296
+ }
5297
+
5298
+ _titleColumn() {
5299
+ const key = this.getAttribute('title-key');
5300
+ return this._columns.find(c => c.key === key) || this._columns.find(c => c.title) || this._columns[0] || null;
5301
+ }
5302
+ _metaColumns() {
5303
+ const keys = (this.getAttribute('meta-keys') || '').split(',').map(s => s.trim()).filter(Boolean);
5304
+ if (keys.length) return keys.map(k => this._columns.find(c => c.key === k)).filter(Boolean);
5305
+ return this._columns.filter(c => c.type === 'select' || c.type === 'date');
5306
+ }
5307
+
5308
+ _render() {
5309
+ if (!this._list) return;
5310
+ const title = this._titleColumn(), meta = this._metaColumns();
5311
+ this._list.replaceChildren();
5312
+ for (const row of this._rows) {
5313
+ const item = this.createElement('div', ['nk-list-item'], { role: 'listitem', tabindex: '0', 'data-id': row.id ?? '' });
5314
+ const icon = this.createElement('span', ['l-icon']);
5315
+ icon.textContent = row.icon || '';
5316
+ if (!row.icon) icon.style.display = 'none';
5317
+ const t = this.createElement('span', ['l-title']);
5318
+ t.textContent = title ? String(row[title.key] ?? '') : '';
5319
+ const m = this.createElement('span', ['l-meta']);
5320
+ for (const c of meta) {
5321
+ const v = row[c.key];
5322
+ if (v === undefined || v === null || v === '') continue;
5323
+ m.appendChild(c.type === 'date' || c.type === 'text' || !c.type ? document.createTextNode(String(v)) : renderPropertyCell(c, v, row));
5324
+ }
5325
+ item.append(icon, t, m);
5326
+ this._list.appendChild(item);
5327
+ }
5328
+ this._newRow.textContent = this.getAttribute('new-row-label') || '+ New page';
5329
+ this._newRow.style.display = this.getBoolAttr('new-row') ? '' : 'none';
5330
+ }
5331
+
5332
+ setupEvents() {
5333
+ this._onClick = (e) => {
5334
+ if (this._newRow.contains(e.target)) { this.emit('nk-action', { action: 'new-row' }); return; }
5335
+ const item = e.target.closest('.nk-list-item');
5336
+ if (item) { const row = this._rowById(item.dataset.id); this.emit('nk-select', { row, id: row?.id, value: row?.id }); }
5337
+ };
5338
+ this._onKey = (e) => {
5339
+ if (e.key !== 'Enter' && e.key !== ' ') return;
5340
+ if (e.target === this._newRow || e.target.classList?.contains('nk-list-item')) { e.preventDefault(); e.target.click(); }
5341
+ };
5342
+ this._box.addEventListener('click', this._onClick);
5343
+ this._box.addEventListener('keydown', this._onKey);
5344
+ }
5345
+
5346
+ teardownEvents() {
5347
+ this._box?.removeEventListener('click', this._onClick);
5348
+ this._box?.removeEventListener('keydown', this._onKey);
5349
+ }
5350
+
5351
+ _rowById(id) { return this._rows.find(r => String(r.id) === String(id)); }
5352
+ onAttributeChanged() { this._render(); }
5353
+
5354
+ get name() { return this.getAttribute('name') || 'list'; }
5355
+ get columns() { return this._columns; }
5356
+ set columns(v) { this._columns = Array.isArray(v) ? v : []; this._render(); }
5357
+ get rows() { return this._rows; }
5358
+ set rows(v) { this._rows = Array.isArray(v) ? v : []; this._render(); }
5359
+ set data({ columns, rows }) { this.setData(columns, rows); }
5360
+ setData(columns, rows) { this._columns = columns || []; this._rows = rows || []; this._render(); }
5361
+ refresh() { this._render(); }
5362
+ }
5363
+
5364
+ customElements.define('nk-list-view', NkListView);
5365
+
5366
+ // <nk-filter-bar add no-filter no-sort></nk-filter-bar>
5367
+ // bar.filters = [{ key: 'status', value: 'done', op: 'is-not', label: 'Status: Open' }];
5368
+ // The filters in effect as NotionKit's filter pills (1.7.0), no inline style:
5369
+ // → <div class="nk-filter-row">[Filter][Sort]
5370
+ // <span class="nk-filter-pill active"><button>Status: Open</button><button class="fp-remove">×</button></span>…
5371
+ // <button class="nk-filter-pill add">+ Filter</button> …slot… [search]</div>
5372
+ // Filter and Sort are .nk-db-tool buttons (hide them with no-filter / no-sort
5373
+ // when the database toolbar carries its own); they fire nk-action. A pill's
5374
+ // label fires nk-action { action: 'edit', index, filter }, the add pill
5375
+ // nk-action { action: 'add' } – each with the clicked button as `anchor`, to
5376
+ // open a menu under it. × removes the filter; every change to filters or
5377
+ // search fires nk-change { filters, search }. In slot="filters" of
5378
+ // <nk-database> the row sits right under the view tabs. The texts are
5379
+ // attributes, for other languages: filter-label, sort-label, add-label,
5380
+ // remove-label (the × reads "<remove-label>: <pill>") and placeholder.
4760
5381
  class NkFilterBar extends NkElement {
4761
- static get observedAttributes() { return ['search', 'placeholder', 'no-filter', 'no-sort', 'value']; }
5382
+ static get observedAttributes() { return ['search', 'placeholder', 'no-filter', 'no-sort', 'value', 'add', 'add-label', 'filter-label', 'sort-label', 'remove-label']; }
4762
5383
 
4763
5384
  render() {
4764
- this._bar = document.createElement('div');
4765
- this._bar.style.cssText = 'display:flex;align-items:center;gap:6px;flex-wrap:wrap;margin:8px 0';
4766
- this._filterBtn = this.createElement('button', ['nk-btn', 'secondary', 'small'], { type: 'button', 'data-action': 'filter' });
4767
- this._filterBtn.textContent = '⚲ Filter';
4768
- this._sortBtn = this.createElement('button', ['nk-btn', 'secondary', 'small'], { type: 'button', 'data-action': 'sort' });
4769
- this._sortBtn.textContent = '↕ Sort';
4770
- this._chips = document.createElement('span');
4771
- this._chips.style.cssText = 'display:inline-flex;gap:4px;flex-wrap:wrap';
5385
+ this._row = this.createElement('div', ['nk-filter-row']);
5386
+ this._filterBtn = this.createElement('button', ['nk-db-tool'], { type: 'button', 'data-action': 'filter' });
5387
+ this._sortBtn = this.createElement('button', ['nk-db-tool'], { type: 'button', 'data-action': 'sort' });
5388
+ this._pillStart = document.createComment('pills');
5389
+ this._addBtn = this.createElement('button', ['nk-filter-pill', 'add'], { type: 'button', 'data-action': 'add' });
4772
5390
  this._input = this.createElement('input', ['nk-input'], { type: 'search', autocomplete: 'off' });
4773
- this._input.style.marginLeft = 'auto';
4774
- this._bar.append(this._filterBtn, this._sortBtn, this._chips, document.createElement('slot'), this._input);
4775
- this._wrapper.appendChild(this._bar);
5391
+ this._row.append(this._filterBtn, this._sortBtn, this._pillStart, this._addBtn, document.createElement('slot'), this._input);
5392
+ this._wrapper.appendChild(this._row);
4776
5393
  this._filters = [];
4777
5394
  this._sync();
4778
5395
  }
4779
5396
 
4780
5397
  _sync() {
4781
- this._filterBtn.style.display = this.getBoolAttr('no-filter') ? 'none' : '';
4782
- this._sortBtn.style.display = this.getBoolAttr('no-sort') ? 'none' : '';
4783
- this._input.style.display = this.getBoolAttr('search') ? '' : 'none';
5398
+ this._filterBtn.textContent = this.getAttribute('filter-label') || 'Filter';
5399
+ this._filterBtn.hidden = this.getBoolAttr('no-filter');
5400
+ this._filterBtn.classList.toggle('active', this._filters.length > 0);
5401
+ this._sortBtn.textContent = this.getAttribute('sort-label') || 'Sort';
5402
+ this._sortBtn.hidden = this.getBoolAttr('no-sort');
5403
+ this._addBtn.textContent = this.getAttribute('add-label') || '+ Filter';
5404
+ this._addBtn.hidden = !this.getBoolAttr('add');
5405
+ this._input.hidden = !this.getBoolAttr('search');
4784
5406
  this._input.placeholder = this.getAttribute('placeholder') || 'Search …';
4785
5407
  if (this.hasAttribute('value') && this._input.value !== this.getAttribute('value')) this._input.value = this.getAttribute('value');
4786
- this._chips.replaceChildren();
4787
- this._filters.forEach((f, i) => {
4788
- const chip = this.createElement('span', ['nk-tag', f.color || 'blue'], { 'data-index': i });
4789
- chip.style.cursor = 'pointer';
4790
- chip.textContent = `${f.label ?? `${f.key}: ${f.value}`} ×`;
4791
- chip.title = 'Remove filter';
4792
- this._chips.appendChild(chip);
4793
- });
5408
+ for (const old of this._row.querySelectorAll('[data-pill]')) old.remove();
5409
+ const removeLabel = this.getAttribute('remove-label') || 'Remove filter';
5410
+ this._pillStart.after(...this._filters.map((f, i) => {
5411
+ const pill = this.createElement('span', ['nk-filter-pill', 'active'], { 'data-pill': i });
5412
+ const label = this.createElement('button', [], { type: 'button', 'data-edit': i });
5413
+ label.textContent = f.label ?? `${f.key}: ${f.value}`;
5414
+ const remove = this.createElement('button', ['fp-remove'], { type: 'button', 'data-remove': i, 'aria-label': `${removeLabel}: ${label.textContent}` });
5415
+ remove.textContent = '×';
5416
+ pill.append(label, remove);
5417
+ return pill;
5418
+ }));
4794
5419
  }
4795
5420
 
4796
5421
  setupEvents() {
4797
5422
  this._onClick = (e) => {
5423
+ const remove = e.target.closest('[data-remove]');
5424
+ if (remove) { this._filters.splice(Number(remove.dataset.remove), 1); this._sync(); this._emitChange(); return; }
5425
+ const edit = e.target.closest('[data-edit]');
5426
+ if (edit) { const index = Number(edit.dataset.edit); this.emit('nk-action', { action: 'edit', index, filter: this._filters[index], anchor: edit }); return; }
4798
5427
  const btn = e.target.closest('[data-action]');
4799
- if (btn) { this.emit('nk-action', { action: btn.dataset.action }); return; }
4800
- const chip = e.target.closest('[data-index]');
4801
- if (chip) { this._filters.splice(Number(chip.dataset.index), 1); this._sync(); this._emitChange(); }
5428
+ if (btn) this.emit('nk-action', { action: btn.dataset.action, anchor: btn });
4802
5429
  };
4803
5430
  this._onInput = () => { clearTimeout(this._debounce); this._debounce = setTimeout(() => this._emitChange(), 150); };
4804
- this._bar.addEventListener('click', this._onClick);
5431
+ this._row.addEventListener('click', this._onClick);
4805
5432
  this._input.addEventListener('input', this._onInput);
4806
5433
  }
4807
5434
 
4808
5435
  teardownEvents() {
4809
- this._bar?.removeEventListener('click', this._onClick);
5436
+ this._row?.removeEventListener('click', this._onClick);
4810
5437
  this._input?.removeEventListener('input', this._onInput);
4811
5438
  clearTimeout(this._debounce);
4812
5439
  }
@@ -4815,13 +5442,18 @@ class NkFilterBar extends NkElement {
4815
5442
  onAttributeChanged() { this._sync(); }
4816
5443
 
4817
5444
  get filters() { return this._filters; }
4818
- set filters(v) { this._filters = Array.isArray(v) ? v : []; this._sync(); }
5445
+ set filters(v) { this._filters = Array.isArray(v) ? v : []; if (this._row) this._sync(); }
4819
5446
  get value() { return this._input?.value ?? ''; }
4820
5447
  set value(v) { if (this._input) this._input.value = v ?? ''; }
4821
- /** Applies filters + search to rows: equality per filter key, substring search over every string field. */
5448
+ /**
5449
+ * Applies filters and search to rows: a filter keeps rows where row[key]
5450
+ * equals value – or differs from it with op: 'is-not'; the search looks
5451
+ * for the text in every string field (a person's name).
5452
+ */
4822
5453
  apply(rows) {
4823
5454
  const q = this.value.trim().toLowerCase();
4824
- return rows.filter(r => this._filters.every(f => r[f.key] === f.value) && (!q || Object.values(r).some(v => String(typeof v === 'object' && v ? v.name ?? '' : v ?? '').toLowerCase().includes(q))));
5455
+ return rows.filter(r => this._filters.every(f => (f.op === 'is-not' ? r[f.key] !== f.value : r[f.key] === f.value))
5456
+ && (!q || Object.values(r).some(v => String(typeof v === 'object' && v ? v.name ?? '' : v ?? '').toLowerCase().includes(q))));
4825
5457
  }
4826
5458
  }
4827
5459
 
@@ -4881,15 +5513,16 @@ class NkComments extends NkElement {
4881
5513
 
4882
5514
  customElements.define('nk-comments', NkComments);
4883
5515
 
4884
- // <nk-comment author="Sara Lindt" time="1 hr ago" avatar="SL" color="#448361">The board view feels close.</nk-comment>
4885
- // → <div class="nk-comment"><span class="mini-avatar">SL</span><div><div class="c-head"><b>Sara Lindt</b> · 1 hr ago</div><div class="c-body">…</div></div></div>
5516
+ // <nk-comment author="Sara Lindt" time="1 hr ago" avatar="SL" color="green">The board view feels close.</nk-comment>
5517
+ // → <div class="nk-comment"><span class="nk-avatar green">SL</span><div><div class="c-head"><b>Sara Lindt</b> · 1 hr ago</div><div class="c-body">…</div></div></div>
5518
+ // color: one of Notion's nine names, or any CSS background; without it the avatar gradient.
4886
5519
  // slot="head" adds content after the name (e.g. an <nk-tag>).
4887
5520
  class NkComment extends NkElement {
4888
5521
  static get observedAttributes() { return ['author', 'time', 'avatar', 'color']; }
4889
5522
 
4890
5523
  render() {
4891
5524
  const box = this.createElement('div', ['nk-comment']);
4892
- this._avatar = this.createElement('span', ['mini-avatar']);
5525
+ this._avatar = this.createElement('span', ['nk-avatar']);
4893
5526
  const avatarSlot = this.createElement('slot', [], { name: 'avatar' });
4894
5527
  avatarSlot.appendChild(this._avatar);
4895
5528
  const text = document.createElement('div');
@@ -4910,8 +5543,8 @@ class NkComment extends NkElement {
4910
5543
  this._author.textContent = author;
4911
5544
  const time = this.getAttribute('time');
4912
5545
  this._time.data = time ? ` · ${time}` : '';
4913
- this._avatar.textContent = this.getAttribute('avatar') || author.split(/\s+/).map(w => w[0]).join('').slice(0, 2).toUpperCase();
4914
- this._avatar.style.background = this.getAttribute('color') || 'var(--nk-text-tertiary)';
5546
+ this._avatar.textContent = this.getAttribute('avatar') || initialsOf(author);
5547
+ paintAvatar(this._avatar, this.getAttribute('color'));
4915
5548
  }
4916
5549
 
4917
5550
  onAttributeChanged() { this._sync(); }
@@ -4935,16 +5568,18 @@ customElements.define('nk-ai-thread', NkAiThread);
4935
5568
  // Two tasks are open …
4936
5569
  // <button slot="actions" value="copy">📋 Copy</button><button slot="actions" value="retry">↻ Rephrase</button>
4937
5570
  // </nk-ai-msg>
5571
+ // <nk-ai-msg role="user" bubble>What is still open?</nk-ai-msg> → a grey bubble on the right, as in Notion's AI chat
4938
5572
  // → <div class="nk-ai-msg user"><span class="mini-avatar">MK</span><div class="a-body"><div class="a-name">You</div>…<div class="nk-ai-actions">…</div></div></div>
4939
5573
  // Action buttons stay in the light DOM (slotted twins) and fire nk-action { action: value }.
4940
5574
  class NkAiMsg extends NkElement {
4941
- static get observedAttributes() { return ['role', 'name', 'badge', 'avatar', 'color']; }
5575
+ static get observedAttributes() { return ['role', 'name', 'badge', 'avatar', 'color', 'bubble']; }
4942
5576
 
4943
5577
  render() {
4944
5578
  this._box = this.createElement('div', ['nk-ai-msg']);
4945
5579
  this._avatar = this.createElement('span', ['mini-avatar']);
4946
5580
  const avatarSlot = this.createElement('slot', [], { name: 'avatar' });
4947
5581
  avatarSlot.appendChild(this._avatar);
5582
+ this._avatarSlot = avatarSlot;
4948
5583
  const body = this.createElement('div', ['a-body']);
4949
5584
  this._name = this.createElement('div', ['a-name']);
4950
5585
  this._nameText = document.createTextNode('');
@@ -4961,12 +5596,16 @@ class NkAiMsg extends NkElement {
4961
5596
 
4962
5597
  _sync() {
4963
5598
  const user = this.getAttribute('role') === 'user';
5599
+ const bubble = this.getBoolAttr('bubble');
4964
5600
  this._box.classList.toggle('user', user);
5601
+ this._box.classList.toggle('bubble', bubble);
4965
5602
  const name = this.getAttribute('name');
4966
5603
  this._nameText.data = name || '';
4967
5604
  const badge = this.getAttribute('badge');
4968
5605
  this._badge.textContent = badge ? ` ${badge}` : '';
4969
- this._name.style.display = name ? '' : 'none';
5606
+ // A bubble stands without avatar and name; the text says who asked.
5607
+ this._name.style.display = name && !bubble ? '' : 'none';
5608
+ this._avatarSlot.style.display = bubble ? 'none' : '';
4970
5609
  this._avatar.textContent = this.getAttribute('avatar') || (user ? (name || 'U').slice(0, 2).toUpperCase() : '✨');
4971
5610
  const color = this.getAttribute('color');
4972
5611
  this._avatar.style.background = color || '';
@@ -5048,4 +5687,4 @@ class NkAiInputRow extends NkElement {
5048
5687
 
5049
5688
  customElements.define('nk-ai-input-row', NkAiInputRow);
5050
5689
 
5051
- export { NkAiInputRow, NkAiMsg, NkAiThread, NkApp, NkAvatarGroup, NkBanner, NkBlockHost, NkBoardView, NkBreadcrumb, NkBtn, NkCallout, NkCheck, NkCmdk, NkCode, NkComment, NkComments, NkDangerZone, NkDatabase, NkDivider, NkElement, NkEmojiPicker, NkEmpty, NkField, NkFields, NkFilterBar, NkFormElement, NkHeading, NkInput, NkKbd, NkMemberList, NkMemberRow, NkMention, NkMenu, NkMenuItem, NkModal, NkModelCard, NkPage, NkPageActions, NkPageCover, NkPageTitle, NkPop, NkProfileRow, NkProgress, NkQuote, NkRadio, NkSectionLabel, NkSegmented, NkSelect, NkSettingsPane, NkSettingsUser, NkSidebar, NkSkeleton, NkSlider, NkStat, NkStats, NkSwitch, NkSynced, NkTab, NkTabBar, NkTabBarItem, NkTableView, NkTabs, NkTag, NkTemplateBtn, NkTextarea, NkThemeToggle, NkToast, NkTodo, NkToggle, NkTopbar, NkTree, NkTreeItem, NkWorkspaceSwitcher, compareBy, renderPropertyCell, tagFor };
5690
+ export { NkAiInputRow, NkAiMsg, NkAiThread, NkApp, NkAvatar, NkAvatarGroup, NkBanner, NkBlockHost, NkBoardView, NkBreadcrumb, NkBtn, NkCallout, NkCheck, NkCmdk, NkCode, NkComment, NkComments, NkDangerZone, NkDatabase, NkDivider, NkElement, NkEmojiPicker, NkEmpty, NkField, NkFields, NkFilterBar, NkFormElement, NkHeading, NkInput, NkKbd, NkListView, NkMemberList, NkMemberRow, NkMention, NkMenu, NkMenuItem, NkModal, NkModelCard, NkPage, NkPageActions, NkPageCover, NkPageTitle, NkPanel, NkPanels, NkPop, NkProfileRow, NkProgress, NkProp, NkProps, NkQuote, NkRadio, NkSectionLabel, NkSegmented, NkSelect, NkSettingsPane, NkSettingsUser, NkSheet, NkSidebar, NkSkeleton, NkSlider, NkStat, NkStats, NkSteps, NkSwitch, NkSynced, NkTab, NkTabBar, NkTabBarItem, NkTableView, NkTabs, NkTag, NkTemplateBtn, NkTextarea, NkThemeToggle, NkToast, NkTodo, NkToggle, NkTopbar, NkTree, NkTreeItem, NkWorkspaceSwitcher, compareBy, componentsSheet, renderPropertyCell, tagFor };